1//===--- ObjCRuntime.h - Objective-C Runtime Configuration ------*- C++ -*-===//
2//
3//                     The LLVM Compiler Infrastructure
4//
5// This file is distributed under the University of Illinois Open Source
6// License. See LICENSE.TXT for details.
7//
8//===----------------------------------------------------------------------===//
9///
10/// \file
11/// \brief Defines types useful for describing an Objective-C runtime.
12///
13//===----------------------------------------------------------------------===//
14
15#ifndef LLVM_CLANG_OBJCRUNTIME_H
16#define LLVM_CLANG_OBJCRUNTIME_H
17
18#include "clang/Basic/VersionTuple.h"
19#include "llvm/ADT/Triple.h"
20#include "llvm/Support/ErrorHandling.h"
21
22namespace clang {
23
24/// \brief The basic abstraction for the target Objective-C runtime.
25class ObjCRuntime {
26public:
27  /// \brief The basic Objective-C runtimes that we know about.
28  enum Kind {
29    /// 'macosx' is the Apple-provided NeXT-derived runtime on Mac OS
30    /// X platforms that use the non-fragile ABI; the version is a
31    /// release of that OS.
32    MacOSX,
33
34    /// 'macosx-fragile' is the Apple-provided NeXT-derived runtime on
35    /// Mac OS X platforms that use the fragile ABI; the version is a
36    /// release of that OS.
37    FragileMacOSX,
38
39    /// 'ios' is the Apple-provided NeXT-derived runtime on iOS or the iOS
40    /// simulator;  it is always non-fragile.  The version is a release
41    /// version of iOS.
42    iOS,
43
44    /// 'gcc' is the Objective-C runtime shipped with GCC, implementing a
45    /// fragile Objective-C ABI
46    GCC,
47
48    /// 'gnustep' is the modern non-fragile GNUstep runtime.
49    GNUstep,
50
51    /// 'objfw' is the Objective-C runtime included in ObjFW
52    ObjFW
53  };
54
55private:
56  Kind TheKind;
57  VersionTuple Version;
58
59public:
60  /// A bogus initialization of the runtime.
61  ObjCRuntime() : TheKind(MacOSX) {}
62
63  ObjCRuntime(Kind kind, const VersionTuple &version)
64    : TheKind(kind), Version(version) {}
65
66  void set(Kind kind, VersionTuple version) {
67    TheKind = kind;
68    Version = version;
69  }
70
71  Kind getKind() const { return TheKind; }
72  const VersionTuple &getVersion() const { return Version; }
73
74  /// \brief Does this runtime follow the set of implied behaviors for a
75  /// "non-fragile" ABI?
76  bool isNonFragile() const {
77    switch (getKind()) {
78    case FragileMacOSX: return false;
79    case GCC: return false;
80    case MacOSX: return true;
81    case GNUstep: return true;
82    case ObjFW: return false;
83    case iOS: return true;
84    }
85    llvm_unreachable("bad kind");
86  }
87
88  /// The inverse of isNonFragile():  does this runtime follow the set of
89  /// implied behaviors for a "fragile" ABI?
90  bool isFragile() const { return !isNonFragile(); }
91
92  /// The default dispatch mechanism to use for the specified architecture
93  bool isLegacyDispatchDefaultForArch(llvm::Triple::ArchType Arch) {
94    // The GNUstep runtime uses a newer dispatch method by default from
95    // version 1.6 onwards
96    if (getKind() == GNUstep && getVersion() >= VersionTuple(1, 6)) {
97      if (Arch == llvm::Triple::arm ||
98          Arch == llvm::Triple::x86 ||
99          Arch == llvm::Triple::x86_64)
100        return false;
101      // Mac runtimes use legacy dispatch everywhere except x86-64
102    } else if (isNeXTFamily() && isNonFragile())
103        return Arch != llvm::Triple::x86_64;
104    return true;
105  }
106
107  /// \brief Is this runtime basically of the GNUstep family of runtimes?
108  bool isGNUFamily() const {
109    switch (getKind()) {
110    case FragileMacOSX:
111    case MacOSX:
112    case iOS:
113      return false;
114    case GCC:
115    case GNUstep:
116    case ObjFW:
117      return true;
118    }
119    llvm_unreachable("bad kind");
120  }
121
122  /// \brief Is this runtime basically of the NeXT family of runtimes?
123  bool isNeXTFamily() const {
124    // For now, this is just the inverse of isGNUFamily(), but that's
125    // not inherently true.
126    return !isGNUFamily();
127  }
128
129  /// \brief Does this runtime allow ARC at all?
130  bool allowsARC() const {
131    switch (getKind()) {
132    case FragileMacOSX: return false;
133    case MacOSX: return true;
134    case iOS: return true;
135    case GCC: return false;
136    case GNUstep: return true;
137    case ObjFW: return true;
138    }
139    llvm_unreachable("bad kind");
140  }
141
142  /// \brief Does this runtime natively provide the ARC entrypoints?
143  ///
144  /// ARC cannot be directly supported on a platform that does not provide
145  /// these entrypoints, although it may be supportable via a stub
146  /// library.
147  bool hasNativeARC() const {
148    switch (getKind()) {
149    case FragileMacOSX: return false;
150    case MacOSX: return getVersion() >= VersionTuple(10, 7);
151    case iOS: return getVersion() >= VersionTuple(5);
152
153    case GCC: return false;
154    case GNUstep: return getVersion() >= VersionTuple(1, 6);
155    case ObjFW: return true;
156    }
157    llvm_unreachable("bad kind");
158  }
159
160  /// Does this runtime allow the use of __weak?
161  bool allowsWeak() const {
162    return hasNativeWeak();
163  }
164
165  /// \brief Does this runtime natively provide ARC-compliant 'weak'
166  /// entrypoints?
167  bool hasNativeWeak() const {
168    // Right now, this is always equivalent to whether the runtime
169    // natively supports ARC decision.
170    return hasNativeARC();
171  }
172
173  /// \brief Does this runtime directly support the subscripting methods?
174  ///
175  /// This is really a property of the library, not the runtime.
176  bool hasSubscripting() const {
177    switch (getKind()) {
178    case FragileMacOSX: return false;
179    case MacOSX: return getVersion() >= VersionTuple(10, 8);
180    case iOS: return false;
181
182    // This is really a lie, because some implementations and versions
183    // of the runtime do not support ARC.  Probably -fgnu-runtime
184    // should imply a "maximal" runtime or something?
185    case GCC: return true;
186    case GNUstep: return true;
187    case ObjFW: return true;
188    }
189    llvm_unreachable("bad kind");
190  }
191
192  /// \brief Does this runtime allow sizeof or alignof on object types?
193  bool allowsSizeofAlignof() const {
194    return isFragile();
195  }
196
197  /// \brief Does this runtime allow pointer arithmetic on objects?
198  ///
199  /// This covers +, -, ++, --, and (if isSubscriptPointerArithmetic()
200  /// yields true) [].
201  bool allowsPointerArithmetic() const {
202    switch (getKind()) {
203    case FragileMacOSX:
204    case GCC:
205      return true;
206    case MacOSX:
207    case iOS:
208    case GNUstep:
209    case ObjFW:
210      return false;
211    }
212    llvm_unreachable("bad kind");
213  }
214
215  /// \brief Is subscripting pointer arithmetic?
216  bool isSubscriptPointerArithmetic() const {
217    return allowsPointerArithmetic();
218  }
219
220  /// \brief Does this runtime provide an objc_terminate function?
221  ///
222  /// This is used in handlers for exceptions during the unwind process;
223  /// without it, abort() must be used in pure ObjC files.
224  bool hasTerminate() const {
225    switch (getKind()) {
226    case FragileMacOSX: return getVersion() >= VersionTuple(10, 8);
227    case MacOSX: return getVersion() >= VersionTuple(10, 8);
228    case iOS: return getVersion() >= VersionTuple(5);
229    case GCC: return false;
230    case GNUstep: return false;
231    case ObjFW: return false;
232    }
233    llvm_unreachable("bad kind");
234  }
235
236  /// \brief Does this runtime support weakly importing classes?
237  bool hasWeakClassImport() const {
238    switch (getKind()) {
239    case MacOSX: return true;
240    case iOS: return true;
241    case FragileMacOSX: return false;
242    case GCC: return true;
243    case GNUstep: return true;
244    case ObjFW: return true;
245    }
246    llvm_unreachable("bad kind");
247  }
248
249  /// \brief Does this runtime use zero-cost exceptions?
250  bool hasUnwindExceptions() const {
251    switch (getKind()) {
252    case MacOSX: return true;
253    case iOS: return true;
254    case FragileMacOSX: return false;
255    case GCC: return true;
256    case GNUstep: return true;
257    case ObjFW: return true;
258    }
259    llvm_unreachable("bad kind");
260  }
261
262  /// \brief Try to parse an Objective-C runtime specification from the given
263  /// string.
264  ///
265  /// \return true on error.
266  bool tryParse(StringRef input);
267
268  std::string getAsString() const;
269
270  friend bool operator==(const ObjCRuntime &left, const ObjCRuntime &right) {
271    return left.getKind() == right.getKind() &&
272           left.getVersion() == right.getVersion();
273  }
274
275  friend bool operator!=(const ObjCRuntime &left, const ObjCRuntime &right) {
276    return !(left == right);
277  }
278};
279
280raw_ostream &operator<<(raw_ostream &out, const ObjCRuntime &value);
281
282}  // end namespace clang
283
284#endif
285