DeclarationName.h revision 6bcf27bb9a4b5c3f79cb44c0e4654a6d7619ad89
1//===-- DeclarationName.h - Representation of declaration names -*- 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// This file declares the DeclarationName and DeclarationNameTable classes.
11//
12//===----------------------------------------------------------------------===//
13#ifndef LLVM_CLANG_AST_DECLARATIONNAME_H
14#define LLVM_CLANG_AST_DECLARATIONNAME_H
15
16#include "clang/Basic/IdentifierTable.h"
17#include "clang/Basic/PartialDiagnostic.h"
18#include "llvm/Support/Compiler.h"
19
20namespace llvm {
21  template <typename T> struct DenseMapInfo;
22}
23
24namespace clang {
25  class ASTContext;
26  class CXXLiteralOperatorIdName;
27  class CXXOperatorIdName;
28  class CXXSpecialName;
29  class DeclarationNameExtra;
30  class IdentifierInfo;
31  class MultiKeywordSelector;
32  enum OverloadedOperatorKind : int;
33  class QualType;
34  class Type;
35  class TypeSourceInfo;
36  class UsingDirectiveDecl;
37
38  template <typename> class CanQual;
39  typedef CanQual<Type> CanQualType;
40
41/// DeclarationName - The name of a declaration. In the common case,
42/// this just stores an IdentifierInfo pointer to a normal
43/// name. However, it also provides encodings for Objective-C
44/// selectors (optimizing zero- and one-argument selectors, which make
45/// up 78% percent of all selectors in Cocoa.h) and special C++ names
46/// for constructors, destructors, and conversion functions.
47class DeclarationName {
48public:
49  /// NameKind - The kind of name this object contains.
50  enum NameKind {
51    Identifier,
52    ObjCZeroArgSelector,
53    ObjCOneArgSelector,
54    ObjCMultiArgSelector,
55    CXXConstructorName,
56    CXXDestructorName,
57    CXXConversionFunctionName,
58    CXXOperatorName,
59    CXXLiteralOperatorName,
60    CXXUsingDirective
61  };
62
63private:
64  /// StoredNameKind - The kind of name that is actually stored in the
65  /// upper bits of the Ptr field. This is only used internally.
66  ///
67  /// Note: The entries here are synchronized with the entries in Selector,
68  /// for efficient translation between the two.
69  enum StoredNameKind {
70    StoredIdentifier = 0,
71    StoredObjCZeroArgSelector = 0x01,
72    StoredObjCOneArgSelector = 0x02,
73    StoredDeclarationNameExtra = 0x03,
74    PtrMask = 0x03
75  };
76
77  /// Ptr - The lowest two bits are used to express what kind of name
78  /// we're actually storing, using the values of NameKind. Depending
79  /// on the kind of name this is, the upper bits of Ptr may have one
80  /// of several different meanings:
81  ///
82  ///   StoredIdentifier - The name is a normal identifier, and Ptr is
83  ///   a normal IdentifierInfo pointer.
84  ///
85  ///   StoredObjCZeroArgSelector - The name is an Objective-C
86  ///   selector with zero arguments, and Ptr is an IdentifierInfo
87  ///   pointer pointing to the selector name.
88  ///
89  ///   StoredObjCOneArgSelector - The name is an Objective-C selector
90  ///   with one argument, and Ptr is an IdentifierInfo pointer
91  ///   pointing to the selector name.
92  ///
93  ///   StoredDeclarationNameExtra - Ptr is actually a pointer to a
94  ///   DeclarationNameExtra structure, whose first value will tell us
95  ///   whether this is an Objective-C selector, C++ operator-id name,
96  ///   or special C++ name.
97  uintptr_t Ptr;
98
99  /// getStoredNameKind - Return the kind of object that is stored in
100  /// Ptr.
101  StoredNameKind getStoredNameKind() const {
102    return static_cast<StoredNameKind>(Ptr & PtrMask);
103  }
104
105  /// getExtra - Get the "extra" information associated with this
106  /// multi-argument selector or C++ special name.
107  DeclarationNameExtra *getExtra() const {
108    assert(getStoredNameKind() == StoredDeclarationNameExtra &&
109           "Declaration name does not store an Extra structure");
110    return reinterpret_cast<DeclarationNameExtra *>(Ptr & ~PtrMask);
111  }
112
113  /// getAsCXXSpecialName - If the stored pointer is actually a
114  /// CXXSpecialName, returns a pointer to it. Otherwise, returns
115  /// a NULL pointer.
116  CXXSpecialName *getAsCXXSpecialName() const {
117    NameKind Kind = getNameKind();
118    if (Kind >= CXXConstructorName && Kind <= CXXConversionFunctionName)
119      return reinterpret_cast<CXXSpecialName *>(Ptr & ~PtrMask);
120    return nullptr;
121  }
122
123  /// getAsCXXOperatorIdName
124  CXXOperatorIdName *getAsCXXOperatorIdName() const {
125    if (getNameKind() == CXXOperatorName)
126      return reinterpret_cast<CXXOperatorIdName *>(Ptr & ~PtrMask);
127    return nullptr;
128  }
129
130  CXXLiteralOperatorIdName *getAsCXXLiteralOperatorIdName() const {
131    if (getNameKind() == CXXLiteralOperatorName)
132      return reinterpret_cast<CXXLiteralOperatorIdName *>(Ptr & ~PtrMask);
133    return nullptr;
134  }
135
136  // Construct a declaration name from the name of a C++ constructor,
137  // destructor, or conversion function.
138  DeclarationName(CXXSpecialName *Name)
139    : Ptr(reinterpret_cast<uintptr_t>(Name)) {
140    assert((Ptr & PtrMask) == 0 && "Improperly aligned CXXSpecialName");
141    Ptr |= StoredDeclarationNameExtra;
142  }
143
144  // Construct a declaration name from the name of a C++ overloaded
145  // operator.
146  DeclarationName(CXXOperatorIdName *Name)
147    : Ptr(reinterpret_cast<uintptr_t>(Name)) {
148    assert((Ptr & PtrMask) == 0 && "Improperly aligned CXXOperatorId");
149    Ptr |= StoredDeclarationNameExtra;
150  }
151
152  DeclarationName(CXXLiteralOperatorIdName *Name)
153    : Ptr(reinterpret_cast<uintptr_t>(Name)) {
154    assert((Ptr & PtrMask) == 0 && "Improperly aligned CXXLiteralOperatorId");
155    Ptr |= StoredDeclarationNameExtra;
156  }
157
158  /// Construct a declaration name from a raw pointer.
159  DeclarationName(uintptr_t Ptr) : Ptr(Ptr) { }
160
161  friend class DeclarationNameTable;
162  friend class NamedDecl;
163
164  /// getFETokenInfoAsVoidSlow - Retrieves the front end-specified pointer
165  /// for this name as a void pointer if it's not an identifier.
166  void *getFETokenInfoAsVoidSlow() const;
167
168public:
169  /// DeclarationName - Used to create an empty selector.
170  DeclarationName() : Ptr(0) { }
171
172  // Construct a declaration name from an IdentifierInfo *.
173  DeclarationName(const IdentifierInfo *II)
174    : Ptr(reinterpret_cast<uintptr_t>(II)) {
175    assert((Ptr & PtrMask) == 0 && "Improperly aligned IdentifierInfo");
176  }
177
178  // Construct a declaration name from an Objective-C selector.
179  DeclarationName(Selector Sel) : Ptr(Sel.InfoPtr) { }
180
181  /// getUsingDirectiveName - Return name for all using-directives.
182  static DeclarationName getUsingDirectiveName();
183
184  // operator bool() - Evaluates true when this declaration name is
185  // non-empty.
186  LLVM_EXPLICIT operator bool() const {
187    return ((Ptr & PtrMask) != 0) ||
188           (reinterpret_cast<IdentifierInfo *>(Ptr & ~PtrMask));
189  }
190
191  /// \brief Evaluates true when this declaration name is empty.
192  bool isEmpty() const {
193    return !*this;
194  }
195
196  /// Predicate functions for querying what type of name this is.
197  bool isIdentifier() const { return getStoredNameKind() == StoredIdentifier; }
198  bool isObjCZeroArgSelector() const {
199    return getStoredNameKind() == StoredObjCZeroArgSelector;
200  }
201  bool isObjCOneArgSelector() const {
202    return getStoredNameKind() == StoredObjCOneArgSelector;
203  }
204
205  /// getNameKind - Determine what kind of name this is.
206  NameKind getNameKind() const;
207
208  /// \brief Determines whether the name itself is dependent, e.g., because it
209  /// involves a C++ type that is itself dependent.
210  ///
211  /// Note that this does not capture all of the notions of "dependent name",
212  /// because an identifier can be a dependent name if it is used as the
213  /// callee in a call expression with dependent arguments.
214  bool isDependentName() const;
215
216  /// getNameAsString - Retrieve the human-readable string for this name.
217  std::string getAsString() const;
218
219  /// getAsIdentifierInfo - Retrieve the IdentifierInfo * stored in
220  /// this declaration name, or NULL if this declaration name isn't a
221  /// simple identifier.
222  IdentifierInfo *getAsIdentifierInfo() const {
223    if (isIdentifier())
224      return reinterpret_cast<IdentifierInfo *>(Ptr);
225    return nullptr;
226  }
227
228  /// getAsOpaqueInteger - Get the representation of this declaration
229  /// name as an opaque integer.
230  uintptr_t getAsOpaqueInteger() const { return Ptr; }
231
232  /// getAsOpaquePtr - Get the representation of this declaration name as
233  /// an opaque pointer.
234  void *getAsOpaquePtr() const { return reinterpret_cast<void*>(Ptr); }
235
236  static DeclarationName getFromOpaquePtr(void *P) {
237    DeclarationName N;
238    N.Ptr = reinterpret_cast<uintptr_t> (P);
239    return N;
240  }
241
242  static DeclarationName getFromOpaqueInteger(uintptr_t P) {
243    DeclarationName N;
244    N.Ptr = P;
245    return N;
246  }
247
248  /// getCXXNameType - If this name is one of the C++ names (of a
249  /// constructor, destructor, or conversion function), return the
250  /// type associated with that name.
251  QualType getCXXNameType() const;
252
253  /// getCXXOverloadedOperator - If this name is the name of an
254  /// overloadable operator in C++ (e.g., @c operator+), retrieve the
255  /// kind of overloaded operator.
256  OverloadedOperatorKind getCXXOverloadedOperator() const;
257
258  /// getCXXLiteralIdentifier - If this name is the name of a literal
259  /// operator, retrieve the identifier associated with it.
260  IdentifierInfo *getCXXLiteralIdentifier() const;
261
262  /// getObjCSelector - Get the Objective-C selector stored in this
263  /// declaration name.
264  Selector getObjCSelector() const {
265    assert((getNameKind() == ObjCZeroArgSelector ||
266            getNameKind() == ObjCOneArgSelector ||
267            getNameKind() == ObjCMultiArgSelector ||
268            Ptr == 0) && "Not a selector!");
269    return Selector(Ptr);
270  }
271
272  /// getFETokenInfo/setFETokenInfo - The language front-end is
273  /// allowed to associate arbitrary metadata with some kinds of
274  /// declaration names, including normal identifiers and C++
275  /// constructors, destructors, and conversion functions.
276  template<typename T>
277  T *getFETokenInfo() const {
278    if (const IdentifierInfo *Info = getAsIdentifierInfo())
279      return Info->getFETokenInfo<T>();
280    return static_cast<T*>(getFETokenInfoAsVoidSlow());
281  }
282
283  void setFETokenInfo(void *T);
284
285  /// operator== - Determine whether the specified names are identical..
286  friend bool operator==(DeclarationName LHS, DeclarationName RHS) {
287    return LHS.Ptr == RHS.Ptr;
288  }
289
290  /// operator!= - Determine whether the specified names are different.
291  friend bool operator!=(DeclarationName LHS, DeclarationName RHS) {
292    return LHS.Ptr != RHS.Ptr;
293  }
294
295  static DeclarationName getEmptyMarker() {
296    return DeclarationName(uintptr_t(-1));
297  }
298
299  static DeclarationName getTombstoneMarker() {
300    return DeclarationName(uintptr_t(-2));
301  }
302
303  static int compare(DeclarationName LHS, DeclarationName RHS);
304
305  void dump() const;
306};
307
308raw_ostream &operator<<(raw_ostream &OS, DeclarationName N);
309
310/// Ordering on two declaration names. If both names are identifiers,
311/// this provides a lexicographical ordering.
312inline bool operator<(DeclarationName LHS, DeclarationName RHS) {
313  return DeclarationName::compare(LHS, RHS) < 0;
314}
315
316/// Ordering on two declaration names. If both names are identifiers,
317/// this provides a lexicographical ordering.
318inline bool operator>(DeclarationName LHS, DeclarationName RHS) {
319  return DeclarationName::compare(LHS, RHS) > 0;
320}
321
322/// Ordering on two declaration names. If both names are identifiers,
323/// this provides a lexicographical ordering.
324inline bool operator<=(DeclarationName LHS, DeclarationName RHS) {
325  return DeclarationName::compare(LHS, RHS) <= 0;
326}
327
328/// Ordering on two declaration names. If both names are identifiers,
329/// this provides a lexicographical ordering.
330inline bool operator>=(DeclarationName LHS, DeclarationName RHS) {
331  return DeclarationName::compare(LHS, RHS) >= 0;
332}
333
334/// DeclarationNameTable - Used to store and retrieve DeclarationName
335/// instances for the various kinds of declaration names, e.g., normal
336/// identifiers, C++ constructor names, etc. This class contains
337/// uniqued versions of each of the C++ special names, which can be
338/// retrieved using its member functions (e.g.,
339/// getCXXConstructorName).
340class DeclarationNameTable {
341  const ASTContext &Ctx;
342  void *CXXSpecialNamesImpl; // Actually a FoldingSet<CXXSpecialName> *
343  CXXOperatorIdName *CXXOperatorNames; // Operator names
344  void *CXXLiteralOperatorNames; // Actually a CXXOperatorIdName*
345
346  DeclarationNameTable(const DeclarationNameTable&) LLVM_DELETED_FUNCTION;
347  void operator=(const DeclarationNameTable&) LLVM_DELETED_FUNCTION;
348
349public:
350  DeclarationNameTable(const ASTContext &C);
351  ~DeclarationNameTable();
352
353  /// getIdentifier - Create a declaration name that is a simple
354  /// identifier.
355  DeclarationName getIdentifier(const IdentifierInfo *ID) {
356    return DeclarationName(ID);
357  }
358
359  /// getCXXConstructorName - Returns the name of a C++ constructor
360  /// for the given Type.
361  DeclarationName getCXXConstructorName(CanQualType Ty);
362
363  /// getCXXDestructorName - Returns the name of a C++ destructor
364  /// for the given Type.
365  DeclarationName getCXXDestructorName(CanQualType Ty);
366
367  /// getCXXConversionFunctionName - Returns the name of a C++
368  /// conversion function for the given Type.
369  DeclarationName getCXXConversionFunctionName(CanQualType Ty);
370
371  /// getCXXSpecialName - Returns a declaration name for special kind
372  /// of C++ name, e.g., for a constructor, destructor, or conversion
373  /// function.
374  DeclarationName getCXXSpecialName(DeclarationName::NameKind Kind,
375                                    CanQualType Ty);
376
377  /// getCXXOperatorName - Get the name of the overloadable C++
378  /// operator corresponding to Op.
379  DeclarationName getCXXOperatorName(OverloadedOperatorKind Op);
380
381  /// getCXXLiteralOperatorName - Get the name of the literal operator function
382  /// with II as the identifier.
383  DeclarationName getCXXLiteralOperatorName(IdentifierInfo *II);
384};
385
386/// DeclarationNameLoc - Additional source/type location info
387/// for a declaration name. Needs a DeclarationName in order
388/// to be interpreted correctly.
389struct DeclarationNameLoc {
390  // The source location for identifier stored elsewhere.
391  // struct {} Identifier;
392
393  // Type info for constructors, destructors and conversion functions.
394  // Locations (if any) for the tilde (destructor) or operator keyword
395  // (conversion) are stored elsewhere.
396  struct NT {
397    TypeSourceInfo* TInfo;
398  };
399
400  // The location (if any) of the operator keyword is stored elsewhere.
401  struct CXXOpName {
402    unsigned BeginOpNameLoc;
403    unsigned EndOpNameLoc;
404  };
405
406  // The location (if any) of the operator keyword is stored elsewhere.
407  struct CXXLitOpName {
408    unsigned OpNameLoc;
409  };
410
411  // struct {} CXXUsingDirective;
412  // struct {} ObjCZeroArgSelector;
413  // struct {} ObjCOneArgSelector;
414  // struct {} ObjCMultiArgSelector;
415  union {
416    struct NT NamedType;
417    struct CXXOpName CXXOperatorName;
418    struct CXXLitOpName CXXLiteralOperatorName;
419  };
420
421  DeclarationNameLoc(DeclarationName Name);
422  // FIXME: this should go away once all DNLocs are properly initialized.
423  DeclarationNameLoc() { memset((void*) this, 0, sizeof(*this)); }
424}; // struct DeclarationNameLoc
425
426
427/// DeclarationNameInfo - A collector data type for bundling together
428/// a DeclarationName and the correspnding source/type location info.
429struct DeclarationNameInfo {
430private:
431  /// Name - The declaration name, also encoding name kind.
432  DeclarationName Name;
433  /// Loc - The main source location for the declaration name.
434  SourceLocation NameLoc;
435  /// Info - Further source/type location info for special kinds of names.
436  DeclarationNameLoc LocInfo;
437
438public:
439  // FIXME: remove it.
440  DeclarationNameInfo() {}
441
442  DeclarationNameInfo(DeclarationName Name, SourceLocation NameLoc)
443    : Name(Name), NameLoc(NameLoc), LocInfo(Name) {}
444
445  DeclarationNameInfo(DeclarationName Name, SourceLocation NameLoc,
446                      DeclarationNameLoc LocInfo)
447    : Name(Name), NameLoc(NameLoc), LocInfo(LocInfo) {}
448
449  /// getName - Returns the embedded declaration name.
450  DeclarationName getName() const { return Name; }
451  /// setName - Sets the embedded declaration name.
452  void setName(DeclarationName N) { Name = N; }
453
454  /// getLoc - Returns the main location of the declaration name.
455  SourceLocation getLoc() const { return NameLoc; }
456  /// setLoc - Sets the main location of the declaration name.
457  void setLoc(SourceLocation L) { NameLoc = L; }
458
459  const DeclarationNameLoc &getInfo() const { return LocInfo; }
460  DeclarationNameLoc &getInfo() { return LocInfo; }
461  void setInfo(const DeclarationNameLoc &Info) { LocInfo = Info; }
462
463  /// getNamedTypeInfo - Returns the source type info associated to
464  /// the name. Assumes it is a constructor, destructor or conversion.
465  TypeSourceInfo *getNamedTypeInfo() const {
466    assert(Name.getNameKind() == DeclarationName::CXXConstructorName ||
467           Name.getNameKind() == DeclarationName::CXXDestructorName ||
468           Name.getNameKind() == DeclarationName::CXXConversionFunctionName);
469    return LocInfo.NamedType.TInfo;
470  }
471  /// setNamedTypeInfo - Sets the source type info associated to
472  /// the name. Assumes it is a constructor, destructor or conversion.
473  void setNamedTypeInfo(TypeSourceInfo *TInfo) {
474    assert(Name.getNameKind() == DeclarationName::CXXConstructorName ||
475           Name.getNameKind() == DeclarationName::CXXDestructorName ||
476           Name.getNameKind() == DeclarationName::CXXConversionFunctionName);
477    LocInfo.NamedType.TInfo = TInfo;
478  }
479
480  /// getCXXOperatorNameRange - Gets the range of the operator name
481  /// (without the operator keyword). Assumes it is a (non-literal) operator.
482  SourceRange getCXXOperatorNameRange() const {
483    assert(Name.getNameKind() == DeclarationName::CXXOperatorName);
484    return SourceRange(
485     SourceLocation::getFromRawEncoding(LocInfo.CXXOperatorName.BeginOpNameLoc),
486     SourceLocation::getFromRawEncoding(LocInfo.CXXOperatorName.EndOpNameLoc)
487                       );
488  }
489  /// setCXXOperatorNameRange - Sets the range of the operator name
490  /// (without the operator keyword). Assumes it is a C++ operator.
491  void setCXXOperatorNameRange(SourceRange R) {
492    assert(Name.getNameKind() == DeclarationName::CXXOperatorName);
493    LocInfo.CXXOperatorName.BeginOpNameLoc = R.getBegin().getRawEncoding();
494    LocInfo.CXXOperatorName.EndOpNameLoc = R.getEnd().getRawEncoding();
495  }
496
497  /// getCXXLiteralOperatorNameLoc - Returns the location of the literal
498  /// operator name (not the operator keyword).
499  /// Assumes it is a literal operator.
500  SourceLocation getCXXLiteralOperatorNameLoc() const {
501    assert(Name.getNameKind() == DeclarationName::CXXLiteralOperatorName);
502    return SourceLocation::
503      getFromRawEncoding(LocInfo.CXXLiteralOperatorName.OpNameLoc);
504  }
505  /// setCXXLiteralOperatorNameLoc - Sets the location of the literal
506  /// operator name (not the operator keyword).
507  /// Assumes it is a literal operator.
508  void setCXXLiteralOperatorNameLoc(SourceLocation Loc) {
509    assert(Name.getNameKind() == DeclarationName::CXXLiteralOperatorName);
510    LocInfo.CXXLiteralOperatorName.OpNameLoc = Loc.getRawEncoding();
511  }
512
513  /// \brief Determine whether this name involves a template parameter.
514  bool isInstantiationDependent() const;
515
516  /// \brief Determine whether this name contains an unexpanded
517  /// parameter pack.
518  bool containsUnexpandedParameterPack() const;
519
520  /// getAsString - Retrieve the human-readable string for this name.
521  std::string getAsString() const;
522
523  /// printName - Print the human-readable name to a stream.
524  void printName(raw_ostream &OS) const;
525
526  /// getBeginLoc - Retrieve the location of the first token.
527  SourceLocation getBeginLoc() const { return NameLoc; }
528  /// getEndLoc - Retrieve the location of the last token.
529  SourceLocation getEndLoc() const;
530  /// getSourceRange - The range of the declaration name.
531  SourceRange getSourceRange() const LLVM_READONLY {
532    return SourceRange(getLocStart(), getLocEnd());
533  }
534  SourceLocation getLocStart() const LLVM_READONLY {
535    return getBeginLoc();
536  }
537  SourceLocation getLocEnd() const LLVM_READONLY {
538    SourceLocation EndLoc = getEndLoc();
539    return EndLoc.isValid() ? EndLoc : getLocStart();
540  }
541};
542
543/// Insertion operator for diagnostics.  This allows sending DeclarationName's
544/// into a diagnostic with <<.
545inline const DiagnosticBuilder &operator<<(const DiagnosticBuilder &DB,
546                                           DeclarationName N) {
547  DB.AddTaggedVal(N.getAsOpaqueInteger(),
548                  DiagnosticsEngine::ak_declarationname);
549  return DB;
550}
551
552/// Insertion operator for partial diagnostics.  This allows binding
553/// DeclarationName's into a partial diagnostic with <<.
554inline const PartialDiagnostic &operator<<(const PartialDiagnostic &PD,
555                                           DeclarationName N) {
556  PD.AddTaggedVal(N.getAsOpaqueInteger(),
557                  DiagnosticsEngine::ak_declarationname);
558  return PD;
559}
560
561inline raw_ostream &operator<<(raw_ostream &OS,
562                                     DeclarationNameInfo DNInfo) {
563  DNInfo.printName(OS);
564  return OS;
565}
566
567}  // end namespace clang
568
569namespace llvm {
570/// Define DenseMapInfo so that DeclarationNames can be used as keys
571/// in DenseMap and DenseSets.
572template<>
573struct DenseMapInfo<clang::DeclarationName> {
574  static inline clang::DeclarationName getEmptyKey() {
575    return clang::DeclarationName::getEmptyMarker();
576  }
577
578  static inline clang::DeclarationName getTombstoneKey() {
579    return clang::DeclarationName::getTombstoneMarker();
580  }
581
582  static unsigned getHashValue(clang::DeclarationName Name) {
583    return DenseMapInfo<void*>::getHashValue(Name.getAsOpaquePtr());
584  }
585
586  static inline bool
587  isEqual(clang::DeclarationName LHS, clang::DeclarationName RHS) {
588    return LHS == RHS;
589  }
590};
591
592template <>
593struct isPodLike<clang::DeclarationName> { static const bool value = true; };
594
595}  // end namespace llvm
596
597#endif
598