diff options
author | Guy Benyei <guy.benyei@intel.com> | 2012-12-18 12:30:03 +0000 |
---|---|---|
committer | Guy Benyei <guy.benyei@intel.com> | 2012-12-18 12:30:03 +0000 |
commit | b13abb952a99d74c6464ab5360bae635365ff8ff (patch) | |
tree | 73d912f69bd6eabad9cd99b82d2b5f659259b77c | |
parent | 42230ae21618d4d9406f2b8a130309246c7a7a12 (diff) | |
download | bcm5719-llvm-b13abb952a99d74c6464ab5360bae635365ff8ff.tar.gz bcm5719-llvm-b13abb952a99d74c6464ab5360bae635365ff8ff.zip |
Add OpenCL images as clang builtin types.
llvm-svn: 170428
33 files changed, 28202 insertions, 27793 deletions
diff --git a/clang/include/clang/AST/ASTContext.h b/clang/include/clang/AST/ASTContext.h index 86b2c42f851..d750ba948d1 100644 --- a/clang/include/clang/AST/ASTContext.h +++ b/clang/include/clang/AST/ASTContext.h @@ -716,6 +716,9 @@ public: CanQualType PseudoObjectTy, ARCUnbridgedCastTy; CanQualType ObjCBuiltinIdTy, ObjCBuiltinClassTy, ObjCBuiltinSelTy; CanQualType ObjCBuiltinBoolTy; + CanQualType OCLImage1dTy, OCLImage1dArrayTy, OCLImage1dBufferTy; + CanQualType OCLImage2dTy, OCLImage2dArrayTy; + CanQualType OCLImage3dTy; // Types for deductions in C++0x [stmt.ranged]'s desugaring. Built on demand. mutable QualType AutoDeductTy; // Deduction against 'auto'. diff --git a/clang/include/clang/AST/BuiltinTypes.def b/clang/include/clang/AST/BuiltinTypes.def index ba322fb3265..75ebb2c5a5e 100644 --- a/clang/include/clang/AST/BuiltinTypes.def +++ b/clang/include/clang/AST/BuiltinTypes.def @@ -1,226 +1,234 @@ -//===-- BuiltinTypeNodes.def - Metadata about BuiltinTypes ------*- C++ -*-===// -// -// The LLVM Compiler Infrastructure -// -// This file is distributed under the University of Illinois Open Source -// License. See LICENSE.TXT for details. -// -//===----------------------------------------------------------------------===// -// -// This file defines the database about various builtin singleton types. -// -// BuiltinType::Id is the enumerator defining the type. -// -// Context.SingletonId is the global singleton of this type. Some global -// singletons are shared by multiple types. -// -// BUILTIN_TYPE(Id, SingletonId) - A builtin type that has not been -// covered by any other #define. Defining this macro covers all -// the builtins. -// -// SIGNED_TYPE(Id, SingletonId) - A signed integral type. -// -// UNSIGNED_TYPE(Id, SingletonId) - An unsigned integral type. -// -// FLOATING_TYPE(Id, SingletonId) - A floating-point type. -// -// PLACEHOLDER_TYPE(Id, SingletonId) - A placeholder type. Placeholder -// types are used to perform context-sensitive checking of specific -// forms of expression. -// -// SHARED_SINGLETON_TYPE(Expansion) - The given expansion corresponds -// to a builtin which uses a shared singleton type. -// -//===----------------------------------------------------------------------===// - -#ifndef SIGNED_TYPE -#define SIGNED_TYPE(Id, SingletonId) BUILTIN_TYPE(Id, SingletonId) -#endif - -#ifndef UNSIGNED_TYPE -#define UNSIGNED_TYPE(Id, SingletonId) BUILTIN_TYPE(Id, SingletonId) -#endif - -#ifndef FLOATING_TYPE -#define FLOATING_TYPE(Id, SingletonId) BUILTIN_TYPE(Id, SingletonId) -#endif - -#ifndef PLACEHOLDER_TYPE -#define PLACEHOLDER_TYPE(Id, SingletonId) BUILTIN_TYPE(Id, SingletonId) -#endif - -#ifndef SHARED_SINGLETON_TYPE -#define SHARED_SINGLETON_TYPE(Expansion) Expansion -#endif - -//===- Builtin Types ------------------------------------------------------===// - -// void -BUILTIN_TYPE(Void, VoidTy) - -//===- Unsigned Types -----------------------------------------------------===// - -// 'bool' in C++, '_Bool' in C99 -UNSIGNED_TYPE(Bool, BoolTy) - -// 'char' for targets where it's unsigned -SHARED_SINGLETON_TYPE(UNSIGNED_TYPE(Char_U, CharTy)) - -// 'unsigned char', explicitly qualified -UNSIGNED_TYPE(UChar, UnsignedCharTy) - -// 'wchar_t' for targets where it's unsigned -SHARED_SINGLETON_TYPE(UNSIGNED_TYPE(WChar_U, WCharTy)) - -// 'char16_t' in C++ -UNSIGNED_TYPE(Char16, Char16Ty) - -// 'char32_t' in C++ -UNSIGNED_TYPE(Char32, Char32Ty) - -// 'unsigned short' -UNSIGNED_TYPE(UShort, UnsignedShortTy) - -// 'unsigned int' -UNSIGNED_TYPE(UInt, UnsignedIntTy) - -// 'unsigned long' -UNSIGNED_TYPE(ULong, UnsignedLongTy) - -// 'unsigned long long' -UNSIGNED_TYPE(ULongLong, UnsignedLongLongTy) - -// '__uint128_t' -UNSIGNED_TYPE(UInt128, UnsignedInt128Ty) - -//===- Signed Types -------------------------------------------------------===// - -// 'char' for targets where it's signed -SHARED_SINGLETON_TYPE(SIGNED_TYPE(Char_S, CharTy)) - -// 'signed char', explicitly qualified -SIGNED_TYPE(SChar, SignedCharTy) - -// 'wchar_t' for targets where it's signed -SHARED_SINGLETON_TYPE(SIGNED_TYPE(WChar_S, WCharTy)) - -// 'short' or 'signed short' -SIGNED_TYPE(Short, ShortTy) - -// 'int' or 'signed int' -SIGNED_TYPE(Int, IntTy) - -// 'long' or 'signed long' -SIGNED_TYPE(Long, LongTy) - -// 'long long' or 'signed long long' -SIGNED_TYPE(LongLong, LongLongTy) - -// '__int128_t' -SIGNED_TYPE(Int128, Int128Ty) - -//===- Floating point types -----------------------------------------------===// - -// 'half' in OpenCL, '__fp16' in ARM NEON. -FLOATING_TYPE(Half, HalfTy) - -// 'float' -FLOATING_TYPE(Float, FloatTy) - -// 'double' -FLOATING_TYPE(Double, DoubleTy) - -// 'long double' -FLOATING_TYPE(LongDouble, LongDoubleTy) - -//===- Language-specific types --------------------------------------------===// - -// This is the type of C++0x 'nullptr'. -BUILTIN_TYPE(NullPtr, NullPtrTy) - -// The primitive Objective C 'id' type. The user-visible 'id' -// type is a typedef of an ObjCObjectPointerType to an -// ObjCObjectType with this as its base. In fact, this only ever -// shows up in an AST as the base type of an ObjCObjectType. -BUILTIN_TYPE(ObjCId, ObjCBuiltinIdTy) - -// The primitive Objective C 'Class' type. The user-visible -// 'Class' type is a typedef of an ObjCObjectPointerType to an -// ObjCObjectType with this as its base. In fact, this only ever -// shows up in an AST as the base type of an ObjCObjectType. -BUILTIN_TYPE(ObjCClass, ObjCBuiltinClassTy) - -// The primitive Objective C 'SEL' type. The user-visible 'SEL' -// type is a typedef of a PointerType to this. -BUILTIN_TYPE(ObjCSel, ObjCBuiltinSelTy) - -// This represents the type of an expression whose type is -// totally unknown, e.g. 'T::foo'. It is permitted for this to -// appear in situations where the structure of the type is -// theoretically deducible. -BUILTIN_TYPE(Dependent, DependentTy) - -// The type of an unresolved overload set. A placeholder type. -// Expressions with this type have one of the following basic -// forms, with parentheses generally permitted: -// foo # possibly qualified, not if an implicit access -// foo # possibly qualified, not if an implicit access -// &foo # possibly qualified, not if an implicit access -// x->foo # only if might be a static member function -// &x->foo # only if might be a static member function -// &Class::foo # when a pointer-to-member; sub-expr also has this type -// OverloadExpr::find can be used to analyze the expression. -// -// Overload should be the first placeholder type, or else change -// BuiltinType::isNonOverloadPlaceholderType() -PLACEHOLDER_TYPE(Overload, OverloadTy) - -// The type of a bound C++ non-static member function. -// A placeholder type. Expressions with this type have one of the -// following basic forms: -// foo # if an implicit access -// x->foo # if only contains non-static members -PLACEHOLDER_TYPE(BoundMember, BoundMemberTy) - -// The type of an expression which refers to a pseudo-object, -// such as those introduced by Objective C's @property or -// VS.NET's __property declarations. A placeholder type. The -// pseudo-object is actually accessed by emitting a call to -// some sort of function or method; typically there is a pair -// of a setter and a getter, with the setter used if the -// pseudo-object reference is used syntactically as the -// left-hand-side of an assignment operator. -// -// A pseudo-object reference naming an Objective-C @property is -// always a dot access with a base of object-pointer type, -// e.g. 'x.foo'. -// -// In VS.NET, a __property declaration creates an implicit -// member with an associated name, which can then be named -// in any of the normal ways an ordinary member could be. -PLACEHOLDER_TYPE(PseudoObject, PseudoObjectTy) - -// __builtin_any_type. A placeholder type. Useful for clients -// like debuggers that don't know what type to give something. -// Only a small number of operations are valid on expressions of -// unknown type, most notably explicit casts. -PLACEHOLDER_TYPE(UnknownAny, UnknownAnyTy) - -PLACEHOLDER_TYPE(BuiltinFn, BuiltinFnTy) - -// The type of a cast which, in ARC, would normally require a -// __bridge, but which might be okay depending on the immediate -// context. -PLACEHOLDER_TYPE(ARCUnbridgedCast, ARCUnbridgedCastTy) - -#ifdef LAST_BUILTIN_TYPE -LAST_BUILTIN_TYPE(ARCUnbridgedCast) -#undef LAST_BUILTIN_TYPE -#endif - -#undef SHARED_SINGLETON_TYPE -#undef PLACEHOLDER_TYPE -#undef FLOATING_TYPE -#undef SIGNED_TYPE -#undef UNSIGNED_TYPE -#undef BUILTIN_TYPE +//===-- BuiltinTypeNodes.def - Metadata about BuiltinTypes ------*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+//
+// This file defines the database about various builtin singleton types.
+//
+// BuiltinType::Id is the enumerator defining the type.
+//
+// Context.SingletonId is the global singleton of this type. Some global
+// singletons are shared by multiple types.
+//
+// BUILTIN_TYPE(Id, SingletonId) - A builtin type that has not been
+// covered by any other #define. Defining this macro covers all
+// the builtins.
+//
+// SIGNED_TYPE(Id, SingletonId) - A signed integral type.
+//
+// UNSIGNED_TYPE(Id, SingletonId) - An unsigned integral type.
+//
+// FLOATING_TYPE(Id, SingletonId) - A floating-point type.
+//
+// PLACEHOLDER_TYPE(Id, SingletonId) - A placeholder type. Placeholder
+// types are used to perform context-sensitive checking of specific
+// forms of expression.
+//
+// SHARED_SINGLETON_TYPE(Expansion) - The given expansion corresponds
+// to a builtin which uses a shared singleton type.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef SIGNED_TYPE
+#define SIGNED_TYPE(Id, SingletonId) BUILTIN_TYPE(Id, SingletonId)
+#endif
+
+#ifndef UNSIGNED_TYPE
+#define UNSIGNED_TYPE(Id, SingletonId) BUILTIN_TYPE(Id, SingletonId)
+#endif
+
+#ifndef FLOATING_TYPE
+#define FLOATING_TYPE(Id, SingletonId) BUILTIN_TYPE(Id, SingletonId)
+#endif
+
+#ifndef PLACEHOLDER_TYPE
+#define PLACEHOLDER_TYPE(Id, SingletonId) BUILTIN_TYPE(Id, SingletonId)
+#endif
+
+#ifndef SHARED_SINGLETON_TYPE
+#define SHARED_SINGLETON_TYPE(Expansion) Expansion
+#endif
+
+//===- Builtin Types ------------------------------------------------------===//
+
+// void
+BUILTIN_TYPE(Void, VoidTy)
+
+//===- Unsigned Types -----------------------------------------------------===//
+
+// 'bool' in C++, '_Bool' in C99
+UNSIGNED_TYPE(Bool, BoolTy)
+
+// 'char' for targets where it's unsigned
+SHARED_SINGLETON_TYPE(UNSIGNED_TYPE(Char_U, CharTy))
+
+// 'unsigned char', explicitly qualified
+UNSIGNED_TYPE(UChar, UnsignedCharTy)
+
+// 'wchar_t' for targets where it's unsigned
+SHARED_SINGLETON_TYPE(UNSIGNED_TYPE(WChar_U, WCharTy))
+
+// 'char16_t' in C++
+UNSIGNED_TYPE(Char16, Char16Ty)
+
+// 'char32_t' in C++
+UNSIGNED_TYPE(Char32, Char32Ty)
+
+// 'unsigned short'
+UNSIGNED_TYPE(UShort, UnsignedShortTy)
+
+// 'unsigned int'
+UNSIGNED_TYPE(UInt, UnsignedIntTy)
+
+// 'unsigned long'
+UNSIGNED_TYPE(ULong, UnsignedLongTy)
+
+// 'unsigned long long'
+UNSIGNED_TYPE(ULongLong, UnsignedLongLongTy)
+
+// '__uint128_t'
+UNSIGNED_TYPE(UInt128, UnsignedInt128Ty)
+
+//===- Signed Types -------------------------------------------------------===//
+
+// 'char' for targets where it's signed
+SHARED_SINGLETON_TYPE(SIGNED_TYPE(Char_S, CharTy))
+
+// 'signed char', explicitly qualified
+SIGNED_TYPE(SChar, SignedCharTy)
+
+// 'wchar_t' for targets where it's signed
+SHARED_SINGLETON_TYPE(SIGNED_TYPE(WChar_S, WCharTy))
+
+// 'short' or 'signed short'
+SIGNED_TYPE(Short, ShortTy)
+
+// 'int' or 'signed int'
+SIGNED_TYPE(Int, IntTy)
+
+// 'long' or 'signed long'
+SIGNED_TYPE(Long, LongTy)
+
+// 'long long' or 'signed long long'
+SIGNED_TYPE(LongLong, LongLongTy)
+
+// '__int128_t'
+SIGNED_TYPE(Int128, Int128Ty)
+
+//===- Floating point types -----------------------------------------------===//
+
+// 'half' in OpenCL, '__fp16' in ARM NEON.
+FLOATING_TYPE(Half, HalfTy)
+
+// 'float'
+FLOATING_TYPE(Float, FloatTy)
+
+// 'double'
+FLOATING_TYPE(Double, DoubleTy)
+
+// 'long double'
+FLOATING_TYPE(LongDouble, LongDoubleTy)
+
+//===- Language-specific types --------------------------------------------===//
+
+// This is the type of C++0x 'nullptr'.
+BUILTIN_TYPE(NullPtr, NullPtrTy)
+
+// The primitive Objective C 'id' type. The user-visible 'id'
+// type is a typedef of an ObjCObjectPointerType to an
+// ObjCObjectType with this as its base. In fact, this only ever
+// shows up in an AST as the base type of an ObjCObjectType.
+BUILTIN_TYPE(ObjCId, ObjCBuiltinIdTy)
+
+// The primitive Objective C 'Class' type. The user-visible
+// 'Class' type is a typedef of an ObjCObjectPointerType to an
+// ObjCObjectType with this as its base. In fact, this only ever
+// shows up in an AST as the base type of an ObjCObjectType.
+BUILTIN_TYPE(ObjCClass, ObjCBuiltinClassTy)
+
+// The primitive Objective C 'SEL' type. The user-visible 'SEL'
+// type is a typedef of a PointerType to this.
+BUILTIN_TYPE(ObjCSel, ObjCBuiltinSelTy)
+
+// OpenCL image types.
+BUILTIN_TYPE(OCLImage1d, OCLImage1dTy)
+BUILTIN_TYPE(OCLImage1dArray, OCLImage1dArrayTy)
+BUILTIN_TYPE(OCLImage1dBuffer, OCLImage1dBufferTy)
+BUILTIN_TYPE(OCLImage2d, OCLImage2dTy)
+BUILTIN_TYPE(OCLImage2dArray, OCLImage2dArrayTy)
+BUILTIN_TYPE(OCLImage3d, OCLImage3dTy)
+
+// This represents the type of an expression whose type is
+// totally unknown, e.g. 'T::foo'. It is permitted for this to
+// appear in situations where the structure of the type is
+// theoretically deducible.
+BUILTIN_TYPE(Dependent, DependentTy)
+
+// The type of an unresolved overload set. A placeholder type.
+// Expressions with this type have one of the following basic
+// forms, with parentheses generally permitted:
+// foo # possibly qualified, not if an implicit access
+// foo # possibly qualified, not if an implicit access
+// &foo # possibly qualified, not if an implicit access
+// x->foo # only if might be a static member function
+// &x->foo # only if might be a static member function
+// &Class::foo # when a pointer-to-member; sub-expr also has this type
+// OverloadExpr::find can be used to analyze the expression.
+//
+// Overload should be the first placeholder type, or else change
+// BuiltinType::isNonOverloadPlaceholderType()
+PLACEHOLDER_TYPE(Overload, OverloadTy)
+
+// The type of a bound C++ non-static member function.
+// A placeholder type. Expressions with this type have one of the
+// following basic forms:
+// foo # if an implicit access
+// x->foo # if only contains non-static members
+PLACEHOLDER_TYPE(BoundMember, BoundMemberTy)
+
+// The type of an expression which refers to a pseudo-object,
+// such as those introduced by Objective C's @property or
+// VS.NET's __property declarations. A placeholder type. The
+// pseudo-object is actually accessed by emitting a call to
+// some sort of function or method; typically there is a pair
+// of a setter and a getter, with the setter used if the
+// pseudo-object reference is used syntactically as the
+// left-hand-side of an assignment operator.
+//
+// A pseudo-object reference naming an Objective-C @property is
+// always a dot access with a base of object-pointer type,
+// e.g. 'x.foo'.
+//
+// In VS.NET, a __property declaration creates an implicit
+// member with an associated name, which can then be named
+// in any of the normal ways an ordinary member could be.
+PLACEHOLDER_TYPE(PseudoObject, PseudoObjectTy)
+
+// __builtin_any_type. A placeholder type. Useful for clients
+// like debuggers that don't know what type to give something.
+// Only a small number of operations are valid on expressions of
+// unknown type, most notably explicit casts.
+PLACEHOLDER_TYPE(UnknownAny, UnknownAnyTy)
+
+PLACEHOLDER_TYPE(BuiltinFn, BuiltinFnTy)
+
+// The type of a cast which, in ARC, would normally require a
+// __bridge, but which might be okay depending on the immediate
+// context.
+PLACEHOLDER_TYPE(ARCUnbridgedCast, ARCUnbridgedCastTy)
+
+#ifdef LAST_BUILTIN_TYPE
+LAST_BUILTIN_TYPE(ARCUnbridgedCast)
+#undef LAST_BUILTIN_TYPE
+#endif
+
+#undef SHARED_SINGLETON_TYPE
+#undef PLACEHOLDER_TYPE
+#undef FLOATING_TYPE
+#undef SIGNED_TYPE
+#undef UNSIGNED_TYPE
+#undef BUILTIN_TYPE
diff --git a/clang/include/clang/AST/Type.h b/clang/include/clang/AST/Type.h index 368be8d6b06..cf3b565fc31 100644 --- a/clang/include/clang/AST/Type.h +++ b/clang/include/clang/AST/Type.h @@ -1580,6 +1580,17 @@ public: bool isNullPtrType() const; // C++0x nullptr_t bool isAtomicType() const; // C11 _Atomic() + bool isImage1dT() const; // OpenCL image1d_t + bool isImage1dArrayT() const; // OpenCL image1d_array_t + bool isImage1dBufferT() const; // OpenCL image1d_buffer_t + bool isImage2dT() const; // OpenCL image2d_t + bool isImage2dArrayT() const; // OpenCL image2d_array_t + bool isImage3dT() const; // OpenCL image3d_t + + bool isImageType() const; // Any OpenCL image type + + bool isOpenCLSpecificType() const; // Any OpenCL specific type + /// Determines if this type, which must satisfy /// isObjCLifetimeType(), is implicitly __unsafe_unretained rather /// than implicitly __strong. @@ -4883,6 +4894,40 @@ inline bool Type::isObjCSelType() const { inline bool Type::isObjCBuiltinType() const { return isObjCIdType() || isObjCClassType() || isObjCSelType(); } + +inline bool Type::isImage1dT() const { + return isSpecificBuiltinType(BuiltinType::OCLImage1d); +} + +inline bool Type::isImage1dArrayT() const { + return isSpecificBuiltinType(BuiltinType::OCLImage1dArray); +} + +inline bool Type::isImage1dBufferT() const { + return isSpecificBuiltinType(BuiltinType::OCLImage1dBuffer); +} + +inline bool Type::isImage2dT() const { + return isSpecificBuiltinType(BuiltinType::OCLImage2d); +} + +inline bool Type::isImage2dArrayT() const { + return isSpecificBuiltinType(BuiltinType::OCLImage2dArray); +} + +inline bool Type::isImage3dT() const { + return isSpecificBuiltinType(BuiltinType::OCLImage3d); +} +inline bool Type::isImageType() const { + return isImage3dT() || + isImage2dT() || isImage2dArrayT() || + isImage1dT() || isImage1dArrayT() || isImage1dBufferT(); +} + +inline bool Type::isOpenCLSpecificType() const { + return isImageType(); +} + inline bool Type::isTemplateTypeParmType() const { return isa<TemplateTypeParmType>(CanonicalType); } diff --git a/clang/include/clang/Basic/Specifiers.h b/clang/include/clang/Basic/Specifiers.h index c82b8cb9188..8a6c62933c0 100644 --- a/clang/include/clang/Basic/Specifiers.h +++ b/clang/include/clang/Basic/Specifiers.h @@ -1,194 +1,200 @@ -//===--- Specifiers.h - Declaration and Type Specifiers ---------*- C++ -*-===// -// -// The LLVM Compiler Infrastructure -// -// This file is distributed under the University of Illinois Open Source -// License. See LICENSE.TXT for details. -// -//===----------------------------------------------------------------------===// -/// -/// \file -/// \brief Defines various enumerations that describe declaration and -/// type specifiers. -/// -//===----------------------------------------------------------------------===// - -#ifndef LLVM_CLANG_BASIC_SPECIFIERS_H -#define LLVM_CLANG_BASIC_SPECIFIERS_H - -namespace clang { - /// \brief Specifies the width of a type, e.g., short, long, or long long. - enum TypeSpecifierWidth { - TSW_unspecified, - TSW_short, - TSW_long, - TSW_longlong - }; - - /// \brief Specifies the signedness of a type, e.g., signed or unsigned. - enum TypeSpecifierSign { - TSS_unspecified, - TSS_signed, - TSS_unsigned - }; - - /// \brief Specifies the kind of type. - enum TypeSpecifierType { - TST_unspecified, - TST_void, - TST_char, - TST_wchar, // C++ wchar_t - TST_char16, // C++0x char16_t - TST_char32, // C++0x char32_t - TST_int, - TST_int128, - TST_half, // OpenCL half, ARM NEON __fp16 - TST_float, - TST_double, - TST_bool, // _Bool - TST_decimal32, // _Decimal32 - TST_decimal64, // _Decimal64 - TST_decimal128, // _Decimal128 - TST_enum, - TST_union, - TST_struct, - TST_class, // C++ class type - TST_interface, // C++ (Microsoft-specific) __interface type - TST_typename, // Typedef, C++ class-name or enum name, etc. - TST_typeofType, - TST_typeofExpr, - TST_decltype, // C++0x decltype - TST_underlyingType, // __underlying_type for C++0x - TST_auto, // C++0x auto - TST_unknown_anytype, // __unknown_anytype extension - TST_atomic, // C11 _Atomic - TST_error // erroneous type - }; - - /// \brief Structure that packs information about the type specifiers that - /// were written in a particular type specifier sequence. - struct WrittenBuiltinSpecs { - /*DeclSpec::TST*/ unsigned Type : 5; - /*DeclSpec::TSS*/ unsigned Sign : 2; - /*DeclSpec::TSW*/ unsigned Width : 2; - bool ModeAttr : 1; - }; - - /// \brief A C++ access specifier (public, private, protected), plus the - /// special value "none" which means different things in different contexts. - enum AccessSpecifier { - AS_public, - AS_protected, - AS_private, - AS_none - }; - - /// \brief The categorization of expression values, currently following the - /// C++11 scheme. - enum ExprValueKind { - /// \brief An r-value expression (a pr-value in the C++11 taxonomy) - /// produces a temporary value. - VK_RValue, - - /// \brief An l-value expression is a reference to an object with - /// independent storage. - VK_LValue, - - /// \brief An x-value expression is a reference to an object with - /// independent storage but which can be "moved", i.e. - /// efficiently cannibalized for its resources. - VK_XValue - }; - - /// \brief A further classification of the kind of object referenced by an - /// l-value or x-value. - enum ExprObjectKind { - /// An ordinary object is located at an address in memory. - OK_Ordinary, - - /// A bitfield object is a bitfield on a C or C++ record. - OK_BitField, - - /// A vector component is an element or range of elements on a vector. - OK_VectorComponent, - - /// An Objective-C property is a logical field of an Objective-C - /// object which is read and written via Objective-C method calls. - OK_ObjCProperty, - - /// An Objective-C array/dictionary subscripting which reads an - /// object or writes at the subscripted array/dictionary element via - /// Objective-C method calls. - OK_ObjCSubscript - }; - - // \brief Describes the kind of template specialization that a - // particular template specialization declaration represents. - enum TemplateSpecializationKind { - /// This template specialization was formed from a template-id but - /// has not yet been declared, defined, or instantiated. - TSK_Undeclared = 0, - /// This template specialization was implicitly instantiated from a - /// template. (C++ [temp.inst]). - TSK_ImplicitInstantiation, - /// This template specialization was declared or defined by an - /// explicit specialization (C++ [temp.expl.spec]) or partial - /// specialization (C++ [temp.class.spec]). - TSK_ExplicitSpecialization, - /// This template specialization was instantiated from a template - /// due to an explicit instantiation declaration request - /// (C++0x [temp.explicit]). - TSK_ExplicitInstantiationDeclaration, - /// This template specialization was instantiated from a template - /// due to an explicit instantiation definition request - /// (C++ [temp.explicit]). - TSK_ExplicitInstantiationDefinition - }; - - /// \brief Storage classes. - enum StorageClass { - // These are legal on both functions and variables. - SC_None, - SC_Extern, - SC_Static, - SC_PrivateExtern, - - // These are only legal on variables. - SC_OpenCLWorkGroupLocal, - SC_Auto, - SC_Register - }; - - /// \brief Checks whether the given storage class is legal for functions. - inline bool isLegalForFunction(StorageClass SC) { - return SC <= SC_PrivateExtern; - } - - /// \brief Checks whether the given storage class is legal for variables. - inline bool isLegalForVariable(StorageClass SC) { - return true; - } - - /// \brief In-class initialization styles for non-static data members. - enum InClassInitStyle { - ICIS_NoInit, ///< No in-class initializer. - ICIS_CopyInit, ///< Copy initialization. - ICIS_ListInit ///< Direct list-initialization. - }; - - /// \brief CallingConv - Specifies the calling convention that a function uses. - enum CallingConv { - CC_Default, - CC_C, // __attribute__((cdecl)) - CC_X86StdCall, // __attribute__((stdcall)) - CC_X86FastCall, // __attribute__((fastcall)) - CC_X86ThisCall, // __attribute__((thiscall)) - CC_X86Pascal, // __attribute__((pascal)) - CC_AAPCS, // __attribute__((pcs("aapcs"))) - CC_AAPCS_VFP, // __attribute__((pcs("aapcs-vfp"))) - CC_PnaclCall // __attribute__((pnaclcall)) - }; - -} // end namespace clang - -#endif // LLVM_CLANG_BASIC_SPECIFIERS_H +//===--- Specifiers.h - Declaration and Type Specifiers ---------*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+///
+/// \file
+/// \brief Defines various enumerations that describe declaration and
+/// type specifiers.
+///
+//===----------------------------------------------------------------------===//
+
+#ifndef LLVM_CLANG_BASIC_SPECIFIERS_H
+#define LLVM_CLANG_BASIC_SPECIFIERS_H
+
+namespace clang {
+ /// \brief Specifies the width of a type, e.g., short, long, or long long.
+ enum TypeSpecifierWidth {
+ TSW_unspecified,
+ TSW_short,
+ TSW_long,
+ TSW_longlong
+ };
+
+ /// \brief Specifies the signedness of a type, e.g., signed or unsigned.
+ enum TypeSpecifierSign {
+ TSS_unspecified,
+ TSS_signed,
+ TSS_unsigned
+ };
+
+ /// \brief Specifies the kind of type.
+ enum TypeSpecifierType {
+ TST_unspecified,
+ TST_void,
+ TST_char,
+ TST_wchar, // C++ wchar_t
+ TST_char16, // C++0x char16_t
+ TST_char32, // C++0x char32_t
+ TST_int,
+ TST_int128,
+ TST_half, // OpenCL half, ARM NEON __fp16
+ TST_float,
+ TST_double,
+ TST_bool, // _Bool
+ TST_decimal32, // _Decimal32
+ TST_decimal64, // _Decimal64
+ TST_decimal128, // _Decimal128
+ TST_enum,
+ TST_union,
+ TST_struct,
+ TST_class, // C++ class type
+ TST_interface, // C++ (Microsoft-specific) __interface type
+ TST_typename, // Typedef, C++ class-name or enum name, etc.
+ TST_typeofType,
+ TST_typeofExpr,
+ TST_decltype, // C++0x decltype
+ TST_underlyingType, // __underlying_type for C++0x
+ TST_auto, // C++0x auto
+ TST_unknown_anytype, // __unknown_anytype extension
+ TST_atomic, // C11 _Atomic
+ TST_image1d_t, // OpenCL image1d_t
+ TST_image1d_array_t, // OpenCL image1d_array_t
+ TST_image1d_buffer_t, // OpenCL image1d_buffer_t
+ TST_image2d_t, // OpenCL image2d_t
+ TST_image2d_array_t, // OpenCL image2d_array_t
+ TST_image3d_t, // OpenCL image3d_t
+ TST_error // erroneous type
+ };
+
+ /// \brief Structure that packs information about the type specifiers that
+ /// were written in a particular type specifier sequence.
+ struct WrittenBuiltinSpecs {
+ /*DeclSpec::TST*/ unsigned Type : 6;
+ /*DeclSpec::TSS*/ unsigned Sign : 2;
+ /*DeclSpec::TSW*/ unsigned Width : 2;
+ bool ModeAttr : 1;
+ };
+
+ /// \brief A C++ access specifier (public, private, protected), plus the
+ /// special value "none" which means different things in different contexts.
+ enum AccessSpecifier {
+ AS_public,
+ AS_protected,
+ AS_private,
+ AS_none
+ };
+
+ /// \brief The categorization of expression values, currently following the
+ /// C++11 scheme.
+ enum ExprValueKind {
+ /// \brief An r-value expression (a pr-value in the C++11 taxonomy)
+ /// produces a temporary value.
+ VK_RValue,
+
+ /// \brief An l-value expression is a reference to an object with
+ /// independent storage.
+ VK_LValue,
+
+ /// \brief An x-value expression is a reference to an object with
+ /// independent storage but which can be "moved", i.e.
+ /// efficiently cannibalized for its resources.
+ VK_XValue
+ };
+
+ /// \brief A further classification of the kind of object referenced by an
+ /// l-value or x-value.
+ enum ExprObjectKind {
+ /// An ordinary object is located at an address in memory.
+ OK_Ordinary,
+
+ /// A bitfield object is a bitfield on a C or C++ record.
+ OK_BitField,
+
+ /// A vector component is an element or range of elements on a vector.
+ OK_VectorComponent,
+
+ /// An Objective-C property is a logical field of an Objective-C
+ /// object which is read and written via Objective-C method calls.
+ OK_ObjCProperty,
+
+ /// An Objective-C array/dictionary subscripting which reads an
+ /// object or writes at the subscripted array/dictionary element via
+ /// Objective-C method calls.
+ OK_ObjCSubscript
+ };
+
+ // \brief Describes the kind of template specialization that a
+ // particular template specialization declaration represents.
+ enum TemplateSpecializationKind {
+ /// This template specialization was formed from a template-id but
+ /// has not yet been declared, defined, or instantiated.
+ TSK_Undeclared = 0,
+ /// This template specialization was implicitly instantiated from a
+ /// template. (C++ [temp.inst]).
+ TSK_ImplicitInstantiation,
+ /// This template specialization was declared or defined by an
+ /// explicit specialization (C++ [temp.expl.spec]) or partial
+ /// specialization (C++ [temp.class.spec]).
+ TSK_ExplicitSpecialization,
+ /// This template specialization was instantiated from a template
+ /// due to an explicit instantiation declaration request
+ /// (C++0x [temp.explicit]).
+ TSK_ExplicitInstantiationDeclaration,
+ /// This template specialization was instantiated from a template
+ /// due to an explicit instantiation definition request
+ /// (C++ [temp.explicit]).
+ TSK_ExplicitInstantiationDefinition
+ };
+
+ /// \brief Storage classes.
+ enum StorageClass {
+ // These are legal on both functions and variables.
+ SC_None,
+ SC_Extern,
+ SC_Static,
+ SC_PrivateExtern,
+
+ // These are only legal on variables.
+ SC_OpenCLWorkGroupLocal,
+ SC_Auto,
+ SC_Register
+ };
+
+ /// \brief Checks whether the given storage class is legal for functions.
+ inline bool isLegalForFunction(StorageClass SC) {
+ return SC <= SC_PrivateExtern;
+ }
+
+ /// \brief Checks whether the given storage class is legal for variables.
+ inline bool isLegalForVariable(StorageClass SC) {
+ return true;
+ }
+
+ /// \brief In-class initialization styles for non-static data members.
+ enum InClassInitStyle {
+ ICIS_NoInit, ///< No in-class initializer.
+ ICIS_CopyInit, ///< Copy initialization.
+ ICIS_ListInit ///< Direct list-initialization.
+ };
+
+ /// \brief CallingConv - Specifies the calling convention that a function uses.
+ enum CallingConv {
+ CC_Default,
+ CC_C, // __attribute__((cdecl))
+ CC_X86StdCall, // __attribute__((stdcall))
+ CC_X86FastCall, // __attribute__((fastcall))
+ CC_X86ThisCall, // __attribute__((thiscall))
+ CC_X86Pascal, // __attribute__((pascal))
+ CC_AAPCS, // __attribute__((pcs("aapcs")))
+ CC_AAPCS_VFP, // __attribute__((pcs("aapcs-vfp")))
+ CC_PnaclCall // __attribute__((pnaclcall))
+ };
+
+} // end namespace clang
+
+#endif // LLVM_CLANG_BASIC_SPECIFIERS_H
diff --git a/clang/include/clang/Basic/TokenKinds.def b/clang/include/clang/Basic/TokenKinds.def index f02ba6438bd..7bc489b25c6 100644 --- a/clang/include/clang/Basic/TokenKinds.def +++ b/clang/include/clang/Basic/TokenKinds.def @@ -448,6 +448,12 @@ ALIAS("read_only", __read_only , KEYOPENCL) ALIAS("write_only", __write_only , KEYOPENCL) ALIAS("read_write", __read_write , KEYOPENCL) KEYWORD(__builtin_astype , KEYOPENCL) +KEYWORD(image1d_t , KEYOPENCL) +KEYWORD(image1d_array_t , KEYOPENCL) +KEYWORD(image1d_buffer_t , KEYOPENCL) +KEYWORD(image2d_t , KEYOPENCL) +KEYWORD(image2d_array_t , KEYOPENCL) +KEYWORD(image3d_t , KEYOPENCL) // Borland Extensions. KEYWORD(__pascal , KEYALL) diff --git a/clang/include/clang/Sema/DeclSpec.h b/clang/include/clang/Sema/DeclSpec.h index d2618105744..bc8fc64699e 100644 --- a/clang/include/clang/Sema/DeclSpec.h +++ b/clang/include/clang/Sema/DeclSpec.h @@ -276,6 +276,12 @@ public: static const TST TST_auto = clang::TST_auto; static const TST TST_unknown_anytype = clang::TST_unknown_anytype; static const TST TST_atomic = clang::TST_atomic; + static const TST TST_image1d_t = clang::TST_image1d_t; + static const TST TST_image1d_array_t = clang::TST_image1d_array_t; + static const TST TST_image1d_buffer_t = clang::TST_image1d_buffer_t; + static const TST TST_image2d_t = clang::TST_image2d_t; + static const TST TST_image2d_array_t = clang::TST_image2d_array_t; + static const TST TST_image3d_t = clang::TST_image3d_t; static const TST TST_error = clang::TST_error; // type-qualifiers @@ -306,7 +312,7 @@ private: /*TSW*/unsigned TypeSpecWidth : 2; /*TSC*/unsigned TypeSpecComplex : 2; /*TSS*/unsigned TypeSpecSign : 2; - /*TST*/unsigned TypeSpecType : 5; + /*TST*/unsigned TypeSpecType : 6; unsigned TypeAltiVecVector : 1; unsigned TypeAltiVecPixel : 1; unsigned TypeAltiVecBool : 1; diff --git a/clang/include/clang/Serialization/ASTBitCodes.h b/clang/include/clang/Serialization/ASTBitCodes.h index 4273e147872..868a1758b6d 100644 --- a/clang/include/clang/Serialization/ASTBitCodes.h +++ b/clang/include/clang/Serialization/ASTBitCodes.h @@ -1,1355 +1,1367 @@ -//===- ASTBitCodes.h - Enum values for the PCH bitcode format ---*- C++ -*-===// -// -// The LLVM Compiler Infrastructure -// -// This file is distributed under the University of Illinois Open Source -// License. See LICENSE.TXT for details. -// -//===----------------------------------------------------------------------===// -// -// This header defines Bitcode enum values for Clang serialized AST files. -// -// The enum values defined in this file should be considered permanent. If -// new features are added, they should have values added at the end of the -// respective lists. -// -//===----------------------------------------------------------------------===// -#ifndef LLVM_CLANG_FRONTEND_PCHBITCODES_H -#define LLVM_CLANG_FRONTEND_PCHBITCODES_H - -#include "clang/AST/Type.h" -#include "llvm/ADT/DenseMap.h" -#include "llvm/Bitcode/BitCodes.h" -#include "llvm/Support/DataTypes.h" - -namespace clang { - namespace serialization { - /// \brief AST file major version number supported by this version of - /// Clang. - /// - /// Whenever the AST file format changes in a way that makes it - /// incompatible with previous versions (such that a reader - /// designed for the previous version could not support reading - /// the new version), this number should be increased. - /// - /// Version 4 of AST files also requires that the version control branch and - /// revision match exactly, since there is no backward compatibility of - /// AST files at this time. - const unsigned VERSION_MAJOR = 5; - - /// \brief AST file minor version number supported by this version of - /// Clang. - /// - /// Whenever the AST format changes in a way that is still - /// compatible with previous versions (such that a reader designed - /// for the previous version could still support reading the new - /// version by ignoring new kinds of subblocks), this number - /// should be increased. - const unsigned VERSION_MINOR = 0; - - /// \brief An ID number that refers to an identifier in an AST file. - /// - /// The ID numbers of identifiers are consecutive (in order of discovery) - /// and start at 1. 0 is reserved for NULL. - typedef uint32_t IdentifierID; - - /// \brief An ID number that refers to a declaration in an AST file. - /// - /// The ID numbers of declarations are consecutive (in order of - /// discovery), with values below NUM_PREDEF_DECL_IDS being reserved. - /// At the start of a chain of precompiled headers, declaration ID 1 is - /// used for the translation unit declaration. - typedef uint32_t DeclID; - - /// \brief a Decl::Kind/DeclID pair. - typedef std::pair<uint32_t, DeclID> KindDeclIDPair; - - // FIXME: Turn these into classes so we can have some type safety when - // we go from local ID to global and vice-versa. - typedef DeclID LocalDeclID; - typedef DeclID GlobalDeclID; - - /// \brief An ID number that refers to a type in an AST file. - /// - /// The ID of a type is partitioned into two parts: the lower - /// three bits are used to store the const/volatile/restrict - /// qualifiers (as with QualType) and the upper bits provide a - /// type index. The type index values are partitioned into two - /// sets. The values below NUM_PREDEF_TYPE_IDs are predefined type - /// IDs (based on the PREDEF_TYPE_*_ID constants), with 0 as a - /// placeholder for "no type". Values from NUM_PREDEF_TYPE_IDs are - /// other types that have serialized representations. - typedef uint32_t TypeID; - - /// \brief A type index; the type ID with the qualifier bits removed. - class TypeIdx { - uint32_t Idx; - public: - TypeIdx() : Idx(0) { } - explicit TypeIdx(uint32_t index) : Idx(index) { } - - uint32_t getIndex() const { return Idx; } - TypeID asTypeID(unsigned FastQuals) const { - if (Idx == uint32_t(-1)) - return TypeID(-1); - - return (Idx << Qualifiers::FastWidth) | FastQuals; - } - static TypeIdx fromTypeID(TypeID ID) { - if (ID == TypeID(-1)) - return TypeIdx(-1); - - return TypeIdx(ID >> Qualifiers::FastWidth); - } - }; - - /// A structure for putting "fast"-unqualified QualTypes into a - /// DenseMap. This uses the standard pointer hash function. - struct UnsafeQualTypeDenseMapInfo { - static inline bool isEqual(QualType A, QualType B) { return A == B; } - static inline QualType getEmptyKey() { - return QualType::getFromOpaquePtr((void*) 1); - } - static inline QualType getTombstoneKey() { - return QualType::getFromOpaquePtr((void*) 2); - } - static inline unsigned getHashValue(QualType T) { - assert(!T.getLocalFastQualifiers() && - "hash invalid for types with fast quals"); - uintptr_t v = reinterpret_cast<uintptr_t>(T.getAsOpaquePtr()); - return (unsigned(v) >> 4) ^ (unsigned(v) >> 9); - } - }; - - /// \brief An ID number that refers to an identifier in an AST file. - typedef uint32_t IdentID; - - /// \brief The number of predefined identifier IDs. - const unsigned int NUM_PREDEF_IDENT_IDS = 1; - - /// \brief An ID number that refers to a macro in an AST file. - typedef uint32_t MacroID; - - /// \brief The number of predefined macro IDs. - const unsigned int NUM_PREDEF_MACRO_IDS = 1; - - /// \brief An ID number that refers to an ObjC selector in an AST file. - typedef uint32_t SelectorID; - - /// \brief The number of predefined selector IDs. - const unsigned int NUM_PREDEF_SELECTOR_IDS = 1; - - /// \brief An ID number that refers to a set of CXXBaseSpecifiers in an - /// AST file. - typedef uint32_t CXXBaseSpecifiersID; - - /// \brief An ID number that refers to an entity in the detailed - /// preprocessing record. - typedef uint32_t PreprocessedEntityID; - - /// \brief An ID number that refers to a submodule in a module file. - typedef uint32_t SubmoduleID; - - /// \brief The number of predefined submodule IDs. - const unsigned int NUM_PREDEF_SUBMODULE_IDS = 1; - - /// \brief Source range/offset of a preprocessed entity. - struct PPEntityOffset { - /// \brief Raw source location of beginning of range. - unsigned Begin; - /// \brief Raw source location of end of range. - unsigned End; - /// \brief Offset in the AST file. - uint32_t BitOffset; - - PPEntityOffset(SourceRange R, uint32_t BitOffset) - : Begin(R.getBegin().getRawEncoding()), - End(R.getEnd().getRawEncoding()), - BitOffset(BitOffset) { } - }; - - /// \brief Source range/offset of a preprocessed entity. - struct DeclOffset { - /// \brief Raw source location. - unsigned Loc; - /// \brief Offset in the AST file. - uint32_t BitOffset; - - DeclOffset() : Loc(0), BitOffset(0) { } - DeclOffset(SourceLocation Loc, uint32_t BitOffset) - : Loc(Loc.getRawEncoding()), - BitOffset(BitOffset) { } - void setLocation(SourceLocation L) { - Loc = L.getRawEncoding(); - } - }; - - /// \brief The number of predefined preprocessed entity IDs. - const unsigned int NUM_PREDEF_PP_ENTITY_IDS = 1; - - /// \brief Describes the various kinds of blocks that occur within - /// an AST file. - enum BlockIDs { - /// \brief The AST block, which acts as a container around the - /// full AST block. - AST_BLOCK_ID = llvm::bitc::FIRST_APPLICATION_BLOCKID, - - /// \brief The block containing information about the source - /// manager. - SOURCE_MANAGER_BLOCK_ID, - - /// \brief The block containing information about the - /// preprocessor. - PREPROCESSOR_BLOCK_ID, - - /// \brief The block containing the definitions of all of the - /// types and decls used within the AST file. - DECLTYPES_BLOCK_ID, - - /// \brief The block containing DECL_UPDATES records. - DECL_UPDATES_BLOCK_ID, - - /// \brief The block containing the detailed preprocessing record. - PREPROCESSOR_DETAIL_BLOCK_ID, - - /// \brief The block containing the submodule structure. - SUBMODULE_BLOCK_ID, - - /// \brief The block containing comments. - COMMENTS_BLOCK_ID, - - /// \brief The control block, which contains all of the - /// information that needs to be validated prior to committing - /// to loading the AST file. - CONTROL_BLOCK_ID, - - /// \brief The block of input files, which were used as inputs - /// to create this AST file. - /// - /// This block is part of the control block. - INPUT_FILES_BLOCK_ID - }; - - /// \brief Record types that occur within the control block. - enum ControlRecordTypes { - /// \brief AST file metadata, including the AST file version number - /// and information about the compiler used to build this AST file. - METADATA = 1, - - /// \brief Record code for the list of other AST files imported by - /// this AST file. - IMPORTS = 2, - - /// \brief Record code for the language options table. - /// - /// The record with this code contains the contents of the - /// LangOptions structure. We serialize the entire contents of - /// the structure, and let the reader decide which options are - /// actually important to check. - LANGUAGE_OPTIONS = 3, - - /// \brief Record code for the target options table. - TARGET_OPTIONS = 4, - - /// \brief Record code for the original file that was used to - /// generate the AST file, including both its file ID and its - /// name. - ORIGINAL_FILE = 5, - - /// \brief The directory that the PCH was originally created in. - ORIGINAL_PCH_DIR = 6, - - /// \brief Record code for file ID of the file or buffer that was used to - /// generate the AST file. - ORIGINAL_FILE_ID = 7, - - /// \brief Offsets into the input-files block where input files - /// reside. - INPUT_FILE_OFFSETS = 8, - - /// \brief Record code for the diagnostic options table. - DIAGNOSTIC_OPTIONS = 9, - - /// \brief Record code for the filesystem options table. - FILE_SYSTEM_OPTIONS = 10, - - /// \brief Record code for the headers search options table. - HEADER_SEARCH_OPTIONS = 11, - - /// \brief Record code for the preprocessor options table. - PREPROCESSOR_OPTIONS = 12 - }; - - /// \brief Record types that occur within the input-files block - /// inside the control block. - enum InputFileRecordTypes { - /// \brief An input file. - INPUT_FILE = 1 - }; - - /// \brief Record types that occur within the AST block itself. - enum ASTRecordTypes { - /// \brief Record code for the offsets of each type. - /// - /// The TYPE_OFFSET constant describes the record that occurs - /// within the AST block. The record itself is an array of offsets that - /// point into the declarations and types block (identified by - /// DECLTYPES_BLOCK_ID). The index into the array is based on the ID - /// of a type. For a given type ID @c T, the lower three bits of - /// @c T are its qualifiers (const, volatile, restrict), as in - /// the QualType class. The upper bits, after being shifted and - /// subtracting NUM_PREDEF_TYPE_IDS, are used to index into the - /// TYPE_OFFSET block to determine the offset of that type's - /// corresponding record within the DECLTYPES_BLOCK_ID block. - TYPE_OFFSET = 1, - - /// \brief Record code for the offsets of each decl. - /// - /// The DECL_OFFSET constant describes the record that occurs - /// within the block identified by DECL_OFFSETS_BLOCK_ID within - /// the AST block. The record itself is an array of offsets that - /// point into the declarations and types block (identified by - /// DECLTYPES_BLOCK_ID). The declaration ID is an index into this - /// record, after subtracting one to account for the use of - /// declaration ID 0 for a NULL declaration pointer. Index 0 is - /// reserved for the translation unit declaration. - DECL_OFFSET = 2, - - /// \brief Record code for the table of offsets of each - /// identifier ID. - /// - /// The offset table contains offsets into the blob stored in - /// the IDENTIFIER_TABLE record. Each offset points to the - /// NULL-terminated string that corresponds to that identifier. - IDENTIFIER_OFFSET = 3, - - /// \brief This is so that older clang versions, before the introduction - /// of the control block, can read and reject the newer PCH format. - /// *DON"T CHANGE THIS NUMBER*. - METADATA_OLD_FORMAT = 4, - - /// \brief Record code for the identifier table. - /// - /// The identifier table is a simple blob that contains - /// NULL-terminated strings for all of the identifiers - /// referenced by the AST file. The IDENTIFIER_OFFSET table - /// contains the mapping from identifier IDs to the characters - /// in this blob. Note that the starting offsets of all of the - /// identifiers are odd, so that, when the identifier offset - /// table is loaded in, we can use the low bit to distinguish - /// between offsets (for unresolved identifier IDs) and - /// IdentifierInfo pointers (for already-resolved identifier - /// IDs). - IDENTIFIER_TABLE = 5, - - /// \brief Record code for the array of external definitions. - /// - /// The AST file contains a list of all of the unnamed external - /// definitions present within the parsed headers, stored as an - /// array of declaration IDs. These external definitions will be - /// reported to the AST consumer after the AST file has been - /// read, since their presence can affect the semantics of the - /// program (e.g., for code generation). - EXTERNAL_DEFINITIONS = 6, - - /// \brief Record code for the set of non-builtin, special - /// types. - /// - /// This record contains the type IDs for the various type nodes - /// that are constructed during semantic analysis (e.g., - /// __builtin_va_list). The SPECIAL_TYPE_* constants provide - /// offsets into this record. - SPECIAL_TYPES = 7, - - /// \brief Record code for the extra statistics we gather while - /// generating an AST file. - STATISTICS = 8, - - /// \brief Record code for the array of tentative definitions. - TENTATIVE_DEFINITIONS = 9, - - /// \brief Record code for the array of locally-scoped external - /// declarations. - LOCALLY_SCOPED_EXTERNAL_DECLS = 10, - - /// \brief Record code for the table of offsets into the - /// Objective-C method pool. - SELECTOR_OFFSETS = 11, - - /// \brief Record code for the Objective-C method pool, - METHOD_POOL = 12, - - /// \brief The value of the next __COUNTER__ to dispense. - /// [PP_COUNTER_VALUE, Val] - PP_COUNTER_VALUE = 13, - - /// \brief Record code for the table of offsets into the block - /// of source-location information. - SOURCE_LOCATION_OFFSETS = 14, - - /// \brief Record code for the set of source location entries - /// that need to be preloaded by the AST reader. - /// - /// This set contains the source location entry for the - /// predefines buffer and for any file entries that need to be - /// preloaded. - SOURCE_LOCATION_PRELOADS = 15, - - /// \brief Record code for the set of ext_vector type names. - EXT_VECTOR_DECLS = 16, - - /// \brief Record code for the array of unused file scoped decls. - UNUSED_FILESCOPED_DECLS = 17, - - /// \brief Record code for the table of offsets to entries in the - /// preprocessing record. - PPD_ENTITIES_OFFSETS = 18, - - /// \brief Record code for the array of VTable uses. - VTABLE_USES = 19, - - /// \brief Record code for the array of dynamic classes. - DYNAMIC_CLASSES = 20, - - /// \brief Record code for referenced selector pool. - REFERENCED_SELECTOR_POOL = 21, - - /// \brief Record code for an update to the TU's lexically contained - /// declarations. - TU_UPDATE_LEXICAL = 22, - - /// \brief Record code for the array describing the locations (in the - /// LOCAL_REDECLARATIONS record) of the redeclaration chains, indexed by - /// the first known ID. - LOCAL_REDECLARATIONS_MAP = 23, - - /// \brief Record code for declarations that Sema keeps references of. - SEMA_DECL_REFS = 24, - - /// \brief Record code for weak undeclared identifiers. - WEAK_UNDECLARED_IDENTIFIERS = 25, - - /// \brief Record code for pending implicit instantiations. - PENDING_IMPLICIT_INSTANTIATIONS = 26, - - /// \brief Record code for a decl replacement block. - /// - /// If a declaration is modified after having been deserialized, and then - /// written to a dependent AST file, its ID and offset must be added to - /// the replacement block. - DECL_REPLACEMENTS = 27, - - /// \brief Record code for an update to a decl context's lookup table. - /// - /// In practice, this should only be used for the TU and namespaces. - UPDATE_VISIBLE = 28, - - /// \brief Record for offsets of DECL_UPDATES records for declarations - /// that were modified after being deserialized and need updates. - DECL_UPDATE_OFFSETS = 29, - - /// \brief Record of updates for a declaration that was modified after - /// being deserialized. - DECL_UPDATES = 30, - - /// \brief Record code for the table of offsets to CXXBaseSpecifier - /// sets. - CXX_BASE_SPECIFIER_OFFSETS = 31, - - /// \brief Record code for \#pragma diagnostic mappings. - DIAG_PRAGMA_MAPPINGS = 32, - - /// \brief Record code for special CUDA declarations. - CUDA_SPECIAL_DECL_REFS = 33, - - /// \brief Record code for header search information. - HEADER_SEARCH_TABLE = 34, - - /// \brief Record code for floating point \#pragma options. - FP_PRAGMA_OPTIONS = 35, - - /// \brief Record code for enabled OpenCL extensions. - OPENCL_EXTENSIONS = 36, - - /// \brief The list of delegating constructor declarations. - DELEGATING_CTORS = 37, - - /// \brief Record code for the set of known namespaces, which are used - /// for typo correction. - KNOWN_NAMESPACES = 38, - - /// \brief Record code for the remapping information used to relate - /// loaded modules to the various offsets and IDs(e.g., source location - /// offests, declaration and type IDs) that are used in that module to - /// refer to other modules. - MODULE_OFFSET_MAP = 39, - - /// \brief Record code for the source manager line table information, - /// which stores information about \#line directives. - SOURCE_MANAGER_LINE_TABLE = 40, - - /// \brief Record code for map of Objective-C class definition IDs to the - /// ObjC categories in a module that are attached to that class. - OBJC_CATEGORIES_MAP = 41, - - /// \brief Record code for a file sorted array of DeclIDs in a module. - FILE_SORTED_DECLS = 42, - - /// \brief Record code for an array of all of the (sub)modules that were - /// imported by the AST file. - IMPORTED_MODULES = 43, - - /// \brief Record code for the set of merged declarations in an AST file. - MERGED_DECLARATIONS = 44, - - /// \brief Record code for the array of redeclaration chains. - /// - /// This array can only be interpreted properly using the local - /// redeclarations map. - LOCAL_REDECLARATIONS = 45, - - /// \brief Record code for the array of Objective-C categories (including - /// extensions). - /// - /// This array can only be interpreted properly using the Objective-C - /// categories map. - OBJC_CATEGORIES = 46, - - /// \brief Record code for the table of offsets of each macro ID. - /// - /// The offset table contains offsets into the blob stored in - /// the preprocessor block. Each offset points to the corresponding - /// macro definition. - MACRO_OFFSET = 47, - - /// \brief Record of updates for a macro that was modified after - /// being deserialized. - MACRO_UPDATES = 48 - }; - - /// \brief Record types used within a source manager block. - enum SourceManagerRecordTypes { - /// \brief Describes a source location entry (SLocEntry) for a - /// file. - SM_SLOC_FILE_ENTRY = 1, - /// \brief Describes a source location entry (SLocEntry) for a - /// buffer. - SM_SLOC_BUFFER_ENTRY = 2, - /// \brief Describes a blob that contains the data for a buffer - /// entry. This kind of record always directly follows a - /// SM_SLOC_BUFFER_ENTRY record or a SM_SLOC_FILE_ENTRY with an - /// overridden buffer. - SM_SLOC_BUFFER_BLOB = 3, - /// \brief Describes a source location entry (SLocEntry) for a - /// macro expansion. - SM_SLOC_EXPANSION_ENTRY = 4 - }; - - /// \brief Record types used within a preprocessor block. - enum PreprocessorRecordTypes { - // The macros in the PP section are a PP_MACRO_* instance followed by a - // list of PP_TOKEN instances for each token in the definition. - - /// \brief An object-like macro definition. - /// [PP_MACRO_OBJECT_LIKE, IdentInfoID, SLoc, IsUsed] - PP_MACRO_OBJECT_LIKE = 1, - - /// \brief A function-like macro definition. - /// [PP_MACRO_FUNCTION_LIKE, \<ObjectLikeStuff>, IsC99Varargs, - /// IsGNUVarars, NumArgs, ArgIdentInfoID* ] - PP_MACRO_FUNCTION_LIKE = 2, - - /// \brief Describes one token. - /// [PP_TOKEN, SLoc, Length, IdentInfoID, Kind, Flags] - PP_TOKEN = 3 - }; - - /// \brief Record types used within a preprocessor detail block. - enum PreprocessorDetailRecordTypes { - /// \brief Describes a macro expansion within the preprocessing record. - PPD_MACRO_EXPANSION = 0, - - /// \brief Describes a macro definition within the preprocessing record. - PPD_MACRO_DEFINITION = 1, - - /// \brief Describes an inclusion directive within the preprocessing - /// record. - PPD_INCLUSION_DIRECTIVE = 2 - }; - - /// \brief Record types used within a submodule description block. - enum SubmoduleRecordTypes { - /// \brief Metadata for submodules as a whole. - SUBMODULE_METADATA = 0, - /// \brief Defines the major attributes of a submodule, including its - /// name and parent. - SUBMODULE_DEFINITION = 1, - /// \brief Specifies the umbrella header used to create this module, - /// if any. - SUBMODULE_UMBRELLA_HEADER = 2, - /// \brief Specifies a header that falls into this (sub)module. - SUBMODULE_HEADER = 3, - /// \brief Specifies a top-level header that falls into this (sub)module. - SUBMODULE_TOPHEADER = 4, - /// \brief Specifies an umbrella directory. - SUBMODULE_UMBRELLA_DIR = 5, - /// \brief Specifies the submodules that are imported by this - /// submodule. - SUBMODULE_IMPORTS = 6, - /// \brief Specifies the submodules that are re-exported from this - /// submodule. - SUBMODULE_EXPORTS = 7, - /// \brief Specifies a required feature. - SUBMODULE_REQUIRES = 8, - /// \brief Specifies a header that has been explicitly excluded - /// from this submodule. - SUBMODULE_EXCLUDED_HEADER = 9 - }; - - /// \brief Record types used within a comments block. - enum CommentRecordTypes { - COMMENTS_RAW_COMMENT = 0 - }; - - /// \defgroup ASTAST AST file AST constants - /// - /// The constants in this group describe various components of the - /// abstract syntax tree within an AST file. - /// - /// @{ - - /// \brief Predefined type IDs. - /// - /// These type IDs correspond to predefined types in the AST - /// context, such as built-in types (int) and special place-holder - /// types (the \<overload> and \<dependent> type markers). Such - /// types are never actually serialized, since they will be built - /// by the AST context when it is created. - enum PredefinedTypeIDs { - /// \brief The NULL type. - PREDEF_TYPE_NULL_ID = 0, - /// \brief The void type. - PREDEF_TYPE_VOID_ID = 1, - /// \brief The 'bool' or '_Bool' type. - PREDEF_TYPE_BOOL_ID = 2, - /// \brief The 'char' type, when it is unsigned. - PREDEF_TYPE_CHAR_U_ID = 3, - /// \brief The 'unsigned char' type. - PREDEF_TYPE_UCHAR_ID = 4, - /// \brief The 'unsigned short' type. - PREDEF_TYPE_USHORT_ID = 5, - /// \brief The 'unsigned int' type. - PREDEF_TYPE_UINT_ID = 6, - /// \brief The 'unsigned long' type. - PREDEF_TYPE_ULONG_ID = 7, - /// \brief The 'unsigned long long' type. - PREDEF_TYPE_ULONGLONG_ID = 8, - /// \brief The 'char' type, when it is signed. - PREDEF_TYPE_CHAR_S_ID = 9, - /// \brief The 'signed char' type. - PREDEF_TYPE_SCHAR_ID = 10, - /// \brief The C++ 'wchar_t' type. - PREDEF_TYPE_WCHAR_ID = 11, - /// \brief The (signed) 'short' type. - PREDEF_TYPE_SHORT_ID = 12, - /// \brief The (signed) 'int' type. - PREDEF_TYPE_INT_ID = 13, - /// \brief The (signed) 'long' type. - PREDEF_TYPE_LONG_ID = 14, - /// \brief The (signed) 'long long' type. - PREDEF_TYPE_LONGLONG_ID = 15, - /// \brief The 'float' type. - PREDEF_TYPE_FLOAT_ID = 16, - /// \brief The 'double' type. - PREDEF_TYPE_DOUBLE_ID = 17, - /// \brief The 'long double' type. - PREDEF_TYPE_LONGDOUBLE_ID = 18, - /// \brief The placeholder type for overloaded function sets. - PREDEF_TYPE_OVERLOAD_ID = 19, - /// \brief The placeholder type for dependent types. - PREDEF_TYPE_DEPENDENT_ID = 20, - /// \brief The '__uint128_t' type. - PREDEF_TYPE_UINT128_ID = 21, - /// \brief The '__int128_t' type. - PREDEF_TYPE_INT128_ID = 22, - /// \brief The type of 'nullptr'. - PREDEF_TYPE_NULLPTR_ID = 23, - /// \brief The C++ 'char16_t' type. - PREDEF_TYPE_CHAR16_ID = 24, - /// \brief The C++ 'char32_t' type. - PREDEF_TYPE_CHAR32_ID = 25, - /// \brief The ObjC 'id' type. - PREDEF_TYPE_OBJC_ID = 26, - /// \brief The ObjC 'Class' type. - PREDEF_TYPE_OBJC_CLASS = 27, - /// \brief The ObjC 'SEL' type. - PREDEF_TYPE_OBJC_SEL = 28, - /// \brief The 'unknown any' placeholder type. - PREDEF_TYPE_UNKNOWN_ANY = 29, - /// \brief The placeholder type for bound member functions. - PREDEF_TYPE_BOUND_MEMBER = 30, - /// \brief The "auto" deduction type. - PREDEF_TYPE_AUTO_DEDUCT = 31, - /// \brief The "auto &&" deduction type. - PREDEF_TYPE_AUTO_RREF_DEDUCT = 32, - /// \brief The OpenCL 'half' / ARM NEON __fp16 type. - PREDEF_TYPE_HALF_ID = 33, - /// \brief ARC's unbridged-cast placeholder type. - PREDEF_TYPE_ARC_UNBRIDGED_CAST = 34, - /// \brief The pseudo-object placeholder type. - PREDEF_TYPE_PSEUDO_OBJECT = 35, - /// \brief The __va_list_tag placeholder type. - PREDEF_TYPE_VA_LIST_TAG = 36, - /// \brief The placeholder type for builtin functions. - PREDEF_TYPE_BUILTIN_FN = 37 - }; - - /// \brief The number of predefined type IDs that are reserved for - /// the PREDEF_TYPE_* constants. - /// - /// Type IDs for non-predefined types will start at - /// NUM_PREDEF_TYPE_IDs. - const unsigned NUM_PREDEF_TYPE_IDS = 100; - - /// \brief The number of allowed abbreviations in bits - const unsigned NUM_ALLOWED_ABBREVS_SIZE = 4; - - /// \brief Record codes for each kind of type. - /// - /// These constants describe the type records that can occur within a - /// block identified by DECLTYPES_BLOCK_ID in the AST file. Each - /// constant describes a record for a specific type class in the - /// AST. - enum TypeCode { - /// \brief An ExtQualType record. - TYPE_EXT_QUAL = 1, - /// \brief A ComplexType record. - TYPE_COMPLEX = 3, - /// \brief A PointerType record. - TYPE_POINTER = 4, - /// \brief A BlockPointerType record. - TYPE_BLOCK_POINTER = 5, - /// \brief An LValueReferenceType record. - TYPE_LVALUE_REFERENCE = 6, - /// \brief An RValueReferenceType record. - TYPE_RVALUE_REFERENCE = 7, - /// \brief A MemberPointerType record. - TYPE_MEMBER_POINTER = 8, - /// \brief A ConstantArrayType record. - TYPE_CONSTANT_ARRAY = 9, - /// \brief An IncompleteArrayType record. - TYPE_INCOMPLETE_ARRAY = 10, - /// \brief A VariableArrayType record. - TYPE_VARIABLE_ARRAY = 11, - /// \brief A VectorType record. - TYPE_VECTOR = 12, - /// \brief An ExtVectorType record. - TYPE_EXT_VECTOR = 13, - /// \brief A FunctionNoProtoType record. - TYPE_FUNCTION_NO_PROTO = 14, - /// \brief A FunctionProtoType record. - TYPE_FUNCTION_PROTO = 15, - /// \brief A TypedefType record. - TYPE_TYPEDEF = 16, - /// \brief A TypeOfExprType record. - TYPE_TYPEOF_EXPR = 17, - /// \brief A TypeOfType record. - TYPE_TYPEOF = 18, - /// \brief A RecordType record. - TYPE_RECORD = 19, - /// \brief An EnumType record. - TYPE_ENUM = 20, - /// \brief An ObjCInterfaceType record. - TYPE_OBJC_INTERFACE = 21, - /// \brief An ObjCObjectPointerType record. - TYPE_OBJC_OBJECT_POINTER = 22, - /// \brief a DecltypeType record. - TYPE_DECLTYPE = 23, - /// \brief An ElaboratedType record. - TYPE_ELABORATED = 24, - /// \brief A SubstTemplateTypeParmType record. - TYPE_SUBST_TEMPLATE_TYPE_PARM = 25, - /// \brief An UnresolvedUsingType record. - TYPE_UNRESOLVED_USING = 26, - /// \brief An InjectedClassNameType record. - TYPE_INJECTED_CLASS_NAME = 27, - /// \brief An ObjCObjectType record. - TYPE_OBJC_OBJECT = 28, - /// \brief An TemplateTypeParmType record. - TYPE_TEMPLATE_TYPE_PARM = 29, - /// \brief An TemplateSpecializationType record. - TYPE_TEMPLATE_SPECIALIZATION = 30, - /// \brief A DependentNameType record. - TYPE_DEPENDENT_NAME = 31, - /// \brief A DependentTemplateSpecializationType record. - TYPE_DEPENDENT_TEMPLATE_SPECIALIZATION = 32, - /// \brief A DependentSizedArrayType record. - TYPE_DEPENDENT_SIZED_ARRAY = 33, - /// \brief A ParenType record. - TYPE_PAREN = 34, - /// \brief A PackExpansionType record. - TYPE_PACK_EXPANSION = 35, - /// \brief An AttributedType record. - TYPE_ATTRIBUTED = 36, - /// \brief A SubstTemplateTypeParmPackType record. - TYPE_SUBST_TEMPLATE_TYPE_PARM_PACK = 37, - /// \brief A AutoType record. - TYPE_AUTO = 38, - /// \brief A UnaryTransformType record. - TYPE_UNARY_TRANSFORM = 39, - /// \brief An AtomicType record. - TYPE_ATOMIC = 40 - }; - - /// \brief The type IDs for special types constructed by semantic - /// analysis. - /// - /// The constants in this enumeration are indices into the - /// SPECIAL_TYPES record. - enum SpecialTypeIDs { - /// \brief CFConstantString type - SPECIAL_TYPE_CF_CONSTANT_STRING = 0, - /// \brief C FILE typedef type - SPECIAL_TYPE_FILE = 1, - /// \brief C jmp_buf typedef type - SPECIAL_TYPE_JMP_BUF = 2, - /// \brief C sigjmp_buf typedef type - SPECIAL_TYPE_SIGJMP_BUF = 3, - /// \brief Objective-C "id" redefinition type - SPECIAL_TYPE_OBJC_ID_REDEFINITION = 4, - /// \brief Objective-C "Class" redefinition type - SPECIAL_TYPE_OBJC_CLASS_REDEFINITION = 5, - /// \brief Objective-C "SEL" redefinition type - SPECIAL_TYPE_OBJC_SEL_REDEFINITION = 6, - /// \brief C ucontext_t typedef type - SPECIAL_TYPE_UCONTEXT_T = 7 - }; - - /// \brief The number of special type IDs. - const unsigned NumSpecialTypeIDs = 8; - - /// \brief Predefined declaration IDs. - /// - /// These declaration IDs correspond to predefined declarations in the AST - /// context, such as the NULL declaration ID. Such declarations are never - /// actually serialized, since they will be built by the AST context when - /// it is created. - enum PredefinedDeclIDs { - /// \brief The NULL declaration. - PREDEF_DECL_NULL_ID = 0, - - /// \brief The translation unit. - PREDEF_DECL_TRANSLATION_UNIT_ID = 1, - - /// \brief The Objective-C 'id' type. - PREDEF_DECL_OBJC_ID_ID = 2, - - /// \brief The Objective-C 'SEL' type. - PREDEF_DECL_OBJC_SEL_ID = 3, - - /// \brief The Objective-C 'Class' type. - PREDEF_DECL_OBJC_CLASS_ID = 4, - - /// \brief The Objective-C 'Protocol' type. - PREDEF_DECL_OBJC_PROTOCOL_ID = 5, - - /// \brief The signed 128-bit integer type. - PREDEF_DECL_INT_128_ID = 6, - - /// \brief The unsigned 128-bit integer type. - PREDEF_DECL_UNSIGNED_INT_128_ID = 7, - - /// \brief The internal 'instancetype' typedef. - PREDEF_DECL_OBJC_INSTANCETYPE_ID = 8, - - /// \brief The internal '__builtin_va_list' typedef. - PREDEF_DECL_BUILTIN_VA_LIST_ID = 9 - }; - - /// \brief The number of declaration IDs that are predefined. - /// - /// For more information about predefined declarations, see the - /// \c PredefinedDeclIDs type and the PREDEF_DECL_*_ID constants. - const unsigned int NUM_PREDEF_DECL_IDS = 10; - - /// \brief Record codes for each kind of declaration. - /// - /// These constants describe the declaration records that can occur within - /// a declarations block (identified by DECLS_BLOCK_ID). Each - /// constant describes a record for a specific declaration class - /// in the AST. - enum DeclCode { - /// \brief A TypedefDecl record. - DECL_TYPEDEF = 51, - /// \brief A TypeAliasDecl record. - DECL_TYPEALIAS, - /// \brief An EnumDecl record. - DECL_ENUM, - /// \brief A RecordDecl record. - DECL_RECORD, - /// \brief An EnumConstantDecl record. - DECL_ENUM_CONSTANT, - /// \brief A FunctionDecl record. - DECL_FUNCTION, - /// \brief A ObjCMethodDecl record. - DECL_OBJC_METHOD, - /// \brief A ObjCInterfaceDecl record. - DECL_OBJC_INTERFACE, - /// \brief A ObjCProtocolDecl record. - DECL_OBJC_PROTOCOL, - /// \brief A ObjCIvarDecl record. - DECL_OBJC_IVAR, - /// \brief A ObjCAtDefsFieldDecl record. - DECL_OBJC_AT_DEFS_FIELD, - /// \brief A ObjCCategoryDecl record. - DECL_OBJC_CATEGORY, - /// \brief A ObjCCategoryImplDecl record. - DECL_OBJC_CATEGORY_IMPL, - /// \brief A ObjCImplementationDecl record. - DECL_OBJC_IMPLEMENTATION, - /// \brief A ObjCCompatibleAliasDecl record. - DECL_OBJC_COMPATIBLE_ALIAS, - /// \brief A ObjCPropertyDecl record. - DECL_OBJC_PROPERTY, - /// \brief A ObjCPropertyImplDecl record. - DECL_OBJC_PROPERTY_IMPL, - /// \brief A FieldDecl record. - DECL_FIELD, - /// \brief A VarDecl record. - DECL_VAR, - /// \brief An ImplicitParamDecl record. - DECL_IMPLICIT_PARAM, - /// \brief A ParmVarDecl record. - DECL_PARM_VAR, - /// \brief A FileScopeAsmDecl record. - DECL_FILE_SCOPE_ASM, - /// \brief A BlockDecl record. - DECL_BLOCK, - /// \brief A record that stores the set of declarations that are - /// lexically stored within a given DeclContext. - /// - /// The record itself is a blob that is an array of declaration IDs, - /// in the order in which those declarations were added to the - /// declaration context. This data is used when iterating over - /// the contents of a DeclContext, e.g., via - /// DeclContext::decls_begin() and DeclContext::decls_end(). - DECL_CONTEXT_LEXICAL, - /// \brief A record that stores the set of declarations that are - /// visible from a given DeclContext. - /// - /// The record itself stores a set of mappings, each of which - /// associates a declaration name with one or more declaration - /// IDs. This data is used when performing qualified name lookup - /// into a DeclContext via DeclContext::lookup. - DECL_CONTEXT_VISIBLE, - /// \brief A LabelDecl record. - DECL_LABEL, - /// \brief A NamespaceDecl record. - DECL_NAMESPACE, - /// \brief A NamespaceAliasDecl record. - DECL_NAMESPACE_ALIAS, - /// \brief A UsingDecl record. - DECL_USING, - /// \brief A UsingShadowDecl record. - DECL_USING_SHADOW, - /// \brief A UsingDirecitveDecl record. - DECL_USING_DIRECTIVE, - /// \brief An UnresolvedUsingValueDecl record. - DECL_UNRESOLVED_USING_VALUE, - /// \brief An UnresolvedUsingTypenameDecl record. - DECL_UNRESOLVED_USING_TYPENAME, - /// \brief A LinkageSpecDecl record. - DECL_LINKAGE_SPEC, - /// \brief A CXXRecordDecl record. - DECL_CXX_RECORD, - /// \brief A CXXMethodDecl record. - DECL_CXX_METHOD, - /// \brief A CXXConstructorDecl record. - DECL_CXX_CONSTRUCTOR, - /// \brief A CXXDestructorDecl record. - DECL_CXX_DESTRUCTOR, - /// \brief A CXXConversionDecl record. - DECL_CXX_CONVERSION, - /// \brief An AccessSpecDecl record. - DECL_ACCESS_SPEC, - - /// \brief A FriendDecl record. - DECL_FRIEND, - /// \brief A FriendTemplateDecl record. - DECL_FRIEND_TEMPLATE, - /// \brief A ClassTemplateDecl record. - DECL_CLASS_TEMPLATE, - /// \brief A ClassTemplateSpecializationDecl record. - DECL_CLASS_TEMPLATE_SPECIALIZATION, - /// \brief A ClassTemplatePartialSpecializationDecl record. - DECL_CLASS_TEMPLATE_PARTIAL_SPECIALIZATION, - /// \brief A FunctionTemplateDecl record. - DECL_FUNCTION_TEMPLATE, - /// \brief A TemplateTypeParmDecl record. - DECL_TEMPLATE_TYPE_PARM, - /// \brief A NonTypeTemplateParmDecl record. - DECL_NON_TYPE_TEMPLATE_PARM, - /// \brief A TemplateTemplateParmDecl record. - DECL_TEMPLATE_TEMPLATE_PARM, - /// \brief A TypeAliasTemplateDecl record. - DECL_TYPE_ALIAS_TEMPLATE, - /// \brief A StaticAssertDecl record. - DECL_STATIC_ASSERT, - /// \brief A record containing CXXBaseSpecifiers. - DECL_CXX_BASE_SPECIFIERS, - /// \brief A IndirectFieldDecl record. - DECL_INDIRECTFIELD, - /// \brief A NonTypeTemplateParmDecl record that stores an expanded - /// non-type template parameter pack. - DECL_EXPANDED_NON_TYPE_TEMPLATE_PARM_PACK, - /// \brief A TemplateTemplateParmDecl record that stores an expanded - /// template template parameter pack. - DECL_EXPANDED_TEMPLATE_TEMPLATE_PARM_PACK, - /// \brief A ClassScopeFunctionSpecializationDecl record a class scope - /// function specialization. (Microsoft extension). - DECL_CLASS_SCOPE_FUNCTION_SPECIALIZATION, - /// \brief An ImportDecl recording a module import. - DECL_IMPORT - }; - - /// \brief Record codes for each kind of statement or expression. - /// - /// These constants describe the records that describe statements - /// or expressions. These records occur within type and declarations - /// block, so they begin with record values of 100. Each constant - /// describes a record for a specific statement or expression class in the - /// AST. - enum StmtCode { - /// \brief A marker record that indicates that we are at the end - /// of an expression. - STMT_STOP = 100, - /// \brief A NULL expression. - STMT_NULL_PTR, - /// \brief A reference to a previously [de]serialized Stmt record. - STMT_REF_PTR, - /// \brief A NullStmt record. - STMT_NULL, - /// \brief A CompoundStmt record. - STMT_COMPOUND, - /// \brief A CaseStmt record. - STMT_CASE, - /// \brief A DefaultStmt record. - STMT_DEFAULT, - /// \brief A LabelStmt record. - STMT_LABEL, - /// \brief An AttributedStmt record. - STMT_ATTRIBUTED, - /// \brief An IfStmt record. - STMT_IF, - /// \brief A SwitchStmt record. - STMT_SWITCH, - /// \brief A WhileStmt record. - STMT_WHILE, - /// \brief A DoStmt record. - STMT_DO, - /// \brief A ForStmt record. - STMT_FOR, - /// \brief A GotoStmt record. - STMT_GOTO, - /// \brief An IndirectGotoStmt record. - STMT_INDIRECT_GOTO, - /// \brief A ContinueStmt record. - STMT_CONTINUE, - /// \brief A BreakStmt record. - STMT_BREAK, - /// \brief A ReturnStmt record. - STMT_RETURN, - /// \brief A DeclStmt record. - STMT_DECL, - /// \brief A GCC-style AsmStmt record. - STMT_GCCASM, - /// \brief A MS-style AsmStmt record. - STMT_MSASM, - /// \brief A PredefinedExpr record. - EXPR_PREDEFINED, - /// \brief A DeclRefExpr record. - EXPR_DECL_REF, - /// \brief An IntegerLiteral record. - EXPR_INTEGER_LITERAL, - /// \brief A FloatingLiteral record. - EXPR_FLOATING_LITERAL, - /// \brief An ImaginaryLiteral record. - EXPR_IMAGINARY_LITERAL, - /// \brief A StringLiteral record. - EXPR_STRING_LITERAL, - /// \brief A CharacterLiteral record. - EXPR_CHARACTER_LITERAL, - /// \brief A ParenExpr record. - EXPR_PAREN, - /// \brief A ParenListExpr record. - EXPR_PAREN_LIST, - /// \brief A UnaryOperator record. - EXPR_UNARY_OPERATOR, - /// \brief An OffsetOfExpr record. - EXPR_OFFSETOF, - /// \brief A SizefAlignOfExpr record. - EXPR_SIZEOF_ALIGN_OF, - /// \brief An ArraySubscriptExpr record. - EXPR_ARRAY_SUBSCRIPT, - /// \brief A CallExpr record. - EXPR_CALL, - /// \brief A MemberExpr record. - EXPR_MEMBER, - /// \brief A BinaryOperator record. - EXPR_BINARY_OPERATOR, - /// \brief A CompoundAssignOperator record. - EXPR_COMPOUND_ASSIGN_OPERATOR, - /// \brief A ConditionOperator record. - EXPR_CONDITIONAL_OPERATOR, - /// \brief An ImplicitCastExpr record. - EXPR_IMPLICIT_CAST, - /// \brief A CStyleCastExpr record. - EXPR_CSTYLE_CAST, - /// \brief A CompoundLiteralExpr record. - EXPR_COMPOUND_LITERAL, - /// \brief An ExtVectorElementExpr record. - EXPR_EXT_VECTOR_ELEMENT, - /// \brief An InitListExpr record. - EXPR_INIT_LIST, - /// \brief A DesignatedInitExpr record. - EXPR_DESIGNATED_INIT, - /// \brief An ImplicitValueInitExpr record. - EXPR_IMPLICIT_VALUE_INIT, - /// \brief A VAArgExpr record. - EXPR_VA_ARG, - /// \brief An AddrLabelExpr record. - EXPR_ADDR_LABEL, - /// \brief A StmtExpr record. - EXPR_STMT, - /// \brief A ChooseExpr record. - EXPR_CHOOSE, - /// \brief A GNUNullExpr record. - EXPR_GNU_NULL, - /// \brief A ShuffleVectorExpr record. - EXPR_SHUFFLE_VECTOR, - /// \brief BlockExpr - EXPR_BLOCK, - /// \brief A GenericSelectionExpr record. - EXPR_GENERIC_SELECTION, - /// \brief A PseudoObjectExpr record. - EXPR_PSEUDO_OBJECT, - /// \brief An AtomicExpr record. - EXPR_ATOMIC, - - // Objective-C - - /// \brief An ObjCStringLiteral record. - EXPR_OBJC_STRING_LITERAL, - - EXPR_OBJC_BOXED_EXPRESSION, - EXPR_OBJC_ARRAY_LITERAL, - EXPR_OBJC_DICTIONARY_LITERAL, - - - /// \brief An ObjCEncodeExpr record. - EXPR_OBJC_ENCODE, - /// \brief An ObjCSelectorExpr record. - EXPR_OBJC_SELECTOR_EXPR, - /// \brief An ObjCProtocolExpr record. - EXPR_OBJC_PROTOCOL_EXPR, - /// \brief An ObjCIvarRefExpr record. - EXPR_OBJC_IVAR_REF_EXPR, - /// \brief An ObjCPropertyRefExpr record. - EXPR_OBJC_PROPERTY_REF_EXPR, - /// \brief An ObjCSubscriptRefExpr record. - EXPR_OBJC_SUBSCRIPT_REF_EXPR, - /// \brief UNUSED - EXPR_OBJC_KVC_REF_EXPR, - /// \brief An ObjCMessageExpr record. - EXPR_OBJC_MESSAGE_EXPR, - /// \brief An ObjCIsa Expr record. - EXPR_OBJC_ISA, - /// \brief An ObjCIndirectCopyRestoreExpr record. - EXPR_OBJC_INDIRECT_COPY_RESTORE, - - /// \brief An ObjCForCollectionStmt record. - STMT_OBJC_FOR_COLLECTION, - /// \brief An ObjCAtCatchStmt record. - STMT_OBJC_CATCH, - /// \brief An ObjCAtFinallyStmt record. - STMT_OBJC_FINALLY, - /// \brief An ObjCAtTryStmt record. - STMT_OBJC_AT_TRY, - /// \brief An ObjCAtSynchronizedStmt record. - STMT_OBJC_AT_SYNCHRONIZED, - /// \brief An ObjCAtThrowStmt record. - STMT_OBJC_AT_THROW, - /// \brief An ObjCAutoreleasePoolStmt record. - STMT_OBJC_AUTORELEASE_POOL, - /// \brief A ObjCBoolLiteralExpr record. - EXPR_OBJC_BOOL_LITERAL, - - // C++ - - /// \brief A CXXCatchStmt record. - STMT_CXX_CATCH, - /// \brief A CXXTryStmt record. - STMT_CXX_TRY, - /// \brief A CXXForRangeStmt record. - STMT_CXX_FOR_RANGE, - - /// \brief A CXXOperatorCallExpr record. - EXPR_CXX_OPERATOR_CALL, - /// \brief A CXXMemberCallExpr record. - EXPR_CXX_MEMBER_CALL, - /// \brief A CXXConstructExpr record. - EXPR_CXX_CONSTRUCT, - /// \brief A CXXTemporaryObjectExpr record. - EXPR_CXX_TEMPORARY_OBJECT, - /// \brief A CXXStaticCastExpr record. - EXPR_CXX_STATIC_CAST, - /// \brief A CXXDynamicCastExpr record. - EXPR_CXX_DYNAMIC_CAST, - /// \brief A CXXReinterpretCastExpr record. - EXPR_CXX_REINTERPRET_CAST, - /// \brief A CXXConstCastExpr record. - EXPR_CXX_CONST_CAST, - /// \brief A CXXFunctionalCastExpr record. - EXPR_CXX_FUNCTIONAL_CAST, - /// \brief A UserDefinedLiteral record. - EXPR_USER_DEFINED_LITERAL, - /// \brief A CXXBoolLiteralExpr record. - EXPR_CXX_BOOL_LITERAL, - EXPR_CXX_NULL_PTR_LITERAL, // CXXNullPtrLiteralExpr - EXPR_CXX_TYPEID_EXPR, // CXXTypeidExpr (of expr). - EXPR_CXX_TYPEID_TYPE, // CXXTypeidExpr (of type). - EXPR_CXX_THIS, // CXXThisExpr - EXPR_CXX_THROW, // CXXThrowExpr - EXPR_CXX_DEFAULT_ARG, // CXXDefaultArgExpr - EXPR_CXX_BIND_TEMPORARY, // CXXBindTemporaryExpr - - EXPR_CXX_SCALAR_VALUE_INIT, // CXXScalarValueInitExpr - EXPR_CXX_NEW, // CXXNewExpr - EXPR_CXX_DELETE, // CXXDeleteExpr - EXPR_CXX_PSEUDO_DESTRUCTOR, // CXXPseudoDestructorExpr - - EXPR_EXPR_WITH_CLEANUPS, // ExprWithCleanups - - EXPR_CXX_DEPENDENT_SCOPE_MEMBER, // CXXDependentScopeMemberExpr - EXPR_CXX_DEPENDENT_SCOPE_DECL_REF, // DependentScopeDeclRefExpr - EXPR_CXX_UNRESOLVED_CONSTRUCT, // CXXUnresolvedConstructExpr - EXPR_CXX_UNRESOLVED_MEMBER, // UnresolvedMemberExpr - EXPR_CXX_UNRESOLVED_LOOKUP, // UnresolvedLookupExpr - - EXPR_CXX_UNARY_TYPE_TRAIT, // UnaryTypeTraitExpr - EXPR_CXX_EXPRESSION_TRAIT, // ExpressionTraitExpr - EXPR_CXX_NOEXCEPT, // CXXNoexceptExpr - - EXPR_OPAQUE_VALUE, // OpaqueValueExpr - EXPR_BINARY_CONDITIONAL_OPERATOR, // BinaryConditionalOperator - EXPR_BINARY_TYPE_TRAIT, // BinaryTypeTraitExpr - EXPR_TYPE_TRAIT, // TypeTraitExpr - EXPR_ARRAY_TYPE_TRAIT, // ArrayTypeTraitIntExpr - - EXPR_PACK_EXPANSION, // PackExpansionExpr - EXPR_SIZEOF_PACK, // SizeOfPackExpr - EXPR_SUBST_NON_TYPE_TEMPLATE_PARM, // SubstNonTypeTemplateParmExpr - EXPR_SUBST_NON_TYPE_TEMPLATE_PARM_PACK,// SubstNonTypeTemplateParmPackExpr - EXPR_FUNCTION_PARM_PACK, // FunctionParmPackExpr - EXPR_MATERIALIZE_TEMPORARY, // MaterializeTemporaryExpr - - // CUDA - EXPR_CUDA_KERNEL_CALL, // CUDAKernelCallExpr - - // OpenCL - EXPR_ASTYPE, // AsTypeExpr - - // Microsoft - EXPR_CXX_UUIDOF_EXPR, // CXXUuidofExpr (of expr). - EXPR_CXX_UUIDOF_TYPE, // CXXUuidofExpr (of type). - STMT_SEH_EXCEPT, // SEHExceptStmt - STMT_SEH_FINALLY, // SEHFinallyStmt - STMT_SEH_TRY, // SEHTryStmt - - // ARC - EXPR_OBJC_BRIDGED_CAST, // ObjCBridgedCastExpr - - STMT_MS_DEPENDENT_EXISTS, // MSDependentExistsStmt - EXPR_LAMBDA // LambdaExpr - }; - - /// \brief The kinds of designators that can occur in a - /// DesignatedInitExpr. - enum DesignatorTypes { - /// \brief Field designator where only the field name is known. - DESIG_FIELD_NAME = 0, - /// \brief Field designator where the field has been resolved to - /// a declaration. - DESIG_FIELD_DECL = 1, - /// \brief Array designator. - DESIG_ARRAY = 2, - /// \brief GNU array range designator. - DESIG_ARRAY_RANGE = 3 - }; - - /// \brief The different kinds of data that can occur in a - /// CtorInitializer. - enum CtorInitializerType { - CTOR_INITIALIZER_BASE, - CTOR_INITIALIZER_DELEGATING, - CTOR_INITIALIZER_MEMBER, - CTOR_INITIALIZER_INDIRECT_MEMBER - }; - - /// \brief Describes the redeclarations of a declaration. - struct LocalRedeclarationsInfo { - DeclID FirstID; // The ID of the first declaration - unsigned Offset; // Offset into the array of redeclaration chains. - - friend bool operator<(const LocalRedeclarationsInfo &X, - const LocalRedeclarationsInfo &Y) { - return X.FirstID < Y.FirstID; - } - - friend bool operator>(const LocalRedeclarationsInfo &X, - const LocalRedeclarationsInfo &Y) { - return X.FirstID > Y.FirstID; - } - - friend bool operator<=(const LocalRedeclarationsInfo &X, - const LocalRedeclarationsInfo &Y) { - return X.FirstID <= Y.FirstID; - } - - friend bool operator>=(const LocalRedeclarationsInfo &X, - const LocalRedeclarationsInfo &Y) { - return X.FirstID >= Y.FirstID; - } - }; - - /// \brief Describes the categories of an Objective-C class. - struct ObjCCategoriesInfo { - DeclID DefinitionID; // The ID of the definition - unsigned Offset; // Offset into the array of category lists. - - friend bool operator<(const ObjCCategoriesInfo &X, - const ObjCCategoriesInfo &Y) { - return X.DefinitionID < Y.DefinitionID; - } - - friend bool operator>(const ObjCCategoriesInfo &X, - const ObjCCategoriesInfo &Y) { - return X.DefinitionID > Y.DefinitionID; - } - - friend bool operator<=(const ObjCCategoriesInfo &X, - const ObjCCategoriesInfo &Y) { - return X.DefinitionID <= Y.DefinitionID; - } - - friend bool operator>=(const ObjCCategoriesInfo &X, - const ObjCCategoriesInfo &Y) { - return X.DefinitionID >= Y.DefinitionID; - } - }; - - /// @} - } -} // end namespace clang - -#endif +//===- ASTBitCodes.h - Enum values for the PCH bitcode format ---*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+//
+// This header defines Bitcode enum values for Clang serialized AST files.
+//
+// The enum values defined in this file should be considered permanent. If
+// new features are added, they should have values added at the end of the
+// respective lists.
+//
+//===----------------------------------------------------------------------===//
+#ifndef LLVM_CLANG_FRONTEND_PCHBITCODES_H
+#define LLVM_CLANG_FRONTEND_PCHBITCODES_H
+
+#include "clang/AST/Type.h"
+#include "llvm/ADT/DenseMap.h"
+#include "llvm/Bitcode/BitCodes.h"
+#include "llvm/Support/DataTypes.h"
+
+namespace clang {
+ namespace serialization {
+ /// \brief AST file major version number supported by this version of
+ /// Clang.
+ ///
+ /// Whenever the AST file format changes in a way that makes it
+ /// incompatible with previous versions (such that a reader
+ /// designed for the previous version could not support reading
+ /// the new version), this number should be increased.
+ ///
+ /// Version 4 of AST files also requires that the version control branch and
+ /// revision match exactly, since there is no backward compatibility of
+ /// AST files at this time.
+ const unsigned VERSION_MAJOR = 5;
+
+ /// \brief AST file minor version number supported by this version of
+ /// Clang.
+ ///
+ /// Whenever the AST format changes in a way that is still
+ /// compatible with previous versions (such that a reader designed
+ /// for the previous version could still support reading the new
+ /// version by ignoring new kinds of subblocks), this number
+ /// should be increased.
+ const unsigned VERSION_MINOR = 0;
+
+ /// \brief An ID number that refers to an identifier in an AST file.
+ ///
+ /// The ID numbers of identifiers are consecutive (in order of discovery)
+ /// and start at 1. 0 is reserved for NULL.
+ typedef uint32_t IdentifierID;
+
+ /// \brief An ID number that refers to a declaration in an AST file.
+ ///
+ /// The ID numbers of declarations are consecutive (in order of
+ /// discovery), with values below NUM_PREDEF_DECL_IDS being reserved.
+ /// At the start of a chain of precompiled headers, declaration ID 1 is
+ /// used for the translation unit declaration.
+ typedef uint32_t DeclID;
+
+ /// \brief a Decl::Kind/DeclID pair.
+ typedef std::pair<uint32_t, DeclID> KindDeclIDPair;
+
+ // FIXME: Turn these into classes so we can have some type safety when
+ // we go from local ID to global and vice-versa.
+ typedef DeclID LocalDeclID;
+ typedef DeclID GlobalDeclID;
+
+ /// \brief An ID number that refers to a type in an AST file.
+ ///
+ /// The ID of a type is partitioned into two parts: the lower
+ /// three bits are used to store the const/volatile/restrict
+ /// qualifiers (as with QualType) and the upper bits provide a
+ /// type index. The type index values are partitioned into two
+ /// sets. The values below NUM_PREDEF_TYPE_IDs are predefined type
+ /// IDs (based on the PREDEF_TYPE_*_ID constants), with 0 as a
+ /// placeholder for "no type". Values from NUM_PREDEF_TYPE_IDs are
+ /// other types that have serialized representations.
+ typedef uint32_t TypeID;
+
+ /// \brief A type index; the type ID with the qualifier bits removed.
+ class TypeIdx {
+ uint32_t Idx;
+ public:
+ TypeIdx() : Idx(0) { }
+ explicit TypeIdx(uint32_t index) : Idx(index) { }
+
+ uint32_t getIndex() const { return Idx; }
+ TypeID asTypeID(unsigned FastQuals) const {
+ if (Idx == uint32_t(-1))
+ return TypeID(-1);
+
+ return (Idx << Qualifiers::FastWidth) | FastQuals;
+ }
+ static TypeIdx fromTypeID(TypeID ID) {
+ if (ID == TypeID(-1))
+ return TypeIdx(-1);
+
+ return TypeIdx(ID >> Qualifiers::FastWidth);
+ }
+ };
+
+ /// A structure for putting "fast"-unqualified QualTypes into a
+ /// DenseMap. This uses the standard pointer hash function.
+ struct UnsafeQualTypeDenseMapInfo {
+ static inline bool isEqual(QualType A, QualType B) { return A == B; }
+ static inline QualType getEmptyKey() {
+ return QualType::getFromOpaquePtr((void*) 1);
+ }
+ static inline QualType getTombstoneKey() {
+ return QualType::getFromOpaquePtr((void*) 2);
+ }
+ static inline unsigned getHashValue(QualType T) {
+ assert(!T.getLocalFastQualifiers() &&
+ "hash invalid for types with fast quals");
+ uintptr_t v = reinterpret_cast<uintptr_t>(T.getAsOpaquePtr());
+ return (unsigned(v) >> 4) ^ (unsigned(v) >> 9);
+ }
+ };
+
+ /// \brief An ID number that refers to an identifier in an AST file.
+ typedef uint32_t IdentID;
+
+ /// \brief The number of predefined identifier IDs.
+ const unsigned int NUM_PREDEF_IDENT_IDS = 1;
+
+ /// \brief An ID number that refers to a macro in an AST file.
+ typedef uint32_t MacroID;
+
+ /// \brief The number of predefined macro IDs.
+ const unsigned int NUM_PREDEF_MACRO_IDS = 1;
+
+ /// \brief An ID number that refers to an ObjC selector in an AST file.
+ typedef uint32_t SelectorID;
+
+ /// \brief The number of predefined selector IDs.
+ const unsigned int NUM_PREDEF_SELECTOR_IDS = 1;
+
+ /// \brief An ID number that refers to a set of CXXBaseSpecifiers in an
+ /// AST file.
+ typedef uint32_t CXXBaseSpecifiersID;
+
+ /// \brief An ID number that refers to an entity in the detailed
+ /// preprocessing record.
+ typedef uint32_t PreprocessedEntityID;
+
+ /// \brief An ID number that refers to a submodule in a module file.
+ typedef uint32_t SubmoduleID;
+
+ /// \brief The number of predefined submodule IDs.
+ const unsigned int NUM_PREDEF_SUBMODULE_IDS = 1;
+
+ /// \brief Source range/offset of a preprocessed entity.
+ struct PPEntityOffset {
+ /// \brief Raw source location of beginning of range.
+ unsigned Begin;
+ /// \brief Raw source location of end of range.
+ unsigned End;
+ /// \brief Offset in the AST file.
+ uint32_t BitOffset;
+
+ PPEntityOffset(SourceRange R, uint32_t BitOffset)
+ : Begin(R.getBegin().getRawEncoding()),
+ End(R.getEnd().getRawEncoding()),
+ BitOffset(BitOffset) { }
+ };
+
+ /// \brief Source range/offset of a preprocessed entity.
+ struct DeclOffset {
+ /// \brief Raw source location.
+ unsigned Loc;
+ /// \brief Offset in the AST file.
+ uint32_t BitOffset;
+
+ DeclOffset() : Loc(0), BitOffset(0) { }
+ DeclOffset(SourceLocation Loc, uint32_t BitOffset)
+ : Loc(Loc.getRawEncoding()),
+ BitOffset(BitOffset) { }
+ void setLocation(SourceLocation L) {
+ Loc = L.getRawEncoding();
+ }
+ };
+
+ /// \brief The number of predefined preprocessed entity IDs.
+ const unsigned int NUM_PREDEF_PP_ENTITY_IDS = 1;
+
+ /// \brief Describes the various kinds of blocks that occur within
+ /// an AST file.
+ enum BlockIDs {
+ /// \brief The AST block, which acts as a container around the
+ /// full AST block.
+ AST_BLOCK_ID = llvm::bitc::FIRST_APPLICATION_BLOCKID,
+
+ /// \brief The block containing information about the source
+ /// manager.
+ SOURCE_MANAGER_BLOCK_ID,
+
+ /// \brief The block containing information about the
+ /// preprocessor.
+ PREPROCESSOR_BLOCK_ID,
+
+ /// \brief The block containing the definitions of all of the
+ /// types and decls used within the AST file.
+ DECLTYPES_BLOCK_ID,
+
+ /// \brief The block containing DECL_UPDATES records.
+ DECL_UPDATES_BLOCK_ID,
+
+ /// \brief The block containing the detailed preprocessing record.
+ PREPROCESSOR_DETAIL_BLOCK_ID,
+
+ /// \brief The block containing the submodule structure.
+ SUBMODULE_BLOCK_ID,
+
+ /// \brief The block containing comments.
+ COMMENTS_BLOCK_ID,
+
+ /// \brief The control block, which contains all of the
+ /// information that needs to be validated prior to committing
+ /// to loading the AST file.
+ CONTROL_BLOCK_ID,
+
+ /// \brief The block of input files, which were used as inputs
+ /// to create this AST file.
+ ///
+ /// This block is part of the control block.
+ INPUT_FILES_BLOCK_ID
+ };
+
+ /// \brief Record types that occur within the control block.
+ enum ControlRecordTypes {
+ /// \brief AST file metadata, including the AST file version number
+ /// and information about the compiler used to build this AST file.
+ METADATA = 1,
+
+ /// \brief Record code for the list of other AST files imported by
+ /// this AST file.
+ IMPORTS = 2,
+
+ /// \brief Record code for the language options table.
+ ///
+ /// The record with this code contains the contents of the
+ /// LangOptions structure. We serialize the entire contents of
+ /// the structure, and let the reader decide which options are
+ /// actually important to check.
+ LANGUAGE_OPTIONS = 3,
+
+ /// \brief Record code for the target options table.
+ TARGET_OPTIONS = 4,
+
+ /// \brief Record code for the original file that was used to
+ /// generate the AST file, including both its file ID and its
+ /// name.
+ ORIGINAL_FILE = 5,
+
+ /// \brief The directory that the PCH was originally created in.
+ ORIGINAL_PCH_DIR = 6,
+
+ /// \brief Record code for file ID of the file or buffer that was used to
+ /// generate the AST file.
+ ORIGINAL_FILE_ID = 7,
+
+ /// \brief Offsets into the input-files block where input files
+ /// reside.
+ INPUT_FILE_OFFSETS = 8,
+
+ /// \brief Record code for the diagnostic options table.
+ DIAGNOSTIC_OPTIONS = 9,
+
+ /// \brief Record code for the filesystem options table.
+ FILE_SYSTEM_OPTIONS = 10,
+
+ /// \brief Record code for the headers search options table.
+ HEADER_SEARCH_OPTIONS = 11,
+
+ /// \brief Record code for the preprocessor options table.
+ PREPROCESSOR_OPTIONS = 12
+ };
+
+ /// \brief Record types that occur within the input-files block
+ /// inside the control block.
+ enum InputFileRecordTypes {
+ /// \brief An input file.
+ INPUT_FILE = 1
+ };
+
+ /// \brief Record types that occur within the AST block itself.
+ enum ASTRecordTypes {
+ /// \brief Record code for the offsets of each type.
+ ///
+ /// The TYPE_OFFSET constant describes the record that occurs
+ /// within the AST block. The record itself is an array of offsets that
+ /// point into the declarations and types block (identified by
+ /// DECLTYPES_BLOCK_ID). The index into the array is based on the ID
+ /// of a type. For a given type ID @c T, the lower three bits of
+ /// @c T are its qualifiers (const, volatile, restrict), as in
+ /// the QualType class. The upper bits, after being shifted and
+ /// subtracting NUM_PREDEF_TYPE_IDS, are used to index into the
+ /// TYPE_OFFSET block to determine the offset of that type's
+ /// corresponding record within the DECLTYPES_BLOCK_ID block.
+ TYPE_OFFSET = 1,
+
+ /// \brief Record code for the offsets of each decl.
+ ///
+ /// The DECL_OFFSET constant describes the record that occurs
+ /// within the block identified by DECL_OFFSETS_BLOCK_ID within
+ /// the AST block. The record itself is an array of offsets that
+ /// point into the declarations and types block (identified by
+ /// DECLTYPES_BLOCK_ID). The declaration ID is an index into this
+ /// record, after subtracting one to account for the use of
+ /// declaration ID 0 for a NULL declaration pointer. Index 0 is
+ /// reserved for the translation unit declaration.
+ DECL_OFFSET = 2,
+
+ /// \brief Record code for the table of offsets of each
+ /// identifier ID.
+ ///
+ /// The offset table contains offsets into the blob stored in
+ /// the IDENTIFIER_TABLE record. Each offset points to the
+ /// NULL-terminated string that corresponds to that identifier.
+ IDENTIFIER_OFFSET = 3,
+
+ /// \brief This is so that older clang versions, before the introduction
+ /// of the control block, can read and reject the newer PCH format.
+ /// *DON"T CHANGE THIS NUMBER*.
+ METADATA_OLD_FORMAT = 4,
+
+ /// \brief Record code for the identifier table.
+ ///
+ /// The identifier table is a simple blob that contains
+ /// NULL-terminated strings for all of the identifiers
+ /// referenced by the AST file. The IDENTIFIER_OFFSET table
+ /// contains the mapping from identifier IDs to the characters
+ /// in this blob. Note that the starting offsets of all of the
+ /// identifiers are odd, so that, when the identifier offset
+ /// table is loaded in, we can use the low bit to distinguish
+ /// between offsets (for unresolved identifier IDs) and
+ /// IdentifierInfo pointers (for already-resolved identifier
+ /// IDs).
+ IDENTIFIER_TABLE = 5,
+
+ /// \brief Record code for the array of external definitions.
+ ///
+ /// The AST file contains a list of all of the unnamed external
+ /// definitions present within the parsed headers, stored as an
+ /// array of declaration IDs. These external definitions will be
+ /// reported to the AST consumer after the AST file has been
+ /// read, since their presence can affect the semantics of the
+ /// program (e.g., for code generation).
+ EXTERNAL_DEFINITIONS = 6,
+
+ /// \brief Record code for the set of non-builtin, special
+ /// types.
+ ///
+ /// This record contains the type IDs for the various type nodes
+ /// that are constructed during semantic analysis (e.g.,
+ /// __builtin_va_list). The SPECIAL_TYPE_* constants provide
+ /// offsets into this record.
+ SPECIAL_TYPES = 7,
+
+ /// \brief Record code for the extra statistics we gather while
+ /// generating an AST file.
+ STATISTICS = 8,
+
+ /// \brief Record code for the array of tentative definitions.
+ TENTATIVE_DEFINITIONS = 9,
+
+ /// \brief Record code for the array of locally-scoped external
+ /// declarations.
+ LOCALLY_SCOPED_EXTERNAL_DECLS = 10,
+
+ /// \brief Record code for the table of offsets into the
+ /// Objective-C method pool.
+ SELECTOR_OFFSETS = 11,
+
+ /// \brief Record code for the Objective-C method pool,
+ METHOD_POOL = 12,
+
+ /// \brief The value of the next __COUNTER__ to dispense.
+ /// [PP_COUNTER_VALUE, Val]
+ PP_COUNTER_VALUE = 13,
+
+ /// \brief Record code for the table of offsets into the block
+ /// of source-location information.
+ SOURCE_LOCATION_OFFSETS = 14,
+
+ /// \brief Record code for the set of source location entries
+ /// that need to be preloaded by the AST reader.
+ ///
+ /// This set contains the source location entry for the
+ /// predefines buffer and for any file entries that need to be
+ /// preloaded.
+ SOURCE_LOCATION_PRELOADS = 15,
+
+ /// \brief Record code for the set of ext_vector type names.
+ EXT_VECTOR_DECLS = 16,
+
+ /// \brief Record code for the array of unused file scoped decls.
+ UNUSED_FILESCOPED_DECLS = 17,
+
+ /// \brief Record code for the table of offsets to entries in the
+ /// preprocessing record.
+ PPD_ENTITIES_OFFSETS = 18,
+
+ /// \brief Record code for the array of VTable uses.
+ VTABLE_USES = 19,
+
+ /// \brief Record code for the array of dynamic classes.
+ DYNAMIC_CLASSES = 20,
+
+ /// \brief Record code for referenced selector pool.
+ REFERENCED_SELECTOR_POOL = 21,
+
+ /// \brief Record code for an update to the TU's lexically contained
+ /// declarations.
+ TU_UPDATE_LEXICAL = 22,
+
+ /// \brief Record code for the array describing the locations (in the
+ /// LOCAL_REDECLARATIONS record) of the redeclaration chains, indexed by
+ /// the first known ID.
+ LOCAL_REDECLARATIONS_MAP = 23,
+
+ /// \brief Record code for declarations that Sema keeps references of.
+ SEMA_DECL_REFS = 24,
+
+ /// \brief Record code for weak undeclared identifiers.
+ WEAK_UNDECLARED_IDENTIFIERS = 25,
+
+ /// \brief Record code for pending implicit instantiations.
+ PENDING_IMPLICIT_INSTANTIATIONS = 26,
+
+ /// \brief Record code for a decl replacement block.
+ ///
+ /// If a declaration is modified after having been deserialized, and then
+ /// written to a dependent AST file, its ID and offset must be added to
+ /// the replacement block.
+ DECL_REPLACEMENTS = 27,
+
+ /// \brief Record code for an update to a decl context's lookup table.
+ ///
+ /// In practice, this should only be used for the TU and namespaces.
+ UPDATE_VISIBLE = 28,
+
+ /// \brief Record for offsets of DECL_UPDATES records for declarations
+ /// that were modified after being deserialized and need updates.
+ DECL_UPDATE_OFFSETS = 29,
+
+ /// \brief Record of updates for a declaration that was modified after
+ /// being deserialized.
+ DECL_UPDATES = 30,
+
+ /// \brief Record code for the table of offsets to CXXBaseSpecifier
+ /// sets.
+ CXX_BASE_SPECIFIER_OFFSETS = 31,
+
+ /// \brief Record code for \#pragma diagnostic mappings.
+ DIAG_PRAGMA_MAPPINGS = 32,
+
+ /// \brief Record code for special CUDA declarations.
+ CUDA_SPECIAL_DECL_REFS = 33,
+
+ /// \brief Record code for header search information.
+ HEADER_SEARCH_TABLE = 34,
+
+ /// \brief Record code for floating point \#pragma options.
+ FP_PRAGMA_OPTIONS = 35,
+
+ /// \brief Record code for enabled OpenCL extensions.
+ OPENCL_EXTENSIONS = 36,
+
+ /// \brief The list of delegating constructor declarations.
+ DELEGATING_CTORS = 37,
+
+ /// \brief Record code for the set of known namespaces, which are used
+ /// for typo correction.
+ KNOWN_NAMESPACES = 38,
+
+ /// \brief Record code for the remapping information used to relate
+ /// loaded modules to the various offsets and IDs(e.g., source location
+ /// offests, declaration and type IDs) that are used in that module to
+ /// refer to other modules.
+ MODULE_OFFSET_MAP = 39,
+
+ /// \brief Record code for the source manager line table information,
+ /// which stores information about \#line directives.
+ SOURCE_MANAGER_LINE_TABLE = 40,
+
+ /// \brief Record code for map of Objective-C class definition IDs to the
+ /// ObjC categories in a module that are attached to that class.
+ OBJC_CATEGORIES_MAP = 41,
+
+ /// \brief Record code for a file sorted array of DeclIDs in a module.
+ FILE_SORTED_DECLS = 42,
+
+ /// \brief Record code for an array of all of the (sub)modules that were
+ /// imported by the AST file.
+ IMPORTED_MODULES = 43,
+
+ /// \brief Record code for the set of merged declarations in an AST file.
+ MERGED_DECLARATIONS = 44,
+
+ /// \brief Record code for the array of redeclaration chains.
+ ///
+ /// This array can only be interpreted properly using the local
+ /// redeclarations map.
+ LOCAL_REDECLARATIONS = 45,
+
+ /// \brief Record code for the array of Objective-C categories (including
+ /// extensions).
+ ///
+ /// This array can only be interpreted properly using the Objective-C
+ /// categories map.
+ OBJC_CATEGORIES = 46,
+
+ /// \brief Record code for the table of offsets of each macro ID.
+ ///
+ /// The offset table contains offsets into the blob stored in
+ /// the preprocessor block. Each offset points to the corresponding
+ /// macro definition.
+ MACRO_OFFSET = 47,
+
+ /// \brief Record of updates for a macro that was modified after
+ /// being deserialized.
+ MACRO_UPDATES = 48
+ };
+
+ /// \brief Record types used within a source manager block.
+ enum SourceManagerRecordTypes {
+ /// \brief Describes a source location entry (SLocEntry) for a
+ /// file.
+ SM_SLOC_FILE_ENTRY = 1,
+ /// \brief Describes a source location entry (SLocEntry) for a
+ /// buffer.
+ SM_SLOC_BUFFER_ENTRY = 2,
+ /// \brief Describes a blob that contains the data for a buffer
+ /// entry. This kind of record always directly follows a
+ /// SM_SLOC_BUFFER_ENTRY record or a SM_SLOC_FILE_ENTRY with an
+ /// overridden buffer.
+ SM_SLOC_BUFFER_BLOB = 3,
+ /// \brief Describes a source location entry (SLocEntry) for a
+ /// macro expansion.
+ SM_SLOC_EXPANSION_ENTRY = 4
+ };
+
+ /// \brief Record types used within a preprocessor block.
+ enum PreprocessorRecordTypes {
+ // The macros in the PP section are a PP_MACRO_* instance followed by a
+ // list of PP_TOKEN instances for each token in the definition.
+
+ /// \brief An object-like macro definition.
+ /// [PP_MACRO_OBJECT_LIKE, IdentInfoID, SLoc, IsUsed]
+ PP_MACRO_OBJECT_LIKE = 1,
+
+ /// \brief A function-like macro definition.
+ /// [PP_MACRO_FUNCTION_LIKE, \<ObjectLikeStuff>, IsC99Varargs,
+ /// IsGNUVarars, NumArgs, ArgIdentInfoID* ]
+ PP_MACRO_FUNCTION_LIKE = 2,
+
+ /// \brief Describes one token.
+ /// [PP_TOKEN, SLoc, Length, IdentInfoID, Kind, Flags]
+ PP_TOKEN = 3
+ };
+
+ /// \brief Record types used within a preprocessor detail block.
+ enum PreprocessorDetailRecordTypes {
+ /// \brief Describes a macro expansion within the preprocessing record.
+ PPD_MACRO_EXPANSION = 0,
+
+ /// \brief Describes a macro definition within the preprocessing record.
+ PPD_MACRO_DEFINITION = 1,
+
+ /// \brief Describes an inclusion directive within the preprocessing
+ /// record.
+ PPD_INCLUSION_DIRECTIVE = 2
+ };
+
+ /// \brief Record types used within a submodule description block.
+ enum SubmoduleRecordTypes {
+ /// \brief Metadata for submodules as a whole.
+ SUBMODULE_METADATA = 0,
+ /// \brief Defines the major attributes of a submodule, including its
+ /// name and parent.
+ SUBMODULE_DEFINITION = 1,
+ /// \brief Specifies the umbrella header used to create this module,
+ /// if any.
+ SUBMODULE_UMBRELLA_HEADER = 2,
+ /// \brief Specifies a header that falls into this (sub)module.
+ SUBMODULE_HEADER = 3,
+ /// \brief Specifies a top-level header that falls into this (sub)module.
+ SUBMODULE_TOPHEADER = 4,
+ /// \brief Specifies an umbrella directory.
+ SUBMODULE_UMBRELLA_DIR = 5,
+ /// \brief Specifies the submodules that are imported by this
+ /// submodule.
+ SUBMODULE_IMPORTS = 6,
+ /// \brief Specifies the submodules that are re-exported from this
+ /// submodule.
+ SUBMODULE_EXPORTS = 7,
+ /// \brief Specifies a required feature.
+ SUBMODULE_REQUIRES = 8,
+ /// \brief Specifies a header that has been explicitly excluded
+ /// from this submodule.
+ SUBMODULE_EXCLUDED_HEADER = 9
+ };
+
+ /// \brief Record types used within a comments block.
+ enum CommentRecordTypes {
+ COMMENTS_RAW_COMMENT = 0
+ };
+
+ /// \defgroup ASTAST AST file AST constants
+ ///
+ /// The constants in this group describe various components of the
+ /// abstract syntax tree within an AST file.
+ ///
+ /// @{
+
+ /// \brief Predefined type IDs.
+ ///
+ /// These type IDs correspond to predefined types in the AST
+ /// context, such as built-in types (int) and special place-holder
+ /// types (the \<overload> and \<dependent> type markers). Such
+ /// types are never actually serialized, since they will be built
+ /// by the AST context when it is created.
+ enum PredefinedTypeIDs {
+ /// \brief The NULL type.
+ PREDEF_TYPE_NULL_ID = 0,
+ /// \brief The void type.
+ PREDEF_TYPE_VOID_ID = 1,
+ /// \brief The 'bool' or '_Bool' type.
+ PREDEF_TYPE_BOOL_ID = 2,
+ /// \brief The 'char' type, when it is unsigned.
+ PREDEF_TYPE_CHAR_U_ID = 3,
+ /// \brief The 'unsigned char' type.
+ PREDEF_TYPE_UCHAR_ID = 4,
+ /// \brief The 'unsigned short' type.
+ PREDEF_TYPE_USHORT_ID = 5,
+ /// \brief The 'unsigned int' type.
+ PREDEF_TYPE_UINT_ID = 6,
+ /// \brief The 'unsigned long' type.
+ PREDEF_TYPE_ULONG_ID = 7,
+ /// \brief The 'unsigned long long' type.
+ PREDEF_TYPE_ULONGLONG_ID = 8,
+ /// \brief The 'char' type, when it is signed.
+ PREDEF_TYPE_CHAR_S_ID = 9,
+ /// \brief The 'signed char' type.
+ PREDEF_TYPE_SCHAR_ID = 10,
+ /// \brief The C++ 'wchar_t' type.
+ PREDEF_TYPE_WCHAR_ID = 11,
+ /// \brief The (signed) 'short' type.
+ PREDEF_TYPE_SHORT_ID = 12,
+ /// \brief The (signed) 'int' type.
+ PREDEF_TYPE_INT_ID = 13,
+ /// \brief The (signed) 'long' type.
+ PREDEF_TYPE_LONG_ID = 14,
+ /// \brief The (signed) 'long long' type.
+ PREDEF_TYPE_LONGLONG_ID = 15,
+ /// \brief The 'float' type.
+ PREDEF_TYPE_FLOAT_ID = 16,
+ /// \brief The 'double' type.
+ PREDEF_TYPE_DOUBLE_ID = 17,
+ /// \brief The 'long double' type.
+ PREDEF_TYPE_LONGDOUBLE_ID = 18,
+ /// \brief The placeholder type for overloaded function sets.
+ PREDEF_TYPE_OVERLOAD_ID = 19,
+ /// \brief The placeholder type for dependent types.
+ PREDEF_TYPE_DEPENDENT_ID = 20,
+ /// \brief The '__uint128_t' type.
+ PREDEF_TYPE_UINT128_ID = 21,
+ /// \brief The '__int128_t' type.
+ PREDEF_TYPE_INT128_ID = 22,
+ /// \brief The type of 'nullptr'.
+ PREDEF_TYPE_NULLPTR_ID = 23,
+ /// \brief The C++ 'char16_t' type.
+ PREDEF_TYPE_CHAR16_ID = 24,
+ /// \brief The C++ 'char32_t' type.
+ PREDEF_TYPE_CHAR32_ID = 25,
+ /// \brief The ObjC 'id' type.
+ PREDEF_TYPE_OBJC_ID = 26,
+ /// \brief The ObjC 'Class' type.
+ PREDEF_TYPE_OBJC_CLASS = 27,
+ /// \brief The ObjC 'SEL' type.
+ PREDEF_TYPE_OBJC_SEL = 28,
+ /// \brief The 'unknown any' placeholder type.
+ PREDEF_TYPE_UNKNOWN_ANY = 29,
+ /// \brief The placeholder type for bound member functions.
+ PREDEF_TYPE_BOUND_MEMBER = 30,
+ /// \brief The "auto" deduction type.
+ PREDEF_TYPE_AUTO_DEDUCT = 31,
+ /// \brief The "auto &&" deduction type.
+ PREDEF_TYPE_AUTO_RREF_DEDUCT = 32,
+ /// \brief The OpenCL 'half' / ARM NEON __fp16 type.
+ PREDEF_TYPE_HALF_ID = 33,
+ /// \brief ARC's unbridged-cast placeholder type.
+ PREDEF_TYPE_ARC_UNBRIDGED_CAST = 34,
+ /// \brief The pseudo-object placeholder type.
+ PREDEF_TYPE_PSEUDO_OBJECT = 35,
+ /// \brief The __va_list_tag placeholder type.
+ PREDEF_TYPE_VA_LIST_TAG = 36,
+ /// \brief The placeholder type for builtin functions.
+ PREDEF_TYPE_BUILTIN_FN = 37,
+ /// \brief OpenCL 1d image type.
+ PREDEF_TYPE_IMAGE1D_ID = 38,
+ /// \brief OpenCL 1d image array type.
+ PREDEF_TYPE_IMAGE1D_ARR_ID = 39,
+ /// \brief OpenCL 1d image buffer type.
+ PREDEF_TYPE_IMAGE1D_BUFF_ID = 40,
+ /// \brief OpenCL 2d image type.
+ PREDEF_TYPE_IMAGE2D_ID = 41,
+ /// \brief OpenCL 2d image array type.
+ PREDEF_TYPE_IMAGE2D_ARR_ID = 42,
+ /// \brief OpenCL 3d image type.
+ PREDEF_TYPE_IMAGE3D_ID = 43
+ };
+
+ /// \brief The number of predefined type IDs that are reserved for
+ /// the PREDEF_TYPE_* constants.
+ ///
+ /// Type IDs for non-predefined types will start at
+ /// NUM_PREDEF_TYPE_IDs.
+ const unsigned NUM_PREDEF_TYPE_IDS = 100;
+
+ /// \brief The number of allowed abbreviations in bits
+ const unsigned NUM_ALLOWED_ABBREVS_SIZE = 4;
+
+ /// \brief Record codes for each kind of type.
+ ///
+ /// These constants describe the type records that can occur within a
+ /// block identified by DECLTYPES_BLOCK_ID in the AST file. Each
+ /// constant describes a record for a specific type class in the
+ /// AST.
+ enum TypeCode {
+ /// \brief An ExtQualType record.
+ TYPE_EXT_QUAL = 1,
+ /// \brief A ComplexType record.
+ TYPE_COMPLEX = 3,
+ /// \brief A PointerType record.
+ TYPE_POINTER = 4,
+ /// \brief A BlockPointerType record.
+ TYPE_BLOCK_POINTER = 5,
+ /// \brief An LValueReferenceType record.
+ TYPE_LVALUE_REFERENCE = 6,
+ /// \brief An RValueReferenceType record.
+ TYPE_RVALUE_REFERENCE = 7,
+ /// \brief A MemberPointerType record.
+ TYPE_MEMBER_POINTER = 8,
+ /// \brief A ConstantArrayType record.
+ TYPE_CONSTANT_ARRAY = 9,
+ /// \brief An IncompleteArrayType record.
+ TYPE_INCOMPLETE_ARRAY = 10,
+ /// \brief A VariableArrayType record.
+ TYPE_VARIABLE_ARRAY = 11,
+ /// \brief A VectorType record.
+ TYPE_VECTOR = 12,
+ /// \brief An ExtVectorType record.
+ TYPE_EXT_VECTOR = 13,
+ /// \brief A FunctionNoProtoType record.
+ TYPE_FUNCTION_NO_PROTO = 14,
+ /// \brief A FunctionProtoType record.
+ TYPE_FUNCTION_PROTO = 15,
+ /// \brief A TypedefType record.
+ TYPE_TYPEDEF = 16,
+ /// \brief A TypeOfExprType record.
+ TYPE_TYPEOF_EXPR = 17,
+ /// \brief A TypeOfType record.
+ TYPE_TYPEOF = 18,
+ /// \brief A RecordType record.
+ TYPE_RECORD = 19,
+ /// \brief An EnumType record.
+ TYPE_ENUM = 20,
+ /// \brief An ObjCInterfaceType record.
+ TYPE_OBJC_INTERFACE = 21,
+ /// \brief An ObjCObjectPointerType record.
+ TYPE_OBJC_OBJECT_POINTER = 22,
+ /// \brief a DecltypeType record.
+ TYPE_DECLTYPE = 23,
+ /// \brief An ElaboratedType record.
+ TYPE_ELABORATED = 24,
+ /// \brief A SubstTemplateTypeParmType record.
+ TYPE_SUBST_TEMPLATE_TYPE_PARM = 25,
+ /// \brief An UnresolvedUsingType record.
+ TYPE_UNRESOLVED_USING = 26,
+ /// \brief An InjectedClassNameType record.
+ TYPE_INJECTED_CLASS_NAME = 27,
+ /// \brief An ObjCObjectType record.
+ TYPE_OBJC_OBJECT = 28,
+ /// \brief An TemplateTypeParmType record.
+ TYPE_TEMPLATE_TYPE_PARM = 29,
+ /// \brief An TemplateSpecializationType record.
+ TYPE_TEMPLATE_SPECIALIZATION = 30,
+ /// \brief A DependentNameType record.
+ TYPE_DEPENDENT_NAME = 31,
+ /// \brief A DependentTemplateSpecializationType record.
+ TYPE_DEPENDENT_TEMPLATE_SPECIALIZATION = 32,
+ /// \brief A DependentSizedArrayType record.
+ TYPE_DEPENDENT_SIZED_ARRAY = 33,
+ /// \brief A ParenType record.
+ TYPE_PAREN = 34,
+ /// \brief A PackExpansionType record.
+ TYPE_PACK_EXPANSION = 35,
+ /// \brief An AttributedType record.
+ TYPE_ATTRIBUTED = 36,
+ /// \brief A SubstTemplateTypeParmPackType record.
+ TYPE_SUBST_TEMPLATE_TYPE_PARM_PACK = 37,
+ /// \brief A AutoType record.
+ TYPE_AUTO = 38,
+ /// \brief A UnaryTransformType record.
+ TYPE_UNARY_TRANSFORM = 39,
+ /// \brief An AtomicType record.
+ TYPE_ATOMIC = 40
+ };
+
+ /// \brief The type IDs for special types constructed by semantic
+ /// analysis.
+ ///
+ /// The constants in this enumeration are indices into the
+ /// SPECIAL_TYPES record.
+ enum SpecialTypeIDs {
+ /// \brief CFConstantString type
+ SPECIAL_TYPE_CF_CONSTANT_STRING = 0,
+ /// \brief C FILE typedef type
+ SPECIAL_TYPE_FILE = 1,
+ /// \brief C jmp_buf typedef type
+ SPECIAL_TYPE_JMP_BUF = 2,
+ /// \brief C sigjmp_buf typedef type
+ SPECIAL_TYPE_SIGJMP_BUF = 3,
+ /// \brief Objective-C "id" redefinition type
+ SPECIAL_TYPE_OBJC_ID_REDEFINITION = 4,
+ /// \brief Objective-C "Class" redefinition type
+ SPECIAL_TYPE_OBJC_CLASS_REDEFINITION = 5,
+ /// \brief Objective-C "SEL" redefinition type
+ SPECIAL_TYPE_OBJC_SEL_REDEFINITION = 6,
+ /// \brief C ucontext_t typedef type
+ SPECIAL_TYPE_UCONTEXT_T = 7
+ };
+
+ /// \brief The number of special type IDs.
+ const unsigned NumSpecialTypeIDs = 8;
+
+ /// \brief Predefined declaration IDs.
+ ///
+ /// These declaration IDs correspond to predefined declarations in the AST
+ /// context, such as the NULL declaration ID. Such declarations are never
+ /// actually serialized, since they will be built by the AST context when
+ /// it is created.
+ enum PredefinedDeclIDs {
+ /// \brief The NULL declaration.
+ PREDEF_DECL_NULL_ID = 0,
+
+ /// \brief The translation unit.
+ PREDEF_DECL_TRANSLATION_UNIT_ID = 1,
+
+ /// \brief The Objective-C 'id' type.
+ PREDEF_DECL_OBJC_ID_ID = 2,
+
+ /// \brief The Objective-C 'SEL' type.
+ PREDEF_DECL_OBJC_SEL_ID = 3,
+
+ /// \brief The Objective-C 'Class' type.
+ PREDEF_DECL_OBJC_CLASS_ID = 4,
+
+ /// \brief The Objective-C 'Protocol' type.
+ PREDEF_DECL_OBJC_PROTOCOL_ID = 5,
+
+ /// \brief The signed 128-bit integer type.
+ PREDEF_DECL_INT_128_ID = 6,
+
+ /// \brief The unsigned 128-bit integer type.
+ PREDEF_DECL_UNSIGNED_INT_128_ID = 7,
+
+ /// \brief The internal 'instancetype' typedef.
+ PREDEF_DECL_OBJC_INSTANCETYPE_ID = 8,
+
+ /// \brief The internal '__builtin_va_list' typedef.
+ PREDEF_DECL_BUILTIN_VA_LIST_ID = 9
+ };
+
+ /// \brief The number of declaration IDs that are predefined.
+ ///
+ /// For more information about predefined declarations, see the
+ /// \c PredefinedDeclIDs type and the PREDEF_DECL_*_ID constants.
+ const unsigned int NUM_PREDEF_DECL_IDS = 10;
+
+ /// \brief Record codes for each kind of declaration.
+ ///
+ /// These constants describe the declaration records that can occur within
+ /// a declarations block (identified by DECLS_BLOCK_ID). Each
+ /// constant describes a record for a specific declaration class
+ /// in the AST.
+ enum DeclCode {
+ /// \brief A TypedefDecl record.
+ DECL_TYPEDEF = 51,
+ /// \brief A TypeAliasDecl record.
+ DECL_TYPEALIAS,
+ /// \brief An EnumDecl record.
+ DECL_ENUM,
+ /// \brief A RecordDecl record.
+ DECL_RECORD,
+ /// \brief An EnumConstantDecl record.
+ DECL_ENUM_CONSTANT,
+ /// \brief A FunctionDecl record.
+ DECL_FUNCTION,
+ /// \brief A ObjCMethodDecl record.
+ DECL_OBJC_METHOD,
+ /// \brief A ObjCInterfaceDecl record.
+ DECL_OBJC_INTERFACE,
+ /// \brief A ObjCProtocolDecl record.
+ DECL_OBJC_PROTOCOL,
+ /// \brief A ObjCIvarDecl record.
+ DECL_OBJC_IVAR,
+ /// \brief A ObjCAtDefsFieldDecl record.
+ DECL_OBJC_AT_DEFS_FIELD,
+ /// \brief A ObjCCategoryDecl record.
+ DECL_OBJC_CATEGORY,
+ /// \brief A ObjCCategoryImplDecl record.
+ DECL_OBJC_CATEGORY_IMPL,
+ /// \brief A ObjCImplementationDecl record.
+ DECL_OBJC_IMPLEMENTATION,
+ /// \brief A ObjCCompatibleAliasDecl record.
+ DECL_OBJC_COMPATIBLE_ALIAS,
+ /// \brief A ObjCPropertyDecl record.
+ DECL_OBJC_PROPERTY,
+ /// \brief A ObjCPropertyImplDecl record.
+ DECL_OBJC_PROPERTY_IMPL,
+ /// \brief A FieldDecl record.
+ DECL_FIELD,
+ /// \brief A VarDecl record.
+ DECL_VAR,
+ /// \brief An ImplicitParamDecl record.
+ DECL_IMPLICIT_PARAM,
+ /// \brief A ParmVarDecl record.
+ DECL_PARM_VAR,
+ /// \brief A FileScopeAsmDecl record.
+ DECL_FILE_SCOPE_ASM,
+ /// \brief A BlockDecl record.
+ DECL_BLOCK,
+ /// \brief A record that stores the set of declarations that are
+ /// lexically stored within a given DeclContext.
+ ///
+ /// The record itself is a blob that is an array of declaration IDs,
+ /// in the order in which those declarations were added to the
+ /// declaration context. This data is used when iterating over
+ /// the contents of a DeclContext, e.g., via
+ /// DeclContext::decls_begin() and DeclContext::decls_end().
+ DECL_CONTEXT_LEXICAL,
+ /// \brief A record that stores the set of declarations that are
+ /// visible from a given DeclContext.
+ ///
+ /// The record itself stores a set of mappings, each of which
+ /// associates a declaration name with one or more declaration
+ /// IDs. This data is used when performing qualified name lookup
+ /// into a DeclContext via DeclContext::lookup.
+ DECL_CONTEXT_VISIBLE,
+ /// \brief A LabelDecl record.
+ DECL_LABEL,
+ /// \brief A NamespaceDecl record.
+ DECL_NAMESPACE,
+ /// \brief A NamespaceAliasDecl record.
+ DECL_NAMESPACE_ALIAS,
+ /// \brief A UsingDecl record.
+ DECL_USING,
+ /// \brief A UsingShadowDecl record.
+ DECL_USING_SHADOW,
+ /// \brief A UsingDirecitveDecl record.
+ DECL_USING_DIRECTIVE,
+ /// \brief An UnresolvedUsingValueDecl record.
+ DECL_UNRESOLVED_USING_VALUE,
+ /// \brief An UnresolvedUsingTypenameDecl record.
+ DECL_UNRESOLVED_USING_TYPENAME,
+ /// \brief A LinkageSpecDecl record.
+ DECL_LINKAGE_SPEC,
+ /// \brief A CXXRecordDecl record.
+ DECL_CXX_RECORD,
+ /// \brief A CXXMethodDecl record.
+ DECL_CXX_METHOD,
+ /// \brief A CXXConstructorDecl record.
+ DECL_CXX_CONSTRUCTOR,
+ /// \brief A CXXDestructorDecl record.
+ DECL_CXX_DESTRUCTOR,
+ /// \brief A CXXConversionDecl record.
+ DECL_CXX_CONVERSION,
+ /// \brief An AccessSpecDecl record.
+ DECL_ACCESS_SPEC,
+
+ /// \brief A FriendDecl record.
+ DECL_FRIEND,
+ /// \brief A FriendTemplateDecl record.
+ DECL_FRIEND_TEMPLATE,
+ /// \brief A ClassTemplateDecl record.
+ DECL_CLASS_TEMPLATE,
+ /// \brief A ClassTemplateSpecializationDecl record.
+ DECL_CLASS_TEMPLATE_SPECIALIZATION,
+ /// \brief A ClassTemplatePartialSpecializationDecl record.
+ DECL_CLASS_TEMPLATE_PARTIAL_SPECIALIZATION,
+ /// \brief A FunctionTemplateDecl record.
+ DECL_FUNCTION_TEMPLATE,
+ /// \brief A TemplateTypeParmDecl record.
+ DECL_TEMPLATE_TYPE_PARM,
+ /// \brief A NonTypeTemplateParmDecl record.
+ DECL_NON_TYPE_TEMPLATE_PARM,
+ /// \brief A TemplateTemplateParmDecl record.
+ DECL_TEMPLATE_TEMPLATE_PARM,
+ /// \brief A TypeAliasTemplateDecl record.
+ DECL_TYPE_ALIAS_TEMPLATE,
+ /// \brief A StaticAssertDecl record.
+ DECL_STATIC_ASSERT,
+ /// \brief A record containing CXXBaseSpecifiers.
+ DECL_CXX_BASE_SPECIFIERS,
+ /// \brief A IndirectFieldDecl record.
+ DECL_INDIRECTFIELD,
+ /// \brief A NonTypeTemplateParmDecl record that stores an expanded
+ /// non-type template parameter pack.
+ DECL_EXPANDED_NON_TYPE_TEMPLATE_PARM_PACK,
+ /// \brief A TemplateTemplateParmDecl record that stores an expanded
+ /// template template parameter pack.
+ DECL_EXPANDED_TEMPLATE_TEMPLATE_PARM_PACK,
+ /// \brief A ClassScopeFunctionSpecializationDecl record a class scope
+ /// function specialization. (Microsoft extension).
+ DECL_CLASS_SCOPE_FUNCTION_SPECIALIZATION,
+ /// \brief An ImportDecl recording a module import.
+ DECL_IMPORT
+ };
+
+ /// \brief Record codes for each kind of statement or expression.
+ ///
+ /// These constants describe the records that describe statements
+ /// or expressions. These records occur within type and declarations
+ /// block, so they begin with record values of 100. Each constant
+ /// describes a record for a specific statement or expression class in the
+ /// AST.
+ enum StmtCode {
+ /// \brief A marker record that indicates that we are at the end
+ /// of an expression.
+ STMT_STOP = 100,
+ /// \brief A NULL expression.
+ STMT_NULL_PTR,
+ /// \brief A reference to a previously [de]serialized Stmt record.
+ STMT_REF_PTR,
+ /// \brief A NullStmt record.
+ STMT_NULL,
+ /// \brief A CompoundStmt record.
+ STMT_COMPOUND,
+ /// \brief A CaseStmt record.
+ STMT_CASE,
+ /// \brief A DefaultStmt record.
+ STMT_DEFAULT,
+ /// \brief A LabelStmt record.
+ STMT_LABEL,
+ /// \brief An AttributedStmt record.
+ STMT_ATTRIBUTED,
+ /// \brief An IfStmt record.
+ STMT_IF,
+ /// \brief A SwitchStmt record.
+ STMT_SWITCH,
+ /// \brief A WhileStmt record.
+ STMT_WHILE,
+ /// \brief A DoStmt record.
+ STMT_DO,
+ /// \brief A ForStmt record.
+ STMT_FOR,
+ /// \brief A GotoStmt record.
+ STMT_GOTO,
+ /// \brief An IndirectGotoStmt record.
+ STMT_INDIRECT_GOTO,
+ /// \brief A ContinueStmt record.
+ STMT_CONTINUE,
+ /// \brief A BreakStmt record.
+ STMT_BREAK,
+ /// \brief A ReturnStmt record.
+ STMT_RETURN,
+ /// \brief A DeclStmt record.
+ STMT_DECL,
+ /// \brief A GCC-style AsmStmt record.
+ STMT_GCCASM,
+ /// \brief A MS-style AsmStmt record.
+ STMT_MSASM,
+ /// \brief A PredefinedExpr record.
+ EXPR_PREDEFINED,
+ /// \brief A DeclRefExpr record.
+ EXPR_DECL_REF,
+ /// \brief An IntegerLiteral record.
+ EXPR_INTEGER_LITERAL,
+ /// \brief A FloatingLiteral record.
+ EXPR_FLOATING_LITERAL,
+ /// \brief An ImaginaryLiteral record.
+ EXPR_IMAGINARY_LITERAL,
+ /// \brief A StringLiteral record.
+ EXPR_STRING_LITERAL,
+ /// \brief A CharacterLiteral record.
+ EXPR_CHARACTER_LITERAL,
+ /// \brief A ParenExpr record.
+ EXPR_PAREN,
+ /// \brief A ParenListExpr record.
+ EXPR_PAREN_LIST,
+ /// \brief A UnaryOperator record.
+ EXPR_UNARY_OPERATOR,
+ /// \brief An OffsetOfExpr record.
+ EXPR_OFFSETOF,
+ /// \brief A SizefAlignOfExpr record.
+ EXPR_SIZEOF_ALIGN_OF,
+ /// \brief An ArraySubscriptExpr record.
+ EXPR_ARRAY_SUBSCRIPT,
+ /// \brief A CallExpr record.
+ EXPR_CALL,
+ /// \brief A MemberExpr record.
+ EXPR_MEMBER,
+ /// \brief A BinaryOperator record.
+ EXPR_BINARY_OPERATOR,
+ /// \brief A CompoundAssignOperator record.
+ EXPR_COMPOUND_ASSIGN_OPERATOR,
+ /// \brief A ConditionOperator record.
+ EXPR_CONDITIONAL_OPERATOR,
+ /// \brief An ImplicitCastExpr record.
+ EXPR_IMPLICIT_CAST,
+ /// \brief A CStyleCastExpr record.
+ EXPR_CSTYLE_CAST,
+ /// \brief A CompoundLiteralExpr record.
+ EXPR_COMPOUND_LITERAL,
+ /// \brief An ExtVectorElementExpr record.
+ EXPR_EXT_VECTOR_ELEMENT,
+ /// \brief An InitListExpr record.
+ EXPR_INIT_LIST,
+ /// \brief A DesignatedInitExpr record.
+ EXPR_DESIGNATED_INIT,
+ /// \brief An ImplicitValueInitExpr record.
+ EXPR_IMPLICIT_VALUE_INIT,
+ /// \brief A VAArgExpr record.
+ EXPR_VA_ARG,
+ /// \brief An AddrLabelExpr record.
+ EXPR_ADDR_LABEL,
+ /// \brief A StmtExpr record.
+ EXPR_STMT,
+ /// \brief A ChooseExpr record.
+ EXPR_CHOOSE,
+ /// \brief A GNUNullExpr record.
+ EXPR_GNU_NULL,
+ /// \brief A ShuffleVectorExpr record.
+ EXPR_SHUFFLE_VECTOR,
+ /// \brief BlockExpr
+ EXPR_BLOCK,
+ /// \brief A GenericSelectionExpr record.
+ EXPR_GENERIC_SELECTION,
+ /// \brief A PseudoObjectExpr record.
+ EXPR_PSEUDO_OBJECT,
+ /// \brief An AtomicExpr record.
+ EXPR_ATOMIC,
+
+ // Objective-C
+
+ /// \brief An ObjCStringLiteral record.
+ EXPR_OBJC_STRING_LITERAL,
+
+ EXPR_OBJC_BOXED_EXPRESSION,
+ EXPR_OBJC_ARRAY_LITERAL,
+ EXPR_OBJC_DICTIONARY_LITERAL,
+
+
+ /// \brief An ObjCEncodeExpr record.
+ EXPR_OBJC_ENCODE,
+ /// \brief An ObjCSelectorExpr record.
+ EXPR_OBJC_SELECTOR_EXPR,
+ /// \brief An ObjCProtocolExpr record.
+ EXPR_OBJC_PROTOCOL_EXPR,
+ /// \brief An ObjCIvarRefExpr record.
+ EXPR_OBJC_IVAR_REF_EXPR,
+ /// \brief An ObjCPropertyRefExpr record.
+ EXPR_OBJC_PROPERTY_REF_EXPR,
+ /// \brief An ObjCSubscriptRefExpr record.
+ EXPR_OBJC_SUBSCRIPT_REF_EXPR,
+ /// \brief UNUSED
+ EXPR_OBJC_KVC_REF_EXPR,
+ /// \brief An ObjCMessageExpr record.
+ EXPR_OBJC_MESSAGE_EXPR,
+ /// \brief An ObjCIsa Expr record.
+ EXPR_OBJC_ISA,
+ /// \brief An ObjCIndirectCopyRestoreExpr record.
+ EXPR_OBJC_INDIRECT_COPY_RESTORE,
+
+ /// \brief An ObjCForCollectionStmt record.
+ STMT_OBJC_FOR_COLLECTION,
+ /// \brief An ObjCAtCatchStmt record.
+ STMT_OBJC_CATCH,
+ /// \brief An ObjCAtFinallyStmt record.
+ STMT_OBJC_FINALLY,
+ /// \brief An ObjCAtTryStmt record.
+ STMT_OBJC_AT_TRY,
+ /// \brief An ObjCAtSynchronizedStmt record.
+ STMT_OBJC_AT_SYNCHRONIZED,
+ /// \brief An ObjCAtThrowStmt record.
+ STMT_OBJC_AT_THROW,
+ /// \brief An ObjCAutoreleasePoolStmt record.
+ STMT_OBJC_AUTORELEASE_POOL,
+ /// \brief A ObjCBoolLiteralExpr record.
+ EXPR_OBJC_BOOL_LITERAL,
+
+ // C++
+
+ /// \brief A CXXCatchStmt record.
+ STMT_CXX_CATCH,
+ /// \brief A CXXTryStmt record.
+ STMT_CXX_TRY,
+ /// \brief A CXXForRangeStmt record.
+ STMT_CXX_FOR_RANGE,
+
+ /// \brief A CXXOperatorCallExpr record.
+ EXPR_CXX_OPERATOR_CALL,
+ /// \brief A CXXMemberCallExpr record.
+ EXPR_CXX_MEMBER_CALL,
+ /// \brief A CXXConstructExpr record.
+ EXPR_CXX_CONSTRUCT,
+ /// \brief A CXXTemporaryObjectExpr record.
+ EXPR_CXX_TEMPORARY_OBJECT,
+ /// \brief A CXXStaticCastExpr record.
+ EXPR_CXX_STATIC_CAST,
+ /// \brief A CXXDynamicCastExpr record.
+ EXPR_CXX_DYNAMIC_CAST,
+ /// \brief A CXXReinterpretCastExpr record.
+ EXPR_CXX_REINTERPRET_CAST,
+ /// \brief A CXXConstCastExpr record.
+ EXPR_CXX_CONST_CAST,
+ /// \brief A CXXFunctionalCastExpr record.
+ EXPR_CXX_FUNCTIONAL_CAST,
+ /// \brief A UserDefinedLiteral record.
+ EXPR_USER_DEFINED_LITERAL,
+ /// \brief A CXXBoolLiteralExpr record.
+ EXPR_CXX_BOOL_LITERAL,
+ EXPR_CXX_NULL_PTR_LITERAL, // CXXNullPtrLiteralExpr
+ EXPR_CXX_TYPEID_EXPR, // CXXTypeidExpr (of expr).
+ EXPR_CXX_TYPEID_TYPE, // CXXTypeidExpr (of type).
+ EXPR_CXX_THIS, // CXXThisExpr
+ EXPR_CXX_THROW, // CXXThrowExpr
+ EXPR_CXX_DEFAULT_ARG, // CXXDefaultArgExpr
+ EXPR_CXX_BIND_TEMPORARY, // CXXBindTemporaryExpr
+
+ EXPR_CXX_SCALAR_VALUE_INIT, // CXXScalarValueInitExpr
+ EXPR_CXX_NEW, // CXXNewExpr
+ EXPR_CXX_DELETE, // CXXDeleteExpr
+ EXPR_CXX_PSEUDO_DESTRUCTOR, // CXXPseudoDestructorExpr
+
+ EXPR_EXPR_WITH_CLEANUPS, // ExprWithCleanups
+
+ EXPR_CXX_DEPENDENT_SCOPE_MEMBER, // CXXDependentScopeMemberExpr
+ EXPR_CXX_DEPENDENT_SCOPE_DECL_REF, // DependentScopeDeclRefExpr
+ EXPR_CXX_UNRESOLVED_CONSTRUCT, // CXXUnresolvedConstructExpr
+ EXPR_CXX_UNRESOLVED_MEMBER, // UnresolvedMemberExpr
+ EXPR_CXX_UNRESOLVED_LOOKUP, // UnresolvedLookupExpr
+
+ EXPR_CXX_UNARY_TYPE_TRAIT, // UnaryTypeTraitExpr
+ EXPR_CXX_EXPRESSION_TRAIT, // ExpressionTraitExpr
+ EXPR_CXX_NOEXCEPT, // CXXNoexceptExpr
+
+ EXPR_OPAQUE_VALUE, // OpaqueValueExpr
+ EXPR_BINARY_CONDITIONAL_OPERATOR, // BinaryConditionalOperator
+ EXPR_BINARY_TYPE_TRAIT, // BinaryTypeTraitExpr
+ EXPR_TYPE_TRAIT, // TypeTraitExpr
+ EXPR_ARRAY_TYPE_TRAIT, // ArrayTypeTraitIntExpr
+
+ EXPR_PACK_EXPANSION, // PackExpansionExpr
+ EXPR_SIZEOF_PACK, // SizeOfPackExpr
+ EXPR_SUBST_NON_TYPE_TEMPLATE_PARM, // SubstNonTypeTemplateParmExpr
+ EXPR_SUBST_NON_TYPE_TEMPLATE_PARM_PACK,// SubstNonTypeTemplateParmPackExpr
+ EXPR_FUNCTION_PARM_PACK, // FunctionParmPackExpr
+ EXPR_MATERIALIZE_TEMPORARY, // MaterializeTemporaryExpr
+
+ // CUDA
+ EXPR_CUDA_KERNEL_CALL, // CUDAKernelCallExpr
+
+ // OpenCL
+ EXPR_ASTYPE, // AsTypeExpr
+
+ // Microsoft
+ EXPR_CXX_UUIDOF_EXPR, // CXXUuidofExpr (of expr).
+ EXPR_CXX_UUIDOF_TYPE, // CXXUuidofExpr (of type).
+ STMT_SEH_EXCEPT, // SEHExceptStmt
+ STMT_SEH_FINALLY, // SEHFinallyStmt
+ STMT_SEH_TRY, // SEHTryStmt
+
+ // ARC
+ EXPR_OBJC_BRIDGED_CAST, // ObjCBridgedCastExpr
+
+ STMT_MS_DEPENDENT_EXISTS, // MSDependentExistsStmt
+ EXPR_LAMBDA // LambdaExpr
+ };
+
+ /// \brief The kinds of designators that can occur in a
+ /// DesignatedInitExpr.
+ enum DesignatorTypes {
+ /// \brief Field designator where only the field name is known.
+ DESIG_FIELD_NAME = 0,
+ /// \brief Field designator where the field has been resolved to
+ /// a declaration.
+ DESIG_FIELD_DECL = 1,
+ /// \brief Array designator.
+ DESIG_ARRAY = 2,
+ /// \brief GNU array range designator.
+ DESIG_ARRAY_RANGE = 3
+ };
+
+ /// \brief The different kinds of data that can occur in a
+ /// CtorInitializer.
+ enum CtorInitializerType {
+ CTOR_INITIALIZER_BASE,
+ CTOR_INITIALIZER_DELEGATING,
+ CTOR_INITIALIZER_MEMBER,
+ CTOR_INITIALIZER_INDIRECT_MEMBER
+ };
+
+ /// \brief Describes the redeclarations of a declaration.
+ struct LocalRedeclarationsInfo {
+ DeclID FirstID; // The ID of the first declaration
+ unsigned Offset; // Offset into the array of redeclaration chains.
+
+ friend bool operator<(const LocalRedeclarationsInfo &X,
+ const LocalRedeclarationsInfo &Y) {
+ return X.FirstID < Y.FirstID;
+ }
+
+ friend bool operator>(const LocalRedeclarationsInfo &X,
+ const LocalRedeclarationsInfo &Y) {
+ return X.FirstID > Y.FirstID;
+ }
+
+ friend bool operator<=(const LocalRedeclarationsInfo &X,
+ const LocalRedeclarationsInfo &Y) {
+ return X.FirstID <= Y.FirstID;
+ }
+
+ friend bool operator>=(const LocalRedeclarationsInfo &X,
+ const LocalRedeclarationsInfo &Y) {
+ return X.FirstID >= Y.FirstID;
+ }
+ };
+
+ /// \brief Describes the categories of an Objective-C class.
+ struct ObjCCategoriesInfo {
+ DeclID DefinitionID; // The ID of the definition
+ unsigned Offset; // Offset into the array of category lists.
+
+ friend bool operator<(const ObjCCategoriesInfo &X,
+ const ObjCCategoriesInfo &Y) {
+ return X.DefinitionID < Y.DefinitionID;
+ }
+
+ friend bool operator>(const ObjCCategoriesInfo &X,
+ const ObjCCategoriesInfo &Y) {
+ return X.DefinitionID > Y.DefinitionID;
+ }
+
+ friend bool operator<=(const ObjCCategoriesInfo &X,
+ const ObjCCategoriesInfo &Y) {
+ return X.DefinitionID <= Y.DefinitionID;
+ }
+
+ friend bool operator>=(const ObjCCategoriesInfo &X,
+ const ObjCCategoriesInfo &Y) {
+ return X.DefinitionID >= Y.DefinitionID;
+ }
+ };
+
+ /// @}
+ }
+} // end namespace clang
+
+#endif
diff --git a/clang/lib/AST/ASTContext.cpp b/clang/lib/AST/ASTContext.cpp index f3fa13584de..b04b830c852 100644 --- a/clang/lib/AST/ASTContext.cpp +++ b/clang/lib/AST/ASTContext.cpp @@ -874,6 +874,15 @@ void ASTContext::InitBuiltinTypes(const TargetInfo &Target) { InitBuiltinType(ObjCBuiltinIdTy, BuiltinType::ObjCId); InitBuiltinType(ObjCBuiltinClassTy, BuiltinType::ObjCClass); InitBuiltinType(ObjCBuiltinSelTy, BuiltinType::ObjCSel); + + if (LangOpts.OpenCL) { + InitBuiltinType(OCLImage1dTy, BuiltinType::OCLImage1d); + InitBuiltinType(OCLImage1dArrayTy, BuiltinType::OCLImage1dArray); + InitBuiltinType(OCLImage1dBufferTy, BuiltinType::OCLImage1dBuffer); + InitBuiltinType(OCLImage2dTy, BuiltinType::OCLImage2d); + InitBuiltinType(OCLImage2dArrayTy, BuiltinType::OCLImage2dArray); + InitBuiltinType(OCLImage3dTy, BuiltinType::OCLImage3d); + } // Builtin type for __objc_yes and __objc_no ObjCBuiltinBoolTy = (Target.useSignedCharForObjCBool() ? @@ -1412,6 +1421,16 @@ ASTContext::getTypeInfoImpl(const Type *T) const { Width = Target->getPointerWidth(0); Align = Target->getPointerAlign(0); break; + case BuiltinType::OCLImage1d: + case BuiltinType::OCLImage1dArray: + case BuiltinType::OCLImage1dBuffer: + case BuiltinType::OCLImage2d: + case BuiltinType::OCLImage2dArray: + case BuiltinType::OCLImage3d: + // Currently these types are pointers to opaque types. + Width = Target->getPointerWidth(0); + Align = Target->getPointerAlign(0); + break; } break; case Type::ObjCObjectPointer: diff --git a/clang/lib/AST/ItaniumMangle.cpp b/clang/lib/AST/ItaniumMangle.cpp index 566a3894cb9..65907f909bb 100644 --- a/clang/lib/AST/ItaniumMangle.cpp +++ b/clang/lib/AST/ItaniumMangle.cpp @@ -1,3574 +1,3580 @@ -//===--- ItaniumMangle.cpp - Itanium C++ Name Mangling ----------*- C++ -*-===// -// -// The LLVM Compiler Infrastructure -// -// This file is distributed under the University of Illinois Open Source -// License. See LICENSE.TXT for details. -// -//===----------------------------------------------------------------------===// -// -// Implements C++ name mangling according to the Itanium C++ ABI, -// which is used in GCC 3.2 and newer (and many compilers that are -// ABI-compatible with GCC): -// -// http://www.codesourcery.com/public/cxx-abi/abi.html -// -//===----------------------------------------------------------------------===// -#include "clang/AST/Mangle.h" -#include "clang/AST/ASTContext.h" -#include "clang/AST/Attr.h" -#include "clang/AST/Decl.h" -#include "clang/AST/DeclCXX.h" -#include "clang/AST/DeclObjC.h" -#include "clang/AST/DeclTemplate.h" -#include "clang/AST/ExprCXX.h" -#include "clang/AST/ExprObjC.h" -#include "clang/AST/TypeLoc.h" -#include "clang/Basic/ABI.h" -#include "clang/Basic/SourceManager.h" -#include "clang/Basic/TargetInfo.h" -#include "llvm/ADT/StringExtras.h" -#include "llvm/Support/ErrorHandling.h" -#include "llvm/Support/raw_ostream.h" - -#define MANGLE_CHECKER 0 - -#if MANGLE_CHECKER -#include <cxxabi.h> -#endif - -using namespace clang; - -namespace { - -/// \brief Retrieve the declaration context that should be used when mangling -/// the given declaration. -static const DeclContext *getEffectiveDeclContext(const Decl *D) { - // The ABI assumes that lambda closure types that occur within - // default arguments live in the context of the function. However, due to - // the way in which Clang parses and creates function declarations, this is - // not the case: the lambda closure type ends up living in the context - // where the function itself resides, because the function declaration itself - // had not yet been created. Fix the context here. - if (const CXXRecordDecl *RD = dyn_cast<CXXRecordDecl>(D)) { - if (RD->isLambda()) - if (ParmVarDecl *ContextParam - = dyn_cast_or_null<ParmVarDecl>(RD->getLambdaContextDecl())) - return ContextParam->getDeclContext(); - } - - return D->getDeclContext(); -} - -static const DeclContext *getEffectiveParentContext(const DeclContext *DC) { - return getEffectiveDeclContext(cast<Decl>(DC)); -} - -static const CXXRecordDecl *GetLocalClassDecl(const NamedDecl *ND) { - const DeclContext *DC = dyn_cast<DeclContext>(ND); - if (!DC) - DC = getEffectiveDeclContext(ND); - while (!DC->isNamespace() && !DC->isTranslationUnit()) { - const DeclContext *Parent = getEffectiveDeclContext(cast<Decl>(DC)); - if (isa<FunctionDecl>(Parent)) - return dyn_cast<CXXRecordDecl>(DC); - DC = Parent; - } - return 0; -} - -static const FunctionDecl *getStructor(const FunctionDecl *fn) { - if (const FunctionTemplateDecl *ftd = fn->getPrimaryTemplate()) - return ftd->getTemplatedDecl(); - - return fn; -} - -static const NamedDecl *getStructor(const NamedDecl *decl) { - const FunctionDecl *fn = dyn_cast_or_null<FunctionDecl>(decl); - return (fn ? getStructor(fn) : decl); -} - -static const unsigned UnknownArity = ~0U; - -class ItaniumMangleContext : public MangleContext { - llvm::DenseMap<const TagDecl *, uint64_t> AnonStructIds; - unsigned Discriminator; - llvm::DenseMap<const NamedDecl*, unsigned> Uniquifier; - -public: - explicit ItaniumMangleContext(ASTContext &Context, - DiagnosticsEngine &Diags) - : MangleContext(Context, Diags) { } - - uint64_t getAnonymousStructId(const TagDecl *TD) { - std::pair<llvm::DenseMap<const TagDecl *, - uint64_t>::iterator, bool> Result = - AnonStructIds.insert(std::make_pair(TD, AnonStructIds.size())); - return Result.first->second; - } - - void startNewFunction() { - MangleContext::startNewFunction(); - mangleInitDiscriminator(); - } - - /// @name Mangler Entry Points - /// @{ - - bool shouldMangleDeclName(const NamedDecl *D); - void mangleName(const NamedDecl *D, raw_ostream &); - void mangleThunk(const CXXMethodDecl *MD, - const ThunkInfo &Thunk, - raw_ostream &); - void mangleCXXDtorThunk(const CXXDestructorDecl *DD, CXXDtorType Type, - const ThisAdjustment &ThisAdjustment, - raw_ostream &); - void mangleReferenceTemporary(const VarDecl *D, - raw_ostream &); - void mangleCXXVTable(const CXXRecordDecl *RD, - raw_ostream &); - void mangleCXXVTT(const CXXRecordDecl *RD, - raw_ostream &); - void mangleCXXCtorVTable(const CXXRecordDecl *RD, int64_t Offset, - const CXXRecordDecl *Type, - raw_ostream &); - void mangleCXXRTTI(QualType T, raw_ostream &); - void mangleCXXRTTIName(QualType T, raw_ostream &); - void mangleCXXCtor(const CXXConstructorDecl *D, CXXCtorType Type, - raw_ostream &); - void mangleCXXDtor(const CXXDestructorDecl *D, CXXDtorType Type, - raw_ostream &); - - void mangleItaniumGuardVariable(const VarDecl *D, raw_ostream &); - - void mangleInitDiscriminator() { - Discriminator = 0; - } - - bool getNextDiscriminator(const NamedDecl *ND, unsigned &disc) { - // Lambda closure types with external linkage (indicated by a - // non-zero lambda mangling number) have their own numbering scheme, so - // they do not need a discriminator. - if (const CXXRecordDecl *RD = dyn_cast<CXXRecordDecl>(ND)) - if (RD->isLambda() && RD->getLambdaManglingNumber() > 0) - return false; - - unsigned &discriminator = Uniquifier[ND]; - if (!discriminator) - discriminator = ++Discriminator; - if (discriminator == 1) - return false; - disc = discriminator-2; - return true; - } - /// @} -}; - -/// CXXNameMangler - Manage the mangling of a single name. -class CXXNameMangler { - ItaniumMangleContext &Context; - raw_ostream &Out; - - /// The "structor" is the top-level declaration being mangled, if - /// that's not a template specialization; otherwise it's the pattern - /// for that specialization. - const NamedDecl *Structor; - unsigned StructorType; - - /// SeqID - The next subsitution sequence number. - unsigned SeqID; - - class FunctionTypeDepthState { - unsigned Bits; - - enum { InResultTypeMask = 1 }; - - public: - FunctionTypeDepthState() : Bits(0) {} - - /// The number of function types we're inside. - unsigned getDepth() const { - return Bits >> 1; - } - - /// True if we're in the return type of the innermost function type. - bool isInResultType() const { - return Bits & InResultTypeMask; - } - - FunctionTypeDepthState push() { - FunctionTypeDepthState tmp = *this; - Bits = (Bits & ~InResultTypeMask) + 2; - return tmp; - } - - void enterResultType() { - Bits |= InResultTypeMask; - } - - void leaveResultType() { - Bits &= ~InResultTypeMask; - } - - void pop(FunctionTypeDepthState saved) { - assert(getDepth() == saved.getDepth() + 1); - Bits = saved.Bits; - } - - } FunctionTypeDepth; - - llvm::DenseMap<uintptr_t, unsigned> Substitutions; - - ASTContext &getASTContext() const { return Context.getASTContext(); } - -public: - CXXNameMangler(ItaniumMangleContext &C, raw_ostream &Out_, - const NamedDecl *D = 0) - : Context(C), Out(Out_), Structor(getStructor(D)), StructorType(0), - SeqID(0) { - // These can't be mangled without a ctor type or dtor type. - assert(!D || (!isa<CXXDestructorDecl>(D) && - !isa<CXXConstructorDecl>(D))); - } - CXXNameMangler(ItaniumMangleContext &C, raw_ostream &Out_, - const CXXConstructorDecl *D, CXXCtorType Type) - : Context(C), Out(Out_), Structor(getStructor(D)), StructorType(Type), - SeqID(0) { } - CXXNameMangler(ItaniumMangleContext &C, raw_ostream &Out_, - const CXXDestructorDecl *D, CXXDtorType Type) - : Context(C), Out(Out_), Structor(getStructor(D)), StructorType(Type), - SeqID(0) { } - -#if MANGLE_CHECKER - ~CXXNameMangler() { - if (Out.str()[0] == '\01') - return; - - int status = 0; - char *result = abi::__cxa_demangle(Out.str().str().c_str(), 0, 0, &status); - assert(status == 0 && "Could not demangle mangled name!"); - free(result); - } -#endif - raw_ostream &getStream() { return Out; } - - void mangle(const NamedDecl *D, StringRef Prefix = "_Z"); - void mangleCallOffset(int64_t NonVirtual, int64_t Virtual); - void mangleNumber(const llvm::APSInt &I); - void mangleNumber(int64_t Number); - void mangleFloat(const llvm::APFloat &F); - void mangleFunctionEncoding(const FunctionDecl *FD); - void mangleName(const NamedDecl *ND); - void mangleType(QualType T); - void mangleNameOrStandardSubstitution(const NamedDecl *ND); - -private: - bool mangleSubstitution(const NamedDecl *ND); - bool mangleSubstitution(QualType T); - bool mangleSubstitution(TemplateName Template); - bool mangleSubstitution(uintptr_t Ptr); - - void mangleExistingSubstitution(QualType type); - void mangleExistingSubstitution(TemplateName name); - - bool mangleStandardSubstitution(const NamedDecl *ND); - - void addSubstitution(const NamedDecl *ND) { - ND = cast<NamedDecl>(ND->getCanonicalDecl()); - - addSubstitution(reinterpret_cast<uintptr_t>(ND)); - } - void addSubstitution(QualType T); - void addSubstitution(TemplateName Template); - void addSubstitution(uintptr_t Ptr); - - void mangleUnresolvedPrefix(NestedNameSpecifier *qualifier, - NamedDecl *firstQualifierLookup, - bool recursive = false); - void mangleUnresolvedName(NestedNameSpecifier *qualifier, - NamedDecl *firstQualifierLookup, - DeclarationName name, - unsigned KnownArity = UnknownArity); - - void mangleName(const TemplateDecl *TD, - const TemplateArgument *TemplateArgs, - unsigned NumTemplateArgs); - void mangleUnqualifiedName(const NamedDecl *ND) { - mangleUnqualifiedName(ND, ND->getDeclName(), UnknownArity); - } - void mangleUnqualifiedName(const NamedDecl *ND, DeclarationName Name, - unsigned KnownArity); - void mangleUnscopedName(const NamedDecl *ND); - void mangleUnscopedTemplateName(const TemplateDecl *ND); - void mangleUnscopedTemplateName(TemplateName); - void mangleSourceName(const IdentifierInfo *II); - void mangleLocalName(const NamedDecl *ND); - void mangleLambda(const CXXRecordDecl *Lambda); - void mangleNestedName(const NamedDecl *ND, const DeclContext *DC, - bool NoFunction=false); - void mangleNestedName(const TemplateDecl *TD, - const TemplateArgument *TemplateArgs, - unsigned NumTemplateArgs); - void manglePrefix(NestedNameSpecifier *qualifier); - void manglePrefix(const DeclContext *DC, bool NoFunction=false); - void manglePrefix(QualType type); - void mangleTemplatePrefix(const TemplateDecl *ND); - void mangleTemplatePrefix(TemplateName Template); - void mangleOperatorName(OverloadedOperatorKind OO, unsigned Arity); - void mangleQualifiers(Qualifiers Quals); - void mangleRefQualifier(RefQualifierKind RefQualifier); - - void mangleObjCMethodName(const ObjCMethodDecl *MD); - - // Declare manglers for every type class. -#define ABSTRACT_TYPE(CLASS, PARENT) -#define NON_CANONICAL_TYPE(CLASS, PARENT) -#define TYPE(CLASS, PARENT) void mangleType(const CLASS##Type *T); -#include "clang/AST/TypeNodes.def" - - void mangleType(const TagType*); - void mangleType(TemplateName); - void mangleBareFunctionType(const FunctionType *T, - bool MangleReturnType); - void mangleNeonVectorType(const VectorType *T); - - void mangleIntegerLiteral(QualType T, const llvm::APSInt &Value); - void mangleMemberExpr(const Expr *base, bool isArrow, - NestedNameSpecifier *qualifier, - NamedDecl *firstQualifierLookup, - DeclarationName name, - unsigned knownArity); - void mangleExpression(const Expr *E, unsigned Arity = UnknownArity); - void mangleCXXCtorType(CXXCtorType T); - void mangleCXXDtorType(CXXDtorType T); - - void mangleTemplateArgs(const ASTTemplateArgumentListInfo &TemplateArgs); - void mangleTemplateArgs(const TemplateArgument *TemplateArgs, - unsigned NumTemplateArgs); - void mangleTemplateArgs(const TemplateArgumentList &AL); - void mangleTemplateArg(TemplateArgument A); - - void mangleTemplateParameter(unsigned Index); - - void mangleFunctionParam(const ParmVarDecl *parm); -}; - -} - -static bool isInCLinkageSpecification(const Decl *D) { - D = D->getCanonicalDecl(); - for (const DeclContext *DC = getEffectiveDeclContext(D); - !DC->isTranslationUnit(); DC = getEffectiveParentContext(DC)) { - if (const LinkageSpecDecl *Linkage = dyn_cast<LinkageSpecDecl>(DC)) - return Linkage->getLanguage() == LinkageSpecDecl::lang_c; - } - - return false; -} - -bool ItaniumMangleContext::shouldMangleDeclName(const NamedDecl *D) { - // In C, functions with no attributes never need to be mangled. Fastpath them. - if (!getASTContext().getLangOpts().CPlusPlus && !D->hasAttrs()) - return false; - - // Any decl can be declared with __asm("foo") on it, and this takes precedence - // over all other naming in the .o file. - if (D->hasAttr<AsmLabelAttr>()) - return true; - - // Clang's "overloadable" attribute extension to C/C++ implies name mangling - // (always) as does passing a C++ member function and a function - // whose name is not a simple identifier. - const FunctionDecl *FD = dyn_cast<FunctionDecl>(D); - if (FD && (FD->hasAttr<OverloadableAttr>() || isa<CXXMethodDecl>(FD) || - !FD->getDeclName().isIdentifier())) - return true; - - // Otherwise, no mangling is done outside C++ mode. - if (!getASTContext().getLangOpts().CPlusPlus) - return false; - - // Variables at global scope with non-internal linkage are not mangled - if (!FD) { - const DeclContext *DC = getEffectiveDeclContext(D); - // Check for extern variable declared locally. - if (DC->isFunctionOrMethod() && D->hasLinkage()) - while (!DC->isNamespace() && !DC->isTranslationUnit()) - DC = getEffectiveParentContext(DC); - if (DC->isTranslationUnit() && D->getLinkage() != InternalLinkage) - return false; - } - - // Class members are always mangled. - if (getEffectiveDeclContext(D)->isRecord()) - return true; - - // C functions and "main" are not mangled. - if ((FD && FD->isMain()) || isInCLinkageSpecification(D)) - return false; - - return true; -} - -void CXXNameMangler::mangle(const NamedDecl *D, StringRef Prefix) { - // Any decl can be declared with __asm("foo") on it, and this takes precedence - // over all other naming in the .o file. - if (const AsmLabelAttr *ALA = D->getAttr<AsmLabelAttr>()) { - // If we have an asm name, then we use it as the mangling. - - // Adding the prefix can cause problems when one file has a "foo" and - // another has a "\01foo". That is known to happen on ELF with the - // tricks normally used for producing aliases (PR9177). Fortunately the - // llvm mangler on ELF is a nop, so we can just avoid adding the \01 - // marker. We also avoid adding the marker if this is an alias for an - // LLVM intrinsic. - StringRef UserLabelPrefix = - getASTContext().getTargetInfo().getUserLabelPrefix(); - if (!UserLabelPrefix.empty() && !ALA->getLabel().startswith("llvm.")) - Out << '\01'; // LLVM IR Marker for __asm("foo") - - Out << ALA->getLabel(); - return; - } - - // <mangled-name> ::= _Z <encoding> - // ::= <data name> - // ::= <special-name> - Out << Prefix; - if (const FunctionDecl *FD = dyn_cast<FunctionDecl>(D)) - mangleFunctionEncoding(FD); - else if (const VarDecl *VD = dyn_cast<VarDecl>(D)) - mangleName(VD); - else - mangleName(cast<FieldDecl>(D)); -} - -void CXXNameMangler::mangleFunctionEncoding(const FunctionDecl *FD) { - // <encoding> ::= <function name> <bare-function-type> - mangleName(FD); - - // Don't mangle in the type if this isn't a decl we should typically mangle. - if (!Context.shouldMangleDeclName(FD)) - return; - - // Whether the mangling of a function type includes the return type depends on - // the context and the nature of the function. The rules for deciding whether - // the return type is included are: - // - // 1. Template functions (names or types) have return types encoded, with - // the exceptions listed below. - // 2. Function types not appearing as part of a function name mangling, - // e.g. parameters, pointer types, etc., have return type encoded, with the - // exceptions listed below. - // 3. Non-template function names do not have return types encoded. - // - // The exceptions mentioned in (1) and (2) above, for which the return type is - // never included, are - // 1. Constructors. - // 2. Destructors. - // 3. Conversion operator functions, e.g. operator int. - bool MangleReturnType = false; - if (FunctionTemplateDecl *PrimaryTemplate = FD->getPrimaryTemplate()) { - if (!(isa<CXXConstructorDecl>(FD) || isa<CXXDestructorDecl>(FD) || - isa<CXXConversionDecl>(FD))) - MangleReturnType = true; - - // Mangle the type of the primary template. - FD = PrimaryTemplate->getTemplatedDecl(); - } - - mangleBareFunctionType(FD->getType()->getAs<FunctionType>(), - MangleReturnType); -} - -static const DeclContext *IgnoreLinkageSpecDecls(const DeclContext *DC) { - while (isa<LinkageSpecDecl>(DC)) { - DC = getEffectiveParentContext(DC); - } - - return DC; -} - -/// isStd - Return whether a given namespace is the 'std' namespace. -static bool isStd(const NamespaceDecl *NS) { - if (!IgnoreLinkageSpecDecls(getEffectiveParentContext(NS)) - ->isTranslationUnit()) - return false; - - const IdentifierInfo *II = NS->getOriginalNamespace()->getIdentifier(); - return II && II->isStr("std"); -} - -// isStdNamespace - Return whether a given decl context is a toplevel 'std' -// namespace. -static bool isStdNamespace(const DeclContext *DC) { - if (!DC->isNamespace()) - return false; - - return isStd(cast<NamespaceDecl>(DC)); -} - -static const TemplateDecl * -isTemplate(const NamedDecl *ND, const TemplateArgumentList *&TemplateArgs) { - // Check if we have a function template. - if (const FunctionDecl *FD = dyn_cast<FunctionDecl>(ND)){ - if (const TemplateDecl *TD = FD->getPrimaryTemplate()) { - TemplateArgs = FD->getTemplateSpecializationArgs(); - return TD; - } - } - - // Check if we have a class template. - if (const ClassTemplateSpecializationDecl *Spec = - dyn_cast<ClassTemplateSpecializationDecl>(ND)) { - TemplateArgs = &Spec->getTemplateArgs(); - return Spec->getSpecializedTemplate(); - } - - return 0; -} - -static bool isLambda(const NamedDecl *ND) { - const CXXRecordDecl *Record = dyn_cast<CXXRecordDecl>(ND); - if (!Record) - return false; - - return Record->isLambda(); -} - -void CXXNameMangler::mangleName(const NamedDecl *ND) { - // <name> ::= <nested-name> - // ::= <unscoped-name> - // ::= <unscoped-template-name> <template-args> - // ::= <local-name> - // - const DeclContext *DC = getEffectiveDeclContext(ND); - - // If this is an extern variable declared locally, the relevant DeclContext - // is that of the containing namespace, or the translation unit. - // FIXME: This is a hack; extern variables declared locally should have - // a proper semantic declaration context! - if (isa<FunctionDecl>(DC) && ND->hasLinkage() && !isLambda(ND)) - while (!DC->isNamespace() && !DC->isTranslationUnit()) - DC = getEffectiveParentContext(DC); - else if (GetLocalClassDecl(ND)) { - mangleLocalName(ND); - return; - } - - DC = IgnoreLinkageSpecDecls(DC); - - if (DC->isTranslationUnit() || isStdNamespace(DC)) { - // Check if we have a template. - const TemplateArgumentList *TemplateArgs = 0; - if (const TemplateDecl *TD = isTemplate(ND, TemplateArgs)) { - mangleUnscopedTemplateName(TD); - mangleTemplateArgs(*TemplateArgs); - return; - } - - mangleUnscopedName(ND); - return; - } - - if (isa<FunctionDecl>(DC) || isa<ObjCMethodDecl>(DC)) { - mangleLocalName(ND); - return; - } - - mangleNestedName(ND, DC); -} -void CXXNameMangler::mangleName(const TemplateDecl *TD, - const TemplateArgument *TemplateArgs, - unsigned NumTemplateArgs) { - const DeclContext *DC = IgnoreLinkageSpecDecls(getEffectiveDeclContext(TD)); - - if (DC->isTranslationUnit() || isStdNamespace(DC)) { - mangleUnscopedTemplateName(TD); - mangleTemplateArgs(TemplateArgs, NumTemplateArgs); - } else { - mangleNestedName(TD, TemplateArgs, NumTemplateArgs); - } -} - -void CXXNameMangler::mangleUnscopedName(const NamedDecl *ND) { - // <unscoped-name> ::= <unqualified-name> - // ::= St <unqualified-name> # ::std:: - - if (isStdNamespace(IgnoreLinkageSpecDecls(getEffectiveDeclContext(ND)))) - Out << "St"; - - mangleUnqualifiedName(ND); -} - -void CXXNameMangler::mangleUnscopedTemplateName(const TemplateDecl *ND) { - // <unscoped-template-name> ::= <unscoped-name> - // ::= <substitution> - if (mangleSubstitution(ND)) - return; - - // <template-template-param> ::= <template-param> - if (const TemplateTemplateParmDecl *TTP - = dyn_cast<TemplateTemplateParmDecl>(ND)) { - mangleTemplateParameter(TTP->getIndex()); - return; - } - - mangleUnscopedName(ND->getTemplatedDecl()); - addSubstitution(ND); -} - -void CXXNameMangler::mangleUnscopedTemplateName(TemplateName Template) { - // <unscoped-template-name> ::= <unscoped-name> - // ::= <substitution> - if (TemplateDecl *TD = Template.getAsTemplateDecl()) - return mangleUnscopedTemplateName(TD); - - if (mangleSubstitution(Template)) - return; - - DependentTemplateName *Dependent = Template.getAsDependentTemplateName(); - assert(Dependent && "Not a dependent template name?"); - if (const IdentifierInfo *Id = Dependent->getIdentifier()) - mangleSourceName(Id); - else - mangleOperatorName(Dependent->getOperator(), UnknownArity); - - addSubstitution(Template); -} - -void CXXNameMangler::mangleFloat(const llvm::APFloat &f) { - // ABI: - // Floating-point literals are encoded using a fixed-length - // lowercase hexadecimal string corresponding to the internal - // representation (IEEE on Itanium), high-order bytes first, - // without leading zeroes. For example: "Lf bf800000 E" is -1.0f - // on Itanium. - // The 'without leading zeroes' thing seems to be an editorial - // mistake; see the discussion on cxx-abi-dev beginning on - // 2012-01-16. - - // Our requirements here are just barely weird enough to justify - // using a custom algorithm instead of post-processing APInt::toString(). - - llvm::APInt valueBits = f.bitcastToAPInt(); - unsigned numCharacters = (valueBits.getBitWidth() + 3) / 4; - assert(numCharacters != 0); - - // Allocate a buffer of the right number of characters. - llvm::SmallVector<char, 20> buffer; - buffer.set_size(numCharacters); - - // Fill the buffer left-to-right. - for (unsigned stringIndex = 0; stringIndex != numCharacters; ++stringIndex) { - // The bit-index of the next hex digit. - unsigned digitBitIndex = 4 * (numCharacters - stringIndex - 1); - - // Project out 4 bits starting at 'digitIndex'. - llvm::integerPart hexDigit - = valueBits.getRawData()[digitBitIndex / llvm::integerPartWidth]; - hexDigit >>= (digitBitIndex % llvm::integerPartWidth); - hexDigit &= 0xF; - - // Map that over to a lowercase hex digit. - static const char charForHex[16] = { - '0', '1', '2', '3', '4', '5', '6', '7', - '8', '9', 'a', 'b', 'c', 'd', 'e', 'f' - }; - buffer[stringIndex] = charForHex[hexDigit]; - } - - Out.write(buffer.data(), numCharacters); -} - -void CXXNameMangler::mangleNumber(const llvm::APSInt &Value) { - if (Value.isSigned() && Value.isNegative()) { - Out << 'n'; - Value.abs().print(Out, /*signed*/ false); - } else { - Value.print(Out, /*signed*/ false); - } -} - -void CXXNameMangler::mangleNumber(int64_t Number) { - // <number> ::= [n] <non-negative decimal integer> - if (Number < 0) { - Out << 'n'; - Number = -Number; - } - - Out << Number; -} - -void CXXNameMangler::mangleCallOffset(int64_t NonVirtual, int64_t Virtual) { - // <call-offset> ::= h <nv-offset> _ - // ::= v <v-offset> _ - // <nv-offset> ::= <offset number> # non-virtual base override - // <v-offset> ::= <offset number> _ <virtual offset number> - // # virtual base override, with vcall offset - if (!Virtual) { - Out << 'h'; - mangleNumber(NonVirtual); - Out << '_'; - return; - } - - Out << 'v'; - mangleNumber(NonVirtual); - Out << '_'; - mangleNumber(Virtual); - Out << '_'; -} - -void CXXNameMangler::manglePrefix(QualType type) { - if (const TemplateSpecializationType *TST = - type->getAs<TemplateSpecializationType>()) { - if (!mangleSubstitution(QualType(TST, 0))) { - mangleTemplatePrefix(TST->getTemplateName()); - - // FIXME: GCC does not appear to mangle the template arguments when - // the template in question is a dependent template name. Should we - // emulate that badness? - mangleTemplateArgs(TST->getArgs(), TST->getNumArgs()); - addSubstitution(QualType(TST, 0)); - } - } else if (const DependentTemplateSpecializationType *DTST - = type->getAs<DependentTemplateSpecializationType>()) { - TemplateName Template - = getASTContext().getDependentTemplateName(DTST->getQualifier(), - DTST->getIdentifier()); - mangleTemplatePrefix(Template); - - // FIXME: GCC does not appear to mangle the template arguments when - // the template in question is a dependent template name. Should we - // emulate that badness? - mangleTemplateArgs(DTST->getArgs(), DTST->getNumArgs()); - } else { - // We use the QualType mangle type variant here because it handles - // substitutions. - mangleType(type); - } -} - -/// Mangle everything prior to the base-unresolved-name in an unresolved-name. -/// -/// \param firstQualifierLookup - the entity found by unqualified lookup -/// for the first name in the qualifier, if this is for a member expression -/// \param recursive - true if this is being called recursively, -/// i.e. if there is more prefix "to the right". -void CXXNameMangler::mangleUnresolvedPrefix(NestedNameSpecifier *qualifier, - NamedDecl *firstQualifierLookup, - bool recursive) { - - // x, ::x - // <unresolved-name> ::= [gs] <base-unresolved-name> - - // T::x / decltype(p)::x - // <unresolved-name> ::= sr <unresolved-type> <base-unresolved-name> - - // T::N::x /decltype(p)::N::x - // <unresolved-name> ::= srN <unresolved-type> <unresolved-qualifier-level>+ E - // <base-unresolved-name> - - // A::x, N::y, A<T>::z; "gs" means leading "::" - // <unresolved-name> ::= [gs] sr <unresolved-qualifier-level>+ E - // <base-unresolved-name> - - switch (qualifier->getKind()) { - case NestedNameSpecifier::Global: - Out << "gs"; - - // We want an 'sr' unless this is the entire NNS. - if (recursive) - Out << "sr"; - - // We never want an 'E' here. - return; - - case NestedNameSpecifier::Namespace: - if (qualifier->getPrefix()) - mangleUnresolvedPrefix(qualifier->getPrefix(), firstQualifierLookup, - /*recursive*/ true); - else - Out << "sr"; - mangleSourceName(qualifier->getAsNamespace()->getIdentifier()); - break; - case NestedNameSpecifier::NamespaceAlias: - if (qualifier->getPrefix()) - mangleUnresolvedPrefix(qualifier->getPrefix(), firstQualifierLookup, - /*recursive*/ true); - else - Out << "sr"; - mangleSourceName(qualifier->getAsNamespaceAlias()->getIdentifier()); - break; - - case NestedNameSpecifier::TypeSpec: - case NestedNameSpecifier::TypeSpecWithTemplate: { - const Type *type = qualifier->getAsType(); - - // We only want to use an unresolved-type encoding if this is one of: - // - a decltype - // - a template type parameter - // - a template template parameter with arguments - // In all of these cases, we should have no prefix. - if (qualifier->getPrefix()) { - mangleUnresolvedPrefix(qualifier->getPrefix(), firstQualifierLookup, - /*recursive*/ true); - } else { - // Otherwise, all the cases want this. - Out << "sr"; - } - - // Only certain other types are valid as prefixes; enumerate them. - switch (type->getTypeClass()) { - case Type::Builtin: - case Type::Complex: - case Type::Pointer: - case Type::BlockPointer: - case Type::LValueReference: - case Type::RValueReference: - case Type::MemberPointer: - case Type::ConstantArray: - case Type::IncompleteArray: - case Type::VariableArray: - case Type::DependentSizedArray: - case Type::DependentSizedExtVector: - case Type::Vector: - case Type::ExtVector: - case Type::FunctionProto: - case Type::FunctionNoProto: - case Type::Enum: - case Type::Paren: - case Type::Elaborated: - case Type::Attributed: - case Type::Auto: - case Type::PackExpansion: - case Type::ObjCObject: - case Type::ObjCInterface: - case Type::ObjCObjectPointer: - case Type::Atomic: - llvm_unreachable("type is illegal as a nested name specifier"); - - case Type::SubstTemplateTypeParmPack: - // FIXME: not clear how to mangle this! - // template <class T...> class A { - // template <class U...> void foo(decltype(T::foo(U())) x...); - // }; - Out << "_SUBSTPACK_"; - break; - - // <unresolved-type> ::= <template-param> - // ::= <decltype> - // ::= <template-template-param> <template-args> - // (this last is not official yet) - case Type::TypeOfExpr: - case Type::TypeOf: - case Type::Decltype: - case Type::TemplateTypeParm: - case Type::UnaryTransform: - case Type::SubstTemplateTypeParm: - unresolvedType: - assert(!qualifier->getPrefix()); - - // We only get here recursively if we're followed by identifiers. - if (recursive) Out << 'N'; - - // This seems to do everything we want. It's not really - // sanctioned for a substituted template parameter, though. - mangleType(QualType(type, 0)); - - // We never want to print 'E' directly after an unresolved-type, - // so we return directly. - return; - - case Type::Typedef: - mangleSourceName(cast<TypedefType>(type)->getDecl()->getIdentifier()); - break; - - case Type::UnresolvedUsing: - mangleSourceName(cast<UnresolvedUsingType>(type)->getDecl() - ->getIdentifier()); - break; - - case Type::Record: - mangleSourceName(cast<RecordType>(type)->getDecl()->getIdentifier()); - break; - - case Type::TemplateSpecialization: { - const TemplateSpecializationType *tst - = cast<TemplateSpecializationType>(type); - TemplateName name = tst->getTemplateName(); - switch (name.getKind()) { - case TemplateName::Template: - case TemplateName::QualifiedTemplate: { - TemplateDecl *temp = name.getAsTemplateDecl(); - - // If the base is a template template parameter, this is an - // unresolved type. - assert(temp && "no template for template specialization type"); - if (isa<TemplateTemplateParmDecl>(temp)) goto unresolvedType; - - mangleSourceName(temp->getIdentifier()); - break; - } - - case TemplateName::OverloadedTemplate: - case TemplateName::DependentTemplate: - llvm_unreachable("invalid base for a template specialization type"); - - case TemplateName::SubstTemplateTemplateParm: { - SubstTemplateTemplateParmStorage *subst - = name.getAsSubstTemplateTemplateParm(); - mangleExistingSubstitution(subst->getReplacement()); - break; - } - - case TemplateName::SubstTemplateTemplateParmPack: { - // FIXME: not clear how to mangle this! - // template <template <class U> class T...> class A { - // template <class U...> void foo(decltype(T<U>::foo) x...); - // }; - Out << "_SUBSTPACK_"; - break; - } - } - - mangleTemplateArgs(tst->getArgs(), tst->getNumArgs()); - break; - } - - case Type::InjectedClassName: - mangleSourceName(cast<InjectedClassNameType>(type)->getDecl() - ->getIdentifier()); - break; - - case Type::DependentName: - mangleSourceName(cast<DependentNameType>(type)->getIdentifier()); - break; - - case Type::DependentTemplateSpecialization: { - const DependentTemplateSpecializationType *tst - = cast<DependentTemplateSpecializationType>(type); - mangleSourceName(tst->getIdentifier()); - mangleTemplateArgs(tst->getArgs(), tst->getNumArgs()); - break; - } - } - break; - } - - case NestedNameSpecifier::Identifier: - // Member expressions can have these without prefixes. - if (qualifier->getPrefix()) { - mangleUnresolvedPrefix(qualifier->getPrefix(), firstQualifierLookup, - /*recursive*/ true); - } else if (firstQualifierLookup) { - - // Try to make a proper qualifier out of the lookup result, and - // then just recurse on that. - NestedNameSpecifier *newQualifier; - if (TypeDecl *typeDecl = dyn_cast<TypeDecl>(firstQualifierLookup)) { - QualType type = getASTContext().getTypeDeclType(typeDecl); - - // Pretend we had a different nested name specifier. - newQualifier = NestedNameSpecifier::Create(getASTContext(), - /*prefix*/ 0, - /*template*/ false, - type.getTypePtr()); - } else if (NamespaceDecl *nspace = - dyn_cast<NamespaceDecl>(firstQualifierLookup)) { - newQualifier = NestedNameSpecifier::Create(getASTContext(), - /*prefix*/ 0, - nspace); - } else if (NamespaceAliasDecl *alias = - dyn_cast<NamespaceAliasDecl>(firstQualifierLookup)) { - newQualifier = NestedNameSpecifier::Create(getASTContext(), - /*prefix*/ 0, - alias); - } else { - // No sensible mangling to do here. - newQualifier = 0; - } - - if (newQualifier) - return mangleUnresolvedPrefix(newQualifier, /*lookup*/ 0, recursive); - - } else { - Out << "sr"; - } - - mangleSourceName(qualifier->getAsIdentifier()); - break; - } - - // If this was the innermost part of the NNS, and we fell out to - // here, append an 'E'. - if (!recursive) - Out << 'E'; -} - -/// Mangle an unresolved-name, which is generally used for names which -/// weren't resolved to specific entities. -void CXXNameMangler::mangleUnresolvedName(NestedNameSpecifier *qualifier, - NamedDecl *firstQualifierLookup, - DeclarationName name, - unsigned knownArity) { - if (qualifier) mangleUnresolvedPrefix(qualifier, firstQualifierLookup); - mangleUnqualifiedName(0, name, knownArity); -} - -static const FieldDecl *FindFirstNamedDataMember(const RecordDecl *RD) { - assert(RD->isAnonymousStructOrUnion() && - "Expected anonymous struct or union!"); - - for (RecordDecl::field_iterator I = RD->field_begin(), E = RD->field_end(); - I != E; ++I) { - if (I->getIdentifier()) - return *I; - - if (const RecordType *RT = I->getType()->getAs<RecordType>()) - if (const FieldDecl *NamedDataMember = - FindFirstNamedDataMember(RT->getDecl())) - return NamedDataMember; - } - - // We didn't find a named data member. - return 0; -} - -void CXXNameMangler::mangleUnqualifiedName(const NamedDecl *ND, - DeclarationName Name, - unsigned KnownArity) { - // <unqualified-name> ::= <operator-name> - // ::= <ctor-dtor-name> - // ::= <source-name> - switch (Name.getNameKind()) { - case DeclarationName::Identifier: { - if (const IdentifierInfo *II = Name.getAsIdentifierInfo()) { - // We must avoid conflicts between internally- and externally- - // linked variable and function declaration names in the same TU: - // void test() { extern void foo(); } - // static void foo(); - // This naming convention is the same as that followed by GCC, - // though it shouldn't actually matter. - if (ND && ND->getLinkage() == InternalLinkage && - getEffectiveDeclContext(ND)->isFileContext()) - Out << 'L'; - - mangleSourceName(II); - break; - } - - // Otherwise, an anonymous entity. We must have a declaration. - assert(ND && "mangling empty name without declaration"); - - if (const NamespaceDecl *NS = dyn_cast<NamespaceDecl>(ND)) { - if (NS->isAnonymousNamespace()) { - // This is how gcc mangles these names. - Out << "12_GLOBAL__N_1"; - break; - } - } - - if (const VarDecl *VD = dyn_cast<VarDecl>(ND)) { - // We must have an anonymous union or struct declaration. - const RecordDecl *RD = - cast<RecordDecl>(VD->getType()->getAs<RecordType>()->getDecl()); - - // Itanium C++ ABI 5.1.2: - // - // For the purposes of mangling, the name of an anonymous union is - // considered to be the name of the first named data member found by a - // pre-order, depth-first, declaration-order walk of the data members of - // the anonymous union. If there is no such data member (i.e., if all of - // the data members in the union are unnamed), then there is no way for - // a program to refer to the anonymous union, and there is therefore no - // need to mangle its name. - const FieldDecl *FD = FindFirstNamedDataMember(RD); - - // It's actually possible for various reasons for us to get here - // with an empty anonymous struct / union. Fortunately, it - // doesn't really matter what name we generate. - if (!FD) break; - assert(FD->getIdentifier() && "Data member name isn't an identifier!"); - - mangleSourceName(FD->getIdentifier()); - break; - } - - // We must have an anonymous struct. - const TagDecl *TD = cast<TagDecl>(ND); - if (const TypedefNameDecl *D = TD->getTypedefNameForAnonDecl()) { - assert(TD->getDeclContext() == D->getDeclContext() && - "Typedef should not be in another decl context!"); - assert(D->getDeclName().getAsIdentifierInfo() && - "Typedef was not named!"); - mangleSourceName(D->getDeclName().getAsIdentifierInfo()); - break; - } - - // <unnamed-type-name> ::= <closure-type-name> - // - // <closure-type-name> ::= Ul <lambda-sig> E [ <nonnegative number> ] _ - // <lambda-sig> ::= <parameter-type>+ # Parameter types or 'v' for 'void'. - if (const CXXRecordDecl *Record = dyn_cast<CXXRecordDecl>(TD)) { - if (Record->isLambda() && Record->getLambdaManglingNumber()) { - mangleLambda(Record); - break; - } - } - - int UnnamedMangle = Context.getASTContext().getUnnamedTagManglingNumber(TD); - if (UnnamedMangle != -1) { - Out << "Ut"; - if (UnnamedMangle != 0) - Out << llvm::utostr(UnnamedMangle - 1); - Out << '_'; - break; - } - - // Get a unique id for the anonymous struct. - uint64_t AnonStructId = Context.getAnonymousStructId(TD); - - // Mangle it as a source name in the form - // [n] $_<id> - // where n is the length of the string. - SmallString<8> Str; - Str += "$_"; - Str += llvm::utostr(AnonStructId); - - Out << Str.size(); - Out << Str.str(); - break; - } - - case DeclarationName::ObjCZeroArgSelector: - case DeclarationName::ObjCOneArgSelector: - case DeclarationName::ObjCMultiArgSelector: - llvm_unreachable("Can't mangle Objective-C selector names here!"); - - case DeclarationName::CXXConstructorName: - if (ND == Structor) - // If the named decl is the C++ constructor we're mangling, use the type - // we were given. - mangleCXXCtorType(static_cast<CXXCtorType>(StructorType)); - else - // Otherwise, use the complete constructor name. This is relevant if a - // class with a constructor is declared within a constructor. - mangleCXXCtorType(Ctor_Complete); - break; - - case DeclarationName::CXXDestructorName: - if (ND == Structor) - // If the named decl is the C++ destructor we're mangling, use the type we - // were given. - mangleCXXDtorType(static_cast<CXXDtorType>(StructorType)); - else - // Otherwise, use the complete destructor name. This is relevant if a - // class with a destructor is declared within a destructor. - mangleCXXDtorType(Dtor_Complete); - break; - - case DeclarationName::CXXConversionFunctionName: - // <operator-name> ::= cv <type> # (cast) - Out << "cv"; - mangleType(Name.getCXXNameType()); - break; - - case DeclarationName::CXXOperatorName: { - unsigned Arity; - if (ND) { - Arity = cast<FunctionDecl>(ND)->getNumParams(); - - // If we have a C++ member function, we need to include the 'this' pointer. - // FIXME: This does not make sense for operators that are static, but their - // names stay the same regardless of the arity (operator new for instance). - if (isa<CXXMethodDecl>(ND)) - Arity++; - } else - Arity = KnownArity; - - mangleOperatorName(Name.getCXXOverloadedOperator(), Arity); - break; - } - - case DeclarationName::CXXLiteralOperatorName: - // FIXME: This mangling is not yet official. - Out << "li"; - mangleSourceName(Name.getCXXLiteralIdentifier()); - break; - - case DeclarationName::CXXUsingDirective: - llvm_unreachable("Can't mangle a using directive name!"); - } -} - -void CXXNameMangler::mangleSourceName(const IdentifierInfo *II) { - // <source-name> ::= <positive length number> <identifier> - // <number> ::= [n] <non-negative decimal integer> - // <identifier> ::= <unqualified source code identifier> - Out << II->getLength() << II->getName(); -} - -void CXXNameMangler::mangleNestedName(const NamedDecl *ND, - const DeclContext *DC, - bool NoFunction) { - // <nested-name> - // ::= N [<CV-qualifiers>] [<ref-qualifier>] <prefix> <unqualified-name> E - // ::= N [<CV-qualifiers>] [<ref-qualifier>] <template-prefix> - // <template-args> E - - Out << 'N'; - if (const CXXMethodDecl *Method = dyn_cast<CXXMethodDecl>(ND)) { - mangleQualifiers(Qualifiers::fromCVRMask(Method->getTypeQualifiers())); - mangleRefQualifier(Method->getRefQualifier()); - } - - // Check if we have a template. - const TemplateArgumentList *TemplateArgs = 0; - if (const TemplateDecl *TD = isTemplate(ND, TemplateArgs)) { - mangleTemplatePrefix(TD); - mangleTemplateArgs(*TemplateArgs); - } - else { - manglePrefix(DC, NoFunction); - mangleUnqualifiedName(ND); - } - - Out << 'E'; -} -void CXXNameMangler::mangleNestedName(const TemplateDecl *TD, - const TemplateArgument *TemplateArgs, - unsigned NumTemplateArgs) { - // <nested-name> ::= N [<CV-qualifiers>] <template-prefix> <template-args> E - - Out << 'N'; - - mangleTemplatePrefix(TD); - mangleTemplateArgs(TemplateArgs, NumTemplateArgs); - - Out << 'E'; -} - -void CXXNameMangler::mangleLocalName(const NamedDecl *ND) { - // <local-name> := Z <function encoding> E <entity name> [<discriminator>] - // := Z <function encoding> E s [<discriminator>] - // <local-name> := Z <function encoding> E d [ <parameter number> ] - // _ <entity name> - // <discriminator> := _ <non-negative number> - const DeclContext *DC = getEffectiveDeclContext(ND); - if (isa<ObjCMethodDecl>(DC) && isa<FunctionDecl>(ND)) { - // Don't add objc method name mangling to locally declared function - mangleUnqualifiedName(ND); - return; - } - - Out << 'Z'; - - if (const ObjCMethodDecl *MD = dyn_cast<ObjCMethodDecl>(DC)) { - mangleObjCMethodName(MD); - } else if (const CXXRecordDecl *RD = GetLocalClassDecl(ND)) { - mangleFunctionEncoding(cast<FunctionDecl>(getEffectiveDeclContext(RD))); - Out << 'E'; - - // The parameter number is omitted for the last parameter, 0 for the - // second-to-last parameter, 1 for the third-to-last parameter, etc. The - // <entity name> will of course contain a <closure-type-name>: Its - // numbering will be local to the particular argument in which it appears - // -- other default arguments do not affect its encoding. - bool SkipDiscriminator = false; - if (RD->isLambda()) { - if (const ParmVarDecl *Parm - = dyn_cast_or_null<ParmVarDecl>(RD->getLambdaContextDecl())) { - if (const FunctionDecl *Func - = dyn_cast<FunctionDecl>(Parm->getDeclContext())) { - Out << 'd'; - unsigned Num = Func->getNumParams() - Parm->getFunctionScopeIndex(); - if (Num > 1) - mangleNumber(Num - 2); - Out << '_'; - SkipDiscriminator = true; - } - } - } - - // Mangle the name relative to the closest enclosing function. - if (ND == RD) // equality ok because RD derived from ND above - mangleUnqualifiedName(ND); - else - mangleNestedName(ND, DC, true /*NoFunction*/); - - if (!SkipDiscriminator) { - unsigned disc; - if (Context.getNextDiscriminator(RD, disc)) { - if (disc < 10) - Out << '_' << disc; - else - Out << "__" << disc << '_'; - } - } - - return; - } - else - mangleFunctionEncoding(cast<FunctionDecl>(DC)); - - Out << 'E'; - mangleUnqualifiedName(ND); -} - -void CXXNameMangler::mangleLambda(const CXXRecordDecl *Lambda) { - // If the context of a closure type is an initializer for a class member - // (static or nonstatic), it is encoded in a qualified name with a final - // <prefix> of the form: - // - // <data-member-prefix> := <member source-name> M - // - // Technically, the data-member-prefix is part of the <prefix>. However, - // since a closure type will always be mangled with a prefix, it's easier - // to emit that last part of the prefix here. - if (Decl *Context = Lambda->getLambdaContextDecl()) { - if ((isa<VarDecl>(Context) || isa<FieldDecl>(Context)) && - Context->getDeclContext()->isRecord()) { - if (const IdentifierInfo *Name - = cast<NamedDecl>(Context)->getIdentifier()) { - mangleSourceName(Name); - Out << 'M'; - } - } - } - - Out << "Ul"; - const FunctionProtoType *Proto = Lambda->getLambdaTypeInfo()->getType()-> - getAs<FunctionProtoType>(); - mangleBareFunctionType(Proto, /*MangleReturnType=*/false); - Out << "E"; - - // The number is omitted for the first closure type with a given - // <lambda-sig> in a given context; it is n-2 for the nth closure type - // (in lexical order) with that same <lambda-sig> and context. - // - // The AST keeps track of the number for us. - unsigned Number = Lambda->getLambdaManglingNumber(); - assert(Number > 0 && "Lambda should be mangled as an unnamed class"); - if (Number > 1) - mangleNumber(Number - 2); - Out << '_'; -} - -void CXXNameMangler::manglePrefix(NestedNameSpecifier *qualifier) { - switch (qualifier->getKind()) { - case NestedNameSpecifier::Global: - // nothing - return; - - case NestedNameSpecifier::Namespace: - mangleName(qualifier->getAsNamespace()); - return; - - case NestedNameSpecifier::NamespaceAlias: - mangleName(qualifier->getAsNamespaceAlias()->getNamespace()); - return; - - case NestedNameSpecifier::TypeSpec: - case NestedNameSpecifier::TypeSpecWithTemplate: - manglePrefix(QualType(qualifier->getAsType(), 0)); - return; - - case NestedNameSpecifier::Identifier: - // Member expressions can have these without prefixes, but that - // should end up in mangleUnresolvedPrefix instead. - assert(qualifier->getPrefix()); - manglePrefix(qualifier->getPrefix()); - - mangleSourceName(qualifier->getAsIdentifier()); - return; - } - - llvm_unreachable("unexpected nested name specifier"); -} - -void CXXNameMangler::manglePrefix(const DeclContext *DC, bool NoFunction) { - // <prefix> ::= <prefix> <unqualified-name> - // ::= <template-prefix> <template-args> - // ::= <template-param> - // ::= # empty - // ::= <substitution> - - DC = IgnoreLinkageSpecDecls(DC); - - if (DC->isTranslationUnit()) - return; - - if (const BlockDecl *Block = dyn_cast<BlockDecl>(DC)) { - manglePrefix(getEffectiveParentContext(DC), NoFunction); - SmallString<64> Name; - llvm::raw_svector_ostream NameStream(Name); - Context.mangleBlock(Block, NameStream); - NameStream.flush(); - Out << Name.size() << Name; - return; - } - - const NamedDecl *ND = cast<NamedDecl>(DC); - if (mangleSubstitution(ND)) - return; - - // Check if we have a template. - const TemplateArgumentList *TemplateArgs = 0; - if (const TemplateDecl *TD = isTemplate(ND, TemplateArgs)) { - mangleTemplatePrefix(TD); - mangleTemplateArgs(*TemplateArgs); - } - else if(NoFunction && (isa<FunctionDecl>(ND) || isa<ObjCMethodDecl>(ND))) - return; - else if (const ObjCMethodDecl *Method = dyn_cast<ObjCMethodDecl>(ND)) - mangleObjCMethodName(Method); - else { - manglePrefix(getEffectiveDeclContext(ND), NoFunction); - mangleUnqualifiedName(ND); - } - - addSubstitution(ND); -} - -void CXXNameMangler::mangleTemplatePrefix(TemplateName Template) { - // <template-prefix> ::= <prefix> <template unqualified-name> - // ::= <template-param> - // ::= <substitution> - if (TemplateDecl *TD = Template.getAsTemplateDecl()) - return mangleTemplatePrefix(TD); - - if (QualifiedTemplateName *Qualified = Template.getAsQualifiedTemplateName()) - manglePrefix(Qualified->getQualifier()); - - if (OverloadedTemplateStorage *Overloaded - = Template.getAsOverloadedTemplate()) { - mangleUnqualifiedName(0, (*Overloaded->begin())->getDeclName(), - UnknownArity); - return; - } - - DependentTemplateName *Dependent = Template.getAsDependentTemplateName(); - assert(Dependent && "Unknown template name kind?"); - manglePrefix(Dependent->getQualifier()); - mangleUnscopedTemplateName(Template); -} - -void CXXNameMangler::mangleTemplatePrefix(const TemplateDecl *ND) { - // <template-prefix> ::= <prefix> <template unqualified-name> - // ::= <template-param> - // ::= <substitution> - // <template-template-param> ::= <template-param> - // <substitution> - - if (mangleSubstitution(ND)) - return; - - // <template-template-param> ::= <template-param> - if (const TemplateTemplateParmDecl *TTP - = dyn_cast<TemplateTemplateParmDecl>(ND)) { - mangleTemplateParameter(TTP->getIndex()); - return; - } - - manglePrefix(getEffectiveDeclContext(ND)); - mangleUnqualifiedName(ND->getTemplatedDecl()); - addSubstitution(ND); -} - -/// Mangles a template name under the production <type>. Required for -/// template template arguments. -/// <type> ::= <class-enum-type> -/// ::= <template-param> -/// ::= <substitution> -void CXXNameMangler::mangleType(TemplateName TN) { - if (mangleSubstitution(TN)) - return; - - TemplateDecl *TD = 0; - - switch (TN.getKind()) { - case TemplateName::QualifiedTemplate: - TD = TN.getAsQualifiedTemplateName()->getTemplateDecl(); - goto HaveDecl; - - case TemplateName::Template: - TD = TN.getAsTemplateDecl(); - goto HaveDecl; - - HaveDecl: - if (isa<TemplateTemplateParmDecl>(TD)) - mangleTemplateParameter(cast<TemplateTemplateParmDecl>(TD)->getIndex()); - else - mangleName(TD); - break; - - case TemplateName::OverloadedTemplate: - llvm_unreachable("can't mangle an overloaded template name as a <type>"); - - case TemplateName::DependentTemplate: { - const DependentTemplateName *Dependent = TN.getAsDependentTemplateName(); - assert(Dependent->isIdentifier()); - - // <class-enum-type> ::= <name> - // <name> ::= <nested-name> - mangleUnresolvedPrefix(Dependent->getQualifier(), 0); - mangleSourceName(Dependent->getIdentifier()); - break; - } - - case TemplateName::SubstTemplateTemplateParm: { - // Substituted template parameters are mangled as the substituted - // template. This will check for the substitution twice, which is - // fine, but we have to return early so that we don't try to *add* - // the substitution twice. - SubstTemplateTemplateParmStorage *subst - = TN.getAsSubstTemplateTemplateParm(); - mangleType(subst->getReplacement()); - return; - } - - case TemplateName::SubstTemplateTemplateParmPack: { - // FIXME: not clear how to mangle this! - // template <template <class> class T...> class A { - // template <template <class> class U...> void foo(B<T,U> x...); - // }; - Out << "_SUBSTPACK_"; - break; - } - } - - addSubstitution(TN); -} - -void -CXXNameMangler::mangleOperatorName(OverloadedOperatorKind OO, unsigned Arity) { - switch (OO) { - // <operator-name> ::= nw # new - case OO_New: Out << "nw"; break; - // ::= na # new[] - case OO_Array_New: Out << "na"; break; - // ::= dl # delete - case OO_Delete: Out << "dl"; break; - // ::= da # delete[] - case OO_Array_Delete: Out << "da"; break; - // ::= ps # + (unary) - // ::= pl # + (binary or unknown) - case OO_Plus: - Out << (Arity == 1? "ps" : "pl"); break; - // ::= ng # - (unary) - // ::= mi # - (binary or unknown) - case OO_Minus: - Out << (Arity == 1? "ng" : "mi"); break; - // ::= ad # & (unary) - // ::= an # & (binary or unknown) - case OO_Amp: - Out << (Arity == 1? "ad" : "an"); break; - // ::= de # * (unary) - // ::= ml # * (binary or unknown) - case OO_Star: - // Use binary when unknown. - Out << (Arity == 1? "de" : "ml"); break; - // ::= co # ~ - case OO_Tilde: Out << "co"; break; - // ::= dv # / - case OO_Slash: Out << "dv"; break; - // ::= rm # % - case OO_Percent: Out << "rm"; break; - // ::= or # | - case OO_Pipe: Out << "or"; break; - // ::= eo # ^ - case OO_Caret: Out << "eo"; break; - // ::= aS # = - case OO_Equal: Out << "aS"; break; - // ::= pL # += - case OO_PlusEqual: Out << "pL"; break; - // ::= mI # -= - case OO_MinusEqual: Out << "mI"; break; - // ::= mL # *= - case OO_StarEqual: Out << "mL"; break; - // ::= dV # /= - case OO_SlashEqual: Out << "dV"; break; - // ::= rM # %= - case OO_PercentEqual: Out << "rM"; break; - // ::= aN # &= - case OO_AmpEqual: Out << "aN"; break; - // ::= oR # |= - case OO_PipeEqual: Out << "oR"; break; - // ::= eO # ^= - case OO_CaretEqual: Out << "eO"; break; - // ::= ls # << - case OO_LessLess: Out << "ls"; break; - // ::= rs # >> - case OO_GreaterGreater: Out << "rs"; break; - // ::= lS # <<= - case OO_LessLessEqual: Out << "lS"; break; - // ::= rS # >>= - case OO_GreaterGreaterEqual: Out << "rS"; break; - // ::= eq # == - case OO_EqualEqual: Out << "eq"; break; - // ::= ne # != - case OO_ExclaimEqual: Out << "ne"; break; - // ::= lt # < - case OO_Less: Out << "lt"; break; - // ::= gt # > - case OO_Greater: Out << "gt"; break; - // ::= le # <= - case OO_LessEqual: Out << "le"; break; - // ::= ge # >= - case OO_GreaterEqual: Out << "ge"; break; - // ::= nt # ! - case OO_Exclaim: Out << "nt"; break; - // ::= aa # && - case OO_AmpAmp: Out << "aa"; break; - // ::= oo # || - case OO_PipePipe: Out << "oo"; break; - // ::= pp # ++ - case OO_PlusPlus: Out << "pp"; break; - // ::= mm # -- - case OO_MinusMinus: Out << "mm"; break; - // ::= cm # , - case OO_Comma: Out << "cm"; break; - // ::= pm # ->* - case OO_ArrowStar: Out << "pm"; break; - // ::= pt # -> - case OO_Arrow: Out << "pt"; break; - // ::= cl # () - case OO_Call: Out << "cl"; break; - // ::= ix # [] - case OO_Subscript: Out << "ix"; break; - - // ::= qu # ? - // The conditional operator can't be overloaded, but we still handle it when - // mangling expressions. - case OO_Conditional: Out << "qu"; break; - - case OO_None: - case NUM_OVERLOADED_OPERATORS: - llvm_unreachable("Not an overloaded operator"); - } -} - -void CXXNameMangler::mangleQualifiers(Qualifiers Quals) { - // <CV-qualifiers> ::= [r] [V] [K] # restrict (C99), volatile, const - if (Quals.hasRestrict()) - Out << 'r'; - if (Quals.hasVolatile()) - Out << 'V'; - if (Quals.hasConst()) - Out << 'K'; - - if (Quals.hasAddressSpace()) { - // Extension: - // - // <type> ::= U <address-space-number> - // - // where <address-space-number> is a source name consisting of 'AS' - // followed by the address space <number>. - SmallString<64> ASString; - ASString = "AS" + llvm::utostr_32(Quals.getAddressSpace()); - Out << 'U' << ASString.size() << ASString; - } - - StringRef LifetimeName; - switch (Quals.getObjCLifetime()) { - // Objective-C ARC Extension: - // - // <type> ::= U "__strong" - // <type> ::= U "__weak" - // <type> ::= U "__autoreleasing" - case Qualifiers::OCL_None: - break; - - case Qualifiers::OCL_Weak: - LifetimeName = "__weak"; - break; - - case Qualifiers::OCL_Strong: - LifetimeName = "__strong"; - break; - - case Qualifiers::OCL_Autoreleasing: - LifetimeName = "__autoreleasing"; - break; - - case Qualifiers::OCL_ExplicitNone: - // The __unsafe_unretained qualifier is *not* mangled, so that - // __unsafe_unretained types in ARC produce the same manglings as the - // equivalent (but, naturally, unqualified) types in non-ARC, providing - // better ABI compatibility. - // - // It's safe to do this because unqualified 'id' won't show up - // in any type signatures that need to be mangled. - break; - } - if (!LifetimeName.empty()) - Out << 'U' << LifetimeName.size() << LifetimeName; -} - -void CXXNameMangler::mangleRefQualifier(RefQualifierKind RefQualifier) { - // <ref-qualifier> ::= R # lvalue reference - // ::= O # rvalue-reference - // Proposal to Itanium C++ ABI list on 1/26/11 - switch (RefQualifier) { - case RQ_None: - break; - - case RQ_LValue: - Out << 'R'; - break; - - case RQ_RValue: - Out << 'O'; - break; - } -} - -void CXXNameMangler::mangleObjCMethodName(const ObjCMethodDecl *MD) { - Context.mangleObjCMethodName(MD, Out); -} - -void CXXNameMangler::mangleType(QualType T) { - // If our type is instantiation-dependent but not dependent, we mangle - // it as it was written in the source, removing any top-level sugar. - // Otherwise, use the canonical type. - // - // FIXME: This is an approximation of the instantiation-dependent name - // mangling rules, since we should really be using the type as written and - // augmented via semantic analysis (i.e., with implicit conversions and - // default template arguments) for any instantiation-dependent type. - // Unfortunately, that requires several changes to our AST: - // - Instantiation-dependent TemplateSpecializationTypes will need to be - // uniqued, so that we can handle substitutions properly - // - Default template arguments will need to be represented in the - // TemplateSpecializationType, since they need to be mangled even though - // they aren't written. - // - Conversions on non-type template arguments need to be expressed, since - // they can affect the mangling of sizeof/alignof. - if (!T->isInstantiationDependentType() || T->isDependentType()) - T = T.getCanonicalType(); - else { - // Desugar any types that are purely sugar. - do { - // Don't desugar through template specialization types that aren't - // type aliases. We need to mangle the template arguments as written. - if (const TemplateSpecializationType *TST - = dyn_cast<TemplateSpecializationType>(T)) - if (!TST->isTypeAlias()) - break; - - QualType Desugared - = T.getSingleStepDesugaredType(Context.getASTContext()); - if (Desugared == T) - break; - - T = Desugared; - } while (true); - } - SplitQualType split = T.split(); - Qualifiers quals = split.Quals; - const Type *ty = split.Ty; - - bool isSubstitutable = quals || !isa<BuiltinType>(T); - if (isSubstitutable && mangleSubstitution(T)) - return; - - // If we're mangling a qualified array type, push the qualifiers to - // the element type. - if (quals && isa<ArrayType>(T)) { - ty = Context.getASTContext().getAsArrayType(T); - quals = Qualifiers(); - - // Note that we don't update T: we want to add the - // substitution at the original type. - } - - if (quals) { - mangleQualifiers(quals); - // Recurse: even if the qualified type isn't yet substitutable, - // the unqualified type might be. - mangleType(QualType(ty, 0)); - } else { - switch (ty->getTypeClass()) { -#define ABSTRACT_TYPE(CLASS, PARENT) -#define NON_CANONICAL_TYPE(CLASS, PARENT) \ - case Type::CLASS: \ - llvm_unreachable("can't mangle non-canonical type " #CLASS "Type"); \ - return; -#define TYPE(CLASS, PARENT) \ - case Type::CLASS: \ - mangleType(static_cast<const CLASS##Type*>(ty)); \ - break; -#include "clang/AST/TypeNodes.def" - } - } - - // Add the substitution. - if (isSubstitutable) - addSubstitution(T); -} - -void CXXNameMangler::mangleNameOrStandardSubstitution(const NamedDecl *ND) { - if (!mangleStandardSubstitution(ND)) - mangleName(ND); -} - -void CXXNameMangler::mangleType(const BuiltinType *T) { - // <type> ::= <builtin-type> - // <builtin-type> ::= v # void - // ::= w # wchar_t - // ::= b # bool - // ::= c # char - // ::= a # signed char - // ::= h # unsigned char - // ::= s # short - // ::= t # unsigned short - // ::= i # int - // ::= j # unsigned int - // ::= l # long - // ::= m # unsigned long - // ::= x # long long, __int64 - // ::= y # unsigned long long, __int64 - // ::= n # __int128 - // UNSUPPORTED: ::= o # unsigned __int128 - // ::= f # float - // ::= d # double - // ::= e # long double, __float80 - // UNSUPPORTED: ::= g # __float128 - // UNSUPPORTED: ::= Dd # IEEE 754r decimal floating point (64 bits) - // UNSUPPORTED: ::= De # IEEE 754r decimal floating point (128 bits) - // UNSUPPORTED: ::= Df # IEEE 754r decimal floating point (32 bits) - // ::= Dh # IEEE 754r half-precision floating point (16 bits) - // ::= Di # char32_t - // ::= Ds # char16_t - // ::= Dn # std::nullptr_t (i.e., decltype(nullptr)) - // ::= u <source-name> # vendor extended type - switch (T->getKind()) { - case BuiltinType::Void: Out << 'v'; break; - case BuiltinType::Bool: Out << 'b'; break; - case BuiltinType::Char_U: case BuiltinType::Char_S: Out << 'c'; break; - case BuiltinType::UChar: Out << 'h'; break; - case BuiltinType::UShort: Out << 't'; break; - case BuiltinType::UInt: Out << 'j'; break; - case BuiltinType::ULong: Out << 'm'; break; - case BuiltinType::ULongLong: Out << 'y'; break; - case BuiltinType::UInt128: Out << 'o'; break; - case BuiltinType::SChar: Out << 'a'; break; - case BuiltinType::WChar_S: - case BuiltinType::WChar_U: Out << 'w'; break; - case BuiltinType::Char16: Out << "Ds"; break; - case BuiltinType::Char32: Out << "Di"; break; - case BuiltinType::Short: Out << 's'; break; - case BuiltinType::Int: Out << 'i'; break; - case BuiltinType::Long: Out << 'l'; break; - case BuiltinType::LongLong: Out << 'x'; break; - case BuiltinType::Int128: Out << 'n'; break; - case BuiltinType::Half: Out << "Dh"; break; - case BuiltinType::Float: Out << 'f'; break; - case BuiltinType::Double: Out << 'd'; break; - case BuiltinType::LongDouble: Out << 'e'; break; - case BuiltinType::NullPtr: Out << "Dn"; break; - -#define BUILTIN_TYPE(Id, SingletonId) -#define PLACEHOLDER_TYPE(Id, SingletonId) \ - case BuiltinType::Id: -#include "clang/AST/BuiltinTypes.def" - case BuiltinType::Dependent: - llvm_unreachable("mangling a placeholder type"); - case BuiltinType::ObjCId: Out << "11objc_object"; break; - case BuiltinType::ObjCClass: Out << "10objc_class"; break; - case BuiltinType::ObjCSel: Out << "13objc_selector"; break; - } -} - -// <type> ::= <function-type> -// <function-type> ::= [<CV-qualifiers>] F [Y] -// <bare-function-type> [<ref-qualifier>] E -// (Proposal to cxx-abi-dev, 2012-05-11) -void CXXNameMangler::mangleType(const FunctionProtoType *T) { - // Mangle CV-qualifiers, if present. These are 'this' qualifiers, - // e.g. "const" in "int (A::*)() const". - mangleQualifiers(Qualifiers::fromCVRMask(T->getTypeQuals())); - - Out << 'F'; - - // FIXME: We don't have enough information in the AST to produce the 'Y' - // encoding for extern "C" function types. - mangleBareFunctionType(T, /*MangleReturnType=*/true); - - // Mangle the ref-qualifier, if present. - mangleRefQualifier(T->getRefQualifier()); - - Out << 'E'; -} -void CXXNameMangler::mangleType(const FunctionNoProtoType *T) { - llvm_unreachable("Can't mangle K&R function prototypes"); -} -void CXXNameMangler::mangleBareFunctionType(const FunctionType *T, - bool MangleReturnType) { - // We should never be mangling something without a prototype. - const FunctionProtoType *Proto = cast<FunctionProtoType>(T); - - // Record that we're in a function type. See mangleFunctionParam - // for details on what we're trying to achieve here. - FunctionTypeDepthState saved = FunctionTypeDepth.push(); - - // <bare-function-type> ::= <signature type>+ - if (MangleReturnType) { - FunctionTypeDepth.enterResultType(); - mangleType(Proto->getResultType()); - FunctionTypeDepth.leaveResultType(); - } - - if (Proto->getNumArgs() == 0 && !Proto->isVariadic()) { - // <builtin-type> ::= v # void - Out << 'v'; - - FunctionTypeDepth.pop(saved); - return; - } - - for (FunctionProtoType::arg_type_iterator Arg = Proto->arg_type_begin(), - ArgEnd = Proto->arg_type_end(); - Arg != ArgEnd; ++Arg) - mangleType(Context.getASTContext().getSignatureParameterType(*Arg)); - - FunctionTypeDepth.pop(saved); - - // <builtin-type> ::= z # ellipsis - if (Proto->isVariadic()) - Out << 'z'; -} - -// <type> ::= <class-enum-type> -// <class-enum-type> ::= <name> -void CXXNameMangler::mangleType(const UnresolvedUsingType *T) { - mangleName(T->getDecl()); -} - -// <type> ::= <class-enum-type> -// <class-enum-type> ::= <name> -void CXXNameMangler::mangleType(const EnumType *T) { - mangleType(static_cast<const TagType*>(T)); -} -void CXXNameMangler::mangleType(const RecordType *T) { - mangleType(static_cast<const TagType*>(T)); -} -void CXXNameMangler::mangleType(const TagType *T) { - mangleName(T->getDecl()); -} - -// <type> ::= <array-type> -// <array-type> ::= A <positive dimension number> _ <element type> -// ::= A [<dimension expression>] _ <element type> -void CXXNameMangler::mangleType(const ConstantArrayType *T) { - Out << 'A' << T->getSize() << '_'; - mangleType(T->getElementType()); -} -void CXXNameMangler::mangleType(const VariableArrayType *T) { - Out << 'A'; - // decayed vla types (size 0) will just be skipped. - if (T->getSizeExpr()) - mangleExpression(T->getSizeExpr()); - Out << '_'; - mangleType(T->getElementType()); -} -void CXXNameMangler::mangleType(const DependentSizedArrayType *T) { - Out << 'A'; - mangleExpression(T->getSizeExpr()); - Out << '_'; - mangleType(T->getElementType()); -} -void CXXNameMangler::mangleType(const IncompleteArrayType *T) { - Out << "A_"; - mangleType(T->getElementType()); -} - -// <type> ::= <pointer-to-member-type> -// <pointer-to-member-type> ::= M <class type> <member type> -void CXXNameMangler::mangleType(const MemberPointerType *T) { - Out << 'M'; - mangleType(QualType(T->getClass(), 0)); - QualType PointeeType = T->getPointeeType(); - if (const FunctionProtoType *FPT = dyn_cast<FunctionProtoType>(PointeeType)) { - mangleType(FPT); - - // Itanium C++ ABI 5.1.8: - // - // The type of a non-static member function is considered to be different, - // for the purposes of substitution, from the type of a namespace-scope or - // static member function whose type appears similar. The types of two - // non-static member functions are considered to be different, for the - // purposes of substitution, if the functions are members of different - // classes. In other words, for the purposes of substitution, the class of - // which the function is a member is considered part of the type of - // function. - - // Given that we already substitute member function pointers as a - // whole, the net effect of this rule is just to unconditionally - // suppress substitution on the function type in a member pointer. - // We increment the SeqID here to emulate adding an entry to the - // substitution table. - ++SeqID; - } else - mangleType(PointeeType); -} - -// <type> ::= <template-param> -void CXXNameMangler::mangleType(const TemplateTypeParmType *T) { - mangleTemplateParameter(T->getIndex()); -} - -// <type> ::= <template-param> -void CXXNameMangler::mangleType(const SubstTemplateTypeParmPackType *T) { - // FIXME: not clear how to mangle this! - // template <class T...> class A { - // template <class U...> void foo(T(*)(U) x...); - // }; - Out << "_SUBSTPACK_"; -} - -// <type> ::= P <type> # pointer-to -void CXXNameMangler::mangleType(const PointerType *T) { - Out << 'P'; - mangleType(T->getPointeeType()); -} -void CXXNameMangler::mangleType(const ObjCObjectPointerType *T) { - Out << 'P'; - mangleType(T->getPointeeType()); -} - -// <type> ::= R <type> # reference-to -void CXXNameMangler::mangleType(const LValueReferenceType *T) { - Out << 'R'; - mangleType(T->getPointeeType()); -} - -// <type> ::= O <type> # rvalue reference-to (C++0x) -void CXXNameMangler::mangleType(const RValueReferenceType *T) { - Out << 'O'; - mangleType(T->getPointeeType()); -} - -// <type> ::= C <type> # complex pair (C 2000) -void CXXNameMangler::mangleType(const ComplexType *T) { - Out << 'C'; - mangleType(T->getElementType()); -} - -// ARM's ABI for Neon vector types specifies that they should be mangled as -// if they are structs (to match ARM's initial implementation). The -// vector type must be one of the special types predefined by ARM. -void CXXNameMangler::mangleNeonVectorType(const VectorType *T) { - QualType EltType = T->getElementType(); - assert(EltType->isBuiltinType() && "Neon vector element not a BuiltinType"); - const char *EltName = 0; - if (T->getVectorKind() == VectorType::NeonPolyVector) { - switch (cast<BuiltinType>(EltType)->getKind()) { - case BuiltinType::SChar: EltName = "poly8_t"; break; - case BuiltinType::Short: EltName = "poly16_t"; break; - default: llvm_unreachable("unexpected Neon polynomial vector element type"); - } - } else { - switch (cast<BuiltinType>(EltType)->getKind()) { - case BuiltinType::SChar: EltName = "int8_t"; break; - case BuiltinType::UChar: EltName = "uint8_t"; break; - case BuiltinType::Short: EltName = "int16_t"; break; - case BuiltinType::UShort: EltName = "uint16_t"; break; - case BuiltinType::Int: EltName = "int32_t"; break; - case BuiltinType::UInt: EltName = "uint32_t"; break; - case BuiltinType::LongLong: EltName = "int64_t"; break; - case BuiltinType::ULongLong: EltName = "uint64_t"; break; - case BuiltinType::Float: EltName = "float32_t"; break; - default: llvm_unreachable("unexpected Neon vector element type"); - } - } - const char *BaseName = 0; - unsigned BitSize = (T->getNumElements() * - getASTContext().getTypeSize(EltType)); - if (BitSize == 64) - BaseName = "__simd64_"; - else { - assert(BitSize == 128 && "Neon vector type not 64 or 128 bits"); - BaseName = "__simd128_"; - } - Out << strlen(BaseName) + strlen(EltName); - Out << BaseName << EltName; -} - -// GNU extension: vector types -// <type> ::= <vector-type> -// <vector-type> ::= Dv <positive dimension number> _ -// <extended element type> -// ::= Dv [<dimension expression>] _ <element type> -// <extended element type> ::= <element type> -// ::= p # AltiVec vector pixel -// ::= b # Altivec vector bool -void CXXNameMangler::mangleType(const VectorType *T) { - if ((T->getVectorKind() == VectorType::NeonVector || - T->getVectorKind() == VectorType::NeonPolyVector)) { - mangleNeonVectorType(T); - return; - } - Out << "Dv" << T->getNumElements() << '_'; - if (T->getVectorKind() == VectorType::AltiVecPixel) - Out << 'p'; - else if (T->getVectorKind() == VectorType::AltiVecBool) - Out << 'b'; - else - mangleType(T->getElementType()); -} -void CXXNameMangler::mangleType(const ExtVectorType *T) { - mangleType(static_cast<const VectorType*>(T)); -} -void CXXNameMangler::mangleType(const DependentSizedExtVectorType *T) { - Out << "Dv"; - mangleExpression(T->getSizeExpr()); - Out << '_'; - mangleType(T->getElementType()); -} - -void CXXNameMangler::mangleType(const PackExpansionType *T) { - // <type> ::= Dp <type> # pack expansion (C++0x) - Out << "Dp"; - mangleType(T->getPattern()); -} - -void CXXNameMangler::mangleType(const ObjCInterfaceType *T) { - mangleSourceName(T->getDecl()->getIdentifier()); -} - -void CXXNameMangler::mangleType(const ObjCObjectType *T) { - // We don't allow overloading by different protocol qualification, - // so mangling them isn't necessary. - mangleType(T->getBaseType()); -} - -void CXXNameMangler::mangleType(const BlockPointerType *T) { - Out << "U13block_pointer"; - mangleType(T->getPointeeType()); -} - -void CXXNameMangler::mangleType(const InjectedClassNameType *T) { - // Mangle injected class name types as if the user had written the - // specialization out fully. It may not actually be possible to see - // this mangling, though. - mangleType(T->getInjectedSpecializationType()); -} - -void CXXNameMangler::mangleType(const TemplateSpecializationType *T) { - if (TemplateDecl *TD = T->getTemplateName().getAsTemplateDecl()) { - mangleName(TD, T->getArgs(), T->getNumArgs()); - } else { - if (mangleSubstitution(QualType(T, 0))) - return; - - mangleTemplatePrefix(T->getTemplateName()); - - // FIXME: GCC does not appear to mangle the template arguments when - // the template in question is a dependent template name. Should we - // emulate that badness? - mangleTemplateArgs(T->getArgs(), T->getNumArgs()); - addSubstitution(QualType(T, 0)); - } -} - -void CXXNameMangler::mangleType(const DependentNameType *T) { - // Typename types are always nested - Out << 'N'; - manglePrefix(T->getQualifier()); - mangleSourceName(T->getIdentifier()); - Out << 'E'; -} - -void CXXNameMangler::mangleType(const DependentTemplateSpecializationType *T) { - // Dependently-scoped template types are nested if they have a prefix. - Out << 'N'; - - // TODO: avoid making this TemplateName. - TemplateName Prefix = - getASTContext().getDependentTemplateName(T->getQualifier(), - T->getIdentifier()); - mangleTemplatePrefix(Prefix); - - // FIXME: GCC does not appear to mangle the template arguments when - // the template in question is a dependent template name. Should we - // emulate that badness? - mangleTemplateArgs(T->getArgs(), T->getNumArgs()); - Out << 'E'; -} - -void CXXNameMangler::mangleType(const TypeOfType *T) { - // FIXME: this is pretty unsatisfactory, but there isn't an obvious - // "extension with parameters" mangling. - Out << "u6typeof"; -} - -void CXXNameMangler::mangleType(const TypeOfExprType *T) { - // FIXME: this is pretty unsatisfactory, but there isn't an obvious - // "extension with parameters" mangling. - Out << "u6typeof"; -} - -void CXXNameMangler::mangleType(const DecltypeType *T) { - Expr *E = T->getUnderlyingExpr(); - - // type ::= Dt <expression> E # decltype of an id-expression - // # or class member access - // ::= DT <expression> E # decltype of an expression - - // This purports to be an exhaustive list of id-expressions and - // class member accesses. Note that we do not ignore parentheses; - // parentheses change the semantics of decltype for these - // expressions (and cause the mangler to use the other form). - if (isa<DeclRefExpr>(E) || - isa<MemberExpr>(E) || - isa<UnresolvedLookupExpr>(E) || - isa<DependentScopeDeclRefExpr>(E) || - isa<CXXDependentScopeMemberExpr>(E) || - isa<UnresolvedMemberExpr>(E)) - Out << "Dt"; - else - Out << "DT"; - mangleExpression(E); - Out << 'E'; -} - -void CXXNameMangler::mangleType(const UnaryTransformType *T) { - // If this is dependent, we need to record that. If not, we simply - // mangle it as the underlying type since they are equivalent. - if (T->isDependentType()) { - Out << 'U'; - - switch (T->getUTTKind()) { - case UnaryTransformType::EnumUnderlyingType: - Out << "3eut"; - break; - } - } - - mangleType(T->getUnderlyingType()); -} - -void CXXNameMangler::mangleType(const AutoType *T) { - QualType D = T->getDeducedType(); - // <builtin-type> ::= Da # dependent auto - if (D.isNull()) - Out << "Da"; - else - mangleType(D); -} - -void CXXNameMangler::mangleType(const AtomicType *T) { - // <type> ::= U <source-name> <type> # vendor extended type qualifier - // (Until there's a standardized mangling...) - Out << "U7_Atomic"; - mangleType(T->getValueType()); -} - -void CXXNameMangler::mangleIntegerLiteral(QualType T, - const llvm::APSInt &Value) { - // <expr-primary> ::= L <type> <value number> E # integer literal - Out << 'L'; - - mangleType(T); - if (T->isBooleanType()) { - // Boolean values are encoded as 0/1. - Out << (Value.getBoolValue() ? '1' : '0'); - } else { - mangleNumber(Value); - } - Out << 'E'; - -} - -/// Mangles a member expression. -void CXXNameMangler::mangleMemberExpr(const Expr *base, - bool isArrow, - NestedNameSpecifier *qualifier, - NamedDecl *firstQualifierLookup, - DeclarationName member, - unsigned arity) { - // <expression> ::= dt <expression> <unresolved-name> - // ::= pt <expression> <unresolved-name> - if (base) { - if (base->isImplicitCXXThis()) { - // Note: GCC mangles member expressions to the implicit 'this' as - // *this., whereas we represent them as this->. The Itanium C++ ABI - // does not specify anything here, so we follow GCC. - Out << "dtdefpT"; - } else { - Out << (isArrow ? "pt" : "dt"); - mangleExpression(base); - } - } - mangleUnresolvedName(qualifier, firstQualifierLookup, member, arity); -} - -/// Look at the callee of the given call expression and determine if -/// it's a parenthesized id-expression which would have triggered ADL -/// otherwise. -static bool isParenthesizedADLCallee(const CallExpr *call) { - const Expr *callee = call->getCallee(); - const Expr *fn = callee->IgnoreParens(); - - // Must be parenthesized. IgnoreParens() skips __extension__ nodes, - // too, but for those to appear in the callee, it would have to be - // parenthesized. - if (callee == fn) return false; - - // Must be an unresolved lookup. - const UnresolvedLookupExpr *lookup = dyn_cast<UnresolvedLookupExpr>(fn); - if (!lookup) return false; - - assert(!lookup->requiresADL()); - - // Must be an unqualified lookup. - if (lookup->getQualifier()) return false; - - // Must not have found a class member. Note that if one is a class - // member, they're all class members. - if (lookup->getNumDecls() > 0 && - (*lookup->decls_begin())->isCXXClassMember()) - return false; - - // Otherwise, ADL would have been triggered. - return true; -} - -void CXXNameMangler::mangleExpression(const Expr *E, unsigned Arity) { - // <expression> ::= <unary operator-name> <expression> - // ::= <binary operator-name> <expression> <expression> - // ::= <trinary operator-name> <expression> <expression> <expression> - // ::= cv <type> expression # conversion with one argument - // ::= cv <type> _ <expression>* E # conversion with a different number of arguments - // ::= st <type> # sizeof (a type) - // ::= at <type> # alignof (a type) - // ::= <template-param> - // ::= <function-param> - // ::= sr <type> <unqualified-name> # dependent name - // ::= sr <type> <unqualified-name> <template-args> # dependent template-id - // ::= ds <expression> <expression> # expr.*expr - // ::= sZ <template-param> # size of a parameter pack - // ::= sZ <function-param> # size of a function parameter pack - // ::= <expr-primary> - // <expr-primary> ::= L <type> <value number> E # integer literal - // ::= L <type <value float> E # floating literal - // ::= L <mangled-name> E # external name - // ::= fpT # 'this' expression - QualType ImplicitlyConvertedToType; - -recurse: - switch (E->getStmtClass()) { - case Expr::NoStmtClass: -#define ABSTRACT_STMT(Type) -#define EXPR(Type, Base) -#define STMT(Type, Base) \ - case Expr::Type##Class: -#include "clang/AST/StmtNodes.inc" - // fallthrough - - // These all can only appear in local or variable-initialization - // contexts and so should never appear in a mangling. - case Expr::AddrLabelExprClass: - case Expr::DesignatedInitExprClass: - case Expr::ImplicitValueInitExprClass: - case Expr::ParenListExprClass: - case Expr::LambdaExprClass: - llvm_unreachable("unexpected statement kind"); - - // FIXME: invent manglings for all these. - case Expr::BlockExprClass: - case Expr::CXXPseudoDestructorExprClass: - case Expr::ChooseExprClass: - case Expr::CompoundLiteralExprClass: - case Expr::ExtVectorElementExprClass: - case Expr::GenericSelectionExprClass: - case Expr::ObjCEncodeExprClass: - case Expr::ObjCIsaExprClass: - case Expr::ObjCIvarRefExprClass: - case Expr::ObjCMessageExprClass: - case Expr::ObjCPropertyRefExprClass: - case Expr::ObjCProtocolExprClass: - case Expr::ObjCSelectorExprClass: - case Expr::ObjCStringLiteralClass: - case Expr::ObjCBoxedExprClass: - case Expr::ObjCArrayLiteralClass: - case Expr::ObjCDictionaryLiteralClass: - case Expr::ObjCSubscriptRefExprClass: - case Expr::ObjCIndirectCopyRestoreExprClass: - case Expr::OffsetOfExprClass: - case Expr::PredefinedExprClass: - case Expr::ShuffleVectorExprClass: - case Expr::StmtExprClass: - case Expr::UnaryTypeTraitExprClass: - case Expr::BinaryTypeTraitExprClass: - case Expr::TypeTraitExprClass: - case Expr::ArrayTypeTraitExprClass: - case Expr::ExpressionTraitExprClass: - case Expr::VAArgExprClass: - case Expr::CXXUuidofExprClass: - case Expr::CUDAKernelCallExprClass: - case Expr::AsTypeExprClass: - case Expr::PseudoObjectExprClass: - case Expr::AtomicExprClass: - { - // As bad as this diagnostic is, it's better than crashing. - DiagnosticsEngine &Diags = Context.getDiags(); - unsigned DiagID = Diags.getCustomDiagID(DiagnosticsEngine::Error, - "cannot yet mangle expression type %0"); - Diags.Report(E->getExprLoc(), DiagID) - << E->getStmtClassName() << E->getSourceRange(); - break; - } - - // Even gcc-4.5 doesn't mangle this. - case Expr::BinaryConditionalOperatorClass: { - DiagnosticsEngine &Diags = Context.getDiags(); - unsigned DiagID = - Diags.getCustomDiagID(DiagnosticsEngine::Error, - "?: operator with omitted middle operand cannot be mangled"); - Diags.Report(E->getExprLoc(), DiagID) - << E->getStmtClassName() << E->getSourceRange(); - break; - } - - // These are used for internal purposes and cannot be meaningfully mangled. - case Expr::OpaqueValueExprClass: - llvm_unreachable("cannot mangle opaque value; mangling wrong thing?"); - - case Expr::InitListExprClass: { - // Proposal by Jason Merrill, 2012-01-03 - Out << "il"; - const InitListExpr *InitList = cast<InitListExpr>(E); - for (unsigned i = 0, e = InitList->getNumInits(); i != e; ++i) - mangleExpression(InitList->getInit(i)); - Out << "E"; - break; - } - - case Expr::CXXDefaultArgExprClass: - mangleExpression(cast<CXXDefaultArgExpr>(E)->getExpr(), Arity); - break; - - case Expr::SubstNonTypeTemplateParmExprClass: - mangleExpression(cast<SubstNonTypeTemplateParmExpr>(E)->getReplacement(), - Arity); - break; - - case Expr::UserDefinedLiteralClass: - // We follow g++'s approach of mangling a UDL as a call to the literal - // operator. - case Expr::CXXMemberCallExprClass: // fallthrough - case Expr::CallExprClass: { - const CallExpr *CE = cast<CallExpr>(E); - - // <expression> ::= cp <simple-id> <expression>* E - // We use this mangling only when the call would use ADL except - // for being parenthesized. Per discussion with David - // Vandervoorde, 2011.04.25. - if (isParenthesizedADLCallee(CE)) { - Out << "cp"; - // The callee here is a parenthesized UnresolvedLookupExpr with - // no qualifier and should always get mangled as a <simple-id> - // anyway. - - // <expression> ::= cl <expression>* E - } else { - Out << "cl"; - } - - mangleExpression(CE->getCallee(), CE->getNumArgs()); - for (unsigned I = 0, N = CE->getNumArgs(); I != N; ++I) - mangleExpression(CE->getArg(I)); - Out << 'E'; - break; - } - - case Expr::CXXNewExprClass: { - const CXXNewExpr *New = cast<CXXNewExpr>(E); - if (New->isGlobalNew()) Out << "gs"; - Out << (New->isArray() ? "na" : "nw"); - for (CXXNewExpr::const_arg_iterator I = New->placement_arg_begin(), - E = New->placement_arg_end(); I != E; ++I) - mangleExpression(*I); - Out << '_'; - mangleType(New->getAllocatedType()); - if (New->hasInitializer()) { - // Proposal by Jason Merrill, 2012-01-03 - if (New->getInitializationStyle() == CXXNewExpr::ListInit) - Out << "il"; - else - Out << "pi"; - const Expr *Init = New->getInitializer(); - if (const CXXConstructExpr *CCE = dyn_cast<CXXConstructExpr>(Init)) { - // Directly inline the initializers. - for (CXXConstructExpr::const_arg_iterator I = CCE->arg_begin(), - E = CCE->arg_end(); - I != E; ++I) - mangleExpression(*I); - } else if (const ParenListExpr *PLE = dyn_cast<ParenListExpr>(Init)) { - for (unsigned i = 0, e = PLE->getNumExprs(); i != e; ++i) - mangleExpression(PLE->getExpr(i)); - } else if (New->getInitializationStyle() == CXXNewExpr::ListInit && - isa<InitListExpr>(Init)) { - // Only take InitListExprs apart for list-initialization. - const InitListExpr *InitList = cast<InitListExpr>(Init); - for (unsigned i = 0, e = InitList->getNumInits(); i != e; ++i) - mangleExpression(InitList->getInit(i)); - } else - mangleExpression(Init); - } - Out << 'E'; - break; - } - - case Expr::MemberExprClass: { - const MemberExpr *ME = cast<MemberExpr>(E); - mangleMemberExpr(ME->getBase(), ME->isArrow(), - ME->getQualifier(), 0, ME->getMemberDecl()->getDeclName(), - Arity); - break; - } - - case Expr::UnresolvedMemberExprClass: { - const UnresolvedMemberExpr *ME = cast<UnresolvedMemberExpr>(E); - mangleMemberExpr(ME->getBase(), ME->isArrow(), - ME->getQualifier(), 0, ME->getMemberName(), - Arity); - if (ME->hasExplicitTemplateArgs()) - mangleTemplateArgs(ME->getExplicitTemplateArgs()); - break; - } - - case Expr::CXXDependentScopeMemberExprClass: { - const CXXDependentScopeMemberExpr *ME - = cast<CXXDependentScopeMemberExpr>(E); - mangleMemberExpr(ME->getBase(), ME->isArrow(), - ME->getQualifier(), ME->getFirstQualifierFoundInScope(), - ME->getMember(), Arity); - if (ME->hasExplicitTemplateArgs()) - mangleTemplateArgs(ME->getExplicitTemplateArgs()); - break; - } - - case Expr::UnresolvedLookupExprClass: { - const UnresolvedLookupExpr *ULE = cast<UnresolvedLookupExpr>(E); - mangleUnresolvedName(ULE->getQualifier(), 0, ULE->getName(), Arity); - - // All the <unresolved-name> productions end in a - // base-unresolved-name, where <template-args> are just tacked - // onto the end. - if (ULE->hasExplicitTemplateArgs()) - mangleTemplateArgs(ULE->getExplicitTemplateArgs()); - break; - } - - case Expr::CXXUnresolvedConstructExprClass: { - const CXXUnresolvedConstructExpr *CE = cast<CXXUnresolvedConstructExpr>(E); - unsigned N = CE->arg_size(); - - Out << "cv"; - mangleType(CE->getType()); - if (N != 1) Out << '_'; - for (unsigned I = 0; I != N; ++I) mangleExpression(CE->getArg(I)); - if (N != 1) Out << 'E'; - break; - } - - case Expr::CXXTemporaryObjectExprClass: - case Expr::CXXConstructExprClass: { - const CXXConstructExpr *CE = cast<CXXConstructExpr>(E); - unsigned N = CE->getNumArgs(); - - // Proposal by Jason Merrill, 2012-01-03 - if (CE->isListInitialization()) - Out << "tl"; - else - Out << "cv"; - mangleType(CE->getType()); - if (N != 1) Out << '_'; - for (unsigned I = 0; I != N; ++I) mangleExpression(CE->getArg(I)); - if (N != 1) Out << 'E'; - break; - } - - case Expr::CXXScalarValueInitExprClass: - Out <<"cv"; - mangleType(E->getType()); - Out <<"_E"; - break; - - case Expr::CXXNoexceptExprClass: - Out << "nx"; - mangleExpression(cast<CXXNoexceptExpr>(E)->getOperand()); - break; - - case Expr::UnaryExprOrTypeTraitExprClass: { - const UnaryExprOrTypeTraitExpr *SAE = cast<UnaryExprOrTypeTraitExpr>(E); - - if (!SAE->isInstantiationDependent()) { - // Itanium C++ ABI: - // If the operand of a sizeof or alignof operator is not - // instantiation-dependent it is encoded as an integer literal - // reflecting the result of the operator. - // - // If the result of the operator is implicitly converted to a known - // integer type, that type is used for the literal; otherwise, the type - // of std::size_t or std::ptrdiff_t is used. - QualType T = (ImplicitlyConvertedToType.isNull() || - !ImplicitlyConvertedToType->isIntegerType())? SAE->getType() - : ImplicitlyConvertedToType; - llvm::APSInt V = SAE->EvaluateKnownConstInt(Context.getASTContext()); - mangleIntegerLiteral(T, V); - break; - } - - switch(SAE->getKind()) { - case UETT_SizeOf: - Out << 's'; - break; - case UETT_AlignOf: - Out << 'a'; - break; - case UETT_VecStep: - DiagnosticsEngine &Diags = Context.getDiags(); - unsigned DiagID = Diags.getCustomDiagID(DiagnosticsEngine::Error, - "cannot yet mangle vec_step expression"); - Diags.Report(DiagID); - return; - } - if (SAE->isArgumentType()) { - Out << 't'; - mangleType(SAE->getArgumentType()); - } else { - Out << 'z'; - mangleExpression(SAE->getArgumentExpr()); - } - break; - } - - case Expr::CXXThrowExprClass: { - const CXXThrowExpr *TE = cast<CXXThrowExpr>(E); - - // Proposal from David Vandervoorde, 2010.06.30 - if (TE->getSubExpr()) { - Out << "tw"; - mangleExpression(TE->getSubExpr()); - } else { - Out << "tr"; - } - break; - } - - case Expr::CXXTypeidExprClass: { - const CXXTypeidExpr *TIE = cast<CXXTypeidExpr>(E); - - // Proposal from David Vandervoorde, 2010.06.30 - if (TIE->isTypeOperand()) { - Out << "ti"; - mangleType(TIE->getTypeOperand()); - } else { - Out << "te"; - mangleExpression(TIE->getExprOperand()); - } - break; - } - - case Expr::CXXDeleteExprClass: { - const CXXDeleteExpr *DE = cast<CXXDeleteExpr>(E); - - // Proposal from David Vandervoorde, 2010.06.30 - if (DE->isGlobalDelete()) Out << "gs"; - Out << (DE->isArrayForm() ? "da" : "dl"); - mangleExpression(DE->getArgument()); - break; - } - - case Expr::UnaryOperatorClass: { - const UnaryOperator *UO = cast<UnaryOperator>(E); - mangleOperatorName(UnaryOperator::getOverloadedOperator(UO->getOpcode()), - /*Arity=*/1); - mangleExpression(UO->getSubExpr()); - break; - } - - case Expr::ArraySubscriptExprClass: { - const ArraySubscriptExpr *AE = cast<ArraySubscriptExpr>(E); - - // Array subscript is treated as a syntactically weird form of - // binary operator. - Out << "ix"; - mangleExpression(AE->getLHS()); - mangleExpression(AE->getRHS()); - break; - } - - case Expr::CompoundAssignOperatorClass: // fallthrough - case Expr::BinaryOperatorClass: { - const BinaryOperator *BO = cast<BinaryOperator>(E); - if (BO->getOpcode() == BO_PtrMemD) - Out << "ds"; - else - mangleOperatorName(BinaryOperator::getOverloadedOperator(BO->getOpcode()), - /*Arity=*/2); - mangleExpression(BO->getLHS()); - mangleExpression(BO->getRHS()); - break; - } - - case Expr::ConditionalOperatorClass: { - const ConditionalOperator *CO = cast<ConditionalOperator>(E); - mangleOperatorName(OO_Conditional, /*Arity=*/3); - mangleExpression(CO->getCond()); - mangleExpression(CO->getLHS(), Arity); - mangleExpression(CO->getRHS(), Arity); - break; - } - - case Expr::ImplicitCastExprClass: { - ImplicitlyConvertedToType = E->getType(); - E = cast<ImplicitCastExpr>(E)->getSubExpr(); - goto recurse; - } - - case Expr::ObjCBridgedCastExprClass: { - // Mangle ownership casts as a vendor extended operator __bridge, - // __bridge_transfer, or __bridge_retain. - StringRef Kind = cast<ObjCBridgedCastExpr>(E)->getBridgeKindName(); - Out << "v1U" << Kind.size() << Kind; - } - // Fall through to mangle the cast itself. - - case Expr::CStyleCastExprClass: - case Expr::CXXStaticCastExprClass: - case Expr::CXXDynamicCastExprClass: - case Expr::CXXReinterpretCastExprClass: - case Expr::CXXConstCastExprClass: - case Expr::CXXFunctionalCastExprClass: { - const ExplicitCastExpr *ECE = cast<ExplicitCastExpr>(E); - Out << "cv"; - mangleType(ECE->getType()); - mangleExpression(ECE->getSubExpr()); - break; - } - - case Expr::CXXOperatorCallExprClass: { - const CXXOperatorCallExpr *CE = cast<CXXOperatorCallExpr>(E); - unsigned NumArgs = CE->getNumArgs(); - mangleOperatorName(CE->getOperator(), /*Arity=*/NumArgs); - // Mangle the arguments. - for (unsigned i = 0; i != NumArgs; ++i) - mangleExpression(CE->getArg(i)); - break; - } - - case Expr::ParenExprClass: - mangleExpression(cast<ParenExpr>(E)->getSubExpr(), Arity); - break; - - case Expr::DeclRefExprClass: { - const NamedDecl *D = cast<DeclRefExpr>(E)->getDecl(); - - switch (D->getKind()) { - default: - // <expr-primary> ::= L <mangled-name> E # external name - Out << 'L'; - mangle(D, "_Z"); - Out << 'E'; - break; - - case Decl::ParmVar: - mangleFunctionParam(cast<ParmVarDecl>(D)); - break; - - case Decl::EnumConstant: { - const EnumConstantDecl *ED = cast<EnumConstantDecl>(D); - mangleIntegerLiteral(ED->getType(), ED->getInitVal()); - break; - } - - case Decl::NonTypeTemplateParm: { - const NonTypeTemplateParmDecl *PD = cast<NonTypeTemplateParmDecl>(D); - mangleTemplateParameter(PD->getIndex()); - break; - } - - } - - break; - } - - case Expr::SubstNonTypeTemplateParmPackExprClass: - // FIXME: not clear how to mangle this! - // template <unsigned N...> class A { - // template <class U...> void foo(U (&x)[N]...); - // }; - Out << "_SUBSTPACK_"; - break; - - case Expr::FunctionParmPackExprClass: { - // FIXME: not clear how to mangle this! - const FunctionParmPackExpr *FPPE = cast<FunctionParmPackExpr>(E); - Out << "v110_SUBSTPACK"; - mangleFunctionParam(FPPE->getParameterPack()); - break; - } - - case Expr::DependentScopeDeclRefExprClass: { - const DependentScopeDeclRefExpr *DRE = cast<DependentScopeDeclRefExpr>(E); - mangleUnresolvedName(DRE->getQualifier(), 0, DRE->getDeclName(), Arity); - - // All the <unresolved-name> productions end in a - // base-unresolved-name, where <template-args> are just tacked - // onto the end. - if (DRE->hasExplicitTemplateArgs()) - mangleTemplateArgs(DRE->getExplicitTemplateArgs()); - break; - } - - case Expr::CXXBindTemporaryExprClass: - mangleExpression(cast<CXXBindTemporaryExpr>(E)->getSubExpr()); - break; - - case Expr::ExprWithCleanupsClass: - mangleExpression(cast<ExprWithCleanups>(E)->getSubExpr(), Arity); - break; - - case Expr::FloatingLiteralClass: { - const FloatingLiteral *FL = cast<FloatingLiteral>(E); - Out << 'L'; - mangleType(FL->getType()); - mangleFloat(FL->getValue()); - Out << 'E'; - break; - } - - case Expr::CharacterLiteralClass: - Out << 'L'; - mangleType(E->getType()); - Out << cast<CharacterLiteral>(E)->getValue(); - Out << 'E'; - break; - - // FIXME. __objc_yes/__objc_no are mangled same as true/false - case Expr::ObjCBoolLiteralExprClass: - Out << "Lb"; - Out << (cast<ObjCBoolLiteralExpr>(E)->getValue() ? '1' : '0'); - Out << 'E'; - break; - - case Expr::CXXBoolLiteralExprClass: - Out << "Lb"; - Out << (cast<CXXBoolLiteralExpr>(E)->getValue() ? '1' : '0'); - Out << 'E'; - break; - - case Expr::IntegerLiteralClass: { - llvm::APSInt Value(cast<IntegerLiteral>(E)->getValue()); - if (E->getType()->isSignedIntegerType()) - Value.setIsSigned(true); - mangleIntegerLiteral(E->getType(), Value); - break; - } - - case Expr::ImaginaryLiteralClass: { - const ImaginaryLiteral *IE = cast<ImaginaryLiteral>(E); - // Mangle as if a complex literal. - // Proposal from David Vandevoorde, 2010.06.30. - Out << 'L'; - mangleType(E->getType()); - if (const FloatingLiteral *Imag = - dyn_cast<FloatingLiteral>(IE->getSubExpr())) { - // Mangle a floating-point zero of the appropriate type. - mangleFloat(llvm::APFloat(Imag->getValue().getSemantics())); - Out << '_'; - mangleFloat(Imag->getValue()); - } else { - Out << "0_"; - llvm::APSInt Value(cast<IntegerLiteral>(IE->getSubExpr())->getValue()); - if (IE->getSubExpr()->getType()->isSignedIntegerType()) - Value.setIsSigned(true); - mangleNumber(Value); - } - Out << 'E'; - break; - } - - case Expr::StringLiteralClass: { - // Revised proposal from David Vandervoorde, 2010.07.15. - Out << 'L'; - assert(isa<ConstantArrayType>(E->getType())); - mangleType(E->getType()); - Out << 'E'; - break; - } - - case Expr::GNUNullExprClass: - // FIXME: should this really be mangled the same as nullptr? - // fallthrough - - case Expr::CXXNullPtrLiteralExprClass: { - // Proposal from David Vandervoorde, 2010.06.30, as - // modified by ABI list discussion. - Out << "LDnE"; - break; - } - - case Expr::PackExpansionExprClass: - Out << "sp"; - mangleExpression(cast<PackExpansionExpr>(E)->getPattern()); - break; - - case Expr::SizeOfPackExprClass: { - Out << "sZ"; - const NamedDecl *Pack = cast<SizeOfPackExpr>(E)->getPack(); - if (const TemplateTypeParmDecl *TTP = dyn_cast<TemplateTypeParmDecl>(Pack)) - mangleTemplateParameter(TTP->getIndex()); - else if (const NonTypeTemplateParmDecl *NTTP - = dyn_cast<NonTypeTemplateParmDecl>(Pack)) - mangleTemplateParameter(NTTP->getIndex()); - else if (const TemplateTemplateParmDecl *TempTP - = dyn_cast<TemplateTemplateParmDecl>(Pack)) - mangleTemplateParameter(TempTP->getIndex()); - else - mangleFunctionParam(cast<ParmVarDecl>(Pack)); - break; - } - - case Expr::MaterializeTemporaryExprClass: { - mangleExpression(cast<MaterializeTemporaryExpr>(E)->GetTemporaryExpr()); - break; - } - - case Expr::CXXThisExprClass: - Out << "fpT"; - break; - } -} - -/// Mangle an expression which refers to a parameter variable. -/// -/// <expression> ::= <function-param> -/// <function-param> ::= fp <top-level CV-qualifiers> _ # L == 0, I == 0 -/// <function-param> ::= fp <top-level CV-qualifiers> -/// <parameter-2 non-negative number> _ # L == 0, I > 0 -/// <function-param> ::= fL <L-1 non-negative number> -/// p <top-level CV-qualifiers> _ # L > 0, I == 0 -/// <function-param> ::= fL <L-1 non-negative number> -/// p <top-level CV-qualifiers> -/// <I-1 non-negative number> _ # L > 0, I > 0 -/// -/// L is the nesting depth of the parameter, defined as 1 if the -/// parameter comes from the innermost function prototype scope -/// enclosing the current context, 2 if from the next enclosing -/// function prototype scope, and so on, with one special case: if -/// we've processed the full parameter clause for the innermost -/// function type, then L is one less. This definition conveniently -/// makes it irrelevant whether a function's result type was written -/// trailing or leading, but is otherwise overly complicated; the -/// numbering was first designed without considering references to -/// parameter in locations other than return types, and then the -/// mangling had to be generalized without changing the existing -/// manglings. -/// -/// I is the zero-based index of the parameter within its parameter -/// declaration clause. Note that the original ABI document describes -/// this using 1-based ordinals. -void CXXNameMangler::mangleFunctionParam(const ParmVarDecl *parm) { - unsigned parmDepth = parm->getFunctionScopeDepth(); - unsigned parmIndex = parm->getFunctionScopeIndex(); - - // Compute 'L'. - // parmDepth does not include the declaring function prototype. - // FunctionTypeDepth does account for that. - assert(parmDepth < FunctionTypeDepth.getDepth()); - unsigned nestingDepth = FunctionTypeDepth.getDepth() - parmDepth; - if (FunctionTypeDepth.isInResultType()) - nestingDepth--; - - if (nestingDepth == 0) { - Out << "fp"; - } else { - Out << "fL" << (nestingDepth - 1) << 'p'; - } - - // Top-level qualifiers. We don't have to worry about arrays here, - // because parameters declared as arrays should already have been - // transformed to have pointer type. FIXME: apparently these don't - // get mangled if used as an rvalue of a known non-class type? - assert(!parm->getType()->isArrayType() - && "parameter's type is still an array type?"); - mangleQualifiers(parm->getType().getQualifiers()); - - // Parameter index. - if (parmIndex != 0) { - Out << (parmIndex - 1); - } - Out << '_'; -} - -void CXXNameMangler::mangleCXXCtorType(CXXCtorType T) { - // <ctor-dtor-name> ::= C1 # complete object constructor - // ::= C2 # base object constructor - // ::= C3 # complete object allocating constructor - // - switch (T) { - case Ctor_Complete: - Out << "C1"; - break; - case Ctor_Base: - Out << "C2"; - break; - case Ctor_CompleteAllocating: - Out << "C3"; - break; - } -} - -void CXXNameMangler::mangleCXXDtorType(CXXDtorType T) { - // <ctor-dtor-name> ::= D0 # deleting destructor - // ::= D1 # complete object destructor - // ::= D2 # base object destructor - // - switch (T) { - case Dtor_Deleting: - Out << "D0"; - break; - case Dtor_Complete: - Out << "D1"; - break; - case Dtor_Base: - Out << "D2"; - break; - } -} - -void CXXNameMangler::mangleTemplateArgs( - const ASTTemplateArgumentListInfo &TemplateArgs) { - // <template-args> ::= I <template-arg>+ E - Out << 'I'; - for (unsigned i = 0, e = TemplateArgs.NumTemplateArgs; i != e; ++i) - mangleTemplateArg(TemplateArgs.getTemplateArgs()[i].getArgument()); - Out << 'E'; -} - -void CXXNameMangler::mangleTemplateArgs(const TemplateArgumentList &AL) { - // <template-args> ::= I <template-arg>+ E - Out << 'I'; - for (unsigned i = 0, e = AL.size(); i != e; ++i) - mangleTemplateArg(AL[i]); - Out << 'E'; -} - -void CXXNameMangler::mangleTemplateArgs(const TemplateArgument *TemplateArgs, - unsigned NumTemplateArgs) { - // <template-args> ::= I <template-arg>+ E - Out << 'I'; - for (unsigned i = 0; i != NumTemplateArgs; ++i) - mangleTemplateArg(TemplateArgs[i]); - Out << 'E'; -} - -void CXXNameMangler::mangleTemplateArg(TemplateArgument A) { - // <template-arg> ::= <type> # type or template - // ::= X <expression> E # expression - // ::= <expr-primary> # simple expressions - // ::= J <template-arg>* E # argument pack - // ::= sp <expression> # pack expansion of (C++0x) - if (!A.isInstantiationDependent() || A.isDependent()) - A = Context.getASTContext().getCanonicalTemplateArgument(A); - - switch (A.getKind()) { - case TemplateArgument::Null: - llvm_unreachable("Cannot mangle NULL template argument"); - - case TemplateArgument::Type: - mangleType(A.getAsType()); - break; - case TemplateArgument::Template: - // This is mangled as <type>. - mangleType(A.getAsTemplate()); - break; - case TemplateArgument::TemplateExpansion: - // <type> ::= Dp <type> # pack expansion (C++0x) - Out << "Dp"; - mangleType(A.getAsTemplateOrTemplatePattern()); - break; - case TemplateArgument::Expression: { - // It's possible to end up with a DeclRefExpr here in certain - // dependent cases, in which case we should mangle as a - // declaration. - const Expr *E = A.getAsExpr()->IgnoreParens(); - if (const DeclRefExpr *DRE = dyn_cast<DeclRefExpr>(E)) { - const ValueDecl *D = DRE->getDecl(); - if (isa<VarDecl>(D) || isa<FunctionDecl>(D)) { - Out << "L"; - mangle(D, "_Z"); - Out << 'E'; - break; - } - } - - Out << 'X'; - mangleExpression(E); - Out << 'E'; - break; - } - case TemplateArgument::Integral: - mangleIntegerLiteral(A.getIntegralType(), A.getAsIntegral()); - break; - case TemplateArgument::Declaration: { - // <expr-primary> ::= L <mangled-name> E # external name - // Clang produces AST's where pointer-to-member-function expressions - // and pointer-to-function expressions are represented as a declaration not - // an expression. We compensate for it here to produce the correct mangling. - ValueDecl *D = A.getAsDecl(); - bool compensateMangling = !A.isDeclForReferenceParam(); - if (compensateMangling) { - Out << 'X'; - mangleOperatorName(OO_Amp, 1); - } - - Out << 'L'; - // References to external entities use the mangled name; if the name would - // not normally be manged then mangle it as unqualified. - // - // FIXME: The ABI specifies that external names here should have _Z, but - // gcc leaves this off. - if (compensateMangling) - mangle(D, "_Z"); - else - mangle(D, "Z"); - Out << 'E'; - - if (compensateMangling) - Out << 'E'; - - break; - } - case TemplateArgument::NullPtr: { - // <expr-primary> ::= L <type> 0 E - Out << 'L'; - mangleType(A.getNullPtrType()); - Out << "0E"; - break; - } - case TemplateArgument::Pack: { - // Note: proposal by Mike Herrick on 12/20/10 - Out << 'J'; - for (TemplateArgument::pack_iterator PA = A.pack_begin(), - PAEnd = A.pack_end(); - PA != PAEnd; ++PA) - mangleTemplateArg(*PA); - Out << 'E'; - } - } -} - -void CXXNameMangler::mangleTemplateParameter(unsigned Index) { - // <template-param> ::= T_ # first template parameter - // ::= T <parameter-2 non-negative number> _ - if (Index == 0) - Out << "T_"; - else - Out << 'T' << (Index - 1) << '_'; -} - -void CXXNameMangler::mangleExistingSubstitution(QualType type) { - bool result = mangleSubstitution(type); - assert(result && "no existing substitution for type"); - (void) result; -} - -void CXXNameMangler::mangleExistingSubstitution(TemplateName tname) { - bool result = mangleSubstitution(tname); - assert(result && "no existing substitution for template name"); - (void) result; -} - -// <substitution> ::= S <seq-id> _ -// ::= S_ -bool CXXNameMangler::mangleSubstitution(const NamedDecl *ND) { - // Try one of the standard substitutions first. - if (mangleStandardSubstitution(ND)) - return true; - - ND = cast<NamedDecl>(ND->getCanonicalDecl()); - return mangleSubstitution(reinterpret_cast<uintptr_t>(ND)); -} - -/// \brief Determine whether the given type has any qualifiers that are -/// relevant for substitutions. -static bool hasMangledSubstitutionQualifiers(QualType T) { - Qualifiers Qs = T.getQualifiers(); - return Qs.getCVRQualifiers() || Qs.hasAddressSpace(); -} - -bool CXXNameMangler::mangleSubstitution(QualType T) { - if (!hasMangledSubstitutionQualifiers(T)) { - if (const RecordType *RT = T->getAs<RecordType>()) - return mangleSubstitution(RT->getDecl()); - } - - uintptr_t TypePtr = reinterpret_cast<uintptr_t>(T.getAsOpaquePtr()); - - return mangleSubstitution(TypePtr); -} - -bool CXXNameMangler::mangleSubstitution(TemplateName Template) { - if (TemplateDecl *TD = Template.getAsTemplateDecl()) - return mangleSubstitution(TD); - - Template = Context.getASTContext().getCanonicalTemplateName(Template); - return mangleSubstitution( - reinterpret_cast<uintptr_t>(Template.getAsVoidPointer())); -} - -bool CXXNameMangler::mangleSubstitution(uintptr_t Ptr) { - llvm::DenseMap<uintptr_t, unsigned>::iterator I = Substitutions.find(Ptr); - if (I == Substitutions.end()) - return false; - - unsigned SeqID = I->second; - if (SeqID == 0) - Out << "S_"; - else { - SeqID--; - - // <seq-id> is encoded in base-36, using digits and upper case letters. - char Buffer[10]; - char *BufferPtr = llvm::array_endof(Buffer); - - if (SeqID == 0) *--BufferPtr = '0'; - - while (SeqID) { - assert(BufferPtr > Buffer && "Buffer overflow!"); - - char c = static_cast<char>(SeqID % 36); - - *--BufferPtr = (c < 10 ? '0' + c : 'A' + c - 10); - SeqID /= 36; - } - - Out << 'S' - << StringRef(BufferPtr, llvm::array_endof(Buffer)-BufferPtr) - << '_'; - } - - return true; -} - -static bool isCharType(QualType T) { - if (T.isNull()) - return false; - - return T->isSpecificBuiltinType(BuiltinType::Char_S) || - T->isSpecificBuiltinType(BuiltinType::Char_U); -} - -/// isCharSpecialization - Returns whether a given type is a template -/// specialization of a given name with a single argument of type char. -static bool isCharSpecialization(QualType T, const char *Name) { - if (T.isNull()) - return false; - - const RecordType *RT = T->getAs<RecordType>(); - if (!RT) - return false; - - const ClassTemplateSpecializationDecl *SD = - dyn_cast<ClassTemplateSpecializationDecl>(RT->getDecl()); - if (!SD) - return false; - - if (!isStdNamespace(getEffectiveDeclContext(SD))) - return false; - - const TemplateArgumentList &TemplateArgs = SD->getTemplateArgs(); - if (TemplateArgs.size() != 1) - return false; - - if (!isCharType(TemplateArgs[0].getAsType())) - return false; - - return SD->getIdentifier()->getName() == Name; -} - -template <std::size_t StrLen> -static bool isStreamCharSpecialization(const ClassTemplateSpecializationDecl*SD, - const char (&Str)[StrLen]) { - if (!SD->getIdentifier()->isStr(Str)) - return false; - - const TemplateArgumentList &TemplateArgs = SD->getTemplateArgs(); - if (TemplateArgs.size() != 2) - return false; - - if (!isCharType(TemplateArgs[0].getAsType())) - return false; - - if (!isCharSpecialization(TemplateArgs[1].getAsType(), "char_traits")) - return false; - - return true; -} - -bool CXXNameMangler::mangleStandardSubstitution(const NamedDecl *ND) { - // <substitution> ::= St # ::std:: - if (const NamespaceDecl *NS = dyn_cast<NamespaceDecl>(ND)) { - if (isStd(NS)) { - Out << "St"; - return true; - } - } - - if (const ClassTemplateDecl *TD = dyn_cast<ClassTemplateDecl>(ND)) { - if (!isStdNamespace(getEffectiveDeclContext(TD))) - return false; - - // <substitution> ::= Sa # ::std::allocator - if (TD->getIdentifier()->isStr("allocator")) { - Out << "Sa"; - return true; - } - - // <<substitution> ::= Sb # ::std::basic_string - if (TD->getIdentifier()->isStr("basic_string")) { - Out << "Sb"; - return true; - } - } - - if (const ClassTemplateSpecializationDecl *SD = - dyn_cast<ClassTemplateSpecializationDecl>(ND)) { - if (!isStdNamespace(getEffectiveDeclContext(SD))) - return false; - - // <substitution> ::= Ss # ::std::basic_string<char, - // ::std::char_traits<char>, - // ::std::allocator<char> > - if (SD->getIdentifier()->isStr("basic_string")) { - const TemplateArgumentList &TemplateArgs = SD->getTemplateArgs(); - - if (TemplateArgs.size() != 3) - return false; - - if (!isCharType(TemplateArgs[0].getAsType())) - return false; - - if (!isCharSpecialization(TemplateArgs[1].getAsType(), "char_traits")) - return false; - - if (!isCharSpecialization(TemplateArgs[2].getAsType(), "allocator")) - return false; - - Out << "Ss"; - return true; - } - - // <substitution> ::= Si # ::std::basic_istream<char, - // ::std::char_traits<char> > - if (isStreamCharSpecialization(SD, "basic_istream")) { - Out << "Si"; - return true; - } - - // <substitution> ::= So # ::std::basic_ostream<char, - // ::std::char_traits<char> > - if (isStreamCharSpecialization(SD, "basic_ostream")) { - Out << "So"; - return true; - } - - // <substitution> ::= Sd # ::std::basic_iostream<char, - // ::std::char_traits<char> > - if (isStreamCharSpecialization(SD, "basic_iostream")) { - Out << "Sd"; - return true; - } - } - return false; -} - -void CXXNameMangler::addSubstitution(QualType T) { - if (!hasMangledSubstitutionQualifiers(T)) { - if (const RecordType *RT = T->getAs<RecordType>()) { - addSubstitution(RT->getDecl()); - return; - } - } - - uintptr_t TypePtr = reinterpret_cast<uintptr_t>(T.getAsOpaquePtr()); - addSubstitution(TypePtr); -} - -void CXXNameMangler::addSubstitution(TemplateName Template) { - if (TemplateDecl *TD = Template.getAsTemplateDecl()) - return addSubstitution(TD); - - Template = Context.getASTContext().getCanonicalTemplateName(Template); - addSubstitution(reinterpret_cast<uintptr_t>(Template.getAsVoidPointer())); -} - -void CXXNameMangler::addSubstitution(uintptr_t Ptr) { - assert(!Substitutions.count(Ptr) && "Substitution already exists!"); - Substitutions[Ptr] = SeqID++; -} - -// - -/// \brief Mangles the name of the declaration D and emits that name to the -/// given output stream. -/// -/// If the declaration D requires a mangled name, this routine will emit that -/// mangled name to \p os and return true. Otherwise, \p os will be unchanged -/// and this routine will return false. In this case, the caller should just -/// emit the identifier of the declaration (\c D->getIdentifier()) as its -/// name. -void ItaniumMangleContext::mangleName(const NamedDecl *D, - raw_ostream &Out) { - assert((isa<FunctionDecl>(D) || isa<VarDecl>(D)) && - "Invalid mangleName() call, argument is not a variable or function!"); - assert(!isa<CXXConstructorDecl>(D) && !isa<CXXDestructorDecl>(D) && - "Invalid mangleName() call on 'structor decl!"); - - PrettyStackTraceDecl CrashInfo(D, SourceLocation(), - getASTContext().getSourceManager(), - "Mangling declaration"); - - CXXNameMangler Mangler(*this, Out, D); - return Mangler.mangle(D); -} - -void ItaniumMangleContext::mangleCXXCtor(const CXXConstructorDecl *D, - CXXCtorType Type, - raw_ostream &Out) { - CXXNameMangler Mangler(*this, Out, D, Type); - Mangler.mangle(D); -} - -void ItaniumMangleContext::mangleCXXDtor(const CXXDestructorDecl *D, - CXXDtorType Type, - raw_ostream &Out) { - CXXNameMangler Mangler(*this, Out, D, Type); - Mangler.mangle(D); -} - -void ItaniumMangleContext::mangleThunk(const CXXMethodDecl *MD, - const ThunkInfo &Thunk, - raw_ostream &Out) { - // <special-name> ::= T <call-offset> <base encoding> - // # base is the nominal target function of thunk - // <special-name> ::= Tc <call-offset> <call-offset> <base encoding> - // # base is the nominal target function of thunk - // # first call-offset is 'this' adjustment - // # second call-offset is result adjustment - - assert(!isa<CXXDestructorDecl>(MD) && - "Use mangleCXXDtor for destructor decls!"); - CXXNameMangler Mangler(*this, Out); - Mangler.getStream() << "_ZT"; - if (!Thunk.Return.isEmpty()) - Mangler.getStream() << 'c'; - - // Mangle the 'this' pointer adjustment. - Mangler.mangleCallOffset(Thunk.This.NonVirtual, Thunk.This.VCallOffsetOffset); - - // Mangle the return pointer adjustment if there is one. - if (!Thunk.Return.isEmpty()) - Mangler.mangleCallOffset(Thunk.Return.NonVirtual, - Thunk.Return.VBaseOffsetOffset); - - Mangler.mangleFunctionEncoding(MD); -} - -void -ItaniumMangleContext::mangleCXXDtorThunk(const CXXDestructorDecl *DD, - CXXDtorType Type, - const ThisAdjustment &ThisAdjustment, - raw_ostream &Out) { - // <special-name> ::= T <call-offset> <base encoding> - // # base is the nominal target function of thunk - CXXNameMangler Mangler(*this, Out, DD, Type); - Mangler.getStream() << "_ZT"; - - // Mangle the 'this' pointer adjustment. - Mangler.mangleCallOffset(ThisAdjustment.NonVirtual, - ThisAdjustment.VCallOffsetOffset); - - Mangler.mangleFunctionEncoding(DD); -} - -/// mangleGuardVariable - Returns the mangled name for a guard variable -/// for the passed in VarDecl. -void ItaniumMangleContext::mangleItaniumGuardVariable(const VarDecl *D, - raw_ostream &Out) { - // <special-name> ::= GV <object name> # Guard variable for one-time - // # initialization - CXXNameMangler Mangler(*this, Out); - Mangler.getStream() << "_ZGV"; - Mangler.mangleName(D); -} - -void ItaniumMangleContext::mangleReferenceTemporary(const VarDecl *D, - raw_ostream &Out) { - // We match the GCC mangling here. - // <special-name> ::= GR <object name> - CXXNameMangler Mangler(*this, Out); - Mangler.getStream() << "_ZGR"; - Mangler.mangleName(D); -} - -void ItaniumMangleContext::mangleCXXVTable(const CXXRecordDecl *RD, - raw_ostream &Out) { - // <special-name> ::= TV <type> # virtual table - CXXNameMangler Mangler(*this, Out); - Mangler.getStream() << "_ZTV"; - Mangler.mangleNameOrStandardSubstitution(RD); -} - -void ItaniumMangleContext::mangleCXXVTT(const CXXRecordDecl *RD, - raw_ostream &Out) { - // <special-name> ::= TT <type> # VTT structure - CXXNameMangler Mangler(*this, Out); - Mangler.getStream() << "_ZTT"; - Mangler.mangleNameOrStandardSubstitution(RD); -} - -void ItaniumMangleContext::mangleCXXCtorVTable(const CXXRecordDecl *RD, - int64_t Offset, - const CXXRecordDecl *Type, - raw_ostream &Out) { - // <special-name> ::= TC <type> <offset number> _ <base type> - CXXNameMangler Mangler(*this, Out); - Mangler.getStream() << "_ZTC"; - Mangler.mangleNameOrStandardSubstitution(RD); - Mangler.getStream() << Offset; - Mangler.getStream() << '_'; - Mangler.mangleNameOrStandardSubstitution(Type); -} - -void ItaniumMangleContext::mangleCXXRTTI(QualType Ty, - raw_ostream &Out) { - // <special-name> ::= TI <type> # typeinfo structure - assert(!Ty.hasQualifiers() && "RTTI info cannot have top-level qualifiers"); - CXXNameMangler Mangler(*this, Out); - Mangler.getStream() << "_ZTI"; - Mangler.mangleType(Ty); -} - -void ItaniumMangleContext::mangleCXXRTTIName(QualType Ty, - raw_ostream &Out) { - // <special-name> ::= TS <type> # typeinfo name (null terminated byte string) - CXXNameMangler Mangler(*this, Out); - Mangler.getStream() << "_ZTS"; - Mangler.mangleType(Ty); -} - -MangleContext *clang::createItaniumMangleContext(ASTContext &Context, - DiagnosticsEngine &Diags) { - return new ItaniumMangleContext(Context, Diags); -} +//===--- ItaniumMangle.cpp - Itanium C++ Name Mangling ----------*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+//
+// Implements C++ name mangling according to the Itanium C++ ABI,
+// which is used in GCC 3.2 and newer (and many compilers that are
+// ABI-compatible with GCC):
+//
+// http://www.codesourcery.com/public/cxx-abi/abi.html
+//
+//===----------------------------------------------------------------------===//
+#include "clang/AST/Mangle.h"
+#include "clang/AST/ASTContext.h"
+#include "clang/AST/Attr.h"
+#include "clang/AST/Decl.h"
+#include "clang/AST/DeclCXX.h"
+#include "clang/AST/DeclObjC.h"
+#include "clang/AST/DeclTemplate.h"
+#include "clang/AST/ExprCXX.h"
+#include "clang/AST/ExprObjC.h"
+#include "clang/AST/TypeLoc.h"
+#include "clang/Basic/ABI.h"
+#include "clang/Basic/SourceManager.h"
+#include "clang/Basic/TargetInfo.h"
+#include "llvm/ADT/StringExtras.h"
+#include "llvm/Support/ErrorHandling.h"
+#include "llvm/Support/raw_ostream.h"
+
+#define MANGLE_CHECKER 0
+
+#if MANGLE_CHECKER
+#include <cxxabi.h>
+#endif
+
+using namespace clang;
+
+namespace {
+
+/// \brief Retrieve the declaration context that should be used when mangling
+/// the given declaration.
+static const DeclContext *getEffectiveDeclContext(const Decl *D) {
+ // The ABI assumes that lambda closure types that occur within
+ // default arguments live in the context of the function. However, due to
+ // the way in which Clang parses and creates function declarations, this is
+ // not the case: the lambda closure type ends up living in the context
+ // where the function itself resides, because the function declaration itself
+ // had not yet been created. Fix the context here.
+ if (const CXXRecordDecl *RD = dyn_cast<CXXRecordDecl>(D)) {
+ if (RD->isLambda())
+ if (ParmVarDecl *ContextParam
+ = dyn_cast_or_null<ParmVarDecl>(RD->getLambdaContextDecl()))
+ return ContextParam->getDeclContext();
+ }
+
+ return D->getDeclContext();
+}
+
+static const DeclContext *getEffectiveParentContext(const DeclContext *DC) {
+ return getEffectiveDeclContext(cast<Decl>(DC));
+}
+
+static const CXXRecordDecl *GetLocalClassDecl(const NamedDecl *ND) {
+ const DeclContext *DC = dyn_cast<DeclContext>(ND);
+ if (!DC)
+ DC = getEffectiveDeclContext(ND);
+ while (!DC->isNamespace() && !DC->isTranslationUnit()) {
+ const DeclContext *Parent = getEffectiveDeclContext(cast<Decl>(DC));
+ if (isa<FunctionDecl>(Parent))
+ return dyn_cast<CXXRecordDecl>(DC);
+ DC = Parent;
+ }
+ return 0;
+}
+
+static const FunctionDecl *getStructor(const FunctionDecl *fn) {
+ if (const FunctionTemplateDecl *ftd = fn->getPrimaryTemplate())
+ return ftd->getTemplatedDecl();
+
+ return fn;
+}
+
+static const NamedDecl *getStructor(const NamedDecl *decl) {
+ const FunctionDecl *fn = dyn_cast_or_null<FunctionDecl>(decl);
+ return (fn ? getStructor(fn) : decl);
+}
+
+static const unsigned UnknownArity = ~0U;
+
+class ItaniumMangleContext : public MangleContext {
+ llvm::DenseMap<const TagDecl *, uint64_t> AnonStructIds;
+ unsigned Discriminator;
+ llvm::DenseMap<const NamedDecl*, unsigned> Uniquifier;
+
+public:
+ explicit ItaniumMangleContext(ASTContext &Context,
+ DiagnosticsEngine &Diags)
+ : MangleContext(Context, Diags) { }
+
+ uint64_t getAnonymousStructId(const TagDecl *TD) {
+ std::pair<llvm::DenseMap<const TagDecl *,
+ uint64_t>::iterator, bool> Result =
+ AnonStructIds.insert(std::make_pair(TD, AnonStructIds.size()));
+ return Result.first->second;
+ }
+
+ void startNewFunction() {
+ MangleContext::startNewFunction();
+ mangleInitDiscriminator();
+ }
+
+ /// @name Mangler Entry Points
+ /// @{
+
+ bool shouldMangleDeclName(const NamedDecl *D);
+ void mangleName(const NamedDecl *D, raw_ostream &);
+ void mangleThunk(const CXXMethodDecl *MD,
+ const ThunkInfo &Thunk,
+ raw_ostream &);
+ void mangleCXXDtorThunk(const CXXDestructorDecl *DD, CXXDtorType Type,
+ const ThisAdjustment &ThisAdjustment,
+ raw_ostream &);
+ void mangleReferenceTemporary(const VarDecl *D,
+ raw_ostream &);
+ void mangleCXXVTable(const CXXRecordDecl *RD,
+ raw_ostream &);
+ void mangleCXXVTT(const CXXRecordDecl *RD,
+ raw_ostream &);
+ void mangleCXXCtorVTable(const CXXRecordDecl *RD, int64_t Offset,
+ const CXXRecordDecl *Type,
+ raw_ostream &);
+ void mangleCXXRTTI(QualType T, raw_ostream &);
+ void mangleCXXRTTIName(QualType T, raw_ostream &);
+ void mangleCXXCtor(const CXXConstructorDecl *D, CXXCtorType Type,
+ raw_ostream &);
+ void mangleCXXDtor(const CXXDestructorDecl *D, CXXDtorType Type,
+ raw_ostream &);
+
+ void mangleItaniumGuardVariable(const VarDecl *D, raw_ostream &);
+
+ void mangleInitDiscriminator() {
+ Discriminator = 0;
+ }
+
+ bool getNextDiscriminator(const NamedDecl *ND, unsigned &disc) {
+ // Lambda closure types with external linkage (indicated by a
+ // non-zero lambda mangling number) have their own numbering scheme, so
+ // they do not need a discriminator.
+ if (const CXXRecordDecl *RD = dyn_cast<CXXRecordDecl>(ND))
+ if (RD->isLambda() && RD->getLambdaManglingNumber() > 0)
+ return false;
+
+ unsigned &discriminator = Uniquifier[ND];
+ if (!discriminator)
+ discriminator = ++Discriminator;
+ if (discriminator == 1)
+ return false;
+ disc = discriminator-2;
+ return true;
+ }
+ /// @}
+};
+
+/// CXXNameMangler - Manage the mangling of a single name.
+class CXXNameMangler {
+ ItaniumMangleContext &Context;
+ raw_ostream &Out;
+
+ /// The "structor" is the top-level declaration being mangled, if
+ /// that's not a template specialization; otherwise it's the pattern
+ /// for that specialization.
+ const NamedDecl *Structor;
+ unsigned StructorType;
+
+ /// SeqID - The next subsitution sequence number.
+ unsigned SeqID;
+
+ class FunctionTypeDepthState {
+ unsigned Bits;
+
+ enum { InResultTypeMask = 1 };
+
+ public:
+ FunctionTypeDepthState() : Bits(0) {}
+
+ /// The number of function types we're inside.
+ unsigned getDepth() const {
+ return Bits >> 1;
+ }
+
+ /// True if we're in the return type of the innermost function type.
+ bool isInResultType() const {
+ return Bits & InResultTypeMask;
+ }
+
+ FunctionTypeDepthState push() {
+ FunctionTypeDepthState tmp = *this;
+ Bits = (Bits & ~InResultTypeMask) + 2;
+ return tmp;
+ }
+
+ void enterResultType() {
+ Bits |= InResultTypeMask;
+ }
+
+ void leaveResultType() {
+ Bits &= ~InResultTypeMask;
+ }
+
+ void pop(FunctionTypeDepthState saved) {
+ assert(getDepth() == saved.getDepth() + 1);
+ Bits = saved.Bits;
+ }
+
+ } FunctionTypeDepth;
+
+ llvm::DenseMap<uintptr_t, unsigned> Substitutions;
+
+ ASTContext &getASTContext() const { return Context.getASTContext(); }
+
+public:
+ CXXNameMangler(ItaniumMangleContext &C, raw_ostream &Out_,
+ const NamedDecl *D = 0)
+ : Context(C), Out(Out_), Structor(getStructor(D)), StructorType(0),
+ SeqID(0) {
+ // These can't be mangled without a ctor type or dtor type.
+ assert(!D || (!isa<CXXDestructorDecl>(D) &&
+ !isa<CXXConstructorDecl>(D)));
+ }
+ CXXNameMangler(ItaniumMangleContext &C, raw_ostream &Out_,
+ const CXXConstructorDecl *D, CXXCtorType Type)
+ : Context(C), Out(Out_), Structor(getStructor(D)), StructorType(Type),
+ SeqID(0) { }
+ CXXNameMangler(ItaniumMangleContext &C, raw_ostream &Out_,
+ const CXXDestructorDecl *D, CXXDtorType Type)
+ : Context(C), Out(Out_), Structor(getStructor(D)), StructorType(Type),
+ SeqID(0) { }
+
+#if MANGLE_CHECKER
+ ~CXXNameMangler() {
+ if (Out.str()[0] == '\01')
+ return;
+
+ int status = 0;
+ char *result = abi::__cxa_demangle(Out.str().str().c_str(), 0, 0, &status);
+ assert(status == 0 && "Could not demangle mangled name!");
+ free(result);
+ }
+#endif
+ raw_ostream &getStream() { return Out; }
+
+ void mangle(const NamedDecl *D, StringRef Prefix = "_Z");
+ void mangleCallOffset(int64_t NonVirtual, int64_t Virtual);
+ void mangleNumber(const llvm::APSInt &I);
+ void mangleNumber(int64_t Number);
+ void mangleFloat(const llvm::APFloat &F);
+ void mangleFunctionEncoding(const FunctionDecl *FD);
+ void mangleName(const NamedDecl *ND);
+ void mangleType(QualType T);
+ void mangleNameOrStandardSubstitution(const NamedDecl *ND);
+
+private:
+ bool mangleSubstitution(const NamedDecl *ND);
+ bool mangleSubstitution(QualType T);
+ bool mangleSubstitution(TemplateName Template);
+ bool mangleSubstitution(uintptr_t Ptr);
+
+ void mangleExistingSubstitution(QualType type);
+ void mangleExistingSubstitution(TemplateName name);
+
+ bool mangleStandardSubstitution(const NamedDecl *ND);
+
+ void addSubstitution(const NamedDecl *ND) {
+ ND = cast<NamedDecl>(ND->getCanonicalDecl());
+
+ addSubstitution(reinterpret_cast<uintptr_t>(ND));
+ }
+ void addSubstitution(QualType T);
+ void addSubstitution(TemplateName Template);
+ void addSubstitution(uintptr_t Ptr);
+
+ void mangleUnresolvedPrefix(NestedNameSpecifier *qualifier,
+ NamedDecl *firstQualifierLookup,
+ bool recursive = false);
+ void mangleUnresolvedName(NestedNameSpecifier *qualifier,
+ NamedDecl *firstQualifierLookup,
+ DeclarationName name,
+ unsigned KnownArity = UnknownArity);
+
+ void mangleName(const TemplateDecl *TD,
+ const TemplateArgument *TemplateArgs,
+ unsigned NumTemplateArgs);
+ void mangleUnqualifiedName(const NamedDecl *ND) {
+ mangleUnqualifiedName(ND, ND->getDeclName(), UnknownArity);
+ }
+ void mangleUnqualifiedName(const NamedDecl *ND, DeclarationName Name,
+ unsigned KnownArity);
+ void mangleUnscopedName(const NamedDecl *ND);
+ void mangleUnscopedTemplateName(const TemplateDecl *ND);
+ void mangleUnscopedTemplateName(TemplateName);
+ void mangleSourceName(const IdentifierInfo *II);
+ void mangleLocalName(const NamedDecl *ND);
+ void mangleLambda(const CXXRecordDecl *Lambda);
+ void mangleNestedName(const NamedDecl *ND, const DeclContext *DC,
+ bool NoFunction=false);
+ void mangleNestedName(const TemplateDecl *TD,
+ const TemplateArgument *TemplateArgs,
+ unsigned NumTemplateArgs);
+ void manglePrefix(NestedNameSpecifier *qualifier);
+ void manglePrefix(const DeclContext *DC, bool NoFunction=false);
+ void manglePrefix(QualType type);
+ void mangleTemplatePrefix(const TemplateDecl *ND);
+ void mangleTemplatePrefix(TemplateName Template);
+ void mangleOperatorName(OverloadedOperatorKind OO, unsigned Arity);
+ void mangleQualifiers(Qualifiers Quals);
+ void mangleRefQualifier(RefQualifierKind RefQualifier);
+
+ void mangleObjCMethodName(const ObjCMethodDecl *MD);
+
+ // Declare manglers for every type class.
+#define ABSTRACT_TYPE(CLASS, PARENT)
+#define NON_CANONICAL_TYPE(CLASS, PARENT)
+#define TYPE(CLASS, PARENT) void mangleType(const CLASS##Type *T);
+#include "clang/AST/TypeNodes.def"
+
+ void mangleType(const TagType*);
+ void mangleType(TemplateName);
+ void mangleBareFunctionType(const FunctionType *T,
+ bool MangleReturnType);
+ void mangleNeonVectorType(const VectorType *T);
+
+ void mangleIntegerLiteral(QualType T, const llvm::APSInt &Value);
+ void mangleMemberExpr(const Expr *base, bool isArrow,
+ NestedNameSpecifier *qualifier,
+ NamedDecl *firstQualifierLookup,
+ DeclarationName name,
+ unsigned knownArity);
+ void mangleExpression(const Expr *E, unsigned Arity = UnknownArity);
+ void mangleCXXCtorType(CXXCtorType T);
+ void mangleCXXDtorType(CXXDtorType T);
+
+ void mangleTemplateArgs(const ASTTemplateArgumentListInfo &TemplateArgs);
+ void mangleTemplateArgs(const TemplateArgument *TemplateArgs,
+ unsigned NumTemplateArgs);
+ void mangleTemplateArgs(const TemplateArgumentList &AL);
+ void mangleTemplateArg(TemplateArgument A);
+
+ void mangleTemplateParameter(unsigned Index);
+
+ void mangleFunctionParam(const ParmVarDecl *parm);
+};
+
+}
+
+static bool isInCLinkageSpecification(const Decl *D) {
+ D = D->getCanonicalDecl();
+ for (const DeclContext *DC = getEffectiveDeclContext(D);
+ !DC->isTranslationUnit(); DC = getEffectiveParentContext(DC)) {
+ if (const LinkageSpecDecl *Linkage = dyn_cast<LinkageSpecDecl>(DC))
+ return Linkage->getLanguage() == LinkageSpecDecl::lang_c;
+ }
+
+ return false;
+}
+
+bool ItaniumMangleContext::shouldMangleDeclName(const NamedDecl *D) {
+ // In C, functions with no attributes never need to be mangled. Fastpath them.
+ if (!getASTContext().getLangOpts().CPlusPlus && !D->hasAttrs())
+ return false;
+
+ // Any decl can be declared with __asm("foo") on it, and this takes precedence
+ // over all other naming in the .o file.
+ if (D->hasAttr<AsmLabelAttr>())
+ return true;
+
+ // Clang's "overloadable" attribute extension to C/C++ implies name mangling
+ // (always) as does passing a C++ member function and a function
+ // whose name is not a simple identifier.
+ const FunctionDecl *FD = dyn_cast<FunctionDecl>(D);
+ if (FD && (FD->hasAttr<OverloadableAttr>() || isa<CXXMethodDecl>(FD) ||
+ !FD->getDeclName().isIdentifier()))
+ return true;
+
+ // Otherwise, no mangling is done outside C++ mode.
+ if (!getASTContext().getLangOpts().CPlusPlus)
+ return false;
+
+ // Variables at global scope with non-internal linkage are not mangled
+ if (!FD) {
+ const DeclContext *DC = getEffectiveDeclContext(D);
+ // Check for extern variable declared locally.
+ if (DC->isFunctionOrMethod() && D->hasLinkage())
+ while (!DC->isNamespace() && !DC->isTranslationUnit())
+ DC = getEffectiveParentContext(DC);
+ if (DC->isTranslationUnit() && D->getLinkage() != InternalLinkage)
+ return false;
+ }
+
+ // Class members are always mangled.
+ if (getEffectiveDeclContext(D)->isRecord())
+ return true;
+
+ // C functions and "main" are not mangled.
+ if ((FD && FD->isMain()) || isInCLinkageSpecification(D))
+ return false;
+
+ return true;
+}
+
+void CXXNameMangler::mangle(const NamedDecl *D, StringRef Prefix) {
+ // Any decl can be declared with __asm("foo") on it, and this takes precedence
+ // over all other naming in the .o file.
+ if (const AsmLabelAttr *ALA = D->getAttr<AsmLabelAttr>()) {
+ // If we have an asm name, then we use it as the mangling.
+
+ // Adding the prefix can cause problems when one file has a "foo" and
+ // another has a "\01foo". That is known to happen on ELF with the
+ // tricks normally used for producing aliases (PR9177). Fortunately the
+ // llvm mangler on ELF is a nop, so we can just avoid adding the \01
+ // marker. We also avoid adding the marker if this is an alias for an
+ // LLVM intrinsic.
+ StringRef UserLabelPrefix =
+ getASTContext().getTargetInfo().getUserLabelPrefix();
+ if (!UserLabelPrefix.empty() && !ALA->getLabel().startswith("llvm."))
+ Out << '\01'; // LLVM IR Marker for __asm("foo")
+
+ Out << ALA->getLabel();
+ return;
+ }
+
+ // <mangled-name> ::= _Z <encoding>
+ // ::= <data name>
+ // ::= <special-name>
+ Out << Prefix;
+ if (const FunctionDecl *FD = dyn_cast<FunctionDecl>(D))
+ mangleFunctionEncoding(FD);
+ else if (const VarDecl *VD = dyn_cast<VarDecl>(D))
+ mangleName(VD);
+ else
+ mangleName(cast<FieldDecl>(D));
+}
+
+void CXXNameMangler::mangleFunctionEncoding(const FunctionDecl *FD) {
+ // <encoding> ::= <function name> <bare-function-type>
+ mangleName(FD);
+
+ // Don't mangle in the type if this isn't a decl we should typically mangle.
+ if (!Context.shouldMangleDeclName(FD))
+ return;
+
+ // Whether the mangling of a function type includes the return type depends on
+ // the context and the nature of the function. The rules for deciding whether
+ // the return type is included are:
+ //
+ // 1. Template functions (names or types) have return types encoded, with
+ // the exceptions listed below.
+ // 2. Function types not appearing as part of a function name mangling,
+ // e.g. parameters, pointer types, etc., have return type encoded, with the
+ // exceptions listed below.
+ // 3. Non-template function names do not have return types encoded.
+ //
+ // The exceptions mentioned in (1) and (2) above, for which the return type is
+ // never included, are
+ // 1. Constructors.
+ // 2. Destructors.
+ // 3. Conversion operator functions, e.g. operator int.
+ bool MangleReturnType = false;
+ if (FunctionTemplateDecl *PrimaryTemplate = FD->getPrimaryTemplate()) {
+ if (!(isa<CXXConstructorDecl>(FD) || isa<CXXDestructorDecl>(FD) ||
+ isa<CXXConversionDecl>(FD)))
+ MangleReturnType = true;
+
+ // Mangle the type of the primary template.
+ FD = PrimaryTemplate->getTemplatedDecl();
+ }
+
+ mangleBareFunctionType(FD->getType()->getAs<FunctionType>(),
+ MangleReturnType);
+}
+
+static const DeclContext *IgnoreLinkageSpecDecls(const DeclContext *DC) {
+ while (isa<LinkageSpecDecl>(DC)) {
+ DC = getEffectiveParentContext(DC);
+ }
+
+ return DC;
+}
+
+/// isStd - Return whether a given namespace is the 'std' namespace.
+static bool isStd(const NamespaceDecl *NS) {
+ if (!IgnoreLinkageSpecDecls(getEffectiveParentContext(NS))
+ ->isTranslationUnit())
+ return false;
+
+ const IdentifierInfo *II = NS->getOriginalNamespace()->getIdentifier();
+ return II && II->isStr("std");
+}
+
+// isStdNamespace - Return whether a given decl context is a toplevel 'std'
+// namespace.
+static bool isStdNamespace(const DeclContext *DC) {
+ if (!DC->isNamespace())
+ return false;
+
+ return isStd(cast<NamespaceDecl>(DC));
+}
+
+static const TemplateDecl *
+isTemplate(const NamedDecl *ND, const TemplateArgumentList *&TemplateArgs) {
+ // Check if we have a function template.
+ if (const FunctionDecl *FD = dyn_cast<FunctionDecl>(ND)){
+ if (const TemplateDecl *TD = FD->getPrimaryTemplate()) {
+ TemplateArgs = FD->getTemplateSpecializationArgs();
+ return TD;
+ }
+ }
+
+ // Check if we have a class template.
+ if (const ClassTemplateSpecializationDecl *Spec =
+ dyn_cast<ClassTemplateSpecializationDecl>(ND)) {
+ TemplateArgs = &Spec->getTemplateArgs();
+ return Spec->getSpecializedTemplate();
+ }
+
+ return 0;
+}
+
+static bool isLambda(const NamedDecl *ND) {
+ const CXXRecordDecl *Record = dyn_cast<CXXRecordDecl>(ND);
+ if (!Record)
+ return false;
+
+ return Record->isLambda();
+}
+
+void CXXNameMangler::mangleName(const NamedDecl *ND) {
+ // <name> ::= <nested-name>
+ // ::= <unscoped-name>
+ // ::= <unscoped-template-name> <template-args>
+ // ::= <local-name>
+ //
+ const DeclContext *DC = getEffectiveDeclContext(ND);
+
+ // If this is an extern variable declared locally, the relevant DeclContext
+ // is that of the containing namespace, or the translation unit.
+ // FIXME: This is a hack; extern variables declared locally should have
+ // a proper semantic declaration context!
+ if (isa<FunctionDecl>(DC) && ND->hasLinkage() && !isLambda(ND))
+ while (!DC->isNamespace() && !DC->isTranslationUnit())
+ DC = getEffectiveParentContext(DC);
+ else if (GetLocalClassDecl(ND)) {
+ mangleLocalName(ND);
+ return;
+ }
+
+ DC = IgnoreLinkageSpecDecls(DC);
+
+ if (DC->isTranslationUnit() || isStdNamespace(DC)) {
+ // Check if we have a template.
+ const TemplateArgumentList *TemplateArgs = 0;
+ if (const TemplateDecl *TD = isTemplate(ND, TemplateArgs)) {
+ mangleUnscopedTemplateName(TD);
+ mangleTemplateArgs(*TemplateArgs);
+ return;
+ }
+
+ mangleUnscopedName(ND);
+ return;
+ }
+
+ if (isa<FunctionDecl>(DC) || isa<ObjCMethodDecl>(DC)) {
+ mangleLocalName(ND);
+ return;
+ }
+
+ mangleNestedName(ND, DC);
+}
+void CXXNameMangler::mangleName(const TemplateDecl *TD,
+ const TemplateArgument *TemplateArgs,
+ unsigned NumTemplateArgs) {
+ const DeclContext *DC = IgnoreLinkageSpecDecls(getEffectiveDeclContext(TD));
+
+ if (DC->isTranslationUnit() || isStdNamespace(DC)) {
+ mangleUnscopedTemplateName(TD);
+ mangleTemplateArgs(TemplateArgs, NumTemplateArgs);
+ } else {
+ mangleNestedName(TD, TemplateArgs, NumTemplateArgs);
+ }
+}
+
+void CXXNameMangler::mangleUnscopedName(const NamedDecl *ND) {
+ // <unscoped-name> ::= <unqualified-name>
+ // ::= St <unqualified-name> # ::std::
+
+ if (isStdNamespace(IgnoreLinkageSpecDecls(getEffectiveDeclContext(ND))))
+ Out << "St";
+
+ mangleUnqualifiedName(ND);
+}
+
+void CXXNameMangler::mangleUnscopedTemplateName(const TemplateDecl *ND) {
+ // <unscoped-template-name> ::= <unscoped-name>
+ // ::= <substitution>
+ if (mangleSubstitution(ND))
+ return;
+
+ // <template-template-param> ::= <template-param>
+ if (const TemplateTemplateParmDecl *TTP
+ = dyn_cast<TemplateTemplateParmDecl>(ND)) {
+ mangleTemplateParameter(TTP->getIndex());
+ return;
+ }
+
+ mangleUnscopedName(ND->getTemplatedDecl());
+ addSubstitution(ND);
+}
+
+void CXXNameMangler::mangleUnscopedTemplateName(TemplateName Template) {
+ // <unscoped-template-name> ::= <unscoped-name>
+ // ::= <substitution>
+ if (TemplateDecl *TD = Template.getAsTemplateDecl())
+ return mangleUnscopedTemplateName(TD);
+
+ if (mangleSubstitution(Template))
+ return;
+
+ DependentTemplateName *Dependent = Template.getAsDependentTemplateName();
+ assert(Dependent && "Not a dependent template name?");
+ if (const IdentifierInfo *Id = Dependent->getIdentifier())
+ mangleSourceName(Id);
+ else
+ mangleOperatorName(Dependent->getOperator(), UnknownArity);
+
+ addSubstitution(Template);
+}
+
+void CXXNameMangler::mangleFloat(const llvm::APFloat &f) {
+ // ABI:
+ // Floating-point literals are encoded using a fixed-length
+ // lowercase hexadecimal string corresponding to the internal
+ // representation (IEEE on Itanium), high-order bytes first,
+ // without leading zeroes. For example: "Lf bf800000 E" is -1.0f
+ // on Itanium.
+ // The 'without leading zeroes' thing seems to be an editorial
+ // mistake; see the discussion on cxx-abi-dev beginning on
+ // 2012-01-16.
+
+ // Our requirements here are just barely weird enough to justify
+ // using a custom algorithm instead of post-processing APInt::toString().
+
+ llvm::APInt valueBits = f.bitcastToAPInt();
+ unsigned numCharacters = (valueBits.getBitWidth() + 3) / 4;
+ assert(numCharacters != 0);
+
+ // Allocate a buffer of the right number of characters.
+ llvm::SmallVector<char, 20> buffer;
+ buffer.set_size(numCharacters);
+
+ // Fill the buffer left-to-right.
+ for (unsigned stringIndex = 0; stringIndex != numCharacters; ++stringIndex) {
+ // The bit-index of the next hex digit.
+ unsigned digitBitIndex = 4 * (numCharacters - stringIndex - 1);
+
+ // Project out 4 bits starting at 'digitIndex'.
+ llvm::integerPart hexDigit
+ = valueBits.getRawData()[digitBitIndex / llvm::integerPartWidth];
+ hexDigit >>= (digitBitIndex % llvm::integerPartWidth);
+ hexDigit &= 0xF;
+
+ // Map that over to a lowercase hex digit.
+ static const char charForHex[16] = {
+ '0', '1', '2', '3', '4', '5', '6', '7',
+ '8', '9', 'a', 'b', 'c', 'd', 'e', 'f'
+ };
+ buffer[stringIndex] = charForHex[hexDigit];
+ }
+
+ Out.write(buffer.data(), numCharacters);
+}
+
+void CXXNameMangler::mangleNumber(const llvm::APSInt &Value) {
+ if (Value.isSigned() && Value.isNegative()) {
+ Out << 'n';
+ Value.abs().print(Out, /*signed*/ false);
+ } else {
+ Value.print(Out, /*signed*/ false);
+ }
+}
+
+void CXXNameMangler::mangleNumber(int64_t Number) {
+ // <number> ::= [n] <non-negative decimal integer>
+ if (Number < 0) {
+ Out << 'n';
+ Number = -Number;
+ }
+
+ Out << Number;
+}
+
+void CXXNameMangler::mangleCallOffset(int64_t NonVirtual, int64_t Virtual) {
+ // <call-offset> ::= h <nv-offset> _
+ // ::= v <v-offset> _
+ // <nv-offset> ::= <offset number> # non-virtual base override
+ // <v-offset> ::= <offset number> _ <virtual offset number>
+ // # virtual base override, with vcall offset
+ if (!Virtual) {
+ Out << 'h';
+ mangleNumber(NonVirtual);
+ Out << '_';
+ return;
+ }
+
+ Out << 'v';
+ mangleNumber(NonVirtual);
+ Out << '_';
+ mangleNumber(Virtual);
+ Out << '_';
+}
+
+void CXXNameMangler::manglePrefix(QualType type) {
+ if (const TemplateSpecializationType *TST =
+ type->getAs<TemplateSpecializationType>()) {
+ if (!mangleSubstitution(QualType(TST, 0))) {
+ mangleTemplatePrefix(TST->getTemplateName());
+
+ // FIXME: GCC does not appear to mangle the template arguments when
+ // the template in question is a dependent template name. Should we
+ // emulate that badness?
+ mangleTemplateArgs(TST->getArgs(), TST->getNumArgs());
+ addSubstitution(QualType(TST, 0));
+ }
+ } else if (const DependentTemplateSpecializationType *DTST
+ = type->getAs<DependentTemplateSpecializationType>()) {
+ TemplateName Template
+ = getASTContext().getDependentTemplateName(DTST->getQualifier(),
+ DTST->getIdentifier());
+ mangleTemplatePrefix(Template);
+
+ // FIXME: GCC does not appear to mangle the template arguments when
+ // the template in question is a dependent template name. Should we
+ // emulate that badness?
+ mangleTemplateArgs(DTST->getArgs(), DTST->getNumArgs());
+ } else {
+ // We use the QualType mangle type variant here because it handles
+ // substitutions.
+ mangleType(type);
+ }
+}
+
+/// Mangle everything prior to the base-unresolved-name in an unresolved-name.
+///
+/// \param firstQualifierLookup - the entity found by unqualified lookup
+/// for the first name in the qualifier, if this is for a member expression
+/// \param recursive - true if this is being called recursively,
+/// i.e. if there is more prefix "to the right".
+void CXXNameMangler::mangleUnresolvedPrefix(NestedNameSpecifier *qualifier,
+ NamedDecl *firstQualifierLookup,
+ bool recursive) {
+
+ // x, ::x
+ // <unresolved-name> ::= [gs] <base-unresolved-name>
+
+ // T::x / decltype(p)::x
+ // <unresolved-name> ::= sr <unresolved-type> <base-unresolved-name>
+
+ // T::N::x /decltype(p)::N::x
+ // <unresolved-name> ::= srN <unresolved-type> <unresolved-qualifier-level>+ E
+ // <base-unresolved-name>
+
+ // A::x, N::y, A<T>::z; "gs" means leading "::"
+ // <unresolved-name> ::= [gs] sr <unresolved-qualifier-level>+ E
+ // <base-unresolved-name>
+
+ switch (qualifier->getKind()) {
+ case NestedNameSpecifier::Global:
+ Out << "gs";
+
+ // We want an 'sr' unless this is the entire NNS.
+ if (recursive)
+ Out << "sr";
+
+ // We never want an 'E' here.
+ return;
+
+ case NestedNameSpecifier::Namespace:
+ if (qualifier->getPrefix())
+ mangleUnresolvedPrefix(qualifier->getPrefix(), firstQualifierLookup,
+ /*recursive*/ true);
+ else
+ Out << "sr";
+ mangleSourceName(qualifier->getAsNamespace()->getIdentifier());
+ break;
+ case NestedNameSpecifier::NamespaceAlias:
+ if (qualifier->getPrefix())
+ mangleUnresolvedPrefix(qualifier->getPrefix(), firstQualifierLookup,
+ /*recursive*/ true);
+ else
+ Out << "sr";
+ mangleSourceName(qualifier->getAsNamespaceAlias()->getIdentifier());
+ break;
+
+ case NestedNameSpecifier::TypeSpec:
+ case NestedNameSpecifier::TypeSpecWithTemplate: {
+ const Type *type = qualifier->getAsType();
+
+ // We only want to use an unresolved-type encoding if this is one of:
+ // - a decltype
+ // - a template type parameter
+ // - a template template parameter with arguments
+ // In all of these cases, we should have no prefix.
+ if (qualifier->getPrefix()) {
+ mangleUnresolvedPrefix(qualifier->getPrefix(), firstQualifierLookup,
+ /*recursive*/ true);
+ } else {
+ // Otherwise, all the cases want this.
+ Out << "sr";
+ }
+
+ // Only certain other types are valid as prefixes; enumerate them.
+ switch (type->getTypeClass()) {
+ case Type::Builtin:
+ case Type::Complex:
+ case Type::Pointer:
+ case Type::BlockPointer:
+ case Type::LValueReference:
+ case Type::RValueReference:
+ case Type::MemberPointer:
+ case Type::ConstantArray:
+ case Type::IncompleteArray:
+ case Type::VariableArray:
+ case Type::DependentSizedArray:
+ case Type::DependentSizedExtVector:
+ case Type::Vector:
+ case Type::ExtVector:
+ case Type::FunctionProto:
+ case Type::FunctionNoProto:
+ case Type::Enum:
+ case Type::Paren:
+ case Type::Elaborated:
+ case Type::Attributed:
+ case Type::Auto:
+ case Type::PackExpansion:
+ case Type::ObjCObject:
+ case Type::ObjCInterface:
+ case Type::ObjCObjectPointer:
+ case Type::Atomic:
+ llvm_unreachable("type is illegal as a nested name specifier");
+
+ case Type::SubstTemplateTypeParmPack:
+ // FIXME: not clear how to mangle this!
+ // template <class T...> class A {
+ // template <class U...> void foo(decltype(T::foo(U())) x...);
+ // };
+ Out << "_SUBSTPACK_";
+ break;
+
+ // <unresolved-type> ::= <template-param>
+ // ::= <decltype>
+ // ::= <template-template-param> <template-args>
+ // (this last is not official yet)
+ case Type::TypeOfExpr:
+ case Type::TypeOf:
+ case Type::Decltype:
+ case Type::TemplateTypeParm:
+ case Type::UnaryTransform:
+ case Type::SubstTemplateTypeParm:
+ unresolvedType:
+ assert(!qualifier->getPrefix());
+
+ // We only get here recursively if we're followed by identifiers.
+ if (recursive) Out << 'N';
+
+ // This seems to do everything we want. It's not really
+ // sanctioned for a substituted template parameter, though.
+ mangleType(QualType(type, 0));
+
+ // We never want to print 'E' directly after an unresolved-type,
+ // so we return directly.
+ return;
+
+ case Type::Typedef:
+ mangleSourceName(cast<TypedefType>(type)->getDecl()->getIdentifier());
+ break;
+
+ case Type::UnresolvedUsing:
+ mangleSourceName(cast<UnresolvedUsingType>(type)->getDecl()
+ ->getIdentifier());
+ break;
+
+ case Type::Record:
+ mangleSourceName(cast<RecordType>(type)->getDecl()->getIdentifier());
+ break;
+
+ case Type::TemplateSpecialization: {
+ const TemplateSpecializationType *tst
+ = cast<TemplateSpecializationType>(type);
+ TemplateName name = tst->getTemplateName();
+ switch (name.getKind()) {
+ case TemplateName::Template:
+ case TemplateName::QualifiedTemplate: {
+ TemplateDecl *temp = name.getAsTemplateDecl();
+
+ // If the base is a template template parameter, this is an
+ // unresolved type.
+ assert(temp && "no template for template specialization type");
+ if (isa<TemplateTemplateParmDecl>(temp)) goto unresolvedType;
+
+ mangleSourceName(temp->getIdentifier());
+ break;
+ }
+
+ case TemplateName::OverloadedTemplate:
+ case TemplateName::DependentTemplate:
+ llvm_unreachable("invalid base for a template specialization type");
+
+ case TemplateName::SubstTemplateTemplateParm: {
+ SubstTemplateTemplateParmStorage *subst
+ = name.getAsSubstTemplateTemplateParm();
+ mangleExistingSubstitution(subst->getReplacement());
+ break;
+ }
+
+ case TemplateName::SubstTemplateTemplateParmPack: {
+ // FIXME: not clear how to mangle this!
+ // template <template <class U> class T...> class A {
+ // template <class U...> void foo(decltype(T<U>::foo) x...);
+ // };
+ Out << "_SUBSTPACK_";
+ break;
+ }
+ }
+
+ mangleTemplateArgs(tst->getArgs(), tst->getNumArgs());
+ break;
+ }
+
+ case Type::InjectedClassName:
+ mangleSourceName(cast<InjectedClassNameType>(type)->getDecl()
+ ->getIdentifier());
+ break;
+
+ case Type::DependentName:
+ mangleSourceName(cast<DependentNameType>(type)->getIdentifier());
+ break;
+
+ case Type::DependentTemplateSpecialization: {
+ const DependentTemplateSpecializationType *tst
+ = cast<DependentTemplateSpecializationType>(type);
+ mangleSourceName(tst->getIdentifier());
+ mangleTemplateArgs(tst->getArgs(), tst->getNumArgs());
+ break;
+ }
+ }
+ break;
+ }
+
+ case NestedNameSpecifier::Identifier:
+ // Member expressions can have these without prefixes.
+ if (qualifier->getPrefix()) {
+ mangleUnresolvedPrefix(qualifier->getPrefix(), firstQualifierLookup,
+ /*recursive*/ true);
+ } else if (firstQualifierLookup) {
+
+ // Try to make a proper qualifier out of the lookup result, and
+ // then just recurse on that.
+ NestedNameSpecifier *newQualifier;
+ if (TypeDecl *typeDecl = dyn_cast<TypeDecl>(firstQualifierLookup)) {
+ QualType type = getASTContext().getTypeDeclType(typeDecl);
+
+ // Pretend we had a different nested name specifier.
+ newQualifier = NestedNameSpecifier::Create(getASTContext(),
+ /*prefix*/ 0,
+ /*template*/ false,
+ type.getTypePtr());
+ } else if (NamespaceDecl *nspace =
+ dyn_cast<NamespaceDecl>(firstQualifierLookup)) {
+ newQualifier = NestedNameSpecifier::Create(getASTContext(),
+ /*prefix*/ 0,
+ nspace);
+ } else if (NamespaceAliasDecl *alias =
+ dyn_cast<NamespaceAliasDecl>(firstQualifierLookup)) {
+ newQualifier = NestedNameSpecifier::Create(getASTContext(),
+ /*prefix*/ 0,
+ alias);
+ } else {
+ // No sensible mangling to do here.
+ newQualifier = 0;
+ }
+
+ if (newQualifier)
+ return mangleUnresolvedPrefix(newQualifier, /*lookup*/ 0, recursive);
+
+ } else {
+ Out << "sr";
+ }
+
+ mangleSourceName(qualifier->getAsIdentifier());
+ break;
+ }
+
+ // If this was the innermost part of the NNS, and we fell out to
+ // here, append an 'E'.
+ if (!recursive)
+ Out << 'E';
+}
+
+/// Mangle an unresolved-name, which is generally used for names which
+/// weren't resolved to specific entities.
+void CXXNameMangler::mangleUnresolvedName(NestedNameSpecifier *qualifier,
+ NamedDecl *firstQualifierLookup,
+ DeclarationName name,
+ unsigned knownArity) {
+ if (qualifier) mangleUnresolvedPrefix(qualifier, firstQualifierLookup);
+ mangleUnqualifiedName(0, name, knownArity);
+}
+
+static const FieldDecl *FindFirstNamedDataMember(const RecordDecl *RD) {
+ assert(RD->isAnonymousStructOrUnion() &&
+ "Expected anonymous struct or union!");
+
+ for (RecordDecl::field_iterator I = RD->field_begin(), E = RD->field_end();
+ I != E; ++I) {
+ if (I->getIdentifier())
+ return *I;
+
+ if (const RecordType *RT = I->getType()->getAs<RecordType>())
+ if (const FieldDecl *NamedDataMember =
+ FindFirstNamedDataMember(RT->getDecl()))
+ return NamedDataMember;
+ }
+
+ // We didn't find a named data member.
+ return 0;
+}
+
+void CXXNameMangler::mangleUnqualifiedName(const NamedDecl *ND,
+ DeclarationName Name,
+ unsigned KnownArity) {
+ // <unqualified-name> ::= <operator-name>
+ // ::= <ctor-dtor-name>
+ // ::= <source-name>
+ switch (Name.getNameKind()) {
+ case DeclarationName::Identifier: {
+ if (const IdentifierInfo *II = Name.getAsIdentifierInfo()) {
+ // We must avoid conflicts between internally- and externally-
+ // linked variable and function declaration names in the same TU:
+ // void test() { extern void foo(); }
+ // static void foo();
+ // This naming convention is the same as that followed by GCC,
+ // though it shouldn't actually matter.
+ if (ND && ND->getLinkage() == InternalLinkage &&
+ getEffectiveDeclContext(ND)->isFileContext())
+ Out << 'L';
+
+ mangleSourceName(II);
+ break;
+ }
+
+ // Otherwise, an anonymous entity. We must have a declaration.
+ assert(ND && "mangling empty name without declaration");
+
+ if (const NamespaceDecl *NS = dyn_cast<NamespaceDecl>(ND)) {
+ if (NS->isAnonymousNamespace()) {
+ // This is how gcc mangles these names.
+ Out << "12_GLOBAL__N_1";
+ break;
+ }
+ }
+
+ if (const VarDecl *VD = dyn_cast<VarDecl>(ND)) {
+ // We must have an anonymous union or struct declaration.
+ const RecordDecl *RD =
+ cast<RecordDecl>(VD->getType()->getAs<RecordType>()->getDecl());
+
+ // Itanium C++ ABI 5.1.2:
+ //
+ // For the purposes of mangling, the name of an anonymous union is
+ // considered to be the name of the first named data member found by a
+ // pre-order, depth-first, declaration-order walk of the data members of
+ // the anonymous union. If there is no such data member (i.e., if all of
+ // the data members in the union are unnamed), then there is no way for
+ // a program to refer to the anonymous union, and there is therefore no
+ // need to mangle its name.
+ const FieldDecl *FD = FindFirstNamedDataMember(RD);
+
+ // It's actually possible for various reasons for us to get here
+ // with an empty anonymous struct / union. Fortunately, it
+ // doesn't really matter what name we generate.
+ if (!FD) break;
+ assert(FD->getIdentifier() && "Data member name isn't an identifier!");
+
+ mangleSourceName(FD->getIdentifier());
+ break;
+ }
+
+ // We must have an anonymous struct.
+ const TagDecl *TD = cast<TagDecl>(ND);
+ if (const TypedefNameDecl *D = TD->getTypedefNameForAnonDecl()) {
+ assert(TD->getDeclContext() == D->getDeclContext() &&
+ "Typedef should not be in another decl context!");
+ assert(D->getDeclName().getAsIdentifierInfo() &&
+ "Typedef was not named!");
+ mangleSourceName(D->getDeclName().getAsIdentifierInfo());
+ break;
+ }
+
+ // <unnamed-type-name> ::= <closure-type-name>
+ //
+ // <closure-type-name> ::= Ul <lambda-sig> E [ <nonnegative number> ] _
+ // <lambda-sig> ::= <parameter-type>+ # Parameter types or 'v' for 'void'.
+ if (const CXXRecordDecl *Record = dyn_cast<CXXRecordDecl>(TD)) {
+ if (Record->isLambda() && Record->getLambdaManglingNumber()) {
+ mangleLambda(Record);
+ break;
+ }
+ }
+
+ int UnnamedMangle = Context.getASTContext().getUnnamedTagManglingNumber(TD);
+ if (UnnamedMangle != -1) {
+ Out << "Ut";
+ if (UnnamedMangle != 0)
+ Out << llvm::utostr(UnnamedMangle - 1);
+ Out << '_';
+ break;
+ }
+
+ // Get a unique id for the anonymous struct.
+ uint64_t AnonStructId = Context.getAnonymousStructId(TD);
+
+ // Mangle it as a source name in the form
+ // [n] $_<id>
+ // where n is the length of the string.
+ SmallString<8> Str;
+ Str += "$_";
+ Str += llvm::utostr(AnonStructId);
+
+ Out << Str.size();
+ Out << Str.str();
+ break;
+ }
+
+ case DeclarationName::ObjCZeroArgSelector:
+ case DeclarationName::ObjCOneArgSelector:
+ case DeclarationName::ObjCMultiArgSelector:
+ llvm_unreachable("Can't mangle Objective-C selector names here!");
+
+ case DeclarationName::CXXConstructorName:
+ if (ND == Structor)
+ // If the named decl is the C++ constructor we're mangling, use the type
+ // we were given.
+ mangleCXXCtorType(static_cast<CXXCtorType>(StructorType));
+ else
+ // Otherwise, use the complete constructor name. This is relevant if a
+ // class with a constructor is declared within a constructor.
+ mangleCXXCtorType(Ctor_Complete);
+ break;
+
+ case DeclarationName::CXXDestructorName:
+ if (ND == Structor)
+ // If the named decl is the C++ destructor we're mangling, use the type we
+ // were given.
+ mangleCXXDtorType(static_cast<CXXDtorType>(StructorType));
+ else
+ // Otherwise, use the complete destructor name. This is relevant if a
+ // class with a destructor is declared within a destructor.
+ mangleCXXDtorType(Dtor_Complete);
+ break;
+
+ case DeclarationName::CXXConversionFunctionName:
+ // <operator-name> ::= cv <type> # (cast)
+ Out << "cv";
+ mangleType(Name.getCXXNameType());
+ break;
+
+ case DeclarationName::CXXOperatorName: {
+ unsigned Arity;
+ if (ND) {
+ Arity = cast<FunctionDecl>(ND)->getNumParams();
+
+ // If we have a C++ member function, we need to include the 'this' pointer.
+ // FIXME: This does not make sense for operators that are static, but their
+ // names stay the same regardless of the arity (operator new for instance).
+ if (isa<CXXMethodDecl>(ND))
+ Arity++;
+ } else
+ Arity = KnownArity;
+
+ mangleOperatorName(Name.getCXXOverloadedOperator(), Arity);
+ break;
+ }
+
+ case DeclarationName::CXXLiteralOperatorName:
+ // FIXME: This mangling is not yet official.
+ Out << "li";
+ mangleSourceName(Name.getCXXLiteralIdentifier());
+ break;
+
+ case DeclarationName::CXXUsingDirective:
+ llvm_unreachable("Can't mangle a using directive name!");
+ }
+}
+
+void CXXNameMangler::mangleSourceName(const IdentifierInfo *II) {
+ // <source-name> ::= <positive length number> <identifier>
+ // <number> ::= [n] <non-negative decimal integer>
+ // <identifier> ::= <unqualified source code identifier>
+ Out << II->getLength() << II->getName();
+}
+
+void CXXNameMangler::mangleNestedName(const NamedDecl *ND,
+ const DeclContext *DC,
+ bool NoFunction) {
+ // <nested-name>
+ // ::= N [<CV-qualifiers>] [<ref-qualifier>] <prefix> <unqualified-name> E
+ // ::= N [<CV-qualifiers>] [<ref-qualifier>] <template-prefix>
+ // <template-args> E
+
+ Out << 'N';
+ if (const CXXMethodDecl *Method = dyn_cast<CXXMethodDecl>(ND)) {
+ mangleQualifiers(Qualifiers::fromCVRMask(Method->getTypeQualifiers()));
+ mangleRefQualifier(Method->getRefQualifier());
+ }
+
+ // Check if we have a template.
+ const TemplateArgumentList *TemplateArgs = 0;
+ if (const TemplateDecl *TD = isTemplate(ND, TemplateArgs)) {
+ mangleTemplatePrefix(TD);
+ mangleTemplateArgs(*TemplateArgs);
+ }
+ else {
+ manglePrefix(DC, NoFunction);
+ mangleUnqualifiedName(ND);
+ }
+
+ Out << 'E';
+}
+void CXXNameMangler::mangleNestedName(const TemplateDecl *TD,
+ const TemplateArgument *TemplateArgs,
+ unsigned NumTemplateArgs) {
+ // <nested-name> ::= N [<CV-qualifiers>] <template-prefix> <template-args> E
+
+ Out << 'N';
+
+ mangleTemplatePrefix(TD);
+ mangleTemplateArgs(TemplateArgs, NumTemplateArgs);
+
+ Out << 'E';
+}
+
+void CXXNameMangler::mangleLocalName(const NamedDecl *ND) {
+ // <local-name> := Z <function encoding> E <entity name> [<discriminator>]
+ // := Z <function encoding> E s [<discriminator>]
+ // <local-name> := Z <function encoding> E d [ <parameter number> ]
+ // _ <entity name>
+ // <discriminator> := _ <non-negative number>
+ const DeclContext *DC = getEffectiveDeclContext(ND);
+ if (isa<ObjCMethodDecl>(DC) && isa<FunctionDecl>(ND)) {
+ // Don't add objc method name mangling to locally declared function
+ mangleUnqualifiedName(ND);
+ return;
+ }
+
+ Out << 'Z';
+
+ if (const ObjCMethodDecl *MD = dyn_cast<ObjCMethodDecl>(DC)) {
+ mangleObjCMethodName(MD);
+ } else if (const CXXRecordDecl *RD = GetLocalClassDecl(ND)) {
+ mangleFunctionEncoding(cast<FunctionDecl>(getEffectiveDeclContext(RD)));
+ Out << 'E';
+
+ // The parameter number is omitted for the last parameter, 0 for the
+ // second-to-last parameter, 1 for the third-to-last parameter, etc. The
+ // <entity name> will of course contain a <closure-type-name>: Its
+ // numbering will be local to the particular argument in which it appears
+ // -- other default arguments do not affect its encoding.
+ bool SkipDiscriminator = false;
+ if (RD->isLambda()) {
+ if (const ParmVarDecl *Parm
+ = dyn_cast_or_null<ParmVarDecl>(RD->getLambdaContextDecl())) {
+ if (const FunctionDecl *Func
+ = dyn_cast<FunctionDecl>(Parm->getDeclContext())) {
+ Out << 'd';
+ unsigned Num = Func->getNumParams() - Parm->getFunctionScopeIndex();
+ if (Num > 1)
+ mangleNumber(Num - 2);
+ Out << '_';
+ SkipDiscriminator = true;
+ }
+ }
+ }
+
+ // Mangle the name relative to the closest enclosing function.
+ if (ND == RD) // equality ok because RD derived from ND above
+ mangleUnqualifiedName(ND);
+ else
+ mangleNestedName(ND, DC, true /*NoFunction*/);
+
+ if (!SkipDiscriminator) {
+ unsigned disc;
+ if (Context.getNextDiscriminator(RD, disc)) {
+ if (disc < 10)
+ Out << '_' << disc;
+ else
+ Out << "__" << disc << '_';
+ }
+ }
+
+ return;
+ }
+ else
+ mangleFunctionEncoding(cast<FunctionDecl>(DC));
+
+ Out << 'E';
+ mangleUnqualifiedName(ND);
+}
+
+void CXXNameMangler::mangleLambda(const CXXRecordDecl *Lambda) {
+ // If the context of a closure type is an initializer for a class member
+ // (static or nonstatic), it is encoded in a qualified name with a final
+ // <prefix> of the form:
+ //
+ // <data-member-prefix> := <member source-name> M
+ //
+ // Technically, the data-member-prefix is part of the <prefix>. However,
+ // since a closure type will always be mangled with a prefix, it's easier
+ // to emit that last part of the prefix here.
+ if (Decl *Context = Lambda->getLambdaContextDecl()) {
+ if ((isa<VarDecl>(Context) || isa<FieldDecl>(Context)) &&
+ Context->getDeclContext()->isRecord()) {
+ if (const IdentifierInfo *Name
+ = cast<NamedDecl>(Context)->getIdentifier()) {
+ mangleSourceName(Name);
+ Out << 'M';
+ }
+ }
+ }
+
+ Out << "Ul";
+ const FunctionProtoType *Proto = Lambda->getLambdaTypeInfo()->getType()->
+ getAs<FunctionProtoType>();
+ mangleBareFunctionType(Proto, /*MangleReturnType=*/false);
+ Out << "E";
+
+ // The number is omitted for the first closure type with a given
+ // <lambda-sig> in a given context; it is n-2 for the nth closure type
+ // (in lexical order) with that same <lambda-sig> and context.
+ //
+ // The AST keeps track of the number for us.
+ unsigned Number = Lambda->getLambdaManglingNumber();
+ assert(Number > 0 && "Lambda should be mangled as an unnamed class");
+ if (Number > 1)
+ mangleNumber(Number - 2);
+ Out << '_';
+}
+
+void CXXNameMangler::manglePrefix(NestedNameSpecifier *qualifier) {
+ switch (qualifier->getKind()) {
+ case NestedNameSpecifier::Global:
+ // nothing
+ return;
+
+ case NestedNameSpecifier::Namespace:
+ mangleName(qualifier->getAsNamespace());
+ return;
+
+ case NestedNameSpecifier::NamespaceAlias:
+ mangleName(qualifier->getAsNamespaceAlias()->getNamespace());
+ return;
+
+ case NestedNameSpecifier::TypeSpec:
+ case NestedNameSpecifier::TypeSpecWithTemplate:
+ manglePrefix(QualType(qualifier->getAsType(), 0));
+ return;
+
+ case NestedNameSpecifier::Identifier:
+ // Member expressions can have these without prefixes, but that
+ // should end up in mangleUnresolvedPrefix instead.
+ assert(qualifier->getPrefix());
+ manglePrefix(qualifier->getPrefix());
+
+ mangleSourceName(qualifier->getAsIdentifier());
+ return;
+ }
+
+ llvm_unreachable("unexpected nested name specifier");
+}
+
+void CXXNameMangler::manglePrefix(const DeclContext *DC, bool NoFunction) {
+ // <prefix> ::= <prefix> <unqualified-name>
+ // ::= <template-prefix> <template-args>
+ // ::= <template-param>
+ // ::= # empty
+ // ::= <substitution>
+
+ DC = IgnoreLinkageSpecDecls(DC);
+
+ if (DC->isTranslationUnit())
+ return;
+
+ if (const BlockDecl *Block = dyn_cast<BlockDecl>(DC)) {
+ manglePrefix(getEffectiveParentContext(DC), NoFunction);
+ SmallString<64> Name;
+ llvm::raw_svector_ostream NameStream(Name);
+ Context.mangleBlock(Block, NameStream);
+ NameStream.flush();
+ Out << Name.size() << Name;
+ return;
+ }
+
+ const NamedDecl *ND = cast<NamedDecl>(DC);
+ if (mangleSubstitution(ND))
+ return;
+
+ // Check if we have a template.
+ const TemplateArgumentList *TemplateArgs = 0;
+ if (const TemplateDecl *TD = isTemplate(ND, TemplateArgs)) {
+ mangleTemplatePrefix(TD);
+ mangleTemplateArgs(*TemplateArgs);
+ }
+ else if(NoFunction && (isa<FunctionDecl>(ND) || isa<ObjCMethodDecl>(ND)))
+ return;
+ else if (const ObjCMethodDecl *Method = dyn_cast<ObjCMethodDecl>(ND))
+ mangleObjCMethodName(Method);
+ else {
+ manglePrefix(getEffectiveDeclContext(ND), NoFunction);
+ mangleUnqualifiedName(ND);
+ }
+
+ addSubstitution(ND);
+}
+
+void CXXNameMangler::mangleTemplatePrefix(TemplateName Template) {
+ // <template-prefix> ::= <prefix> <template unqualified-name>
+ // ::= <template-param>
+ // ::= <substitution>
+ if (TemplateDecl *TD = Template.getAsTemplateDecl())
+ return mangleTemplatePrefix(TD);
+
+ if (QualifiedTemplateName *Qualified = Template.getAsQualifiedTemplateName())
+ manglePrefix(Qualified->getQualifier());
+
+ if (OverloadedTemplateStorage *Overloaded
+ = Template.getAsOverloadedTemplate()) {
+ mangleUnqualifiedName(0, (*Overloaded->begin())->getDeclName(),
+ UnknownArity);
+ return;
+ }
+
+ DependentTemplateName *Dependent = Template.getAsDependentTemplateName();
+ assert(Dependent && "Unknown template name kind?");
+ manglePrefix(Dependent->getQualifier());
+ mangleUnscopedTemplateName(Template);
+}
+
+void CXXNameMangler::mangleTemplatePrefix(const TemplateDecl *ND) {
+ // <template-prefix> ::= <prefix> <template unqualified-name>
+ // ::= <template-param>
+ // ::= <substitution>
+ // <template-template-param> ::= <template-param>
+ // <substitution>
+
+ if (mangleSubstitution(ND))
+ return;
+
+ // <template-template-param> ::= <template-param>
+ if (const TemplateTemplateParmDecl *TTP
+ = dyn_cast<TemplateTemplateParmDecl>(ND)) {
+ mangleTemplateParameter(TTP->getIndex());
+ return;
+ }
+
+ manglePrefix(getEffectiveDeclContext(ND));
+ mangleUnqualifiedName(ND->getTemplatedDecl());
+ addSubstitution(ND);
+}
+
+/// Mangles a template name under the production <type>. Required for
+/// template template arguments.
+/// <type> ::= <class-enum-type>
+/// ::= <template-param>
+/// ::= <substitution>
+void CXXNameMangler::mangleType(TemplateName TN) {
+ if (mangleSubstitution(TN))
+ return;
+
+ TemplateDecl *TD = 0;
+
+ switch (TN.getKind()) {
+ case TemplateName::QualifiedTemplate:
+ TD = TN.getAsQualifiedTemplateName()->getTemplateDecl();
+ goto HaveDecl;
+
+ case TemplateName::Template:
+ TD = TN.getAsTemplateDecl();
+ goto HaveDecl;
+
+ HaveDecl:
+ if (isa<TemplateTemplateParmDecl>(TD))
+ mangleTemplateParameter(cast<TemplateTemplateParmDecl>(TD)->getIndex());
+ else
+ mangleName(TD);
+ break;
+
+ case TemplateName::OverloadedTemplate:
+ llvm_unreachable("can't mangle an overloaded template name as a <type>");
+
+ case TemplateName::DependentTemplate: {
+ const DependentTemplateName *Dependent = TN.getAsDependentTemplateName();
+ assert(Dependent->isIdentifier());
+
+ // <class-enum-type> ::= <name>
+ // <name> ::= <nested-name>
+ mangleUnresolvedPrefix(Dependent->getQualifier(), 0);
+ mangleSourceName(Dependent->getIdentifier());
+ break;
+ }
+
+ case TemplateName::SubstTemplateTemplateParm: {
+ // Substituted template parameters are mangled as the substituted
+ // template. This will check for the substitution twice, which is
+ // fine, but we have to return early so that we don't try to *add*
+ // the substitution twice.
+ SubstTemplateTemplateParmStorage *subst
+ = TN.getAsSubstTemplateTemplateParm();
+ mangleType(subst->getReplacement());
+ return;
+ }
+
+ case TemplateName::SubstTemplateTemplateParmPack: {
+ // FIXME: not clear how to mangle this!
+ // template <template <class> class T...> class A {
+ // template <template <class> class U...> void foo(B<T,U> x...);
+ // };
+ Out << "_SUBSTPACK_";
+ break;
+ }
+ }
+
+ addSubstitution(TN);
+}
+
+void
+CXXNameMangler::mangleOperatorName(OverloadedOperatorKind OO, unsigned Arity) {
+ switch (OO) {
+ // <operator-name> ::= nw # new
+ case OO_New: Out << "nw"; break;
+ // ::= na # new[]
+ case OO_Array_New: Out << "na"; break;
+ // ::= dl # delete
+ case OO_Delete: Out << "dl"; break;
+ // ::= da # delete[]
+ case OO_Array_Delete: Out << "da"; break;
+ // ::= ps # + (unary)
+ // ::= pl # + (binary or unknown)
+ case OO_Plus:
+ Out << (Arity == 1? "ps" : "pl"); break;
+ // ::= ng # - (unary)
+ // ::= mi # - (binary or unknown)
+ case OO_Minus:
+ Out << (Arity == 1? "ng" : "mi"); break;
+ // ::= ad # & (unary)
+ // ::= an # & (binary or unknown)
+ case OO_Amp:
+ Out << (Arity == 1? "ad" : "an"); break;
+ // ::= de # * (unary)
+ // ::= ml # * (binary or unknown)
+ case OO_Star:
+ // Use binary when unknown.
+ Out << (Arity == 1? "de" : "ml"); break;
+ // ::= co # ~
+ case OO_Tilde: Out << "co"; break;
+ // ::= dv # /
+ case OO_Slash: Out << "dv"; break;
+ // ::= rm # %
+ case OO_Percent: Out << "rm"; break;
+ // ::= or # |
+ case OO_Pipe: Out << "or"; break;
+ // ::= eo # ^
+ case OO_Caret: Out << "eo"; break;
+ // ::= aS # =
+ case OO_Equal: Out << "aS"; break;
+ // ::= pL # +=
+ case OO_PlusEqual: Out << "pL"; break;
+ // ::= mI # -=
+ case OO_MinusEqual: Out << "mI"; break;
+ // ::= mL # *=
+ case OO_StarEqual: Out << "mL"; break;
+ // ::= dV # /=
+ case OO_SlashEqual: Out << "dV"; break;
+ // ::= rM # %=
+ case OO_PercentEqual: Out << "rM"; break;
+ // ::= aN # &=
+ case OO_AmpEqual: Out << "aN"; break;
+ // ::= oR # |=
+ case OO_PipeEqual: Out << "oR"; break;
+ // ::= eO # ^=
+ case OO_CaretEqual: Out << "eO"; break;
+ // ::= ls # <<
+ case OO_LessLess: Out << "ls"; break;
+ // ::= rs # >>
+ case OO_GreaterGreater: Out << "rs"; break;
+ // ::= lS # <<=
+ case OO_LessLessEqual: Out << "lS"; break;
+ // ::= rS # >>=
+ case OO_GreaterGreaterEqual: Out << "rS"; break;
+ // ::= eq # ==
+ case OO_EqualEqual: Out << "eq"; break;
+ // ::= ne # !=
+ case OO_ExclaimEqual: Out << "ne"; break;
+ // ::= lt # <
+ case OO_Less: Out << "lt"; break;
+ // ::= gt # >
+ case OO_Greater: Out << "gt"; break;
+ // ::= le # <=
+ case OO_LessEqual: Out << "le"; break;
+ // ::= ge # >=
+ case OO_GreaterEqual: Out << "ge"; break;
+ // ::= nt # !
+ case OO_Exclaim: Out << "nt"; break;
+ // ::= aa # &&
+ case OO_AmpAmp: Out << "aa"; break;
+ // ::= oo # ||
+ case OO_PipePipe: Out << "oo"; break;
+ // ::= pp # ++
+ case OO_PlusPlus: Out << "pp"; break;
+ // ::= mm # --
+ case OO_MinusMinus: Out << "mm"; break;
+ // ::= cm # ,
+ case OO_Comma: Out << "cm"; break;
+ // ::= pm # ->*
+ case OO_ArrowStar: Out << "pm"; break;
+ // ::= pt # ->
+ case OO_Arrow: Out << "pt"; break;
+ // ::= cl # ()
+ case OO_Call: Out << "cl"; break;
+ // ::= ix # []
+ case OO_Subscript: Out << "ix"; break;
+
+ // ::= qu # ?
+ // The conditional operator can't be overloaded, but we still handle it when
+ // mangling expressions.
+ case OO_Conditional: Out << "qu"; break;
+
+ case OO_None:
+ case NUM_OVERLOADED_OPERATORS:
+ llvm_unreachable("Not an overloaded operator");
+ }
+}
+
+void CXXNameMangler::mangleQualifiers(Qualifiers Quals) {
+ // <CV-qualifiers> ::= [r] [V] [K] # restrict (C99), volatile, const
+ if (Quals.hasRestrict())
+ Out << 'r';
+ if (Quals.hasVolatile())
+ Out << 'V';
+ if (Quals.hasConst())
+ Out << 'K';
+
+ if (Quals.hasAddressSpace()) {
+ // Extension:
+ //
+ // <type> ::= U <address-space-number>
+ //
+ // where <address-space-number> is a source name consisting of 'AS'
+ // followed by the address space <number>.
+ SmallString<64> ASString;
+ ASString = "AS" + llvm::utostr_32(Quals.getAddressSpace());
+ Out << 'U' << ASString.size() << ASString;
+ }
+
+ StringRef LifetimeName;
+ switch (Quals.getObjCLifetime()) {
+ // Objective-C ARC Extension:
+ //
+ // <type> ::= U "__strong"
+ // <type> ::= U "__weak"
+ // <type> ::= U "__autoreleasing"
+ case Qualifiers::OCL_None:
+ break;
+
+ case Qualifiers::OCL_Weak:
+ LifetimeName = "__weak";
+ break;
+
+ case Qualifiers::OCL_Strong:
+ LifetimeName = "__strong";
+ break;
+
+ case Qualifiers::OCL_Autoreleasing:
+ LifetimeName = "__autoreleasing";
+ break;
+
+ case Qualifiers::OCL_ExplicitNone:
+ // The __unsafe_unretained qualifier is *not* mangled, so that
+ // __unsafe_unretained types in ARC produce the same manglings as the
+ // equivalent (but, naturally, unqualified) types in non-ARC, providing
+ // better ABI compatibility.
+ //
+ // It's safe to do this because unqualified 'id' won't show up
+ // in any type signatures that need to be mangled.
+ break;
+ }
+ if (!LifetimeName.empty())
+ Out << 'U' << LifetimeName.size() << LifetimeName;
+}
+
+void CXXNameMangler::mangleRefQualifier(RefQualifierKind RefQualifier) {
+ // <ref-qualifier> ::= R # lvalue reference
+ // ::= O # rvalue-reference
+ // Proposal to Itanium C++ ABI list on 1/26/11
+ switch (RefQualifier) {
+ case RQ_None:
+ break;
+
+ case RQ_LValue:
+ Out << 'R';
+ break;
+
+ case RQ_RValue:
+ Out << 'O';
+ break;
+ }
+}
+
+void CXXNameMangler::mangleObjCMethodName(const ObjCMethodDecl *MD) {
+ Context.mangleObjCMethodName(MD, Out);
+}
+
+void CXXNameMangler::mangleType(QualType T) {
+ // If our type is instantiation-dependent but not dependent, we mangle
+ // it as it was written in the source, removing any top-level sugar.
+ // Otherwise, use the canonical type.
+ //
+ // FIXME: This is an approximation of the instantiation-dependent name
+ // mangling rules, since we should really be using the type as written and
+ // augmented via semantic analysis (i.e., with implicit conversions and
+ // default template arguments) for any instantiation-dependent type.
+ // Unfortunately, that requires several changes to our AST:
+ // - Instantiation-dependent TemplateSpecializationTypes will need to be
+ // uniqued, so that we can handle substitutions properly
+ // - Default template arguments will need to be represented in the
+ // TemplateSpecializationType, since they need to be mangled even though
+ // they aren't written.
+ // - Conversions on non-type template arguments need to be expressed, since
+ // they can affect the mangling of sizeof/alignof.
+ if (!T->isInstantiationDependentType() || T->isDependentType())
+ T = T.getCanonicalType();
+ else {
+ // Desugar any types that are purely sugar.
+ do {
+ // Don't desugar through template specialization types that aren't
+ // type aliases. We need to mangle the template arguments as written.
+ if (const TemplateSpecializationType *TST
+ = dyn_cast<TemplateSpecializationType>(T))
+ if (!TST->isTypeAlias())
+ break;
+
+ QualType Desugared
+ = T.getSingleStepDesugaredType(Context.getASTContext());
+ if (Desugared == T)
+ break;
+
+ T = Desugared;
+ } while (true);
+ }
+ SplitQualType split = T.split();
+ Qualifiers quals = split.Quals;
+ const Type *ty = split.Ty;
+
+ bool isSubstitutable = quals || !isa<BuiltinType>(T);
+ if (isSubstitutable && mangleSubstitution(T))
+ return;
+
+ // If we're mangling a qualified array type, push the qualifiers to
+ // the element type.
+ if (quals && isa<ArrayType>(T)) {
+ ty = Context.getASTContext().getAsArrayType(T);
+ quals = Qualifiers();
+
+ // Note that we don't update T: we want to add the
+ // substitution at the original type.
+ }
+
+ if (quals) {
+ mangleQualifiers(quals);
+ // Recurse: even if the qualified type isn't yet substitutable,
+ // the unqualified type might be.
+ mangleType(QualType(ty, 0));
+ } else {
+ switch (ty->getTypeClass()) {
+#define ABSTRACT_TYPE(CLASS, PARENT)
+#define NON_CANONICAL_TYPE(CLASS, PARENT) \
+ case Type::CLASS: \
+ llvm_unreachable("can't mangle non-canonical type " #CLASS "Type"); \
+ return;
+#define TYPE(CLASS, PARENT) \
+ case Type::CLASS: \
+ mangleType(static_cast<const CLASS##Type*>(ty)); \
+ break;
+#include "clang/AST/TypeNodes.def"
+ }
+ }
+
+ // Add the substitution.
+ if (isSubstitutable)
+ addSubstitution(T);
+}
+
+void CXXNameMangler::mangleNameOrStandardSubstitution(const NamedDecl *ND) {
+ if (!mangleStandardSubstitution(ND))
+ mangleName(ND);
+}
+
+void CXXNameMangler::mangleType(const BuiltinType *T) {
+ // <type> ::= <builtin-type>
+ // <builtin-type> ::= v # void
+ // ::= w # wchar_t
+ // ::= b # bool
+ // ::= c # char
+ // ::= a # signed char
+ // ::= h # unsigned char
+ // ::= s # short
+ // ::= t # unsigned short
+ // ::= i # int
+ // ::= j # unsigned int
+ // ::= l # long
+ // ::= m # unsigned long
+ // ::= x # long long, __int64
+ // ::= y # unsigned long long, __int64
+ // ::= n # __int128
+ // UNSUPPORTED: ::= o # unsigned __int128
+ // ::= f # float
+ // ::= d # double
+ // ::= e # long double, __float80
+ // UNSUPPORTED: ::= g # __float128
+ // UNSUPPORTED: ::= Dd # IEEE 754r decimal floating point (64 bits)
+ // UNSUPPORTED: ::= De # IEEE 754r decimal floating point (128 bits)
+ // UNSUPPORTED: ::= Df # IEEE 754r decimal floating point (32 bits)
+ // ::= Dh # IEEE 754r half-precision floating point (16 bits)
+ // ::= Di # char32_t
+ // ::= Ds # char16_t
+ // ::= Dn # std::nullptr_t (i.e., decltype(nullptr))
+ // ::= u <source-name> # vendor extended type
+ switch (T->getKind()) {
+ case BuiltinType::Void: Out << 'v'; break;
+ case BuiltinType::Bool: Out << 'b'; break;
+ case BuiltinType::Char_U: case BuiltinType::Char_S: Out << 'c'; break;
+ case BuiltinType::UChar: Out << 'h'; break;
+ case BuiltinType::UShort: Out << 't'; break;
+ case BuiltinType::UInt: Out << 'j'; break;
+ case BuiltinType::ULong: Out << 'm'; break;
+ case BuiltinType::ULongLong: Out << 'y'; break;
+ case BuiltinType::UInt128: Out << 'o'; break;
+ case BuiltinType::SChar: Out << 'a'; break;
+ case BuiltinType::WChar_S:
+ case BuiltinType::WChar_U: Out << 'w'; break;
+ case BuiltinType::Char16: Out << "Ds"; break;
+ case BuiltinType::Char32: Out << "Di"; break;
+ case BuiltinType::Short: Out << 's'; break;
+ case BuiltinType::Int: Out << 'i'; break;
+ case BuiltinType::Long: Out << 'l'; break;
+ case BuiltinType::LongLong: Out << 'x'; break;
+ case BuiltinType::Int128: Out << 'n'; break;
+ case BuiltinType::Half: Out << "Dh"; break;
+ case BuiltinType::Float: Out << 'f'; break;
+ case BuiltinType::Double: Out << 'd'; break;
+ case BuiltinType::LongDouble: Out << 'e'; break;
+ case BuiltinType::NullPtr: Out << "Dn"; break;
+
+#define BUILTIN_TYPE(Id, SingletonId)
+#define PLACEHOLDER_TYPE(Id, SingletonId) \
+ case BuiltinType::Id:
+#include "clang/AST/BuiltinTypes.def"
+ case BuiltinType::Dependent:
+ llvm_unreachable("mangling a placeholder type");
+ case BuiltinType::ObjCId: Out << "11objc_object"; break;
+ case BuiltinType::ObjCClass: Out << "10objc_class"; break;
+ case BuiltinType::ObjCSel: Out << "13objc_selector"; break;
+ case BuiltinType::OCLImage1d: Out << "11ocl_image1d"; break;
+ case BuiltinType::OCLImage1dArray: Out << "16ocl_image1darray"; break;
+ case BuiltinType::OCLImage1dBuffer: Out << "17ocl_image1dbuffer"; break;
+ case BuiltinType::OCLImage2d: Out << "11ocl_image2d"; break;
+ case BuiltinType::OCLImage2dArray: Out << "16ocl_image2darray"; break;
+ case BuiltinType::OCLImage3d: Out << "11ocl_image3d"; break;
+ }
+}
+
+// <type> ::= <function-type>
+// <function-type> ::= [<CV-qualifiers>] F [Y]
+// <bare-function-type> [<ref-qualifier>] E
+// (Proposal to cxx-abi-dev, 2012-05-11)
+void CXXNameMangler::mangleType(const FunctionProtoType *T) {
+ // Mangle CV-qualifiers, if present. These are 'this' qualifiers,
+ // e.g. "const" in "int (A::*)() const".
+ mangleQualifiers(Qualifiers::fromCVRMask(T->getTypeQuals()));
+
+ Out << 'F';
+
+ // FIXME: We don't have enough information in the AST to produce the 'Y'
+ // encoding for extern "C" function types.
+ mangleBareFunctionType(T, /*MangleReturnType=*/true);
+
+ // Mangle the ref-qualifier, if present.
+ mangleRefQualifier(T->getRefQualifier());
+
+ Out << 'E';
+}
+void CXXNameMangler::mangleType(const FunctionNoProtoType *T) {
+ llvm_unreachable("Can't mangle K&R function prototypes");
+}
+void CXXNameMangler::mangleBareFunctionType(const FunctionType *T,
+ bool MangleReturnType) {
+ // We should never be mangling something without a prototype.
+ const FunctionProtoType *Proto = cast<FunctionProtoType>(T);
+
+ // Record that we're in a function type. See mangleFunctionParam
+ // for details on what we're trying to achieve here.
+ FunctionTypeDepthState saved = FunctionTypeDepth.push();
+
+ // <bare-function-type> ::= <signature type>+
+ if (MangleReturnType) {
+ FunctionTypeDepth.enterResultType();
+ mangleType(Proto->getResultType());
+ FunctionTypeDepth.leaveResultType();
+ }
+
+ if (Proto->getNumArgs() == 0 && !Proto->isVariadic()) {
+ // <builtin-type> ::= v # void
+ Out << 'v';
+
+ FunctionTypeDepth.pop(saved);
+ return;
+ }
+
+ for (FunctionProtoType::arg_type_iterator Arg = Proto->arg_type_begin(),
+ ArgEnd = Proto->arg_type_end();
+ Arg != ArgEnd; ++Arg)
+ mangleType(Context.getASTContext().getSignatureParameterType(*Arg));
+
+ FunctionTypeDepth.pop(saved);
+
+ // <builtin-type> ::= z # ellipsis
+ if (Proto->isVariadic())
+ Out << 'z';
+}
+
+// <type> ::= <class-enum-type>
+// <class-enum-type> ::= <name>
+void CXXNameMangler::mangleType(const UnresolvedUsingType *T) {
+ mangleName(T->getDecl());
+}
+
+// <type> ::= <class-enum-type>
+// <class-enum-type> ::= <name>
+void CXXNameMangler::mangleType(const EnumType *T) {
+ mangleType(static_cast<const TagType*>(T));
+}
+void CXXNameMangler::mangleType(const RecordType *T) {
+ mangleType(static_cast<const TagType*>(T));
+}
+void CXXNameMangler::mangleType(const TagType *T) {
+ mangleName(T->getDecl());
+}
+
+// <type> ::= <array-type>
+// <array-type> ::= A <positive dimension number> _ <element type>
+// ::= A [<dimension expression>] _ <element type>
+void CXXNameMangler::mangleType(const ConstantArrayType *T) {
+ Out << 'A' << T->getSize() << '_';
+ mangleType(T->getElementType());
+}
+void CXXNameMangler::mangleType(const VariableArrayType *T) {
+ Out << 'A';
+ // decayed vla types (size 0) will just be skipped.
+ if (T->getSizeExpr())
+ mangleExpression(T->getSizeExpr());
+ Out << '_';
+ mangleType(T->getElementType());
+}
+void CXXNameMangler::mangleType(const DependentSizedArrayType *T) {
+ Out << 'A';
+ mangleExpression(T->getSizeExpr());
+ Out << '_';
+ mangleType(T->getElementType());
+}
+void CXXNameMangler::mangleType(const IncompleteArrayType *T) {
+ Out << "A_";
+ mangleType(T->getElementType());
+}
+
+// <type> ::= <pointer-to-member-type>
+// <pointer-to-member-type> ::= M <class type> <member type>
+void CXXNameMangler::mangleType(const MemberPointerType *T) {
+ Out << 'M';
+ mangleType(QualType(T->getClass(), 0));
+ QualType PointeeType = T->getPointeeType();
+ if (const FunctionProtoType *FPT = dyn_cast<FunctionProtoType>(PointeeType)) {
+ mangleType(FPT);
+
+ // Itanium C++ ABI 5.1.8:
+ //
+ // The type of a non-static member function is considered to be different,
+ // for the purposes of substitution, from the type of a namespace-scope or
+ // static member function whose type appears similar. The types of two
+ // non-static member functions are considered to be different, for the
+ // purposes of substitution, if the functions are members of different
+ // classes. In other words, for the purposes of substitution, the class of
+ // which the function is a member is considered part of the type of
+ // function.
+
+ // Given that we already substitute member function pointers as a
+ // whole, the net effect of this rule is just to unconditionally
+ // suppress substitution on the function type in a member pointer.
+ // We increment the SeqID here to emulate adding an entry to the
+ // substitution table.
+ ++SeqID;
+ } else
+ mangleType(PointeeType);
+}
+
+// <type> ::= <template-param>
+void CXXNameMangler::mangleType(const TemplateTypeParmType *T) {
+ mangleTemplateParameter(T->getIndex());
+}
+
+// <type> ::= <template-param>
+void CXXNameMangler::mangleType(const SubstTemplateTypeParmPackType *T) {
+ // FIXME: not clear how to mangle this!
+ // template <class T...> class A {
+ // template <class U...> void foo(T(*)(U) x...);
+ // };
+ Out << "_SUBSTPACK_";
+}
+
+// <type> ::= P <type> # pointer-to
+void CXXNameMangler::mangleType(const PointerType *T) {
+ Out << 'P';
+ mangleType(T->getPointeeType());
+}
+void CXXNameMangler::mangleType(const ObjCObjectPointerType *T) {
+ Out << 'P';
+ mangleType(T->getPointeeType());
+}
+
+// <type> ::= R <type> # reference-to
+void CXXNameMangler::mangleType(const LValueReferenceType *T) {
+ Out << 'R';
+ mangleType(T->getPointeeType());
+}
+
+// <type> ::= O <type> # rvalue reference-to (C++0x)
+void CXXNameMangler::mangleType(const RValueReferenceType *T) {
+ Out << 'O';
+ mangleType(T->getPointeeType());
+}
+
+// <type> ::= C <type> # complex pair (C 2000)
+void CXXNameMangler::mangleType(const ComplexType *T) {
+ Out << 'C';
+ mangleType(T->getElementType());
+}
+
+// ARM's ABI for Neon vector types specifies that they should be mangled as
+// if they are structs (to match ARM's initial implementation). The
+// vector type must be one of the special types predefined by ARM.
+void CXXNameMangler::mangleNeonVectorType(const VectorType *T) {
+ QualType EltType = T->getElementType();
+ assert(EltType->isBuiltinType() && "Neon vector element not a BuiltinType");
+ const char *EltName = 0;
+ if (T->getVectorKind() == VectorType::NeonPolyVector) {
+ switch (cast<BuiltinType>(EltType)->getKind()) {
+ case BuiltinType::SChar: EltName = "poly8_t"; break;
+ case BuiltinType::Short: EltName = "poly16_t"; break;
+ default: llvm_unreachable("unexpected Neon polynomial vector element type");
+ }
+ } else {
+ switch (cast<BuiltinType>(EltType)->getKind()) {
+ case BuiltinType::SChar: EltName = "int8_t"; break;
+ case BuiltinType::UChar: EltName = "uint8_t"; break;
+ case BuiltinType::Short: EltName = "int16_t"; break;
+ case BuiltinType::UShort: EltName = "uint16_t"; break;
+ case BuiltinType::Int: EltName = "int32_t"; break;
+ case BuiltinType::UInt: EltName = "uint32_t"; break;
+ case BuiltinType::LongLong: EltName = "int64_t"; break;
+ case BuiltinType::ULongLong: EltName = "uint64_t"; break;
+ case BuiltinType::Float: EltName = "float32_t"; break;
+ default: llvm_unreachable("unexpected Neon vector element type");
+ }
+ }
+ const char *BaseName = 0;
+ unsigned BitSize = (T->getNumElements() *
+ getASTContext().getTypeSize(EltType));
+ if (BitSize == 64)
+ BaseName = "__simd64_";
+ else {
+ assert(BitSize == 128 && "Neon vector type not 64 or 128 bits");
+ BaseName = "__simd128_";
+ }
+ Out << strlen(BaseName) + strlen(EltName);
+ Out << BaseName << EltName;
+}
+
+// GNU extension: vector types
+// <type> ::= <vector-type>
+// <vector-type> ::= Dv <positive dimension number> _
+// <extended element type>
+// ::= Dv [<dimension expression>] _ <element type>
+// <extended element type> ::= <element type>
+// ::= p # AltiVec vector pixel
+// ::= b # Altivec vector bool
+void CXXNameMangler::mangleType(const VectorType *T) {
+ if ((T->getVectorKind() == VectorType::NeonVector ||
+ T->getVectorKind() == VectorType::NeonPolyVector)) {
+ mangleNeonVectorType(T);
+ return;
+ }
+ Out << "Dv" << T->getNumElements() << '_';
+ if (T->getVectorKind() == VectorType::AltiVecPixel)
+ Out << 'p';
+ else if (T->getVectorKind() == VectorType::AltiVecBool)
+ Out << 'b';
+ else
+ mangleType(T->getElementType());
+}
+void CXXNameMangler::mangleType(const ExtVectorType *T) {
+ mangleType(static_cast<const VectorType*>(T));
+}
+void CXXNameMangler::mangleType(const DependentSizedExtVectorType *T) {
+ Out << "Dv";
+ mangleExpression(T->getSizeExpr());
+ Out << '_';
+ mangleType(T->getElementType());
+}
+
+void CXXNameMangler::mangleType(const PackExpansionType *T) {
+ // <type> ::= Dp <type> # pack expansion (C++0x)
+ Out << "Dp";
+ mangleType(T->getPattern());
+}
+
+void CXXNameMangler::mangleType(const ObjCInterfaceType *T) {
+ mangleSourceName(T->getDecl()->getIdentifier());
+}
+
+void CXXNameMangler::mangleType(const ObjCObjectType *T) {
+ // We don't allow overloading by different protocol qualification,
+ // so mangling them isn't necessary.
+ mangleType(T->getBaseType());
+}
+
+void CXXNameMangler::mangleType(const BlockPointerType *T) {
+ Out << "U13block_pointer";
+ mangleType(T->getPointeeType());
+}
+
+void CXXNameMangler::mangleType(const InjectedClassNameType *T) {
+ // Mangle injected class name types as if the user had written the
+ // specialization out fully. It may not actually be possible to see
+ // this mangling, though.
+ mangleType(T->getInjectedSpecializationType());
+}
+
+void CXXNameMangler::mangleType(const TemplateSpecializationType *T) {
+ if (TemplateDecl *TD = T->getTemplateName().getAsTemplateDecl()) {
+ mangleName(TD, T->getArgs(), T->getNumArgs());
+ } else {
+ if (mangleSubstitution(QualType(T, 0)))
+ return;
+
+ mangleTemplatePrefix(T->getTemplateName());
+
+ // FIXME: GCC does not appear to mangle the template arguments when
+ // the template in question is a dependent template name. Should we
+ // emulate that badness?
+ mangleTemplateArgs(T->getArgs(), T->getNumArgs());
+ addSubstitution(QualType(T, 0));
+ }
+}
+
+void CXXNameMangler::mangleType(const DependentNameType *T) {
+ // Typename types are always nested
+ Out << 'N';
+ manglePrefix(T->getQualifier());
+ mangleSourceName(T->getIdentifier());
+ Out << 'E';
+}
+
+void CXXNameMangler::mangleType(const DependentTemplateSpecializationType *T) {
+ // Dependently-scoped template types are nested if they have a prefix.
+ Out << 'N';
+
+ // TODO: avoid making this TemplateName.
+ TemplateName Prefix =
+ getASTContext().getDependentTemplateName(T->getQualifier(),
+ T->getIdentifier());
+ mangleTemplatePrefix(Prefix);
+
+ // FIXME: GCC does not appear to mangle the template arguments when
+ // the template in question is a dependent template name. Should we
+ // emulate that badness?
+ mangleTemplateArgs(T->getArgs(), T->getNumArgs());
+ Out << 'E';
+}
+
+void CXXNameMangler::mangleType(const TypeOfType *T) {
+ // FIXME: this is pretty unsatisfactory, but there isn't an obvious
+ // "extension with parameters" mangling.
+ Out << "u6typeof";
+}
+
+void CXXNameMangler::mangleType(const TypeOfExprType *T) {
+ // FIXME: this is pretty unsatisfactory, but there isn't an obvious
+ // "extension with parameters" mangling.
+ Out << "u6typeof";
+}
+
+void CXXNameMangler::mangleType(const DecltypeType *T) {
+ Expr *E = T->getUnderlyingExpr();
+
+ // type ::= Dt <expression> E # decltype of an id-expression
+ // # or class member access
+ // ::= DT <expression> E # decltype of an expression
+
+ // This purports to be an exhaustive list of id-expressions and
+ // class member accesses. Note that we do not ignore parentheses;
+ // parentheses change the semantics of decltype for these
+ // expressions (and cause the mangler to use the other form).
+ if (isa<DeclRefExpr>(E) ||
+ isa<MemberExpr>(E) ||
+ isa<UnresolvedLookupExpr>(E) ||
+ isa<DependentScopeDeclRefExpr>(E) ||
+ isa<CXXDependentScopeMemberExpr>(E) ||
+ isa<UnresolvedMemberExpr>(E))
+ Out << "Dt";
+ else
+ Out << "DT";
+ mangleExpression(E);
+ Out << 'E';
+}
+
+void CXXNameMangler::mangleType(const UnaryTransformType *T) {
+ // If this is dependent, we need to record that. If not, we simply
+ // mangle it as the underlying type since they are equivalent.
+ if (T->isDependentType()) {
+ Out << 'U';
+
+ switch (T->getUTTKind()) {
+ case UnaryTransformType::EnumUnderlyingType:
+ Out << "3eut";
+ break;
+ }
+ }
+
+ mangleType(T->getUnderlyingType());
+}
+
+void CXXNameMangler::mangleType(const AutoType *T) {
+ QualType D = T->getDeducedType();
+ // <builtin-type> ::= Da # dependent auto
+ if (D.isNull())
+ Out << "Da";
+ else
+ mangleType(D);
+}
+
+void CXXNameMangler::mangleType(const AtomicType *T) {
+ // <type> ::= U <source-name> <type> # vendor extended type qualifier
+ // (Until there's a standardized mangling...)
+ Out << "U7_Atomic";
+ mangleType(T->getValueType());
+}
+
+void CXXNameMangler::mangleIntegerLiteral(QualType T,
+ const llvm::APSInt &Value) {
+ // <expr-primary> ::= L <type> <value number> E # integer literal
+ Out << 'L';
+
+ mangleType(T);
+ if (T->isBooleanType()) {
+ // Boolean values are encoded as 0/1.
+ Out << (Value.getBoolValue() ? '1' : '0');
+ } else {
+ mangleNumber(Value);
+ }
+ Out << 'E';
+
+}
+
+/// Mangles a member expression.
+void CXXNameMangler::mangleMemberExpr(const Expr *base,
+ bool isArrow,
+ NestedNameSpecifier *qualifier,
+ NamedDecl *firstQualifierLookup,
+ DeclarationName member,
+ unsigned arity) {
+ // <expression> ::= dt <expression> <unresolved-name>
+ // ::= pt <expression> <unresolved-name>
+ if (base) {
+ if (base->isImplicitCXXThis()) {
+ // Note: GCC mangles member expressions to the implicit 'this' as
+ // *this., whereas we represent them as this->. The Itanium C++ ABI
+ // does not specify anything here, so we follow GCC.
+ Out << "dtdefpT";
+ } else {
+ Out << (isArrow ? "pt" : "dt");
+ mangleExpression(base);
+ }
+ }
+ mangleUnresolvedName(qualifier, firstQualifierLookup, member, arity);
+}
+
+/// Look at the callee of the given call expression and determine if
+/// it's a parenthesized id-expression which would have triggered ADL
+/// otherwise.
+static bool isParenthesizedADLCallee(const CallExpr *call) {
+ const Expr *callee = call->getCallee();
+ const Expr *fn = callee->IgnoreParens();
+
+ // Must be parenthesized. IgnoreParens() skips __extension__ nodes,
+ // too, but for those to appear in the callee, it would have to be
+ // parenthesized.
+ if (callee == fn) return false;
+
+ // Must be an unresolved lookup.
+ const UnresolvedLookupExpr *lookup = dyn_cast<UnresolvedLookupExpr>(fn);
+ if (!lookup) return false;
+
+ assert(!lookup->requiresADL());
+
+ // Must be an unqualified lookup.
+ if (lookup->getQualifier()) return false;
+
+ // Must not have found a class member. Note that if one is a class
+ // member, they're all class members.
+ if (lookup->getNumDecls() > 0 &&
+ (*lookup->decls_begin())->isCXXClassMember())
+ return false;
+
+ // Otherwise, ADL would have been triggered.
+ return true;
+}
+
+void CXXNameMangler::mangleExpression(const Expr *E, unsigned Arity) {
+ // <expression> ::= <unary operator-name> <expression>
+ // ::= <binary operator-name> <expression> <expression>
+ // ::= <trinary operator-name> <expression> <expression> <expression>
+ // ::= cv <type> expression # conversion with one argument
+ // ::= cv <type> _ <expression>* E # conversion with a different number of arguments
+ // ::= st <type> # sizeof (a type)
+ // ::= at <type> # alignof (a type)
+ // ::= <template-param>
+ // ::= <function-param>
+ // ::= sr <type> <unqualified-name> # dependent name
+ // ::= sr <type> <unqualified-name> <template-args> # dependent template-id
+ // ::= ds <expression> <expression> # expr.*expr
+ // ::= sZ <template-param> # size of a parameter pack
+ // ::= sZ <function-param> # size of a function parameter pack
+ // ::= <expr-primary>
+ // <expr-primary> ::= L <type> <value number> E # integer literal
+ // ::= L <type <value float> E # floating literal
+ // ::= L <mangled-name> E # external name
+ // ::= fpT # 'this' expression
+ QualType ImplicitlyConvertedToType;
+
+recurse:
+ switch (E->getStmtClass()) {
+ case Expr::NoStmtClass:
+#define ABSTRACT_STMT(Type)
+#define EXPR(Type, Base)
+#define STMT(Type, Base) \
+ case Expr::Type##Class:
+#include "clang/AST/StmtNodes.inc"
+ // fallthrough
+
+ // These all can only appear in local or variable-initialization
+ // contexts and so should never appear in a mangling.
+ case Expr::AddrLabelExprClass:
+ case Expr::DesignatedInitExprClass:
+ case Expr::ImplicitValueInitExprClass:
+ case Expr::ParenListExprClass:
+ case Expr::LambdaExprClass:
+ llvm_unreachable("unexpected statement kind");
+
+ // FIXME: invent manglings for all these.
+ case Expr::BlockExprClass:
+ case Expr::CXXPseudoDestructorExprClass:
+ case Expr::ChooseExprClass:
+ case Expr::CompoundLiteralExprClass:
+ case Expr::ExtVectorElementExprClass:
+ case Expr::GenericSelectionExprClass:
+ case Expr::ObjCEncodeExprClass:
+ case Expr::ObjCIsaExprClass:
+ case Expr::ObjCIvarRefExprClass:
+ case Expr::ObjCMessageExprClass:
+ case Expr::ObjCPropertyRefExprClass:
+ case Expr::ObjCProtocolExprClass:
+ case Expr::ObjCSelectorExprClass:
+ case Expr::ObjCStringLiteralClass:
+ case Expr::ObjCBoxedExprClass:
+ case Expr::ObjCArrayLiteralClass:
+ case Expr::ObjCDictionaryLiteralClass:
+ case Expr::ObjCSubscriptRefExprClass:
+ case Expr::ObjCIndirectCopyRestoreExprClass:
+ case Expr::OffsetOfExprClass:
+ case Expr::PredefinedExprClass:
+ case Expr::ShuffleVectorExprClass:
+ case Expr::StmtExprClass:
+ case Expr::UnaryTypeTraitExprClass:
+ case Expr::BinaryTypeTraitExprClass:
+ case Expr::TypeTraitExprClass:
+ case Expr::ArrayTypeTraitExprClass:
+ case Expr::ExpressionTraitExprClass:
+ case Expr::VAArgExprClass:
+ case Expr::CXXUuidofExprClass:
+ case Expr::CUDAKernelCallExprClass:
+ case Expr::AsTypeExprClass:
+ case Expr::PseudoObjectExprClass:
+ case Expr::AtomicExprClass:
+ {
+ // As bad as this diagnostic is, it's better than crashing.
+ DiagnosticsEngine &Diags = Context.getDiags();
+ unsigned DiagID = Diags.getCustomDiagID(DiagnosticsEngine::Error,
+ "cannot yet mangle expression type %0");
+ Diags.Report(E->getExprLoc(), DiagID)
+ << E->getStmtClassName() << E->getSourceRange();
+ break;
+ }
+
+ // Even gcc-4.5 doesn't mangle this.
+ case Expr::BinaryConditionalOperatorClass: {
+ DiagnosticsEngine &Diags = Context.getDiags();
+ unsigned DiagID =
+ Diags.getCustomDiagID(DiagnosticsEngine::Error,
+ "?: operator with omitted middle operand cannot be mangled");
+ Diags.Report(E->getExprLoc(), DiagID)
+ << E->getStmtClassName() << E->getSourceRange();
+ break;
+ }
+
+ // These are used for internal purposes and cannot be meaningfully mangled.
+ case Expr::OpaqueValueExprClass:
+ llvm_unreachable("cannot mangle opaque value; mangling wrong thing?");
+
+ case Expr::InitListExprClass: {
+ // Proposal by Jason Merrill, 2012-01-03
+ Out << "il";
+ const InitListExpr *InitList = cast<InitListExpr>(E);
+ for (unsigned i = 0, e = InitList->getNumInits(); i != e; ++i)
+ mangleExpression(InitList->getInit(i));
+ Out << "E";
+ break;
+ }
+
+ case Expr::CXXDefaultArgExprClass:
+ mangleExpression(cast<CXXDefaultArgExpr>(E)->getExpr(), Arity);
+ break;
+
+ case Expr::SubstNonTypeTemplateParmExprClass:
+ mangleExpression(cast<SubstNonTypeTemplateParmExpr>(E)->getReplacement(),
+ Arity);
+ break;
+
+ case Expr::UserDefinedLiteralClass:
+ // We follow g++'s approach of mangling a UDL as a call to the literal
+ // operator.
+ case Expr::CXXMemberCallExprClass: // fallthrough
+ case Expr::CallExprClass: {
+ const CallExpr *CE = cast<CallExpr>(E);
+
+ // <expression> ::= cp <simple-id> <expression>* E
+ // We use this mangling only when the call would use ADL except
+ // for being parenthesized. Per discussion with David
+ // Vandervoorde, 2011.04.25.
+ if (isParenthesizedADLCallee(CE)) {
+ Out << "cp";
+ // The callee here is a parenthesized UnresolvedLookupExpr with
+ // no qualifier and should always get mangled as a <simple-id>
+ // anyway.
+
+ // <expression> ::= cl <expression>* E
+ } else {
+ Out << "cl";
+ }
+
+ mangleExpression(CE->getCallee(), CE->getNumArgs());
+ for (unsigned I = 0, N = CE->getNumArgs(); I != N; ++I)
+ mangleExpression(CE->getArg(I));
+ Out << 'E';
+ break;
+ }
+
+ case Expr::CXXNewExprClass: {
+ const CXXNewExpr *New = cast<CXXNewExpr>(E);
+ if (New->isGlobalNew()) Out << "gs";
+ Out << (New->isArray() ? "na" : "nw");
+ for (CXXNewExpr::const_arg_iterator I = New->placement_arg_begin(),
+ E = New->placement_arg_end(); I != E; ++I)
+ mangleExpression(*I);
+ Out << '_';
+ mangleType(New->getAllocatedType());
+ if (New->hasInitializer()) {
+ // Proposal by Jason Merrill, 2012-01-03
+ if (New->getInitializationStyle() == CXXNewExpr::ListInit)
+ Out << "il";
+ else
+ Out << "pi";
+ const Expr *Init = New->getInitializer();
+ if (const CXXConstructExpr *CCE = dyn_cast<CXXConstructExpr>(Init)) {
+ // Directly inline the initializers.
+ for (CXXConstructExpr::const_arg_iterator I = CCE->arg_begin(),
+ E = CCE->arg_end();
+ I != E; ++I)
+ mangleExpression(*I);
+ } else if (const ParenListExpr *PLE = dyn_cast<ParenListExpr>(Init)) {
+ for (unsigned i = 0, e = PLE->getNumExprs(); i != e; ++i)
+ mangleExpression(PLE->getExpr(i));
+ } else if (New->getInitializationStyle() == CXXNewExpr::ListInit &&
+ isa<InitListExpr>(Init)) {
+ // Only take InitListExprs apart for list-initialization.
+ const InitListExpr *InitList = cast<InitListExpr>(Init);
+ for (unsigned i = 0, e = InitList->getNumInits(); i != e; ++i)
+ mangleExpression(InitList->getInit(i));
+ } else
+ mangleExpression(Init);
+ }
+ Out << 'E';
+ break;
+ }
+
+ case Expr::MemberExprClass: {
+ const MemberExpr *ME = cast<MemberExpr>(E);
+ mangleMemberExpr(ME->getBase(), ME->isArrow(),
+ ME->getQualifier(), 0, ME->getMemberDecl()->getDeclName(),
+ Arity);
+ break;
+ }
+
+ case Expr::UnresolvedMemberExprClass: {
+ const UnresolvedMemberExpr *ME = cast<UnresolvedMemberExpr>(E);
+ mangleMemberExpr(ME->getBase(), ME->isArrow(),
+ ME->getQualifier(), 0, ME->getMemberName(),
+ Arity);
+ if (ME->hasExplicitTemplateArgs())
+ mangleTemplateArgs(ME->getExplicitTemplateArgs());
+ break;
+ }
+
+ case Expr::CXXDependentScopeMemberExprClass: {
+ const CXXDependentScopeMemberExpr *ME
+ = cast<CXXDependentScopeMemberExpr>(E);
+ mangleMemberExpr(ME->getBase(), ME->isArrow(),
+ ME->getQualifier(), ME->getFirstQualifierFoundInScope(),
+ ME->getMember(), Arity);
+ if (ME->hasExplicitTemplateArgs())
+ mangleTemplateArgs(ME->getExplicitTemplateArgs());
+ break;
+ }
+
+ case Expr::UnresolvedLookupExprClass: {
+ const UnresolvedLookupExpr *ULE = cast<UnresolvedLookupExpr>(E);
+ mangleUnresolvedName(ULE->getQualifier(), 0, ULE->getName(), Arity);
+
+ // All the <unresolved-name> productions end in a
+ // base-unresolved-name, where <template-args> are just tacked
+ // onto the end.
+ if (ULE->hasExplicitTemplateArgs())
+ mangleTemplateArgs(ULE->getExplicitTemplateArgs());
+ break;
+ }
+
+ case Expr::CXXUnresolvedConstructExprClass: {
+ const CXXUnresolvedConstructExpr *CE = cast<CXXUnresolvedConstructExpr>(E);
+ unsigned N = CE->arg_size();
+
+ Out << "cv";
+ mangleType(CE->getType());
+ if (N != 1) Out << '_';
+ for (unsigned I = 0; I != N; ++I) mangleExpression(CE->getArg(I));
+ if (N != 1) Out << 'E';
+ break;
+ }
+
+ case Expr::CXXTemporaryObjectExprClass:
+ case Expr::CXXConstructExprClass: {
+ const CXXConstructExpr *CE = cast<CXXConstructExpr>(E);
+ unsigned N = CE->getNumArgs();
+
+ // Proposal by Jason Merrill, 2012-01-03
+ if (CE->isListInitialization())
+ Out << "tl";
+ else
+ Out << "cv";
+ mangleType(CE->getType());
+ if (N != 1) Out << '_';
+ for (unsigned I = 0; I != N; ++I) mangleExpression(CE->getArg(I));
+ if (N != 1) Out << 'E';
+ break;
+ }
+
+ case Expr::CXXScalarValueInitExprClass:
+ Out <<"cv";
+ mangleType(E->getType());
+ Out <<"_E";
+ break;
+
+ case Expr::CXXNoexceptExprClass:
+ Out << "nx";
+ mangleExpression(cast<CXXNoexceptExpr>(E)->getOperand());
+ break;
+
+ case Expr::UnaryExprOrTypeTraitExprClass: {
+ const UnaryExprOrTypeTraitExpr *SAE = cast<UnaryExprOrTypeTraitExpr>(E);
+
+ if (!SAE->isInstantiationDependent()) {
+ // Itanium C++ ABI:
+ // If the operand of a sizeof or alignof operator is not
+ // instantiation-dependent it is encoded as an integer literal
+ // reflecting the result of the operator.
+ //
+ // If the result of the operator is implicitly converted to a known
+ // integer type, that type is used for the literal; otherwise, the type
+ // of std::size_t or std::ptrdiff_t is used.
+ QualType T = (ImplicitlyConvertedToType.isNull() ||
+ !ImplicitlyConvertedToType->isIntegerType())? SAE->getType()
+ : ImplicitlyConvertedToType;
+ llvm::APSInt V = SAE->EvaluateKnownConstInt(Context.getASTContext());
+ mangleIntegerLiteral(T, V);
+ break;
+ }
+
+ switch(SAE->getKind()) {
+ case UETT_SizeOf:
+ Out << 's';
+ break;
+ case UETT_AlignOf:
+ Out << 'a';
+ break;
+ case UETT_VecStep:
+ DiagnosticsEngine &Diags = Context.getDiags();
+ unsigned DiagID = Diags.getCustomDiagID(DiagnosticsEngine::Error,
+ "cannot yet mangle vec_step expression");
+ Diags.Report(DiagID);
+ return;
+ }
+ if (SAE->isArgumentType()) {
+ Out << 't';
+ mangleType(SAE->getArgumentType());
+ } else {
+ Out << 'z';
+ mangleExpression(SAE->getArgumentExpr());
+ }
+ break;
+ }
+
+ case Expr::CXXThrowExprClass: {
+ const CXXThrowExpr *TE = cast<CXXThrowExpr>(E);
+
+ // Proposal from David Vandervoorde, 2010.06.30
+ if (TE->getSubExpr()) {
+ Out << "tw";
+ mangleExpression(TE->getSubExpr());
+ } else {
+ Out << "tr";
+ }
+ break;
+ }
+
+ case Expr::CXXTypeidExprClass: {
+ const CXXTypeidExpr *TIE = cast<CXXTypeidExpr>(E);
+
+ // Proposal from David Vandervoorde, 2010.06.30
+ if (TIE->isTypeOperand()) {
+ Out << "ti";
+ mangleType(TIE->getTypeOperand());
+ } else {
+ Out << "te";
+ mangleExpression(TIE->getExprOperand());
+ }
+ break;
+ }
+
+ case Expr::CXXDeleteExprClass: {
+ const CXXDeleteExpr *DE = cast<CXXDeleteExpr>(E);
+
+ // Proposal from David Vandervoorde, 2010.06.30
+ if (DE->isGlobalDelete()) Out << "gs";
+ Out << (DE->isArrayForm() ? "da" : "dl");
+ mangleExpression(DE->getArgument());
+ break;
+ }
+
+ case Expr::UnaryOperatorClass: {
+ const UnaryOperator *UO = cast<UnaryOperator>(E);
+ mangleOperatorName(UnaryOperator::getOverloadedOperator(UO->getOpcode()),
+ /*Arity=*/1);
+ mangleExpression(UO->getSubExpr());
+ break;
+ }
+
+ case Expr::ArraySubscriptExprClass: {
+ const ArraySubscriptExpr *AE = cast<ArraySubscriptExpr>(E);
+
+ // Array subscript is treated as a syntactically weird form of
+ // binary operator.
+ Out << "ix";
+ mangleExpression(AE->getLHS());
+ mangleExpression(AE->getRHS());
+ break;
+ }
+
+ case Expr::CompoundAssignOperatorClass: // fallthrough
+ case Expr::BinaryOperatorClass: {
+ const BinaryOperator *BO = cast<BinaryOperator>(E);
+ if (BO->getOpcode() == BO_PtrMemD)
+ Out << "ds";
+ else
+ mangleOperatorName(BinaryOperator::getOverloadedOperator(BO->getOpcode()),
+ /*Arity=*/2);
+ mangleExpression(BO->getLHS());
+ mangleExpression(BO->getRHS());
+ break;
+ }
+
+ case Expr::ConditionalOperatorClass: {
+ const ConditionalOperator *CO = cast<ConditionalOperator>(E);
+ mangleOperatorName(OO_Conditional, /*Arity=*/3);
+ mangleExpression(CO->getCond());
+ mangleExpression(CO->getLHS(), Arity);
+ mangleExpression(CO->getRHS(), Arity);
+ break;
+ }
+
+ case Expr::ImplicitCastExprClass: {
+ ImplicitlyConvertedToType = E->getType();
+ E = cast<ImplicitCastExpr>(E)->getSubExpr();
+ goto recurse;
+ }
+
+ case Expr::ObjCBridgedCastExprClass: {
+ // Mangle ownership casts as a vendor extended operator __bridge,
+ // __bridge_transfer, or __bridge_retain.
+ StringRef Kind = cast<ObjCBridgedCastExpr>(E)->getBridgeKindName();
+ Out << "v1U" << Kind.size() << Kind;
+ }
+ // Fall through to mangle the cast itself.
+
+ case Expr::CStyleCastExprClass:
+ case Expr::CXXStaticCastExprClass:
+ case Expr::CXXDynamicCastExprClass:
+ case Expr::CXXReinterpretCastExprClass:
+ case Expr::CXXConstCastExprClass:
+ case Expr::CXXFunctionalCastExprClass: {
+ const ExplicitCastExpr *ECE = cast<ExplicitCastExpr>(E);
+ Out << "cv";
+ mangleType(ECE->getType());
+ mangleExpression(ECE->getSubExpr());
+ break;
+ }
+
+ case Expr::CXXOperatorCallExprClass: {
+ const CXXOperatorCallExpr *CE = cast<CXXOperatorCallExpr>(E);
+ unsigned NumArgs = CE->getNumArgs();
+ mangleOperatorName(CE->getOperator(), /*Arity=*/NumArgs);
+ // Mangle the arguments.
+ for (unsigned i = 0; i != NumArgs; ++i)
+ mangleExpression(CE->getArg(i));
+ break;
+ }
+
+ case Expr::ParenExprClass:
+ mangleExpression(cast<ParenExpr>(E)->getSubExpr(), Arity);
+ break;
+
+ case Expr::DeclRefExprClass: {
+ const NamedDecl *D = cast<DeclRefExpr>(E)->getDecl();
+
+ switch (D->getKind()) {
+ default:
+ // <expr-primary> ::= L <mangled-name> E # external name
+ Out << 'L';
+ mangle(D, "_Z");
+ Out << 'E';
+ break;
+
+ case Decl::ParmVar:
+ mangleFunctionParam(cast<ParmVarDecl>(D));
+ break;
+
+ case Decl::EnumConstant: {
+ const EnumConstantDecl *ED = cast<EnumConstantDecl>(D);
+ mangleIntegerLiteral(ED->getType(), ED->getInitVal());
+ break;
+ }
+
+ case Decl::NonTypeTemplateParm: {
+ const NonTypeTemplateParmDecl *PD = cast<NonTypeTemplateParmDecl>(D);
+ mangleTemplateParameter(PD->getIndex());
+ break;
+ }
+
+ }
+
+ break;
+ }
+
+ case Expr::SubstNonTypeTemplateParmPackExprClass:
+ // FIXME: not clear how to mangle this!
+ // template <unsigned N...> class A {
+ // template <class U...> void foo(U (&x)[N]...);
+ // };
+ Out << "_SUBSTPACK_";
+ break;
+
+ case Expr::FunctionParmPackExprClass: {
+ // FIXME: not clear how to mangle this!
+ const FunctionParmPackExpr *FPPE = cast<FunctionParmPackExpr>(E);
+ Out << "v110_SUBSTPACK";
+ mangleFunctionParam(FPPE->getParameterPack());
+ break;
+ }
+
+ case Expr::DependentScopeDeclRefExprClass: {
+ const DependentScopeDeclRefExpr *DRE = cast<DependentScopeDeclRefExpr>(E);
+ mangleUnresolvedName(DRE->getQualifier(), 0, DRE->getDeclName(), Arity);
+
+ // All the <unresolved-name> productions end in a
+ // base-unresolved-name, where <template-args> are just tacked
+ // onto the end.
+ if (DRE->hasExplicitTemplateArgs())
+ mangleTemplateArgs(DRE->getExplicitTemplateArgs());
+ break;
+ }
+
+ case Expr::CXXBindTemporaryExprClass:
+ mangleExpression(cast<CXXBindTemporaryExpr>(E)->getSubExpr());
+ break;
+
+ case Expr::ExprWithCleanupsClass:
+ mangleExpression(cast<ExprWithCleanups>(E)->getSubExpr(), Arity);
+ break;
+
+ case Expr::FloatingLiteralClass: {
+ const FloatingLiteral *FL = cast<FloatingLiteral>(E);
+ Out << 'L';
+ mangleType(FL->getType());
+ mangleFloat(FL->getValue());
+ Out << 'E';
+ break;
+ }
+
+ case Expr::CharacterLiteralClass:
+ Out << 'L';
+ mangleType(E->getType());
+ Out << cast<CharacterLiteral>(E)->getValue();
+ Out << 'E';
+ break;
+
+ // FIXME. __objc_yes/__objc_no are mangled same as true/false
+ case Expr::ObjCBoolLiteralExprClass:
+ Out << "Lb";
+ Out << (cast<ObjCBoolLiteralExpr>(E)->getValue() ? '1' : '0');
+ Out << 'E';
+ break;
+
+ case Expr::CXXBoolLiteralExprClass:
+ Out << "Lb";
+ Out << (cast<CXXBoolLiteralExpr>(E)->getValue() ? '1' : '0');
+ Out << 'E';
+ break;
+
+ case Expr::IntegerLiteralClass: {
+ llvm::APSInt Value(cast<IntegerLiteral>(E)->getValue());
+ if (E->getType()->isSignedIntegerType())
+ Value.setIsSigned(true);
+ mangleIntegerLiteral(E->getType(), Value);
+ break;
+ }
+
+ case Expr::ImaginaryLiteralClass: {
+ const ImaginaryLiteral *IE = cast<ImaginaryLiteral>(E);
+ // Mangle as if a complex literal.
+ // Proposal from David Vandevoorde, 2010.06.30.
+ Out << 'L';
+ mangleType(E->getType());
+ if (const FloatingLiteral *Imag =
+ dyn_cast<FloatingLiteral>(IE->getSubExpr())) {
+ // Mangle a floating-point zero of the appropriate type.
+ mangleFloat(llvm::APFloat(Imag->getValue().getSemantics()));
+ Out << '_';
+ mangleFloat(Imag->getValue());
+ } else {
+ Out << "0_";
+ llvm::APSInt Value(cast<IntegerLiteral>(IE->getSubExpr())->getValue());
+ if (IE->getSubExpr()->getType()->isSignedIntegerType())
+ Value.setIsSigned(true);
+ mangleNumber(Value);
+ }
+ Out << 'E';
+ break;
+ }
+
+ case Expr::StringLiteralClass: {
+ // Revised proposal from David Vandervoorde, 2010.07.15.
+ Out << 'L';
+ assert(isa<ConstantArrayType>(E->getType()));
+ mangleType(E->getType());
+ Out << 'E';
+ break;
+ }
+
+ case Expr::GNUNullExprClass:
+ // FIXME: should this really be mangled the same as nullptr?
+ // fallthrough
+
+ case Expr::CXXNullPtrLiteralExprClass: {
+ // Proposal from David Vandervoorde, 2010.06.30, as
+ // modified by ABI list discussion.
+ Out << "LDnE";
+ break;
+ }
+
+ case Expr::PackExpansionExprClass:
+ Out << "sp";
+ mangleExpression(cast<PackExpansionExpr>(E)->getPattern());
+ break;
+
+ case Expr::SizeOfPackExprClass: {
+ Out << "sZ";
+ const NamedDecl *Pack = cast<SizeOfPackExpr>(E)->getPack();
+ if (const TemplateTypeParmDecl *TTP = dyn_cast<TemplateTypeParmDecl>(Pack))
+ mangleTemplateParameter(TTP->getIndex());
+ else if (const NonTypeTemplateParmDecl *NTTP
+ = dyn_cast<NonTypeTemplateParmDecl>(Pack))
+ mangleTemplateParameter(NTTP->getIndex());
+ else if (const TemplateTemplateParmDecl *TempTP
+ = dyn_cast<TemplateTemplateParmDecl>(Pack))
+ mangleTemplateParameter(TempTP->getIndex());
+ else
+ mangleFunctionParam(cast<ParmVarDecl>(Pack));
+ break;
+ }
+
+ case Expr::MaterializeTemporaryExprClass: {
+ mangleExpression(cast<MaterializeTemporaryExpr>(E)->GetTemporaryExpr());
+ break;
+ }
+
+ case Expr::CXXThisExprClass:
+ Out << "fpT";
+ break;
+ }
+}
+
+/// Mangle an expression which refers to a parameter variable.
+///
+/// <expression> ::= <function-param>
+/// <function-param> ::= fp <top-level CV-qualifiers> _ # L == 0, I == 0
+/// <function-param> ::= fp <top-level CV-qualifiers>
+/// <parameter-2 non-negative number> _ # L == 0, I > 0
+/// <function-param> ::= fL <L-1 non-negative number>
+/// p <top-level CV-qualifiers> _ # L > 0, I == 0
+/// <function-param> ::= fL <L-1 non-negative number>
+/// p <top-level CV-qualifiers>
+/// <I-1 non-negative number> _ # L > 0, I > 0
+///
+/// L is the nesting depth of the parameter, defined as 1 if the
+/// parameter comes from the innermost function prototype scope
+/// enclosing the current context, 2 if from the next enclosing
+/// function prototype scope, and so on, with one special case: if
+/// we've processed the full parameter clause for the innermost
+/// function type, then L is one less. This definition conveniently
+/// makes it irrelevant whether a function's result type was written
+/// trailing or leading, but is otherwise overly complicated; the
+/// numbering was first designed without considering references to
+/// parameter in locations other than return types, and then the
+/// mangling had to be generalized without changing the existing
+/// manglings.
+///
+/// I is the zero-based index of the parameter within its parameter
+/// declaration clause. Note that the original ABI document describes
+/// this using 1-based ordinals.
+void CXXNameMangler::mangleFunctionParam(const ParmVarDecl *parm) {
+ unsigned parmDepth = parm->getFunctionScopeDepth();
+ unsigned parmIndex = parm->getFunctionScopeIndex();
+
+ // Compute 'L'.
+ // parmDepth does not include the declaring function prototype.
+ // FunctionTypeDepth does account for that.
+ assert(parmDepth < FunctionTypeDepth.getDepth());
+ unsigned nestingDepth = FunctionTypeDepth.getDepth() - parmDepth;
+ if (FunctionTypeDepth.isInResultType())
+ nestingDepth--;
+
+ if (nestingDepth == 0) {
+ Out << "fp";
+ } else {
+ Out << "fL" << (nestingDepth - 1) << 'p';
+ }
+
+ // Top-level qualifiers. We don't have to worry about arrays here,
+ // because parameters declared as arrays should already have been
+ // transformed to have pointer type. FIXME: apparently these don't
+ // get mangled if used as an rvalue of a known non-class type?
+ assert(!parm->getType()->isArrayType()
+ && "parameter's type is still an array type?");
+ mangleQualifiers(parm->getType().getQualifiers());
+
+ // Parameter index.
+ if (parmIndex != 0) {
+ Out << (parmIndex - 1);
+ }
+ Out << '_';
+}
+
+void CXXNameMangler::mangleCXXCtorType(CXXCtorType T) {
+ // <ctor-dtor-name> ::= C1 # complete object constructor
+ // ::= C2 # base object constructor
+ // ::= C3 # complete object allocating constructor
+ //
+ switch (T) {
+ case Ctor_Complete:
+ Out << "C1";
+ break;
+ case Ctor_Base:
+ Out << "C2";
+ break;
+ case Ctor_CompleteAllocating:
+ Out << "C3";
+ break;
+ }
+}
+
+void CXXNameMangler::mangleCXXDtorType(CXXDtorType T) {
+ // <ctor-dtor-name> ::= D0 # deleting destructor
+ // ::= D1 # complete object destructor
+ // ::= D2 # base object destructor
+ //
+ switch (T) {
+ case Dtor_Deleting:
+ Out << "D0";
+ break;
+ case Dtor_Complete:
+ Out << "D1";
+ break;
+ case Dtor_Base:
+ Out << "D2";
+ break;
+ }
+}
+
+void CXXNameMangler::mangleTemplateArgs(
+ const ASTTemplateArgumentListInfo &TemplateArgs) {
+ // <template-args> ::= I <template-arg>+ E
+ Out << 'I';
+ for (unsigned i = 0, e = TemplateArgs.NumTemplateArgs; i != e; ++i)
+ mangleTemplateArg(TemplateArgs.getTemplateArgs()[i].getArgument());
+ Out << 'E';
+}
+
+void CXXNameMangler::mangleTemplateArgs(const TemplateArgumentList &AL) {
+ // <template-args> ::= I <template-arg>+ E
+ Out << 'I';
+ for (unsigned i = 0, e = AL.size(); i != e; ++i)
+ mangleTemplateArg(AL[i]);
+ Out << 'E';
+}
+
+void CXXNameMangler::mangleTemplateArgs(const TemplateArgument *TemplateArgs,
+ unsigned NumTemplateArgs) {
+ // <template-args> ::= I <template-arg>+ E
+ Out << 'I';
+ for (unsigned i = 0; i != NumTemplateArgs; ++i)
+ mangleTemplateArg(TemplateArgs[i]);
+ Out << 'E';
+}
+
+void CXXNameMangler::mangleTemplateArg(TemplateArgument A) {
+ // <template-arg> ::= <type> # type or template
+ // ::= X <expression> E # expression
+ // ::= <expr-primary> # simple expressions
+ // ::= J <template-arg>* E # argument pack
+ // ::= sp <expression> # pack expansion of (C++0x)
+ if (!A.isInstantiationDependent() || A.isDependent())
+ A = Context.getASTContext().getCanonicalTemplateArgument(A);
+
+ switch (A.getKind()) {
+ case TemplateArgument::Null:
+ llvm_unreachable("Cannot mangle NULL template argument");
+
+ case TemplateArgument::Type:
+ mangleType(A.getAsType());
+ break;
+ case TemplateArgument::Template:
+ // This is mangled as <type>.
+ mangleType(A.getAsTemplate());
+ break;
+ case TemplateArgument::TemplateExpansion:
+ // <type> ::= Dp <type> # pack expansion (C++0x)
+ Out << "Dp";
+ mangleType(A.getAsTemplateOrTemplatePattern());
+ break;
+ case TemplateArgument::Expression: {
+ // It's possible to end up with a DeclRefExpr here in certain
+ // dependent cases, in which case we should mangle as a
+ // declaration.
+ const Expr *E = A.getAsExpr()->IgnoreParens();
+ if (const DeclRefExpr *DRE = dyn_cast<DeclRefExpr>(E)) {
+ const ValueDecl *D = DRE->getDecl();
+ if (isa<VarDecl>(D) || isa<FunctionDecl>(D)) {
+ Out << "L";
+ mangle(D, "_Z");
+ Out << 'E';
+ break;
+ }
+ }
+
+ Out << 'X';
+ mangleExpression(E);
+ Out << 'E';
+ break;
+ }
+ case TemplateArgument::Integral:
+ mangleIntegerLiteral(A.getIntegralType(), A.getAsIntegral());
+ break;
+ case TemplateArgument::Declaration: {
+ // <expr-primary> ::= L <mangled-name> E # external name
+ // Clang produces AST's where pointer-to-member-function expressions
+ // and pointer-to-function expressions are represented as a declaration not
+ // an expression. We compensate for it here to produce the correct mangling.
+ ValueDecl *D = A.getAsDecl();
+ bool compensateMangling = !A.isDeclForReferenceParam();
+ if (compensateMangling) {
+ Out << 'X';
+ mangleOperatorName(OO_Amp, 1);
+ }
+
+ Out << 'L';
+ // References to external entities use the mangled name; if the name would
+ // not normally be manged then mangle it as unqualified.
+ //
+ // FIXME: The ABI specifies that external names here should have _Z, but
+ // gcc leaves this off.
+ if (compensateMangling)
+ mangle(D, "_Z");
+ else
+ mangle(D, "Z");
+ Out << 'E';
+
+ if (compensateMangling)
+ Out << 'E';
+
+ break;
+ }
+ case TemplateArgument::NullPtr: {
+ // <expr-primary> ::= L <type> 0 E
+ Out << 'L';
+ mangleType(A.getNullPtrType());
+ Out << "0E";
+ break;
+ }
+ case TemplateArgument::Pack: {
+ // Note: proposal by Mike Herrick on 12/20/10
+ Out << 'J';
+ for (TemplateArgument::pack_iterator PA = A.pack_begin(),
+ PAEnd = A.pack_end();
+ PA != PAEnd; ++PA)
+ mangleTemplateArg(*PA);
+ Out << 'E';
+ }
+ }
+}
+
+void CXXNameMangler::mangleTemplateParameter(unsigned Index) {
+ // <template-param> ::= T_ # first template parameter
+ // ::= T <parameter-2 non-negative number> _
+ if (Index == 0)
+ Out << "T_";
+ else
+ Out << 'T' << (Index - 1) << '_';
+}
+
+void CXXNameMangler::mangleExistingSubstitution(QualType type) {
+ bool result = mangleSubstitution(type);
+ assert(result && "no existing substitution for type");
+ (void) result;
+}
+
+void CXXNameMangler::mangleExistingSubstitution(TemplateName tname) {
+ bool result = mangleSubstitution(tname);
+ assert(result && "no existing substitution for template name");
+ (void) result;
+}
+
+// <substitution> ::= S <seq-id> _
+// ::= S_
+bool CXXNameMangler::mangleSubstitution(const NamedDecl *ND) {
+ // Try one of the standard substitutions first.
+ if (mangleStandardSubstitution(ND))
+ return true;
+
+ ND = cast<NamedDecl>(ND->getCanonicalDecl());
+ return mangleSubstitution(reinterpret_cast<uintptr_t>(ND));
+}
+
+/// \brief Determine whether the given type has any qualifiers that are
+/// relevant for substitutions.
+static bool hasMangledSubstitutionQualifiers(QualType T) {
+ Qualifiers Qs = T.getQualifiers();
+ return Qs.getCVRQualifiers() || Qs.hasAddressSpace();
+}
+
+bool CXXNameMangler::mangleSubstitution(QualType T) {
+ if (!hasMangledSubstitutionQualifiers(T)) {
+ if (const RecordType *RT = T->getAs<RecordType>())
+ return mangleSubstitution(RT->getDecl());
+ }
+
+ uintptr_t TypePtr = reinterpret_cast<uintptr_t>(T.getAsOpaquePtr());
+
+ return mangleSubstitution(TypePtr);
+}
+
+bool CXXNameMangler::mangleSubstitution(TemplateName Template) {
+ if (TemplateDecl *TD = Template.getAsTemplateDecl())
+ return mangleSubstitution(TD);
+
+ Template = Context.getASTContext().getCanonicalTemplateName(Template);
+ return mangleSubstitution(
+ reinterpret_cast<uintptr_t>(Template.getAsVoidPointer()));
+}
+
+bool CXXNameMangler::mangleSubstitution(uintptr_t Ptr) {
+ llvm::DenseMap<uintptr_t, unsigned>::iterator I = Substitutions.find(Ptr);
+ if (I == Substitutions.end())
+ return false;
+
+ unsigned SeqID = I->second;
+ if (SeqID == 0)
+ Out << "S_";
+ else {
+ SeqID--;
+
+ // <seq-id> is encoded in base-36, using digits and upper case letters.
+ char Buffer[10];
+ char *BufferPtr = llvm::array_endof(Buffer);
+
+ if (SeqID == 0) *--BufferPtr = '0';
+
+ while (SeqID) {
+ assert(BufferPtr > Buffer && "Buffer overflow!");
+
+ char c = static_cast<char>(SeqID % 36);
+
+ *--BufferPtr = (c < 10 ? '0' + c : 'A' + c - 10);
+ SeqID /= 36;
+ }
+
+ Out << 'S'
+ << StringRef(BufferPtr, llvm::array_endof(Buffer)-BufferPtr)
+ << '_';
+ }
+
+ return true;
+}
+
+static bool isCharType(QualType T) {
+ if (T.isNull())
+ return false;
+
+ return T->isSpecificBuiltinType(BuiltinType::Char_S) ||
+ T->isSpecificBuiltinType(BuiltinType::Char_U);
+}
+
+/// isCharSpecialization - Returns whether a given type is a template
+/// specialization of a given name with a single argument of type char.
+static bool isCharSpecialization(QualType T, const char *Name) {
+ if (T.isNull())
+ return false;
+
+ const RecordType *RT = T->getAs<RecordType>();
+ if (!RT)
+ return false;
+
+ const ClassTemplateSpecializationDecl *SD =
+ dyn_cast<ClassTemplateSpecializationDecl>(RT->getDecl());
+ if (!SD)
+ return false;
+
+ if (!isStdNamespace(getEffectiveDeclContext(SD)))
+ return false;
+
+ const TemplateArgumentList &TemplateArgs = SD->getTemplateArgs();
+ if (TemplateArgs.size() != 1)
+ return false;
+
+ if (!isCharType(TemplateArgs[0].getAsType()))
+ return false;
+
+ return SD->getIdentifier()->getName() == Name;
+}
+
+template <std::size_t StrLen>
+static bool isStreamCharSpecialization(const ClassTemplateSpecializationDecl*SD,
+ const char (&Str)[StrLen]) {
+ if (!SD->getIdentifier()->isStr(Str))
+ return false;
+
+ const TemplateArgumentList &TemplateArgs = SD->getTemplateArgs();
+ if (TemplateArgs.size() != 2)
+ return false;
+
+ if (!isCharType(TemplateArgs[0].getAsType()))
+ return false;
+
+ if (!isCharSpecialization(TemplateArgs[1].getAsType(), "char_traits"))
+ return false;
+
+ return true;
+}
+
+bool CXXNameMangler::mangleStandardSubstitution(const NamedDecl *ND) {
+ // <substitution> ::= St # ::std::
+ if (const NamespaceDecl *NS = dyn_cast<NamespaceDecl>(ND)) {
+ if (isStd(NS)) {
+ Out << "St";
+ return true;
+ }
+ }
+
+ if (const ClassTemplateDecl *TD = dyn_cast<ClassTemplateDecl>(ND)) {
+ if (!isStdNamespace(getEffectiveDeclContext(TD)))
+ return false;
+
+ // <substitution> ::= Sa # ::std::allocator
+ if (TD->getIdentifier()->isStr("allocator")) {
+ Out << "Sa";
+ return true;
+ }
+
+ // <<substitution> ::= Sb # ::std::basic_string
+ if (TD->getIdentifier()->isStr("basic_string")) {
+ Out << "Sb";
+ return true;
+ }
+ }
+
+ if (const ClassTemplateSpecializationDecl *SD =
+ dyn_cast<ClassTemplateSpecializationDecl>(ND)) {
+ if (!isStdNamespace(getEffectiveDeclContext(SD)))
+ return false;
+
+ // <substitution> ::= Ss # ::std::basic_string<char,
+ // ::std::char_traits<char>,
+ // ::std::allocator<char> >
+ if (SD->getIdentifier()->isStr("basic_string")) {
+ const TemplateArgumentList &TemplateArgs = SD->getTemplateArgs();
+
+ if (TemplateArgs.size() != 3)
+ return false;
+
+ if (!isCharType(TemplateArgs[0].getAsType()))
+ return false;
+
+ if (!isCharSpecialization(TemplateArgs[1].getAsType(), "char_traits"))
+ return false;
+
+ if (!isCharSpecialization(TemplateArgs[2].getAsType(), "allocator"))
+ return false;
+
+ Out << "Ss";
+ return true;
+ }
+
+ // <substitution> ::= Si # ::std::basic_istream<char,
+ // ::std::char_traits<char> >
+ if (isStreamCharSpecialization(SD, "basic_istream")) {
+ Out << "Si";
+ return true;
+ }
+
+ // <substitution> ::= So # ::std::basic_ostream<char,
+ // ::std::char_traits<char> >
+ if (isStreamCharSpecialization(SD, "basic_ostream")) {
+ Out << "So";
+ return true;
+ }
+
+ // <substitution> ::= Sd # ::std::basic_iostream<char,
+ // ::std::char_traits<char> >
+ if (isStreamCharSpecialization(SD, "basic_iostream")) {
+ Out << "Sd";
+ return true;
+ }
+ }
+ return false;
+}
+
+void CXXNameMangler::addSubstitution(QualType T) {
+ if (!hasMangledSubstitutionQualifiers(T)) {
+ if (const RecordType *RT = T->getAs<RecordType>()) {
+ addSubstitution(RT->getDecl());
+ return;
+ }
+ }
+
+ uintptr_t TypePtr = reinterpret_cast<uintptr_t>(T.getAsOpaquePtr());
+ addSubstitution(TypePtr);
+}
+
+void CXXNameMangler::addSubstitution(TemplateName Template) {
+ if (TemplateDecl *TD = Template.getAsTemplateDecl())
+ return addSubstitution(TD);
+
+ Template = Context.getASTContext().getCanonicalTemplateName(Template);
+ addSubstitution(reinterpret_cast<uintptr_t>(Template.getAsVoidPointer()));
+}
+
+void CXXNameMangler::addSubstitution(uintptr_t Ptr) {
+ assert(!Substitutions.count(Ptr) && "Substitution already exists!");
+ Substitutions[Ptr] = SeqID++;
+}
+
+//
+
+/// \brief Mangles the name of the declaration D and emits that name to the
+/// given output stream.
+///
+/// If the declaration D requires a mangled name, this routine will emit that
+/// mangled name to \p os and return true. Otherwise, \p os will be unchanged
+/// and this routine will return false. In this case, the caller should just
+/// emit the identifier of the declaration (\c D->getIdentifier()) as its
+/// name.
+void ItaniumMangleContext::mangleName(const NamedDecl *D,
+ raw_ostream &Out) {
+ assert((isa<FunctionDecl>(D) || isa<VarDecl>(D)) &&
+ "Invalid mangleName() call, argument is not a variable or function!");
+ assert(!isa<CXXConstructorDecl>(D) && !isa<CXXDestructorDecl>(D) &&
+ "Invalid mangleName() call on 'structor decl!");
+
+ PrettyStackTraceDecl CrashInfo(D, SourceLocation(),
+ getASTContext().getSourceManager(),
+ "Mangling declaration");
+
+ CXXNameMangler Mangler(*this, Out, D);
+ return Mangler.mangle(D);
+}
+
+void ItaniumMangleContext::mangleCXXCtor(const CXXConstructorDecl *D,
+ CXXCtorType Type,
+ raw_ostream &Out) {
+ CXXNameMangler Mangler(*this, Out, D, Type);
+ Mangler.mangle(D);
+}
+
+void ItaniumMangleContext::mangleCXXDtor(const CXXDestructorDecl *D,
+ CXXDtorType Type,
+ raw_ostream &Out) {
+ CXXNameMangler Mangler(*this, Out, D, Type);
+ Mangler.mangle(D);
+}
+
+void ItaniumMangleContext::mangleThunk(const CXXMethodDecl *MD,
+ const ThunkInfo &Thunk,
+ raw_ostream &Out) {
+ // <special-name> ::= T <call-offset> <base encoding>
+ // # base is the nominal target function of thunk
+ // <special-name> ::= Tc <call-offset> <call-offset> <base encoding>
+ // # base is the nominal target function of thunk
+ // # first call-offset is 'this' adjustment
+ // # second call-offset is result adjustment
+
+ assert(!isa<CXXDestructorDecl>(MD) &&
+ "Use mangleCXXDtor for destructor decls!");
+ CXXNameMangler Mangler(*this, Out);
+ Mangler.getStream() << "_ZT";
+ if (!Thunk.Return.isEmpty())
+ Mangler.getStream() << 'c';
+
+ // Mangle the 'this' pointer adjustment.
+ Mangler.mangleCallOffset(Thunk.This.NonVirtual, Thunk.This.VCallOffsetOffset);
+
+ // Mangle the return pointer adjustment if there is one.
+ if (!Thunk.Return.isEmpty())
+ Mangler.mangleCallOffset(Thunk.Return.NonVirtual,
+ Thunk.Return.VBaseOffsetOffset);
+
+ Mangler.mangleFunctionEncoding(MD);
+}
+
+void
+ItaniumMangleContext::mangleCXXDtorThunk(const CXXDestructorDecl *DD,
+ CXXDtorType Type,
+ const ThisAdjustment &ThisAdjustment,
+ raw_ostream &Out) {
+ // <special-name> ::= T <call-offset> <base encoding>
+ // # base is the nominal target function of thunk
+ CXXNameMangler Mangler(*this, Out, DD, Type);
+ Mangler.getStream() << "_ZT";
+
+ // Mangle the 'this' pointer adjustment.
+ Mangler.mangleCallOffset(ThisAdjustment.NonVirtual,
+ ThisAdjustment.VCallOffsetOffset);
+
+ Mangler.mangleFunctionEncoding(DD);
+}
+
+/// mangleGuardVariable - Returns the mangled name for a guard variable
+/// for the passed in VarDecl.
+void ItaniumMangleContext::mangleItaniumGuardVariable(const VarDecl *D,
+ raw_ostream &Out) {
+ // <special-name> ::= GV <object name> # Guard variable for one-time
+ // # initialization
+ CXXNameMangler Mangler(*this, Out);
+ Mangler.getStream() << "_ZGV";
+ Mangler.mangleName(D);
+}
+
+void ItaniumMangleContext::mangleReferenceTemporary(const VarDecl *D,
+ raw_ostream &Out) {
+ // We match the GCC mangling here.
+ // <special-name> ::= GR <object name>
+ CXXNameMangler Mangler(*this, Out);
+ Mangler.getStream() << "_ZGR";
+ Mangler.mangleName(D);
+}
+
+void ItaniumMangleContext::mangleCXXVTable(const CXXRecordDecl *RD,
+ raw_ostream &Out) {
+ // <special-name> ::= TV <type> # virtual table
+ CXXNameMangler Mangler(*this, Out);
+ Mangler.getStream() << "_ZTV";
+ Mangler.mangleNameOrStandardSubstitution(RD);
+}
+
+void ItaniumMangleContext::mangleCXXVTT(const CXXRecordDecl *RD,
+ raw_ostream &Out) {
+ // <special-name> ::= TT <type> # VTT structure
+ CXXNameMangler Mangler(*this, Out);
+ Mangler.getStream() << "_ZTT";
+ Mangler.mangleNameOrStandardSubstitution(RD);
+}
+
+void ItaniumMangleContext::mangleCXXCtorVTable(const CXXRecordDecl *RD,
+ int64_t Offset,
+ const CXXRecordDecl *Type,
+ raw_ostream &Out) {
+ // <special-name> ::= TC <type> <offset number> _ <base type>
+ CXXNameMangler Mangler(*this, Out);
+ Mangler.getStream() << "_ZTC";
+ Mangler.mangleNameOrStandardSubstitution(RD);
+ Mangler.getStream() << Offset;
+ Mangler.getStream() << '_';
+ Mangler.mangleNameOrStandardSubstitution(Type);
+}
+
+void ItaniumMangleContext::mangleCXXRTTI(QualType Ty,
+ raw_ostream &Out) {
+ // <special-name> ::= TI <type> # typeinfo structure
+ assert(!Ty.hasQualifiers() && "RTTI info cannot have top-level qualifiers");
+ CXXNameMangler Mangler(*this, Out);
+ Mangler.getStream() << "_ZTI";
+ Mangler.mangleType(Ty);
+}
+
+void ItaniumMangleContext::mangleCXXRTTIName(QualType Ty,
+ raw_ostream &Out) {
+ // <special-name> ::= TS <type> # typeinfo name (null terminated byte string)
+ CXXNameMangler Mangler(*this, Out);
+ Mangler.getStream() << "_ZTS";
+ Mangler.mangleType(Ty);
+}
+
+MangleContext *clang::createItaniumMangleContext(ASTContext &Context,
+ DiagnosticsEngine &Diags) {
+ return new ItaniumMangleContext(Context, Diags);
+}
diff --git a/clang/lib/AST/MicrosoftMangle.cpp b/clang/lib/AST/MicrosoftMangle.cpp index 0da7f516db9..a8737e73e9d 100644 --- a/clang/lib/AST/MicrosoftMangle.cpp +++ b/clang/lib/AST/MicrosoftMangle.cpp @@ -1,1718 +1,1725 @@ -//===--- MicrosoftMangle.cpp - Microsoft Visual C++ Name Mangling ---------===// -// -// The LLVM Compiler Infrastructure -// -// This file is distributed under the University of Illinois Open Source -// License. See LICENSE.TXT for details. -// -//===----------------------------------------------------------------------===// -// -// This provides C++ name mangling targeting the Microsoft Visual C++ ABI. -// -//===----------------------------------------------------------------------===// - -#include "clang/AST/Mangle.h" -#include "clang/AST/ASTContext.h" -#include "clang/AST/Attr.h" -#include "clang/AST/CharUnits.h" -#include "clang/AST/Decl.h" -#include "clang/AST/DeclCXX.h" -#include "clang/AST/DeclObjC.h" -#include "clang/AST/DeclTemplate.h" -#include "clang/AST/ExprCXX.h" -#include "clang/Basic/ABI.h" -#include "clang/Basic/DiagnosticOptions.h" -#include <map> - -using namespace clang; - -namespace { - -/// MicrosoftCXXNameMangler - Manage the mangling of a single name for the -/// Microsoft Visual C++ ABI. -class MicrosoftCXXNameMangler { - MangleContext &Context; - raw_ostream &Out; - - // FIXME: audit the performance of BackRefMap as it might do way too many - // copying of strings. - typedef std::map<std::string, unsigned> BackRefMap; - BackRefMap NameBackReferences; - bool UseNameBackReferences; - - typedef llvm::DenseMap<void*, unsigned> ArgBackRefMap; - ArgBackRefMap TypeBackReferences; - - ASTContext &getASTContext() const { return Context.getASTContext(); } - -public: - MicrosoftCXXNameMangler(MangleContext &C, raw_ostream &Out_) - : Context(C), Out(Out_), UseNameBackReferences(true) { } - - raw_ostream &getStream() const { return Out; } - - void mangle(const NamedDecl *D, StringRef Prefix = "\01?"); - void mangleName(const NamedDecl *ND); - void mangleFunctionEncoding(const FunctionDecl *FD); - void mangleVariableEncoding(const VarDecl *VD); - void mangleNumber(int64_t Number); - void mangleNumber(const llvm::APSInt &Value); - void mangleType(QualType T, SourceRange Range, bool MangleQualifiers = true); - -private: - void disableBackReferences() { UseNameBackReferences = false; } - void mangleUnqualifiedName(const NamedDecl *ND) { - mangleUnqualifiedName(ND, ND->getDeclName()); - } - void mangleUnqualifiedName(const NamedDecl *ND, DeclarationName Name); - void mangleSourceName(const IdentifierInfo *II); - void manglePostfix(const DeclContext *DC, bool NoFunction=false); - void mangleOperatorName(OverloadedOperatorKind OO, SourceLocation Loc); - void mangleQualifiers(Qualifiers Quals, bool IsMember); - void manglePointerQualifiers(Qualifiers Quals); - - void mangleUnscopedTemplateName(const TemplateDecl *ND); - void mangleTemplateInstantiationName(const TemplateDecl *TD, - const SmallVectorImpl<TemplateArgumentLoc> &TemplateArgs); - void mangleObjCMethodName(const ObjCMethodDecl *MD); - void mangleLocalName(const FunctionDecl *FD); - - void mangleArgumentType(QualType T, SourceRange Range); - - // Declare manglers for every type class. -#define ABSTRACT_TYPE(CLASS, PARENT) -#define NON_CANONICAL_TYPE(CLASS, PARENT) -#define TYPE(CLASS, PARENT) void mangleType(const CLASS##Type *T, \ - SourceRange Range); -#include "clang/AST/TypeNodes.def" -#undef ABSTRACT_TYPE -#undef NON_CANONICAL_TYPE -#undef TYPE - - void mangleType(const TagType*); - void mangleType(const FunctionType *T, const FunctionDecl *D, - bool IsStructor, bool IsInstMethod); - void mangleType(const ArrayType *T, bool IsGlobal); - void mangleExtraDimensions(QualType T); - void mangleFunctionClass(const FunctionDecl *FD); - void mangleCallingConvention(const FunctionType *T, bool IsInstMethod = false); - void mangleIntegerLiteral(const llvm::APSInt &Number, bool IsBoolean); - void mangleExpression(const Expr *E); - void mangleThrowSpecification(const FunctionProtoType *T); - - void mangleTemplateArgs( - const SmallVectorImpl<TemplateArgumentLoc> &TemplateArgs); - -}; - -/// MicrosoftMangleContext - Overrides the default MangleContext for the -/// Microsoft Visual C++ ABI. -class MicrosoftMangleContext : public MangleContext { -public: - MicrosoftMangleContext(ASTContext &Context, - DiagnosticsEngine &Diags) : MangleContext(Context, Diags) { } - virtual bool shouldMangleDeclName(const NamedDecl *D); - virtual void mangleName(const NamedDecl *D, raw_ostream &Out); - virtual void mangleThunk(const CXXMethodDecl *MD, - const ThunkInfo &Thunk, - raw_ostream &); - virtual void mangleCXXDtorThunk(const CXXDestructorDecl *DD, CXXDtorType Type, - const ThisAdjustment &ThisAdjustment, - raw_ostream &); - virtual void mangleCXXVTable(const CXXRecordDecl *RD, - raw_ostream &); - virtual void mangleCXXVTT(const CXXRecordDecl *RD, - raw_ostream &); - virtual void mangleCXXCtorVTable(const CXXRecordDecl *RD, int64_t Offset, - const CXXRecordDecl *Type, - raw_ostream &); - virtual void mangleCXXRTTI(QualType T, raw_ostream &); - virtual void mangleCXXRTTIName(QualType T, raw_ostream &); - virtual void mangleCXXCtor(const CXXConstructorDecl *D, CXXCtorType Type, - raw_ostream &); - virtual void mangleCXXDtor(const CXXDestructorDecl *D, CXXDtorType Type, - raw_ostream &); - virtual void mangleReferenceTemporary(const clang::VarDecl *, - raw_ostream &); -}; - -} - -static bool isInCLinkageSpecification(const Decl *D) { - D = D->getCanonicalDecl(); - for (const DeclContext *DC = D->getDeclContext(); - !DC->isTranslationUnit(); DC = DC->getParent()) { - if (const LinkageSpecDecl *Linkage = dyn_cast<LinkageSpecDecl>(DC)) - return Linkage->getLanguage() == LinkageSpecDecl::lang_c; - } - - return false; -} - -bool MicrosoftMangleContext::shouldMangleDeclName(const NamedDecl *D) { - // In C, functions with no attributes never need to be mangled. Fastpath them. - if (!getASTContext().getLangOpts().CPlusPlus && !D->hasAttrs()) - return false; - - // Any decl can be declared with __asm("foo") on it, and this takes precedence - // over all other naming in the .o file. - if (D->hasAttr<AsmLabelAttr>()) - return true; - - // Clang's "overloadable" attribute extension to C/C++ implies name mangling - // (always) as does passing a C++ member function and a function - // whose name is not a simple identifier. - const FunctionDecl *FD = dyn_cast<FunctionDecl>(D); - if (FD && (FD->hasAttr<OverloadableAttr>() || isa<CXXMethodDecl>(FD) || - !FD->getDeclName().isIdentifier())) - return true; - - // Otherwise, no mangling is done outside C++ mode. - if (!getASTContext().getLangOpts().CPlusPlus) - return false; - - // Variables at global scope with internal linkage are not mangled. - if (!FD) { - const DeclContext *DC = D->getDeclContext(); - if (DC->isTranslationUnit() && D->getLinkage() == InternalLinkage) - return false; - } - - // C functions and "main" are not mangled. - if ((FD && FD->isMain()) || isInCLinkageSpecification(D)) - return false; - - return true; -} - -void MicrosoftCXXNameMangler::mangle(const NamedDecl *D, - StringRef Prefix) { - // MSVC doesn't mangle C++ names the same way it mangles extern "C" names. - // Therefore it's really important that we don't decorate the - // name with leading underscores or leading/trailing at signs. So, by - // default, we emit an asm marker at the start so we get the name right. - // Callers can override this with a custom prefix. - - // Any decl can be declared with __asm("foo") on it, and this takes precedence - // over all other naming in the .o file. - if (const AsmLabelAttr *ALA = D->getAttr<AsmLabelAttr>()) { - // If we have an asm name, then we use it as the mangling. - Out << '\01' << ALA->getLabel(); - return; - } - - // <mangled-name> ::= ? <name> <type-encoding> - Out << Prefix; - mangleName(D); - if (const FunctionDecl *FD = dyn_cast<FunctionDecl>(D)) - mangleFunctionEncoding(FD); - else if (const VarDecl *VD = dyn_cast<VarDecl>(D)) - mangleVariableEncoding(VD); - else { - // TODO: Fields? Can MSVC even mangle them? - // Issue a diagnostic for now. - DiagnosticsEngine &Diags = Context.getDiags(); - unsigned DiagID = Diags.getCustomDiagID(DiagnosticsEngine::Error, - "cannot mangle this declaration yet"); - Diags.Report(D->getLocation(), DiagID) - << D->getSourceRange(); - } -} - -void MicrosoftCXXNameMangler::mangleFunctionEncoding(const FunctionDecl *FD) { - // <type-encoding> ::= <function-class> <function-type> - - // Don't mangle in the type if this isn't a decl we should typically mangle. - if (!Context.shouldMangleDeclName(FD)) - return; - - // We should never ever see a FunctionNoProtoType at this point. - // We don't even know how to mangle their types anyway :). - const FunctionProtoType *FT = FD->getType()->castAs<FunctionProtoType>(); - - bool InStructor = false, InInstMethod = false; - const CXXMethodDecl *MD = dyn_cast<CXXMethodDecl>(FD); - if (MD) { - if (MD->isInstance()) - InInstMethod = true; - if (isa<CXXConstructorDecl>(MD) || isa<CXXDestructorDecl>(MD)) - InStructor = true; - } - - // First, the function class. - mangleFunctionClass(FD); - - mangleType(FT, FD, InStructor, InInstMethod); -} - -void MicrosoftCXXNameMangler::mangleVariableEncoding(const VarDecl *VD) { - // <type-encoding> ::= <storage-class> <variable-type> - // <storage-class> ::= 0 # private static member - // ::= 1 # protected static member - // ::= 2 # public static member - // ::= 3 # global - // ::= 4 # static local - - // The first character in the encoding (after the name) is the storage class. - if (VD->isStaticDataMember()) { - // If it's a static member, it also encodes the access level. - switch (VD->getAccess()) { - default: - case AS_private: Out << '0'; break; - case AS_protected: Out << '1'; break; - case AS_public: Out << '2'; break; - } - } - else if (!VD->isStaticLocal()) - Out << '3'; - else - Out << '4'; - // Now mangle the type. - // <variable-type> ::= <type> <cvr-qualifiers> - // ::= <type> <pointee-cvr-qualifiers> # pointers, references - // Pointers and references are odd. The type of 'int * const foo;' gets - // mangled as 'QAHA' instead of 'PAHB', for example. - TypeLoc TL = VD->getTypeSourceInfo()->getTypeLoc(); - QualType Ty = TL.getType(); - if (Ty->isPointerType() || Ty->isReferenceType()) { - mangleType(Ty, TL.getSourceRange()); - mangleQualifiers(Ty->getPointeeType().getQualifiers(), false); - } else if (const ArrayType *AT = getASTContext().getAsArrayType(Ty)) { - // Global arrays are funny, too. - mangleType(AT, true); - mangleQualifiers(Ty.getQualifiers(), false); - } else { - mangleType(Ty.getLocalUnqualifiedType(), TL.getSourceRange()); - mangleQualifiers(Ty.getLocalQualifiers(), false); - } -} - -void MicrosoftCXXNameMangler::mangleName(const NamedDecl *ND) { - // <name> ::= <unscoped-name> {[<named-scope>]+ | [<nested-name>]}? @ - const DeclContext *DC = ND->getDeclContext(); - - // Always start with the unqualified name. - mangleUnqualifiedName(ND); - - // If this is an extern variable declared locally, the relevant DeclContext - // is that of the containing namespace, or the translation unit. - if (isa<FunctionDecl>(DC) && ND->hasLinkage()) - while (!DC->isNamespace() && !DC->isTranslationUnit()) - DC = DC->getParent(); - - manglePostfix(DC); - - // Terminate the whole name with an '@'. - Out << '@'; -} - -void MicrosoftCXXNameMangler::mangleNumber(int64_t Number) { - llvm::APSInt APSNumber(/*BitWidth=*/64, /*isUnsigned=*/false); - APSNumber = Number; - mangleNumber(APSNumber); -} - -void MicrosoftCXXNameMangler::mangleNumber(const llvm::APSInt &Value) { - // <number> ::= [?] <decimal digit> # 1 <= Number <= 10 - // ::= [?] <hex digit>+ @ # 0 or > 9; A = 0, B = 1, etc... - // ::= [?] @ # 0 (alternate mangling, not emitted by VC) - if (Value.isSigned() && Value.isNegative()) { - Out << '?'; - mangleNumber(llvm::APSInt(Value.abs())); - return; - } - llvm::APSInt Temp(Value); - // There's a special shorter mangling for 0, but Microsoft - // chose not to use it. Instead, 0 gets mangled as "A@". Oh well... - if (Value.uge(1) && Value.ule(10)) { - --Temp; - Temp.print(Out, false); - } else { - // We have to build up the encoding in reverse order, so it will come - // out right when we write it out. - char Encoding[64]; - char *EndPtr = Encoding+sizeof(Encoding); - char *CurPtr = EndPtr; - llvm::APSInt NibbleMask(Value.getBitWidth(), Value.isUnsigned()); - NibbleMask = 0xf; - do { - *--CurPtr = 'A' + Temp.And(NibbleMask).getLimitedValue(0xf); - Temp = Temp.lshr(4); - } while (Temp != 0); - Out.write(CurPtr, EndPtr-CurPtr); - Out << '@'; - } -} - -static const TemplateDecl * -isTemplate(const NamedDecl *ND, - SmallVectorImpl<TemplateArgumentLoc> &TemplateArgs) { - // Check if we have a function template. - if (const FunctionDecl *FD = dyn_cast<FunctionDecl>(ND)){ - if (const TemplateDecl *TD = FD->getPrimaryTemplate()) { - if (FD->getTemplateSpecializationArgsAsWritten()) { - const ASTTemplateArgumentListInfo *ArgList = - FD->getTemplateSpecializationArgsAsWritten(); - TemplateArgs.append(ArgList->getTemplateArgs(), - ArgList->getTemplateArgs() + - ArgList->NumTemplateArgs); - } else { - const TemplateArgumentList *ArgList = - FD->getTemplateSpecializationArgs(); - TemplateArgumentListInfo LI; - for (unsigned i = 0, e = ArgList->size(); i != e; ++i) - TemplateArgs.push_back(TemplateArgumentLoc(ArgList->get(i), - FD->getTypeSourceInfo())); - } - return TD; - } - } - - // Check if we have a class template. - if (const ClassTemplateSpecializationDecl *Spec = - dyn_cast<ClassTemplateSpecializationDecl>(ND)) { - TypeSourceInfo *TSI = Spec->getTypeAsWritten(); - if (TSI) { - TemplateSpecializationTypeLoc TSTL = - cast<TemplateSpecializationTypeLoc>(TSI->getTypeLoc()); - TemplateArgumentListInfo LI(TSTL.getLAngleLoc(), TSTL.getRAngleLoc()); - for (unsigned i = 0, e = TSTL.getNumArgs(); i != e; ++i) - TemplateArgs.push_back(TSTL.getArgLoc(i)); - } else { - TemplateArgumentListInfo LI; - const TemplateArgumentList &ArgList = - Spec->getTemplateArgs(); - for (unsigned i = 0, e = ArgList.size(); i != e; ++i) - TemplateArgs.push_back(TemplateArgumentLoc(ArgList[i], - TemplateArgumentLocInfo())); - } - return Spec->getSpecializedTemplate(); - } - - return 0; -} - -void -MicrosoftCXXNameMangler::mangleUnqualifiedName(const NamedDecl *ND, - DeclarationName Name) { - // <unqualified-name> ::= <operator-name> - // ::= <ctor-dtor-name> - // ::= <source-name> - // ::= <template-name> - SmallVector<TemplateArgumentLoc, 2> TemplateArgs; - // Check if we have a template. - if (const TemplateDecl *TD = isTemplate(ND, TemplateArgs)) { - // We have a template. - // Here comes the tricky thing: if we need to mangle something like - // void foo(A::X<Y>, B::X<Y>), - // the X<Y> part is aliased. However, if you need to mangle - // void foo(A::X<A::Y>, A::X<B::Y>), - // the A::X<> part is not aliased. - // That said, from the mangler's perspective we have a structure like this: - // namespace[s] -> type[ -> template-parameters] - // but from the Clang perspective we have - // type [ -> template-parameters] - // \-> namespace[s] - // What we do is we create a new mangler, mangle the same type (without - // a namespace suffix) using the extra mangler with back references - // disabled (to avoid infinite recursion) and then use the mangled type - // name as a key to check the mangling of different types for aliasing. - - std::string BackReferenceKey; - BackRefMap::iterator Found; - if (UseNameBackReferences) { - llvm::raw_string_ostream Stream(BackReferenceKey); - MicrosoftCXXNameMangler Extra(Context, Stream); - Extra.disableBackReferences(); - Extra.mangleUnqualifiedName(ND, Name); - Stream.flush(); - - Found = NameBackReferences.find(BackReferenceKey); - } - if (!UseNameBackReferences || Found == NameBackReferences.end()) { - mangleTemplateInstantiationName(TD, TemplateArgs); - if (UseNameBackReferences && NameBackReferences.size() < 10) { - size_t Size = NameBackReferences.size(); - NameBackReferences[BackReferenceKey] = Size; - } - } else { - Out << Found->second; - } - return; - } - - switch (Name.getNameKind()) { - case DeclarationName::Identifier: { - if (const IdentifierInfo *II = Name.getAsIdentifierInfo()) { - mangleSourceName(II); - break; - } - - // Otherwise, an anonymous entity. We must have a declaration. - assert(ND && "mangling empty name without declaration"); - - if (const NamespaceDecl *NS = dyn_cast<NamespaceDecl>(ND)) { - if (NS->isAnonymousNamespace()) { - Out << "?A@"; - break; - } - } - - // We must have an anonymous struct. - const TagDecl *TD = cast<TagDecl>(ND); - if (const TypedefNameDecl *D = TD->getTypedefNameForAnonDecl()) { - assert(TD->getDeclContext() == D->getDeclContext() && - "Typedef should not be in another decl context!"); - assert(D->getDeclName().getAsIdentifierInfo() && - "Typedef was not named!"); - mangleSourceName(D->getDeclName().getAsIdentifierInfo()); - break; - } - - // When VC encounters an anonymous type with no tag and no typedef, - // it literally emits '<unnamed-tag>'. - Out << "<unnamed-tag>"; - break; - } - - case DeclarationName::ObjCZeroArgSelector: - case DeclarationName::ObjCOneArgSelector: - case DeclarationName::ObjCMultiArgSelector: - llvm_unreachable("Can't mangle Objective-C selector names here!"); - - case DeclarationName::CXXConstructorName: - Out << "?0"; - break; - - case DeclarationName::CXXDestructorName: - Out << "?1"; - break; - - case DeclarationName::CXXConversionFunctionName: - // <operator-name> ::= ?B # (cast) - // The target type is encoded as the return type. - Out << "?B"; - break; - - case DeclarationName::CXXOperatorName: - mangleOperatorName(Name.getCXXOverloadedOperator(), ND->getLocation()); - break; - - case DeclarationName::CXXLiteralOperatorName: { - // FIXME: Was this added in VS2010? Does MS even know how to mangle this? - DiagnosticsEngine Diags = Context.getDiags(); - unsigned DiagID = Diags.getCustomDiagID(DiagnosticsEngine::Error, - "cannot mangle this literal operator yet"); - Diags.Report(ND->getLocation(), DiagID); - break; - } - - case DeclarationName::CXXUsingDirective: - llvm_unreachable("Can't mangle a using directive name!"); - } -} - -void MicrosoftCXXNameMangler::manglePostfix(const DeclContext *DC, - bool NoFunction) { - // <postfix> ::= <unqualified-name> [<postfix>] - // ::= <substitution> [<postfix>] - - if (!DC) return; - - while (isa<LinkageSpecDecl>(DC)) - DC = DC->getParent(); - - if (DC->isTranslationUnit()) - return; - - if (const BlockDecl *BD = dyn_cast<BlockDecl>(DC)) { - Context.mangleBlock(BD, Out); - Out << '@'; - return manglePostfix(DC->getParent(), NoFunction); - } - - if (NoFunction && (isa<FunctionDecl>(DC) || isa<ObjCMethodDecl>(DC))) - return; - else if (const ObjCMethodDecl *Method = dyn_cast<ObjCMethodDecl>(DC)) - mangleObjCMethodName(Method); - else if (const FunctionDecl *Func = dyn_cast<FunctionDecl>(DC)) - mangleLocalName(Func); - else { - mangleUnqualifiedName(cast<NamedDecl>(DC)); - manglePostfix(DC->getParent(), NoFunction); - } -} - -void MicrosoftCXXNameMangler::mangleOperatorName(OverloadedOperatorKind OO, - SourceLocation Loc) { - switch (OO) { - // ?0 # constructor - // ?1 # destructor - // <operator-name> ::= ?2 # new - case OO_New: Out << "?2"; break; - // <operator-name> ::= ?3 # delete - case OO_Delete: Out << "?3"; break; - // <operator-name> ::= ?4 # = - case OO_Equal: Out << "?4"; break; - // <operator-name> ::= ?5 # >> - case OO_GreaterGreater: Out << "?5"; break; - // <operator-name> ::= ?6 # << - case OO_LessLess: Out << "?6"; break; - // <operator-name> ::= ?7 # ! - case OO_Exclaim: Out << "?7"; break; - // <operator-name> ::= ?8 # == - case OO_EqualEqual: Out << "?8"; break; - // <operator-name> ::= ?9 # != - case OO_ExclaimEqual: Out << "?9"; break; - // <operator-name> ::= ?A # [] - case OO_Subscript: Out << "?A"; break; - // ?B # conversion - // <operator-name> ::= ?C # -> - case OO_Arrow: Out << "?C"; break; - // <operator-name> ::= ?D # * - case OO_Star: Out << "?D"; break; - // <operator-name> ::= ?E # ++ - case OO_PlusPlus: Out << "?E"; break; - // <operator-name> ::= ?F # -- - case OO_MinusMinus: Out << "?F"; break; - // <operator-name> ::= ?G # - - case OO_Minus: Out << "?G"; break; - // <operator-name> ::= ?H # + - case OO_Plus: Out << "?H"; break; - // <operator-name> ::= ?I # & - case OO_Amp: Out << "?I"; break; - // <operator-name> ::= ?J # ->* - case OO_ArrowStar: Out << "?J"; break; - // <operator-name> ::= ?K # / - case OO_Slash: Out << "?K"; break; - // <operator-name> ::= ?L # % - case OO_Percent: Out << "?L"; break; - // <operator-name> ::= ?M # < - case OO_Less: Out << "?M"; break; - // <operator-name> ::= ?N # <= - case OO_LessEqual: Out << "?N"; break; - // <operator-name> ::= ?O # > - case OO_Greater: Out << "?O"; break; - // <operator-name> ::= ?P # >= - case OO_GreaterEqual: Out << "?P"; break; - // <operator-name> ::= ?Q # , - case OO_Comma: Out << "?Q"; break; - // <operator-name> ::= ?R # () - case OO_Call: Out << "?R"; break; - // <operator-name> ::= ?S # ~ - case OO_Tilde: Out << "?S"; break; - // <operator-name> ::= ?T # ^ - case OO_Caret: Out << "?T"; break; - // <operator-name> ::= ?U # | - case OO_Pipe: Out << "?U"; break; - // <operator-name> ::= ?V # && - case OO_AmpAmp: Out << "?V"; break; - // <operator-name> ::= ?W # || - case OO_PipePipe: Out << "?W"; break; - // <operator-name> ::= ?X # *= - case OO_StarEqual: Out << "?X"; break; - // <operator-name> ::= ?Y # += - case OO_PlusEqual: Out << "?Y"; break; - // <operator-name> ::= ?Z # -= - case OO_MinusEqual: Out << "?Z"; break; - // <operator-name> ::= ?_0 # /= - case OO_SlashEqual: Out << "?_0"; break; - // <operator-name> ::= ?_1 # %= - case OO_PercentEqual: Out << "?_1"; break; - // <operator-name> ::= ?_2 # >>= - case OO_GreaterGreaterEqual: Out << "?_2"; break; - // <operator-name> ::= ?_3 # <<= - case OO_LessLessEqual: Out << "?_3"; break; - // <operator-name> ::= ?_4 # &= - case OO_AmpEqual: Out << "?_4"; break; - // <operator-name> ::= ?_5 # |= - case OO_PipeEqual: Out << "?_5"; break; - // <operator-name> ::= ?_6 # ^= - case OO_CaretEqual: Out << "?_6"; break; - // ?_7 # vftable - // ?_8 # vbtable - // ?_9 # vcall - // ?_A # typeof - // ?_B # local static guard - // ?_C # string - // ?_D # vbase destructor - // ?_E # vector deleting destructor - // ?_F # default constructor closure - // ?_G # scalar deleting destructor - // ?_H # vector constructor iterator - // ?_I # vector destructor iterator - // ?_J # vector vbase constructor iterator - // ?_K # virtual displacement map - // ?_L # eh vector constructor iterator - // ?_M # eh vector destructor iterator - // ?_N # eh vector vbase constructor iterator - // ?_O # copy constructor closure - // ?_P<name> # udt returning <name> - // ?_Q # <unknown> - // ?_R0 # RTTI Type Descriptor - // ?_R1 # RTTI Base Class Descriptor at (a,b,c,d) - // ?_R2 # RTTI Base Class Array - // ?_R3 # RTTI Class Hierarchy Descriptor - // ?_R4 # RTTI Complete Object Locator - // ?_S # local vftable - // ?_T # local vftable constructor closure - // <operator-name> ::= ?_U # new[] - case OO_Array_New: Out << "?_U"; break; - // <operator-name> ::= ?_V # delete[] - case OO_Array_Delete: Out << "?_V"; break; - - case OO_Conditional: { - DiagnosticsEngine &Diags = Context.getDiags(); - unsigned DiagID = Diags.getCustomDiagID(DiagnosticsEngine::Error, - "cannot mangle this conditional operator yet"); - Diags.Report(Loc, DiagID); - break; - } - - case OO_None: - case NUM_OVERLOADED_OPERATORS: - llvm_unreachable("Not an overloaded operator"); - } -} - -void MicrosoftCXXNameMangler::mangleSourceName(const IdentifierInfo *II) { - // <source name> ::= <identifier> @ - std::string key = II->getNameStart(); - BackRefMap::iterator Found; - if (UseNameBackReferences) - Found = NameBackReferences.find(key); - if (!UseNameBackReferences || Found == NameBackReferences.end()) { - Out << II->getName() << '@'; - if (UseNameBackReferences && NameBackReferences.size() < 10) { - size_t Size = NameBackReferences.size(); - NameBackReferences[key] = Size; - } - } else { - Out << Found->second; - } -} - -void MicrosoftCXXNameMangler::mangleObjCMethodName(const ObjCMethodDecl *MD) { - Context.mangleObjCMethodName(MD, Out); -} - -// Find out how many function decls live above this one and return an integer -// suitable for use as the number in a numbered anonymous scope. -// TODO: Memoize. -static unsigned getLocalNestingLevel(const FunctionDecl *FD) { - const DeclContext *DC = FD->getParent(); - int level = 1; - - while (DC && !DC->isTranslationUnit()) { - if (isa<FunctionDecl>(DC) || isa<ObjCMethodDecl>(DC)) level++; - DC = DC->getParent(); - } - - return 2*level; -} - -void MicrosoftCXXNameMangler::mangleLocalName(const FunctionDecl *FD) { - // <nested-name> ::= <numbered-anonymous-scope> ? <mangled-name> - // <numbered-anonymous-scope> ::= ? <number> - // Even though the name is rendered in reverse order (e.g. - // A::B::C is rendered as C@B@A), VC numbers the scopes from outermost to - // innermost. So a method bar in class C local to function foo gets mangled - // as something like: - // ?bar@C@?1??foo@@YAXXZ@QAEXXZ - // This is more apparent when you have a type nested inside a method of a - // type nested inside a function. A method baz in class D local to method - // bar of class C local to function foo gets mangled as: - // ?baz@D@?3??bar@C@?1??foo@@YAXXZ@QAEXXZ@QAEXXZ - // This scheme is general enough to support GCC-style nested - // functions. You could have a method baz of class C inside a function bar - // inside a function foo, like so: - // ?baz@C@?3??bar@?1??foo@@YAXXZ@YAXXZ@QAEXXZ - int NestLevel = getLocalNestingLevel(FD); - Out << '?'; - mangleNumber(NestLevel); - Out << '?'; - mangle(FD, "?"); -} - -void MicrosoftCXXNameMangler::mangleTemplateInstantiationName( - const TemplateDecl *TD, - const SmallVectorImpl<TemplateArgumentLoc> &TemplateArgs) { - // <template-name> ::= <unscoped-template-name> <template-args> - // ::= <substitution> - // Always start with the unqualified name. - - // Templates have their own context for back references. - ArgBackRefMap OuterArgsContext; - BackRefMap OuterTemplateContext; - NameBackReferences.swap(OuterTemplateContext); - TypeBackReferences.swap(OuterArgsContext); - - mangleUnscopedTemplateName(TD); - mangleTemplateArgs(TemplateArgs); - - // Restore the previous back reference contexts. - NameBackReferences.swap(OuterTemplateContext); - TypeBackReferences.swap(OuterArgsContext); -} - -void -MicrosoftCXXNameMangler::mangleUnscopedTemplateName(const TemplateDecl *TD) { - // <unscoped-template-name> ::= ?$ <unqualified-name> - Out << "?$"; - mangleUnqualifiedName(TD); -} - -void -MicrosoftCXXNameMangler::mangleIntegerLiteral(const llvm::APSInt &Value, - bool IsBoolean) { - // <integer-literal> ::= $0 <number> - Out << "$0"; - // Make sure booleans are encoded as 0/1. - if (IsBoolean && Value.getBoolValue()) - mangleNumber(1); - else - mangleNumber(Value); -} - -void -MicrosoftCXXNameMangler::mangleExpression(const Expr *E) { - // See if this is a constant expression. - llvm::APSInt Value; - if (E->isIntegerConstantExpr(Value, Context.getASTContext())) { - mangleIntegerLiteral(Value, E->getType()->isBooleanType()); - return; - } - - // As bad as this diagnostic is, it's better than crashing. - DiagnosticsEngine &Diags = Context.getDiags(); - unsigned DiagID = Diags.getCustomDiagID(DiagnosticsEngine::Error, - "cannot yet mangle expression type %0"); - Diags.Report(E->getExprLoc(), DiagID) - << E->getStmtClassName() << E->getSourceRange(); -} - -void -MicrosoftCXXNameMangler::mangleTemplateArgs( - const SmallVectorImpl<TemplateArgumentLoc> &TemplateArgs) { - // <template-args> ::= {<type> | <integer-literal>}+ @ - unsigned NumTemplateArgs = TemplateArgs.size(); - for (unsigned i = 0; i < NumTemplateArgs; ++i) { - const TemplateArgumentLoc &TAL = TemplateArgs[i]; - const TemplateArgument &TA = TAL.getArgument(); - switch (TA.getKind()) { - case TemplateArgument::Null: - llvm_unreachable("Can't mangle null template arguments!"); - case TemplateArgument::Type: - mangleType(TA.getAsType(), TAL.getSourceRange()); - break; - case TemplateArgument::Integral: - mangleIntegerLiteral(TA.getAsIntegral(), - TA.getIntegralType()->isBooleanType()); - break; - case TemplateArgument::Expression: - mangleExpression(TA.getAsExpr()); - break; - case TemplateArgument::Template: - case TemplateArgument::TemplateExpansion: - case TemplateArgument::Declaration: - case TemplateArgument::NullPtr: - case TemplateArgument::Pack: { - // Issue a diagnostic. - DiagnosticsEngine &Diags = Context.getDiags(); - unsigned DiagID = Diags.getCustomDiagID(DiagnosticsEngine::Error, - "cannot mangle this %select{ERROR|ERROR|pointer/reference|nullptr|" - "integral|template|template pack expansion|ERROR|parameter pack}0 " - "template argument yet"); - Diags.Report(TAL.getLocation(), DiagID) - << TA.getKind() - << TAL.getSourceRange(); - } - } - } - Out << '@'; -} - -void MicrosoftCXXNameMangler::mangleQualifiers(Qualifiers Quals, - bool IsMember) { - // <cvr-qualifiers> ::= [E] [F] [I] <base-cvr-qualifiers> - // 'E' means __ptr64 (32-bit only); 'F' means __unaligned (32/64-bit only); - // 'I' means __restrict (32/64-bit). - // Note that the MSVC __restrict keyword isn't the same as the C99 restrict - // keyword! - // <base-cvr-qualifiers> ::= A # near - // ::= B # near const - // ::= C # near volatile - // ::= D # near const volatile - // ::= E # far (16-bit) - // ::= F # far const (16-bit) - // ::= G # far volatile (16-bit) - // ::= H # far const volatile (16-bit) - // ::= I # huge (16-bit) - // ::= J # huge const (16-bit) - // ::= K # huge volatile (16-bit) - // ::= L # huge const volatile (16-bit) - // ::= M <basis> # based - // ::= N <basis> # based const - // ::= O <basis> # based volatile - // ::= P <basis> # based const volatile - // ::= Q # near member - // ::= R # near const member - // ::= S # near volatile member - // ::= T # near const volatile member - // ::= U # far member (16-bit) - // ::= V # far const member (16-bit) - // ::= W # far volatile member (16-bit) - // ::= X # far const volatile member (16-bit) - // ::= Y # huge member (16-bit) - // ::= Z # huge const member (16-bit) - // ::= 0 # huge volatile member (16-bit) - // ::= 1 # huge const volatile member (16-bit) - // ::= 2 <basis> # based member - // ::= 3 <basis> # based const member - // ::= 4 <basis> # based volatile member - // ::= 5 <basis> # based const volatile member - // ::= 6 # near function (pointers only) - // ::= 7 # far function (pointers only) - // ::= 8 # near method (pointers only) - // ::= 9 # far method (pointers only) - // ::= _A <basis> # based function (pointers only) - // ::= _B <basis> # based function (far?) (pointers only) - // ::= _C <basis> # based method (pointers only) - // ::= _D <basis> # based method (far?) (pointers only) - // ::= _E # block (Clang) - // <basis> ::= 0 # __based(void) - // ::= 1 # __based(segment)? - // ::= 2 <name> # __based(name) - // ::= 3 # ? - // ::= 4 # ? - // ::= 5 # not really based - bool HasConst = Quals.hasConst(), - HasVolatile = Quals.hasVolatile(); - if (!IsMember) { - if (HasConst && HasVolatile) { - Out << 'D'; - } else if (HasVolatile) { - Out << 'C'; - } else if (HasConst) { - Out << 'B'; - } else { - Out << 'A'; - } - } else { - if (HasConst && HasVolatile) { - Out << 'T'; - } else if (HasVolatile) { - Out << 'S'; - } else if (HasConst) { - Out << 'R'; - } else { - Out << 'Q'; - } - } - - // FIXME: For now, just drop all extension qualifiers on the floor. -} - -void MicrosoftCXXNameMangler::manglePointerQualifiers(Qualifiers Quals) { - // <pointer-cvr-qualifiers> ::= P # no qualifiers - // ::= Q # const - // ::= R # volatile - // ::= S # const volatile - bool HasConst = Quals.hasConst(), - HasVolatile = Quals.hasVolatile(); - if (HasConst && HasVolatile) { - Out << 'S'; - } else if (HasVolatile) { - Out << 'R'; - } else if (HasConst) { - Out << 'Q'; - } else { - Out << 'P'; - } -} - -void MicrosoftCXXNameMangler::mangleArgumentType(QualType T, - SourceRange Range) { - void *TypePtr = getASTContext().getCanonicalType(T).getAsOpaquePtr(); - ArgBackRefMap::iterator Found = TypeBackReferences.find(TypePtr); - - if (Found == TypeBackReferences.end()) { - size_t OutSizeBefore = Out.GetNumBytesInBuffer(); - - mangleType(T, Range, false); - - // See if it's worth creating a back reference. - // Only types longer than 1 character are considered - // and only 10 back references slots are available: - bool LongerThanOneChar = (Out.GetNumBytesInBuffer() - OutSizeBefore > 1); - if (LongerThanOneChar && TypeBackReferences.size() < 10) { - size_t Size = TypeBackReferences.size(); - TypeBackReferences[TypePtr] = Size; - } - } else { - Out << Found->second; - } -} - -void MicrosoftCXXNameMangler::mangleType(QualType T, SourceRange Range, - bool MangleQualifiers) { - // Only operate on the canonical type! - T = getASTContext().getCanonicalType(T); - - Qualifiers Quals = T.getLocalQualifiers(); - // We have to mangle these now, while we still have enough information. - if (T->isAnyPointerType() || T->isMemberPointerType() || - T->isBlockPointerType()) { - manglePointerQualifiers(Quals); - } else if (Quals && MangleQualifiers) { - mangleQualifiers(Quals, false); - } - - SplitQualType split = T.split(); - const Type *ty = split.Ty; - - // If we're mangling a qualified array type, push the qualifiers to - // the element type. - if (split.Quals && isa<ArrayType>(T)) { - ty = Context.getASTContext().getAsArrayType(T); - } - - switch (ty->getTypeClass()) { -#define ABSTRACT_TYPE(CLASS, PARENT) -#define NON_CANONICAL_TYPE(CLASS, PARENT) \ - case Type::CLASS: \ - llvm_unreachable("can't mangle non-canonical type " #CLASS "Type"); \ - return; -#define TYPE(CLASS, PARENT) \ - case Type::CLASS: \ - mangleType(cast<CLASS##Type>(ty), Range); \ - break; -#include "clang/AST/TypeNodes.def" -#undef ABSTRACT_TYPE -#undef NON_CANONICAL_TYPE -#undef TYPE - } -} - -void MicrosoftCXXNameMangler::mangleType(const BuiltinType *T, - SourceRange Range) { - // <type> ::= <builtin-type> - // <builtin-type> ::= X # void - // ::= C # signed char - // ::= D # char - // ::= E # unsigned char - // ::= F # short - // ::= G # unsigned short (or wchar_t if it's not a builtin) - // ::= H # int - // ::= I # unsigned int - // ::= J # long - // ::= K # unsigned long - // L # <none> - // ::= M # float - // ::= N # double - // ::= O # long double (__float80 is mangled differently) - // ::= _J # long long, __int64 - // ::= _K # unsigned long long, __int64 - // ::= _L # __int128 - // ::= _M # unsigned __int128 - // ::= _N # bool - // _O # <array in parameter> - // ::= _T # __float80 (Intel) - // ::= _W # wchar_t - // ::= _Z # __float80 (Digital Mars) - switch (T->getKind()) { - case BuiltinType::Void: Out << 'X'; break; - case BuiltinType::SChar: Out << 'C'; break; - case BuiltinType::Char_U: case BuiltinType::Char_S: Out << 'D'; break; - case BuiltinType::UChar: Out << 'E'; break; - case BuiltinType::Short: Out << 'F'; break; - case BuiltinType::UShort: Out << 'G'; break; - case BuiltinType::Int: Out << 'H'; break; - case BuiltinType::UInt: Out << 'I'; break; - case BuiltinType::Long: Out << 'J'; break; - case BuiltinType::ULong: Out << 'K'; break; - case BuiltinType::Float: Out << 'M'; break; - case BuiltinType::Double: Out << 'N'; break; - // TODO: Determine size and mangle accordingly - case BuiltinType::LongDouble: Out << 'O'; break; - case BuiltinType::LongLong: Out << "_J"; break; - case BuiltinType::ULongLong: Out << "_K"; break; - case BuiltinType::Int128: Out << "_L"; break; - case BuiltinType::UInt128: Out << "_M"; break; - case BuiltinType::Bool: Out << "_N"; break; - case BuiltinType::WChar_S: - case BuiltinType::WChar_U: Out << "_W"; break; - -#define BUILTIN_TYPE(Id, SingletonId) -#define PLACEHOLDER_TYPE(Id, SingletonId) \ - case BuiltinType::Id: -#include "clang/AST/BuiltinTypes.def" - case BuiltinType::Dependent: - llvm_unreachable("placeholder types shouldn't get to name mangling"); - - case BuiltinType::ObjCId: Out << "PAUobjc_object@@"; break; - case BuiltinType::ObjCClass: Out << "PAUobjc_class@@"; break; - case BuiltinType::ObjCSel: Out << "PAUobjc_selector@@"; break; - - case BuiltinType::NullPtr: Out << "$$T"; break; - - case BuiltinType::Char16: - case BuiltinType::Char32: - case BuiltinType::Half: { - DiagnosticsEngine &Diags = Context.getDiags(); - unsigned DiagID = Diags.getCustomDiagID(DiagnosticsEngine::Error, - "cannot mangle this built-in %0 type yet"); - Diags.Report(Range.getBegin(), DiagID) - << T->getName(Context.getASTContext().getPrintingPolicy()) - << Range; - break; - } - } -} - -// <type> ::= <function-type> -void MicrosoftCXXNameMangler::mangleType(const FunctionProtoType *T, - SourceRange) { - // Structors only appear in decls, so at this point we know it's not a - // structor type. - // FIXME: This may not be lambda-friendly. - Out << "$$A6"; - mangleType(T, NULL, false, false); -} -void MicrosoftCXXNameMangler::mangleType(const FunctionNoProtoType *T, - SourceRange) { - llvm_unreachable("Can't mangle K&R function prototypes"); -} - -void MicrosoftCXXNameMangler::mangleType(const FunctionType *T, - const FunctionDecl *D, - bool IsStructor, - bool IsInstMethod) { - // <function-type> ::= <this-cvr-qualifiers> <calling-convention> - // <return-type> <argument-list> <throw-spec> - const FunctionProtoType *Proto = cast<FunctionProtoType>(T); - - // If this is a C++ instance method, mangle the CVR qualifiers for the - // this pointer. - if (IsInstMethod) - mangleQualifiers(Qualifiers::fromCVRMask(Proto->getTypeQuals()), false); - - mangleCallingConvention(T, IsInstMethod); - - // <return-type> ::= <type> - // ::= @ # structors (they have no declared return type) - if (IsStructor) - Out << '@'; - else { - QualType Result = Proto->getResultType(); - const Type* RT = Result.getTypePtr(); - if (!RT->isAnyPointerType() && !RT->isReferenceType()) { - if (Result.hasQualifiers() || !RT->isBuiltinType()) - Out << '?'; - if (!RT->isBuiltinType() && !Result.hasQualifiers()) { - // Lack of qualifiers for user types is mangled as 'A'. - Out << 'A'; - } - } - - // FIXME: Get the source range for the result type. Or, better yet, - // implement the unimplemented stuff so we don't need accurate source - // location info anymore :). - mangleType(Result, SourceRange()); - } - - // <argument-list> ::= X # void - // ::= <type>+ @ - // ::= <type>* Z # varargs - if (Proto->getNumArgs() == 0 && !Proto->isVariadic()) { - Out << 'X'; - } else { - if (D) { - // If we got a decl, use the type-as-written to make sure arrays - // get mangled right. Note that we can't rely on the TSI - // existing if (for example) the parameter was synthesized. - for (FunctionDecl::param_const_iterator Parm = D->param_begin(), - ParmEnd = D->param_end(); Parm != ParmEnd; ++Parm) { - TypeSourceInfo *TSI = (*Parm)->getTypeSourceInfo(); - QualType Type = TSI ? TSI->getType() : (*Parm)->getType(); - mangleArgumentType(Type, (*Parm)->getSourceRange()); - } - } else { - // Happens for function pointer type arguments for example. - for (FunctionProtoType::arg_type_iterator Arg = Proto->arg_type_begin(), - ArgEnd = Proto->arg_type_end(); - Arg != ArgEnd; ++Arg) - mangleArgumentType(*Arg, SourceRange()); - } - // <builtin-type> ::= Z # ellipsis - if (Proto->isVariadic()) - Out << 'Z'; - else - Out << '@'; - } - - mangleThrowSpecification(Proto); -} - -void MicrosoftCXXNameMangler::mangleFunctionClass(const FunctionDecl *FD) { - // <function-class> ::= A # private: near - // ::= B # private: far - // ::= C # private: static near - // ::= D # private: static far - // ::= E # private: virtual near - // ::= F # private: virtual far - // ::= G # private: thunk near - // ::= H # private: thunk far - // ::= I # protected: near - // ::= J # protected: far - // ::= K # protected: static near - // ::= L # protected: static far - // ::= M # protected: virtual near - // ::= N # protected: virtual far - // ::= O # protected: thunk near - // ::= P # protected: thunk far - // ::= Q # public: near - // ::= R # public: far - // ::= S # public: static near - // ::= T # public: static far - // ::= U # public: virtual near - // ::= V # public: virtual far - // ::= W # public: thunk near - // ::= X # public: thunk far - // ::= Y # global near - // ::= Z # global far - if (const CXXMethodDecl *MD = dyn_cast<CXXMethodDecl>(FD)) { - switch (MD->getAccess()) { - default: - case AS_private: - if (MD->isStatic()) - Out << 'C'; - else if (MD->isVirtual()) - Out << 'E'; - else - Out << 'A'; - break; - case AS_protected: - if (MD->isStatic()) - Out << 'K'; - else if (MD->isVirtual()) - Out << 'M'; - else - Out << 'I'; - break; - case AS_public: - if (MD->isStatic()) - Out << 'S'; - else if (MD->isVirtual()) - Out << 'U'; - else - Out << 'Q'; - } - } else - Out << 'Y'; -} -void MicrosoftCXXNameMangler::mangleCallingConvention(const FunctionType *T, - bool IsInstMethod) { - // <calling-convention> ::= A # __cdecl - // ::= B # __export __cdecl - // ::= C # __pascal - // ::= D # __export __pascal - // ::= E # __thiscall - // ::= F # __export __thiscall - // ::= G # __stdcall - // ::= H # __export __stdcall - // ::= I # __fastcall - // ::= J # __export __fastcall - // The 'export' calling conventions are from a bygone era - // (*cough*Win16*cough*) when functions were declared for export with - // that keyword. (It didn't actually export them, it just made them so - // that they could be in a DLL and somebody from another module could call - // them.) - CallingConv CC = T->getCallConv(); - if (CC == CC_Default) { - if (IsInstMethod) { - const FunctionProtoType *FPT = - T->getCanonicalTypeUnqualified().castAs<FunctionProtoType>(); - bool isVariadic = FPT->isVariadic(); - CC = getASTContext().getDefaultCXXMethodCallConv(isVariadic); - } else { - CC = CC_C; - } - } - switch (CC) { - default: - llvm_unreachable("Unsupported CC for mangling"); - case CC_Default: - case CC_C: Out << 'A'; break; - case CC_X86Pascal: Out << 'C'; break; - case CC_X86ThisCall: Out << 'E'; break; - case CC_X86StdCall: Out << 'G'; break; - case CC_X86FastCall: Out << 'I'; break; - } -} -void MicrosoftCXXNameMangler::mangleThrowSpecification( - const FunctionProtoType *FT) { - // <throw-spec> ::= Z # throw(...) (default) - // ::= @ # throw() or __declspec/__attribute__((nothrow)) - // ::= <type>+ - // NOTE: Since the Microsoft compiler ignores throw specifications, they are - // all actually mangled as 'Z'. (They're ignored because their associated - // functionality isn't implemented, and probably never will be.) - Out << 'Z'; -} - -void MicrosoftCXXNameMangler::mangleType(const UnresolvedUsingType *T, - SourceRange Range) { - // Probably should be mangled as a template instantiation; need to see what - // VC does first. - DiagnosticsEngine &Diags = Context.getDiags(); - unsigned DiagID = Diags.getCustomDiagID(DiagnosticsEngine::Error, - "cannot mangle this unresolved dependent type yet"); - Diags.Report(Range.getBegin(), DiagID) - << Range; -} - -// <type> ::= <union-type> | <struct-type> | <class-type> | <enum-type> -// <union-type> ::= T <name> -// <struct-type> ::= U <name> -// <class-type> ::= V <name> -// <enum-type> ::= W <size> <name> -void MicrosoftCXXNameMangler::mangleType(const EnumType *T, SourceRange) { - mangleType(cast<TagType>(T)); -} -void MicrosoftCXXNameMangler::mangleType(const RecordType *T, SourceRange) { - mangleType(cast<TagType>(T)); -} -void MicrosoftCXXNameMangler::mangleType(const TagType *T) { - switch (T->getDecl()->getTagKind()) { - case TTK_Union: - Out << 'T'; - break; - case TTK_Struct: - case TTK_Interface: - Out << 'U'; - break; - case TTK_Class: - Out << 'V'; - break; - case TTK_Enum: - Out << 'W'; - Out << getASTContext().getTypeSizeInChars( - cast<EnumDecl>(T->getDecl())->getIntegerType()).getQuantity(); - break; - } - mangleName(T->getDecl()); -} - -// <type> ::= <array-type> -// <array-type> ::= <pointer-cvr-qualifiers> <cvr-qualifiers> -// [Y <dimension-count> <dimension>+] -// <element-type> # as global -// ::= Q <cvr-qualifiers> [Y <dimension-count> <dimension>+] -// <element-type> # as param -// It's supposed to be the other way around, but for some strange reason, it -// isn't. Today this behavior is retained for the sole purpose of backwards -// compatibility. -void MicrosoftCXXNameMangler::mangleType(const ArrayType *T, bool IsGlobal) { - // This isn't a recursive mangling, so now we have to do it all in this - // one call. - if (IsGlobal) { - manglePointerQualifiers(T->getElementType().getQualifiers()); - } else { - Out << 'Q'; - } - mangleExtraDimensions(T->getElementType()); -} -void MicrosoftCXXNameMangler::mangleType(const ConstantArrayType *T, - SourceRange) { - mangleType(cast<ArrayType>(T), false); -} -void MicrosoftCXXNameMangler::mangleType(const VariableArrayType *T, - SourceRange) { - mangleType(cast<ArrayType>(T), false); -} -void MicrosoftCXXNameMangler::mangleType(const DependentSizedArrayType *T, - SourceRange) { - mangleType(cast<ArrayType>(T), false); -} -void MicrosoftCXXNameMangler::mangleType(const IncompleteArrayType *T, - SourceRange) { - mangleType(cast<ArrayType>(T), false); -} -void MicrosoftCXXNameMangler::mangleExtraDimensions(QualType ElementTy) { - SmallVector<llvm::APInt, 3> Dimensions; - for (;;) { - if (const ConstantArrayType *CAT = - getASTContext().getAsConstantArrayType(ElementTy)) { - Dimensions.push_back(CAT->getSize()); - ElementTy = CAT->getElementType(); - } else if (ElementTy->isVariableArrayType()) { - const VariableArrayType *VAT = - getASTContext().getAsVariableArrayType(ElementTy); - DiagnosticsEngine &Diags = Context.getDiags(); - unsigned DiagID = Diags.getCustomDiagID(DiagnosticsEngine::Error, - "cannot mangle this variable-length array yet"); - Diags.Report(VAT->getSizeExpr()->getExprLoc(), DiagID) - << VAT->getBracketsRange(); - return; - } else if (ElementTy->isDependentSizedArrayType()) { - // The dependent expression has to be folded into a constant (TODO). - const DependentSizedArrayType *DSAT = - getASTContext().getAsDependentSizedArrayType(ElementTy); - DiagnosticsEngine &Diags = Context.getDiags(); - unsigned DiagID = Diags.getCustomDiagID(DiagnosticsEngine::Error, - "cannot mangle this dependent-length array yet"); - Diags.Report(DSAT->getSizeExpr()->getExprLoc(), DiagID) - << DSAT->getBracketsRange(); - return; - } else if (ElementTy->isIncompleteArrayType()) continue; - else break; - } - mangleQualifiers(ElementTy.getQualifiers(), false); - // If there are any additional dimensions, mangle them now. - if (Dimensions.size() > 0) { - Out << 'Y'; - // <dimension-count> ::= <number> # number of extra dimensions - mangleNumber(Dimensions.size()); - for (unsigned Dim = 0; Dim < Dimensions.size(); ++Dim) { - mangleNumber(Dimensions[Dim].getLimitedValue()); - } - } - mangleType(ElementTy.getLocalUnqualifiedType(), SourceRange()); -} - -// <type> ::= <pointer-to-member-type> -// <pointer-to-member-type> ::= <pointer-cvr-qualifiers> <cvr-qualifiers> -// <class name> <type> -void MicrosoftCXXNameMangler::mangleType(const MemberPointerType *T, - SourceRange Range) { - QualType PointeeType = T->getPointeeType(); - if (const FunctionProtoType *FPT = PointeeType->getAs<FunctionProtoType>()) { - Out << '8'; - mangleName(T->getClass()->castAs<RecordType>()->getDecl()); - mangleType(FPT, NULL, false, true); - } else { - mangleQualifiers(PointeeType.getQualifiers(), true); - mangleName(T->getClass()->castAs<RecordType>()->getDecl()); - mangleType(PointeeType.getLocalUnqualifiedType(), Range); - } -} - -void MicrosoftCXXNameMangler::mangleType(const TemplateTypeParmType *T, - SourceRange Range) { - DiagnosticsEngine &Diags = Context.getDiags(); - unsigned DiagID = Diags.getCustomDiagID(DiagnosticsEngine::Error, - "cannot mangle this template type parameter type yet"); - Diags.Report(Range.getBegin(), DiagID) - << Range; -} - -void MicrosoftCXXNameMangler::mangleType( - const SubstTemplateTypeParmPackType *T, - SourceRange Range) { - DiagnosticsEngine &Diags = Context.getDiags(); - unsigned DiagID = Diags.getCustomDiagID(DiagnosticsEngine::Error, - "cannot mangle this substituted parameter pack yet"); - Diags.Report(Range.getBegin(), DiagID) - << Range; -} - -// <type> ::= <pointer-type> -// <pointer-type> ::= <pointer-cvr-qualifiers> <cvr-qualifiers> <type> -void MicrosoftCXXNameMangler::mangleType(const PointerType *T, - SourceRange Range) { - QualType PointeeTy = T->getPointeeType(); - if (PointeeTy->isArrayType()) { - // Pointers to arrays are mangled like arrays. - mangleExtraDimensions(PointeeTy); - } else if (const FunctionType *FT = PointeeTy->getAs<FunctionType>()) { - // Function pointers are special. - Out << '6'; - mangleType(FT, NULL, false, false); - } else { - mangleQualifiers(PointeeTy.getQualifiers(), false); - mangleType(PointeeTy, Range, false); - } -} -void MicrosoftCXXNameMangler::mangleType(const ObjCObjectPointerType *T, - SourceRange Range) { - // Object pointers never have qualifiers. - Out << 'A'; - mangleType(T->getPointeeType(), Range); -} - -// <type> ::= <reference-type> -// <reference-type> ::= A <cvr-qualifiers> <type> -void MicrosoftCXXNameMangler::mangleType(const LValueReferenceType *T, - SourceRange Range) { - Out << 'A'; - QualType PointeeTy = T->getPointeeType(); - if (!PointeeTy.hasQualifiers()) - // Lack of qualifiers is mangled as 'A'. - Out << 'A'; - mangleType(PointeeTy, Range); -} - -// <type> ::= <r-value-reference-type> -// <r-value-reference-type> ::= $$Q <cvr-qualifiers> <type> -void MicrosoftCXXNameMangler::mangleType(const RValueReferenceType *T, - SourceRange Range) { - Out << "$$Q"; - QualType PointeeTy = T->getPointeeType(); - if (!PointeeTy.hasQualifiers()) - // Lack of qualifiers is mangled as 'A'. - Out << 'A'; - mangleType(PointeeTy, Range); -} - -void MicrosoftCXXNameMangler::mangleType(const ComplexType *T, - SourceRange Range) { - DiagnosticsEngine &Diags = Context.getDiags(); - unsigned DiagID = Diags.getCustomDiagID(DiagnosticsEngine::Error, - "cannot mangle this complex number type yet"); - Diags.Report(Range.getBegin(), DiagID) - << Range; -} - -void MicrosoftCXXNameMangler::mangleType(const VectorType *T, - SourceRange Range) { - DiagnosticsEngine &Diags = Context.getDiags(); - unsigned DiagID = Diags.getCustomDiagID(DiagnosticsEngine::Error, - "cannot mangle this vector type yet"); - Diags.Report(Range.getBegin(), DiagID) - << Range; -} -void MicrosoftCXXNameMangler::mangleType(const ExtVectorType *T, - SourceRange Range) { - DiagnosticsEngine &Diags = Context.getDiags(); - unsigned DiagID = Diags.getCustomDiagID(DiagnosticsEngine::Error, - "cannot mangle this extended vector type yet"); - Diags.Report(Range.getBegin(), DiagID) - << Range; -} -void MicrosoftCXXNameMangler::mangleType(const DependentSizedExtVectorType *T, - SourceRange Range) { - DiagnosticsEngine &Diags = Context.getDiags(); - unsigned DiagID = Diags.getCustomDiagID(DiagnosticsEngine::Error, - "cannot mangle this dependent-sized extended vector type yet"); - Diags.Report(Range.getBegin(), DiagID) - << Range; -} - -void MicrosoftCXXNameMangler::mangleType(const ObjCInterfaceType *T, - SourceRange) { - // ObjC interfaces have structs underlying them. - Out << 'U'; - mangleName(T->getDecl()); -} - -void MicrosoftCXXNameMangler::mangleType(const ObjCObjectType *T, - SourceRange Range) { - // We don't allow overloading by different protocol qualification, - // so mangling them isn't necessary. - mangleType(T->getBaseType(), Range); -} - -void MicrosoftCXXNameMangler::mangleType(const BlockPointerType *T, - SourceRange Range) { - Out << "_E"; - - QualType pointee = T->getPointeeType(); - mangleType(pointee->castAs<FunctionProtoType>(), NULL, false, false); -} - -void MicrosoftCXXNameMangler::mangleType(const InjectedClassNameType *T, - SourceRange Range) { - DiagnosticsEngine &Diags = Context.getDiags(); - unsigned DiagID = Diags.getCustomDiagID(DiagnosticsEngine::Error, - "cannot mangle this injected class name type yet"); - Diags.Report(Range.getBegin(), DiagID) - << Range; -} - -void MicrosoftCXXNameMangler::mangleType(const TemplateSpecializationType *T, - SourceRange Range) { - DiagnosticsEngine &Diags = Context.getDiags(); - unsigned DiagID = Diags.getCustomDiagID(DiagnosticsEngine::Error, - "cannot mangle this template specialization type yet"); - Diags.Report(Range.getBegin(), DiagID) - << Range; -} - -void MicrosoftCXXNameMangler::mangleType(const DependentNameType *T, - SourceRange Range) { - DiagnosticsEngine &Diags = Context.getDiags(); - unsigned DiagID = Diags.getCustomDiagID(DiagnosticsEngine::Error, - "cannot mangle this dependent name type yet"); - Diags.Report(Range.getBegin(), DiagID) - << Range; -} - -void MicrosoftCXXNameMangler::mangleType( - const DependentTemplateSpecializationType *T, - SourceRange Range) { - DiagnosticsEngine &Diags = Context.getDiags(); - unsigned DiagID = Diags.getCustomDiagID(DiagnosticsEngine::Error, - "cannot mangle this dependent template specialization type yet"); - Diags.Report(Range.getBegin(), DiagID) - << Range; -} - -void MicrosoftCXXNameMangler::mangleType(const PackExpansionType *T, - SourceRange Range) { - DiagnosticsEngine &Diags = Context.getDiags(); - unsigned DiagID = Diags.getCustomDiagID(DiagnosticsEngine::Error, - "cannot mangle this pack expansion yet"); - Diags.Report(Range.getBegin(), DiagID) - << Range; -} - -void MicrosoftCXXNameMangler::mangleType(const TypeOfType *T, - SourceRange Range) { - DiagnosticsEngine &Diags = Context.getDiags(); - unsigned DiagID = Diags.getCustomDiagID(DiagnosticsEngine::Error, - "cannot mangle this typeof(type) yet"); - Diags.Report(Range.getBegin(), DiagID) - << Range; -} - -void MicrosoftCXXNameMangler::mangleType(const TypeOfExprType *T, - SourceRange Range) { - DiagnosticsEngine &Diags = Context.getDiags(); - unsigned DiagID = Diags.getCustomDiagID(DiagnosticsEngine::Error, - "cannot mangle this typeof(expression) yet"); - Diags.Report(Range.getBegin(), DiagID) - << Range; -} - -void MicrosoftCXXNameMangler::mangleType(const DecltypeType *T, - SourceRange Range) { - DiagnosticsEngine &Diags = Context.getDiags(); - unsigned DiagID = Diags.getCustomDiagID(DiagnosticsEngine::Error, - "cannot mangle this decltype() yet"); - Diags.Report(Range.getBegin(), DiagID) - << Range; -} - -void MicrosoftCXXNameMangler::mangleType(const UnaryTransformType *T, - SourceRange Range) { - DiagnosticsEngine &Diags = Context.getDiags(); - unsigned DiagID = Diags.getCustomDiagID(DiagnosticsEngine::Error, - "cannot mangle this unary transform type yet"); - Diags.Report(Range.getBegin(), DiagID) - << Range; -} - -void MicrosoftCXXNameMangler::mangleType(const AutoType *T, SourceRange Range) { - DiagnosticsEngine &Diags = Context.getDiags(); - unsigned DiagID = Diags.getCustomDiagID(DiagnosticsEngine::Error, - "cannot mangle this 'auto' type yet"); - Diags.Report(Range.getBegin(), DiagID) - << Range; -} - -void MicrosoftCXXNameMangler::mangleType(const AtomicType *T, - SourceRange Range) { - DiagnosticsEngine &Diags = Context.getDiags(); - unsigned DiagID = Diags.getCustomDiagID(DiagnosticsEngine::Error, - "cannot mangle this C11 atomic type yet"); - Diags.Report(Range.getBegin(), DiagID) - << Range; -} - -void MicrosoftMangleContext::mangleName(const NamedDecl *D, - raw_ostream &Out) { - assert((isa<FunctionDecl>(D) || isa<VarDecl>(D)) && - "Invalid mangleName() call, argument is not a variable or function!"); - assert(!isa<CXXConstructorDecl>(D) && !isa<CXXDestructorDecl>(D) && - "Invalid mangleName() call on 'structor decl!"); - - PrettyStackTraceDecl CrashInfo(D, SourceLocation(), - getASTContext().getSourceManager(), - "Mangling declaration"); - - MicrosoftCXXNameMangler Mangler(*this, Out); - return Mangler.mangle(D); -} -void MicrosoftMangleContext::mangleThunk(const CXXMethodDecl *MD, - const ThunkInfo &Thunk, - raw_ostream &) { - unsigned DiagID = getDiags().getCustomDiagID(DiagnosticsEngine::Error, - "cannot mangle thunk for this method yet"); - getDiags().Report(MD->getLocation(), DiagID); -} -void MicrosoftMangleContext::mangleCXXDtorThunk(const CXXDestructorDecl *DD, - CXXDtorType Type, - const ThisAdjustment &, - raw_ostream &) { - unsigned DiagID = getDiags().getCustomDiagID(DiagnosticsEngine::Error, - "cannot mangle thunk for this destructor yet"); - getDiags().Report(DD->getLocation(), DiagID); -} -void MicrosoftMangleContext::mangleCXXVTable(const CXXRecordDecl *RD, - raw_ostream &Out) { - // <mangled-name> ::= ? <operator-name> <class-name> <storage-class> - // <cvr-qualifiers> [<name>] @ - // <operator-name> ::= _7 # vftable - // ::= _8 # vbtable - // NOTE: <cvr-qualifiers> here is always 'B' (const). <storage-class> - // is always '6' for vftables and '7' for vbtables. (The difference is - // beyond me.) - // TODO: vbtables. - MicrosoftCXXNameMangler Mangler(*this, Out); - Mangler.getStream() << "\01??_7"; - Mangler.mangleName(RD); - Mangler.getStream() << "6B"; - // TODO: If the class has more than one vtable, mangle in the class it came - // from. - Mangler.getStream() << '@'; -} -void MicrosoftMangleContext::mangleCXXVTT(const CXXRecordDecl *RD, - raw_ostream &) { - llvm_unreachable("The MS C++ ABI does not have virtual table tables!"); -} -void MicrosoftMangleContext::mangleCXXCtorVTable(const CXXRecordDecl *RD, - int64_t Offset, - const CXXRecordDecl *Type, - raw_ostream &) { - llvm_unreachable("The MS C++ ABI does not have constructor vtables!"); -} -void MicrosoftMangleContext::mangleCXXRTTI(QualType T, - raw_ostream &) { - // FIXME: Give a location... - unsigned DiagID = getDiags().getCustomDiagID(DiagnosticsEngine::Error, - "cannot mangle RTTI descriptors for type %0 yet"); - getDiags().Report(DiagID) - << T.getBaseTypeIdentifier(); -} -void MicrosoftMangleContext::mangleCXXRTTIName(QualType T, - raw_ostream &) { - // FIXME: Give a location... - unsigned DiagID = getDiags().getCustomDiagID(DiagnosticsEngine::Error, - "cannot mangle the name of type %0 into RTTI descriptors yet"); - getDiags().Report(DiagID) - << T.getBaseTypeIdentifier(); -} -void MicrosoftMangleContext::mangleCXXCtor(const CXXConstructorDecl *D, - CXXCtorType Type, - raw_ostream & Out) { - MicrosoftCXXNameMangler mangler(*this, Out); - mangler.mangle(D); -} -void MicrosoftMangleContext::mangleCXXDtor(const CXXDestructorDecl *D, - CXXDtorType Type, - raw_ostream & Out) { - MicrosoftCXXNameMangler mangler(*this, Out); - mangler.mangle(D); -} -void MicrosoftMangleContext::mangleReferenceTemporary(const clang::VarDecl *VD, - raw_ostream &) { - unsigned DiagID = getDiags().getCustomDiagID(DiagnosticsEngine::Error, - "cannot mangle this reference temporary yet"); - getDiags().Report(VD->getLocation(), DiagID); -} - -MangleContext *clang::createMicrosoftMangleContext(ASTContext &Context, - DiagnosticsEngine &Diags) { - return new MicrosoftMangleContext(Context, Diags); -} +//===--- MicrosoftMangle.cpp - Microsoft Visual C++ Name Mangling ---------===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+//
+// This provides C++ name mangling targeting the Microsoft Visual C++ ABI.
+//
+//===----------------------------------------------------------------------===//
+
+#include "clang/AST/Mangle.h"
+#include "clang/AST/ASTContext.h"
+#include "clang/AST/Attr.h"
+#include "clang/AST/CharUnits.h"
+#include "clang/AST/Decl.h"
+#include "clang/AST/DeclCXX.h"
+#include "clang/AST/DeclObjC.h"
+#include "clang/AST/DeclTemplate.h"
+#include "clang/AST/ExprCXX.h"
+#include "clang/Basic/ABI.h"
+#include "clang/Basic/DiagnosticOptions.h"
+#include <map>
+
+using namespace clang;
+
+namespace {
+
+/// MicrosoftCXXNameMangler - Manage the mangling of a single name for the
+/// Microsoft Visual C++ ABI.
+class MicrosoftCXXNameMangler {
+ MangleContext &Context;
+ raw_ostream &Out;
+
+ // FIXME: audit the performance of BackRefMap as it might do way too many
+ // copying of strings.
+ typedef std::map<std::string, unsigned> BackRefMap;
+ BackRefMap NameBackReferences;
+ bool UseNameBackReferences;
+
+ typedef llvm::DenseMap<void*, unsigned> ArgBackRefMap;
+ ArgBackRefMap TypeBackReferences;
+
+ ASTContext &getASTContext() const { return Context.getASTContext(); }
+
+public:
+ MicrosoftCXXNameMangler(MangleContext &C, raw_ostream &Out_)
+ : Context(C), Out(Out_), UseNameBackReferences(true) { }
+
+ raw_ostream &getStream() const { return Out; }
+
+ void mangle(const NamedDecl *D, StringRef Prefix = "\01?");
+ void mangleName(const NamedDecl *ND);
+ void mangleFunctionEncoding(const FunctionDecl *FD);
+ void mangleVariableEncoding(const VarDecl *VD);
+ void mangleNumber(int64_t Number);
+ void mangleNumber(const llvm::APSInt &Value);
+ void mangleType(QualType T, SourceRange Range, bool MangleQualifiers = true);
+
+private:
+ void disableBackReferences() { UseNameBackReferences = false; }
+ void mangleUnqualifiedName(const NamedDecl *ND) {
+ mangleUnqualifiedName(ND, ND->getDeclName());
+ }
+ void mangleUnqualifiedName(const NamedDecl *ND, DeclarationName Name);
+ void mangleSourceName(const IdentifierInfo *II);
+ void manglePostfix(const DeclContext *DC, bool NoFunction=false);
+ void mangleOperatorName(OverloadedOperatorKind OO, SourceLocation Loc);
+ void mangleQualifiers(Qualifiers Quals, bool IsMember);
+ void manglePointerQualifiers(Qualifiers Quals);
+
+ void mangleUnscopedTemplateName(const TemplateDecl *ND);
+ void mangleTemplateInstantiationName(const TemplateDecl *TD,
+ const SmallVectorImpl<TemplateArgumentLoc> &TemplateArgs);
+ void mangleObjCMethodName(const ObjCMethodDecl *MD);
+ void mangleLocalName(const FunctionDecl *FD);
+
+ void mangleArgumentType(QualType T, SourceRange Range);
+
+ // Declare manglers for every type class.
+#define ABSTRACT_TYPE(CLASS, PARENT)
+#define NON_CANONICAL_TYPE(CLASS, PARENT)
+#define TYPE(CLASS, PARENT) void mangleType(const CLASS##Type *T, \
+ SourceRange Range);
+#include "clang/AST/TypeNodes.def"
+#undef ABSTRACT_TYPE
+#undef NON_CANONICAL_TYPE
+#undef TYPE
+
+ void mangleType(const TagType*);
+ void mangleType(const FunctionType *T, const FunctionDecl *D,
+ bool IsStructor, bool IsInstMethod);
+ void mangleType(const ArrayType *T, bool IsGlobal);
+ void mangleExtraDimensions(QualType T);
+ void mangleFunctionClass(const FunctionDecl *FD);
+ void mangleCallingConvention(const FunctionType *T, bool IsInstMethod = false);
+ void mangleIntegerLiteral(const llvm::APSInt &Number, bool IsBoolean);
+ void mangleExpression(const Expr *E);
+ void mangleThrowSpecification(const FunctionProtoType *T);
+
+ void mangleTemplateArgs(
+ const SmallVectorImpl<TemplateArgumentLoc> &TemplateArgs);
+
+};
+
+/// MicrosoftMangleContext - Overrides the default MangleContext for the
+/// Microsoft Visual C++ ABI.
+class MicrosoftMangleContext : public MangleContext {
+public:
+ MicrosoftMangleContext(ASTContext &Context,
+ DiagnosticsEngine &Diags) : MangleContext(Context, Diags) { }
+ virtual bool shouldMangleDeclName(const NamedDecl *D);
+ virtual void mangleName(const NamedDecl *D, raw_ostream &Out);
+ virtual void mangleThunk(const CXXMethodDecl *MD,
+ const ThunkInfo &Thunk,
+ raw_ostream &);
+ virtual void mangleCXXDtorThunk(const CXXDestructorDecl *DD, CXXDtorType Type,
+ const ThisAdjustment &ThisAdjustment,
+ raw_ostream &);
+ virtual void mangleCXXVTable(const CXXRecordDecl *RD,
+ raw_ostream &);
+ virtual void mangleCXXVTT(const CXXRecordDecl *RD,
+ raw_ostream &);
+ virtual void mangleCXXCtorVTable(const CXXRecordDecl *RD, int64_t Offset,
+ const CXXRecordDecl *Type,
+ raw_ostream &);
+ virtual void mangleCXXRTTI(QualType T, raw_ostream &);
+ virtual void mangleCXXRTTIName(QualType T, raw_ostream &);
+ virtual void mangleCXXCtor(const CXXConstructorDecl *D, CXXCtorType Type,
+ raw_ostream &);
+ virtual void mangleCXXDtor(const CXXDestructorDecl *D, CXXDtorType Type,
+ raw_ostream &);
+ virtual void mangleReferenceTemporary(const clang::VarDecl *,
+ raw_ostream &);
+};
+
+}
+
+static bool isInCLinkageSpecification(const Decl *D) {
+ D = D->getCanonicalDecl();
+ for (const DeclContext *DC = D->getDeclContext();
+ !DC->isTranslationUnit(); DC = DC->getParent()) {
+ if (const LinkageSpecDecl *Linkage = dyn_cast<LinkageSpecDecl>(DC))
+ return Linkage->getLanguage() == LinkageSpecDecl::lang_c;
+ }
+
+ return false;
+}
+
+bool MicrosoftMangleContext::shouldMangleDeclName(const NamedDecl *D) {
+ // In C, functions with no attributes never need to be mangled. Fastpath them.
+ if (!getASTContext().getLangOpts().CPlusPlus && !D->hasAttrs())
+ return false;
+
+ // Any decl can be declared with __asm("foo") on it, and this takes precedence
+ // over all other naming in the .o file.
+ if (D->hasAttr<AsmLabelAttr>())
+ return true;
+
+ // Clang's "overloadable" attribute extension to C/C++ implies name mangling
+ // (always) as does passing a C++ member function and a function
+ // whose name is not a simple identifier.
+ const FunctionDecl *FD = dyn_cast<FunctionDecl>(D);
+ if (FD && (FD->hasAttr<OverloadableAttr>() || isa<CXXMethodDecl>(FD) ||
+ !FD->getDeclName().isIdentifier()))
+ return true;
+
+ // Otherwise, no mangling is done outside C++ mode.
+ if (!getASTContext().getLangOpts().CPlusPlus)
+ return false;
+
+ // Variables at global scope with internal linkage are not mangled.
+ if (!FD) {
+ const DeclContext *DC = D->getDeclContext();
+ if (DC->isTranslationUnit() && D->getLinkage() == InternalLinkage)
+ return false;
+ }
+
+ // C functions and "main" are not mangled.
+ if ((FD && FD->isMain()) || isInCLinkageSpecification(D))
+ return false;
+
+ return true;
+}
+
+void MicrosoftCXXNameMangler::mangle(const NamedDecl *D,
+ StringRef Prefix) {
+ // MSVC doesn't mangle C++ names the same way it mangles extern "C" names.
+ // Therefore it's really important that we don't decorate the
+ // name with leading underscores or leading/trailing at signs. So, by
+ // default, we emit an asm marker at the start so we get the name right.
+ // Callers can override this with a custom prefix.
+
+ // Any decl can be declared with __asm("foo") on it, and this takes precedence
+ // over all other naming in the .o file.
+ if (const AsmLabelAttr *ALA = D->getAttr<AsmLabelAttr>()) {
+ // If we have an asm name, then we use it as the mangling.
+ Out << '\01' << ALA->getLabel();
+ return;
+ }
+
+ // <mangled-name> ::= ? <name> <type-encoding>
+ Out << Prefix;
+ mangleName(D);
+ if (const FunctionDecl *FD = dyn_cast<FunctionDecl>(D))
+ mangleFunctionEncoding(FD);
+ else if (const VarDecl *VD = dyn_cast<VarDecl>(D))
+ mangleVariableEncoding(VD);
+ else {
+ // TODO: Fields? Can MSVC even mangle them?
+ // Issue a diagnostic for now.
+ DiagnosticsEngine &Diags = Context.getDiags();
+ unsigned DiagID = Diags.getCustomDiagID(DiagnosticsEngine::Error,
+ "cannot mangle this declaration yet");
+ Diags.Report(D->getLocation(), DiagID)
+ << D->getSourceRange();
+ }
+}
+
+void MicrosoftCXXNameMangler::mangleFunctionEncoding(const FunctionDecl *FD) {
+ // <type-encoding> ::= <function-class> <function-type>
+
+ // Don't mangle in the type if this isn't a decl we should typically mangle.
+ if (!Context.shouldMangleDeclName(FD))
+ return;
+
+ // We should never ever see a FunctionNoProtoType at this point.
+ // We don't even know how to mangle their types anyway :).
+ const FunctionProtoType *FT = FD->getType()->castAs<FunctionProtoType>();
+
+ bool InStructor = false, InInstMethod = false;
+ const CXXMethodDecl *MD = dyn_cast<CXXMethodDecl>(FD);
+ if (MD) {
+ if (MD->isInstance())
+ InInstMethod = true;
+ if (isa<CXXConstructorDecl>(MD) || isa<CXXDestructorDecl>(MD))
+ InStructor = true;
+ }
+
+ // First, the function class.
+ mangleFunctionClass(FD);
+
+ mangleType(FT, FD, InStructor, InInstMethod);
+}
+
+void MicrosoftCXXNameMangler::mangleVariableEncoding(const VarDecl *VD) {
+ // <type-encoding> ::= <storage-class> <variable-type>
+ // <storage-class> ::= 0 # private static member
+ // ::= 1 # protected static member
+ // ::= 2 # public static member
+ // ::= 3 # global
+ // ::= 4 # static local
+
+ // The first character in the encoding (after the name) is the storage class.
+ if (VD->isStaticDataMember()) {
+ // If it's a static member, it also encodes the access level.
+ switch (VD->getAccess()) {
+ default:
+ case AS_private: Out << '0'; break;
+ case AS_protected: Out << '1'; break;
+ case AS_public: Out << '2'; break;
+ }
+ }
+ else if (!VD->isStaticLocal())
+ Out << '3';
+ else
+ Out << '4';
+ // Now mangle the type.
+ // <variable-type> ::= <type> <cvr-qualifiers>
+ // ::= <type> <pointee-cvr-qualifiers> # pointers, references
+ // Pointers and references are odd. The type of 'int * const foo;' gets
+ // mangled as 'QAHA' instead of 'PAHB', for example.
+ TypeLoc TL = VD->getTypeSourceInfo()->getTypeLoc();
+ QualType Ty = TL.getType();
+ if (Ty->isPointerType() || Ty->isReferenceType()) {
+ mangleType(Ty, TL.getSourceRange());
+ mangleQualifiers(Ty->getPointeeType().getQualifiers(), false);
+ } else if (const ArrayType *AT = getASTContext().getAsArrayType(Ty)) {
+ // Global arrays are funny, too.
+ mangleType(AT, true);
+ mangleQualifiers(Ty.getQualifiers(), false);
+ } else {
+ mangleType(Ty.getLocalUnqualifiedType(), TL.getSourceRange());
+ mangleQualifiers(Ty.getLocalQualifiers(), false);
+ }
+}
+
+void MicrosoftCXXNameMangler::mangleName(const NamedDecl *ND) {
+ // <name> ::= <unscoped-name> {[<named-scope>]+ | [<nested-name>]}? @
+ const DeclContext *DC = ND->getDeclContext();
+
+ // Always start with the unqualified name.
+ mangleUnqualifiedName(ND);
+
+ // If this is an extern variable declared locally, the relevant DeclContext
+ // is that of the containing namespace, or the translation unit.
+ if (isa<FunctionDecl>(DC) && ND->hasLinkage())
+ while (!DC->isNamespace() && !DC->isTranslationUnit())
+ DC = DC->getParent();
+
+ manglePostfix(DC);
+
+ // Terminate the whole name with an '@'.
+ Out << '@';
+}
+
+void MicrosoftCXXNameMangler::mangleNumber(int64_t Number) {
+ llvm::APSInt APSNumber(/*BitWidth=*/64, /*isUnsigned=*/false);
+ APSNumber = Number;
+ mangleNumber(APSNumber);
+}
+
+void MicrosoftCXXNameMangler::mangleNumber(const llvm::APSInt &Value) {
+ // <number> ::= [?] <decimal digit> # 1 <= Number <= 10
+ // ::= [?] <hex digit>+ @ # 0 or > 9; A = 0, B = 1, etc...
+ // ::= [?] @ # 0 (alternate mangling, not emitted by VC)
+ if (Value.isSigned() && Value.isNegative()) {
+ Out << '?';
+ mangleNumber(llvm::APSInt(Value.abs()));
+ return;
+ }
+ llvm::APSInt Temp(Value);
+ // There's a special shorter mangling for 0, but Microsoft
+ // chose not to use it. Instead, 0 gets mangled as "A@". Oh well...
+ if (Value.uge(1) && Value.ule(10)) {
+ --Temp;
+ Temp.print(Out, false);
+ } else {
+ // We have to build up the encoding in reverse order, so it will come
+ // out right when we write it out.
+ char Encoding[64];
+ char *EndPtr = Encoding+sizeof(Encoding);
+ char *CurPtr = EndPtr;
+ llvm::APSInt NibbleMask(Value.getBitWidth(), Value.isUnsigned());
+ NibbleMask = 0xf;
+ do {
+ *--CurPtr = 'A' + Temp.And(NibbleMask).getLimitedValue(0xf);
+ Temp = Temp.lshr(4);
+ } while (Temp != 0);
+ Out.write(CurPtr, EndPtr-CurPtr);
+ Out << '@';
+ }
+}
+
+static const TemplateDecl *
+isTemplate(const NamedDecl *ND,
+ SmallVectorImpl<TemplateArgumentLoc> &TemplateArgs) {
+ // Check if we have a function template.
+ if (const FunctionDecl *FD = dyn_cast<FunctionDecl>(ND)){
+ if (const TemplateDecl *TD = FD->getPrimaryTemplate()) {
+ if (FD->getTemplateSpecializationArgsAsWritten()) {
+ const ASTTemplateArgumentListInfo *ArgList =
+ FD->getTemplateSpecializationArgsAsWritten();
+ TemplateArgs.append(ArgList->getTemplateArgs(),
+ ArgList->getTemplateArgs() +
+ ArgList->NumTemplateArgs);
+ } else {
+ const TemplateArgumentList *ArgList =
+ FD->getTemplateSpecializationArgs();
+ TemplateArgumentListInfo LI;
+ for (unsigned i = 0, e = ArgList->size(); i != e; ++i)
+ TemplateArgs.push_back(TemplateArgumentLoc(ArgList->get(i),
+ FD->getTypeSourceInfo()));
+ }
+ return TD;
+ }
+ }
+
+ // Check if we have a class template.
+ if (const ClassTemplateSpecializationDecl *Spec =
+ dyn_cast<ClassTemplateSpecializationDecl>(ND)) {
+ TypeSourceInfo *TSI = Spec->getTypeAsWritten();
+ if (TSI) {
+ TemplateSpecializationTypeLoc TSTL =
+ cast<TemplateSpecializationTypeLoc>(TSI->getTypeLoc());
+ TemplateArgumentListInfo LI(TSTL.getLAngleLoc(), TSTL.getRAngleLoc());
+ for (unsigned i = 0, e = TSTL.getNumArgs(); i != e; ++i)
+ TemplateArgs.push_back(TSTL.getArgLoc(i));
+ } else {
+ TemplateArgumentListInfo LI;
+ const TemplateArgumentList &ArgList =
+ Spec->getTemplateArgs();
+ for (unsigned i = 0, e = ArgList.size(); i != e; ++i)
+ TemplateArgs.push_back(TemplateArgumentLoc(ArgList[i],
+ TemplateArgumentLocInfo()));
+ }
+ return Spec->getSpecializedTemplate();
+ }
+
+ return 0;
+}
+
+void
+MicrosoftCXXNameMangler::mangleUnqualifiedName(const NamedDecl *ND,
+ DeclarationName Name) {
+ // <unqualified-name> ::= <operator-name>
+ // ::= <ctor-dtor-name>
+ // ::= <source-name>
+ // ::= <template-name>
+ SmallVector<TemplateArgumentLoc, 2> TemplateArgs;
+ // Check if we have a template.
+ if (const TemplateDecl *TD = isTemplate(ND, TemplateArgs)) {
+ // We have a template.
+ // Here comes the tricky thing: if we need to mangle something like
+ // void foo(A::X<Y>, B::X<Y>),
+ // the X<Y> part is aliased. However, if you need to mangle
+ // void foo(A::X<A::Y>, A::X<B::Y>),
+ // the A::X<> part is not aliased.
+ // That said, from the mangler's perspective we have a structure like this:
+ // namespace[s] -> type[ -> template-parameters]
+ // but from the Clang perspective we have
+ // type [ -> template-parameters]
+ // \-> namespace[s]
+ // What we do is we create a new mangler, mangle the same type (without
+ // a namespace suffix) using the extra mangler with back references
+ // disabled (to avoid infinite recursion) and then use the mangled type
+ // name as a key to check the mangling of different types for aliasing.
+
+ std::string BackReferenceKey;
+ BackRefMap::iterator Found;
+ if (UseNameBackReferences) {
+ llvm::raw_string_ostream Stream(BackReferenceKey);
+ MicrosoftCXXNameMangler Extra(Context, Stream);
+ Extra.disableBackReferences();
+ Extra.mangleUnqualifiedName(ND, Name);
+ Stream.flush();
+
+ Found = NameBackReferences.find(BackReferenceKey);
+ }
+ if (!UseNameBackReferences || Found == NameBackReferences.end()) {
+ mangleTemplateInstantiationName(TD, TemplateArgs);
+ if (UseNameBackReferences && NameBackReferences.size() < 10) {
+ size_t Size = NameBackReferences.size();
+ NameBackReferences[BackReferenceKey] = Size;
+ }
+ } else {
+ Out << Found->second;
+ }
+ return;
+ }
+
+ switch (Name.getNameKind()) {
+ case DeclarationName::Identifier: {
+ if (const IdentifierInfo *II = Name.getAsIdentifierInfo()) {
+ mangleSourceName(II);
+ break;
+ }
+
+ // Otherwise, an anonymous entity. We must have a declaration.
+ assert(ND && "mangling empty name without declaration");
+
+ if (const NamespaceDecl *NS = dyn_cast<NamespaceDecl>(ND)) {
+ if (NS->isAnonymousNamespace()) {
+ Out << "?A@";
+ break;
+ }
+ }
+
+ // We must have an anonymous struct.
+ const TagDecl *TD = cast<TagDecl>(ND);
+ if (const TypedefNameDecl *D = TD->getTypedefNameForAnonDecl()) {
+ assert(TD->getDeclContext() == D->getDeclContext() &&
+ "Typedef should not be in another decl context!");
+ assert(D->getDeclName().getAsIdentifierInfo() &&
+ "Typedef was not named!");
+ mangleSourceName(D->getDeclName().getAsIdentifierInfo());
+ break;
+ }
+
+ // When VC encounters an anonymous type with no tag and no typedef,
+ // it literally emits '<unnamed-tag>'.
+ Out << "<unnamed-tag>";
+ break;
+ }
+
+ case DeclarationName::ObjCZeroArgSelector:
+ case DeclarationName::ObjCOneArgSelector:
+ case DeclarationName::ObjCMultiArgSelector:
+ llvm_unreachable("Can't mangle Objective-C selector names here!");
+
+ case DeclarationName::CXXConstructorName:
+ Out << "?0";
+ break;
+
+ case DeclarationName::CXXDestructorName:
+ Out << "?1";
+ break;
+
+ case DeclarationName::CXXConversionFunctionName:
+ // <operator-name> ::= ?B # (cast)
+ // The target type is encoded as the return type.
+ Out << "?B";
+ break;
+
+ case DeclarationName::CXXOperatorName:
+ mangleOperatorName(Name.getCXXOverloadedOperator(), ND->getLocation());
+ break;
+
+ case DeclarationName::CXXLiteralOperatorName: {
+ // FIXME: Was this added in VS2010? Does MS even know how to mangle this?
+ DiagnosticsEngine Diags = Context.getDiags();
+ unsigned DiagID = Diags.getCustomDiagID(DiagnosticsEngine::Error,
+ "cannot mangle this literal operator yet");
+ Diags.Report(ND->getLocation(), DiagID);
+ break;
+ }
+
+ case DeclarationName::CXXUsingDirective:
+ llvm_unreachable("Can't mangle a using directive name!");
+ }
+}
+
+void MicrosoftCXXNameMangler::manglePostfix(const DeclContext *DC,
+ bool NoFunction) {
+ // <postfix> ::= <unqualified-name> [<postfix>]
+ // ::= <substitution> [<postfix>]
+
+ if (!DC) return;
+
+ while (isa<LinkageSpecDecl>(DC))
+ DC = DC->getParent();
+
+ if (DC->isTranslationUnit())
+ return;
+
+ if (const BlockDecl *BD = dyn_cast<BlockDecl>(DC)) {
+ Context.mangleBlock(BD, Out);
+ Out << '@';
+ return manglePostfix(DC->getParent(), NoFunction);
+ }
+
+ if (NoFunction && (isa<FunctionDecl>(DC) || isa<ObjCMethodDecl>(DC)))
+ return;
+ else if (const ObjCMethodDecl *Method = dyn_cast<ObjCMethodDecl>(DC))
+ mangleObjCMethodName(Method);
+ else if (const FunctionDecl *Func = dyn_cast<FunctionDecl>(DC))
+ mangleLocalName(Func);
+ else {
+ mangleUnqualifiedName(cast<NamedDecl>(DC));
+ manglePostfix(DC->getParent(), NoFunction);
+ }
+}
+
+void MicrosoftCXXNameMangler::mangleOperatorName(OverloadedOperatorKind OO,
+ SourceLocation Loc) {
+ switch (OO) {
+ // ?0 # constructor
+ // ?1 # destructor
+ // <operator-name> ::= ?2 # new
+ case OO_New: Out << "?2"; break;
+ // <operator-name> ::= ?3 # delete
+ case OO_Delete: Out << "?3"; break;
+ // <operator-name> ::= ?4 # =
+ case OO_Equal: Out << "?4"; break;
+ // <operator-name> ::= ?5 # >>
+ case OO_GreaterGreater: Out << "?5"; break;
+ // <operator-name> ::= ?6 # <<
+ case OO_LessLess: Out << "?6"; break;
+ // <operator-name> ::= ?7 # !
+ case OO_Exclaim: Out << "?7"; break;
+ // <operator-name> ::= ?8 # ==
+ case OO_EqualEqual: Out << "?8"; break;
+ // <operator-name> ::= ?9 # !=
+ case OO_ExclaimEqual: Out << "?9"; break;
+ // <operator-name> ::= ?A # []
+ case OO_Subscript: Out << "?A"; break;
+ // ?B # conversion
+ // <operator-name> ::= ?C # ->
+ case OO_Arrow: Out << "?C"; break;
+ // <operator-name> ::= ?D # *
+ case OO_Star: Out << "?D"; break;
+ // <operator-name> ::= ?E # ++
+ case OO_PlusPlus: Out << "?E"; break;
+ // <operator-name> ::= ?F # --
+ case OO_MinusMinus: Out << "?F"; break;
+ // <operator-name> ::= ?G # -
+ case OO_Minus: Out << "?G"; break;
+ // <operator-name> ::= ?H # +
+ case OO_Plus: Out << "?H"; break;
+ // <operator-name> ::= ?I # &
+ case OO_Amp: Out << "?I"; break;
+ // <operator-name> ::= ?J # ->*
+ case OO_ArrowStar: Out << "?J"; break;
+ // <operator-name> ::= ?K # /
+ case OO_Slash: Out << "?K"; break;
+ // <operator-name> ::= ?L # %
+ case OO_Percent: Out << "?L"; break;
+ // <operator-name> ::= ?M # <
+ case OO_Less: Out << "?M"; break;
+ // <operator-name> ::= ?N # <=
+ case OO_LessEqual: Out << "?N"; break;
+ // <operator-name> ::= ?O # >
+ case OO_Greater: Out << "?O"; break;
+ // <operator-name> ::= ?P # >=
+ case OO_GreaterEqual: Out << "?P"; break;
+ // <operator-name> ::= ?Q # ,
+ case OO_Comma: Out << "?Q"; break;
+ // <operator-name> ::= ?R # ()
+ case OO_Call: Out << "?R"; break;
+ // <operator-name> ::= ?S # ~
+ case OO_Tilde: Out << "?S"; break;
+ // <operator-name> ::= ?T # ^
+ case OO_Caret: Out << "?T"; break;
+ // <operator-name> ::= ?U # |
+ case OO_Pipe: Out << "?U"; break;
+ // <operator-name> ::= ?V # &&
+ case OO_AmpAmp: Out << "?V"; break;
+ // <operator-name> ::= ?W # ||
+ case OO_PipePipe: Out << "?W"; break;
+ // <operator-name> ::= ?X # *=
+ case OO_StarEqual: Out << "?X"; break;
+ // <operator-name> ::= ?Y # +=
+ case OO_PlusEqual: Out << "?Y"; break;
+ // <operator-name> ::= ?Z # -=
+ case OO_MinusEqual: Out << "?Z"; break;
+ // <operator-name> ::= ?_0 # /=
+ case OO_SlashEqual: Out << "?_0"; break;
+ // <operator-name> ::= ?_1 # %=
+ case OO_PercentEqual: Out << "?_1"; break;
+ // <operator-name> ::= ?_2 # >>=
+ case OO_GreaterGreaterEqual: Out << "?_2"; break;
+ // <operator-name> ::= ?_3 # <<=
+ case OO_LessLessEqual: Out << "?_3"; break;
+ // <operator-name> ::= ?_4 # &=
+ case OO_AmpEqual: Out << "?_4"; break;
+ // <operator-name> ::= ?_5 # |=
+ case OO_PipeEqual: Out << "?_5"; break;
+ // <operator-name> ::= ?_6 # ^=
+ case OO_CaretEqual: Out << "?_6"; break;
+ // ?_7 # vftable
+ // ?_8 # vbtable
+ // ?_9 # vcall
+ // ?_A # typeof
+ // ?_B # local static guard
+ // ?_C # string
+ // ?_D # vbase destructor
+ // ?_E # vector deleting destructor
+ // ?_F # default constructor closure
+ // ?_G # scalar deleting destructor
+ // ?_H # vector constructor iterator
+ // ?_I # vector destructor iterator
+ // ?_J # vector vbase constructor iterator
+ // ?_K # virtual displacement map
+ // ?_L # eh vector constructor iterator
+ // ?_M # eh vector destructor iterator
+ // ?_N # eh vector vbase constructor iterator
+ // ?_O # copy constructor closure
+ // ?_P<name> # udt returning <name>
+ // ?_Q # <unknown>
+ // ?_R0 # RTTI Type Descriptor
+ // ?_R1 # RTTI Base Class Descriptor at (a,b,c,d)
+ // ?_R2 # RTTI Base Class Array
+ // ?_R3 # RTTI Class Hierarchy Descriptor
+ // ?_R4 # RTTI Complete Object Locator
+ // ?_S # local vftable
+ // ?_T # local vftable constructor closure
+ // <operator-name> ::= ?_U # new[]
+ case OO_Array_New: Out << "?_U"; break;
+ // <operator-name> ::= ?_V # delete[]
+ case OO_Array_Delete: Out << "?_V"; break;
+
+ case OO_Conditional: {
+ DiagnosticsEngine &Diags = Context.getDiags();
+ unsigned DiagID = Diags.getCustomDiagID(DiagnosticsEngine::Error,
+ "cannot mangle this conditional operator yet");
+ Diags.Report(Loc, DiagID);
+ break;
+ }
+
+ case OO_None:
+ case NUM_OVERLOADED_OPERATORS:
+ llvm_unreachable("Not an overloaded operator");
+ }
+}
+
+void MicrosoftCXXNameMangler::mangleSourceName(const IdentifierInfo *II) {
+ // <source name> ::= <identifier> @
+ std::string key = II->getNameStart();
+ BackRefMap::iterator Found;
+ if (UseNameBackReferences)
+ Found = NameBackReferences.find(key);
+ if (!UseNameBackReferences || Found == NameBackReferences.end()) {
+ Out << II->getName() << '@';
+ if (UseNameBackReferences && NameBackReferences.size() < 10) {
+ size_t Size = NameBackReferences.size();
+ NameBackReferences[key] = Size;
+ }
+ } else {
+ Out << Found->second;
+ }
+}
+
+void MicrosoftCXXNameMangler::mangleObjCMethodName(const ObjCMethodDecl *MD) {
+ Context.mangleObjCMethodName(MD, Out);
+}
+
+// Find out how many function decls live above this one and return an integer
+// suitable for use as the number in a numbered anonymous scope.
+// TODO: Memoize.
+static unsigned getLocalNestingLevel(const FunctionDecl *FD) {
+ const DeclContext *DC = FD->getParent();
+ int level = 1;
+
+ while (DC && !DC->isTranslationUnit()) {
+ if (isa<FunctionDecl>(DC) || isa<ObjCMethodDecl>(DC)) level++;
+ DC = DC->getParent();
+ }
+
+ return 2*level;
+}
+
+void MicrosoftCXXNameMangler::mangleLocalName(const FunctionDecl *FD) {
+ // <nested-name> ::= <numbered-anonymous-scope> ? <mangled-name>
+ // <numbered-anonymous-scope> ::= ? <number>
+ // Even though the name is rendered in reverse order (e.g.
+ // A::B::C is rendered as C@B@A), VC numbers the scopes from outermost to
+ // innermost. So a method bar in class C local to function foo gets mangled
+ // as something like:
+ // ?bar@C@?1??foo@@YAXXZ@QAEXXZ
+ // This is more apparent when you have a type nested inside a method of a
+ // type nested inside a function. A method baz in class D local to method
+ // bar of class C local to function foo gets mangled as:
+ // ?baz@D@?3??bar@C@?1??foo@@YAXXZ@QAEXXZ@QAEXXZ
+ // This scheme is general enough to support GCC-style nested
+ // functions. You could have a method baz of class C inside a function bar
+ // inside a function foo, like so:
+ // ?baz@C@?3??bar@?1??foo@@YAXXZ@YAXXZ@QAEXXZ
+ int NestLevel = getLocalNestingLevel(FD);
+ Out << '?';
+ mangleNumber(NestLevel);
+ Out << '?';
+ mangle(FD, "?");
+}
+
+void MicrosoftCXXNameMangler::mangleTemplateInstantiationName(
+ const TemplateDecl *TD,
+ const SmallVectorImpl<TemplateArgumentLoc> &TemplateArgs) {
+ // <template-name> ::= <unscoped-template-name> <template-args>
+ // ::= <substitution>
+ // Always start with the unqualified name.
+
+ // Templates have their own context for back references.
+ ArgBackRefMap OuterArgsContext;
+ BackRefMap OuterTemplateContext;
+ NameBackReferences.swap(OuterTemplateContext);
+ TypeBackReferences.swap(OuterArgsContext);
+
+ mangleUnscopedTemplateName(TD);
+ mangleTemplateArgs(TemplateArgs);
+
+ // Restore the previous back reference contexts.
+ NameBackReferences.swap(OuterTemplateContext);
+ TypeBackReferences.swap(OuterArgsContext);
+}
+
+void
+MicrosoftCXXNameMangler::mangleUnscopedTemplateName(const TemplateDecl *TD) {
+ // <unscoped-template-name> ::= ?$ <unqualified-name>
+ Out << "?$";
+ mangleUnqualifiedName(TD);
+}
+
+void
+MicrosoftCXXNameMangler::mangleIntegerLiteral(const llvm::APSInt &Value,
+ bool IsBoolean) {
+ // <integer-literal> ::= $0 <number>
+ Out << "$0";
+ // Make sure booleans are encoded as 0/1.
+ if (IsBoolean && Value.getBoolValue())
+ mangleNumber(1);
+ else
+ mangleNumber(Value);
+}
+
+void
+MicrosoftCXXNameMangler::mangleExpression(const Expr *E) {
+ // See if this is a constant expression.
+ llvm::APSInt Value;
+ if (E->isIntegerConstantExpr(Value, Context.getASTContext())) {
+ mangleIntegerLiteral(Value, E->getType()->isBooleanType());
+ return;
+ }
+
+ // As bad as this diagnostic is, it's better than crashing.
+ DiagnosticsEngine &Diags = Context.getDiags();
+ unsigned DiagID = Diags.getCustomDiagID(DiagnosticsEngine::Error,
+ "cannot yet mangle expression type %0");
+ Diags.Report(E->getExprLoc(), DiagID)
+ << E->getStmtClassName() << E->getSourceRange();
+}
+
+void
+MicrosoftCXXNameMangler::mangleTemplateArgs(
+ const SmallVectorImpl<TemplateArgumentLoc> &TemplateArgs) {
+ // <template-args> ::= {<type> | <integer-literal>}+ @
+ unsigned NumTemplateArgs = TemplateArgs.size();
+ for (unsigned i = 0; i < NumTemplateArgs; ++i) {
+ const TemplateArgumentLoc &TAL = TemplateArgs[i];
+ const TemplateArgument &TA = TAL.getArgument();
+ switch (TA.getKind()) {
+ case TemplateArgument::Null:
+ llvm_unreachable("Can't mangle null template arguments!");
+ case TemplateArgument::Type:
+ mangleType(TA.getAsType(), TAL.getSourceRange());
+ break;
+ case TemplateArgument::Integral:
+ mangleIntegerLiteral(TA.getAsIntegral(),
+ TA.getIntegralType()->isBooleanType());
+ break;
+ case TemplateArgument::Expression:
+ mangleExpression(TA.getAsExpr());
+ break;
+ case TemplateArgument::Template:
+ case TemplateArgument::TemplateExpansion:
+ case TemplateArgument::Declaration:
+ case TemplateArgument::NullPtr:
+ case TemplateArgument::Pack: {
+ // Issue a diagnostic.
+ DiagnosticsEngine &Diags = Context.getDiags();
+ unsigned DiagID = Diags.getCustomDiagID(DiagnosticsEngine::Error,
+ "cannot mangle this %select{ERROR|ERROR|pointer/reference|nullptr|"
+ "integral|template|template pack expansion|ERROR|parameter pack}0 "
+ "template argument yet");
+ Diags.Report(TAL.getLocation(), DiagID)
+ << TA.getKind()
+ << TAL.getSourceRange();
+ }
+ }
+ }
+ Out << '@';
+}
+
+void MicrosoftCXXNameMangler::mangleQualifiers(Qualifiers Quals,
+ bool IsMember) {
+ // <cvr-qualifiers> ::= [E] [F] [I] <base-cvr-qualifiers>
+ // 'E' means __ptr64 (32-bit only); 'F' means __unaligned (32/64-bit only);
+ // 'I' means __restrict (32/64-bit).
+ // Note that the MSVC __restrict keyword isn't the same as the C99 restrict
+ // keyword!
+ // <base-cvr-qualifiers> ::= A # near
+ // ::= B # near const
+ // ::= C # near volatile
+ // ::= D # near const volatile
+ // ::= E # far (16-bit)
+ // ::= F # far const (16-bit)
+ // ::= G # far volatile (16-bit)
+ // ::= H # far const volatile (16-bit)
+ // ::= I # huge (16-bit)
+ // ::= J # huge const (16-bit)
+ // ::= K # huge volatile (16-bit)
+ // ::= L # huge const volatile (16-bit)
+ // ::= M <basis> # based
+ // ::= N <basis> # based const
+ // ::= O <basis> # based volatile
+ // ::= P <basis> # based const volatile
+ // ::= Q # near member
+ // ::= R # near const member
+ // ::= S # near volatile member
+ // ::= T # near const volatile member
+ // ::= U # far member (16-bit)
+ // ::= V # far const member (16-bit)
+ // ::= W # far volatile member (16-bit)
+ // ::= X # far const volatile member (16-bit)
+ // ::= Y # huge member (16-bit)
+ // ::= Z # huge const member (16-bit)
+ // ::= 0 # huge volatile member (16-bit)
+ // ::= 1 # huge const volatile member (16-bit)
+ // ::= 2 <basis> # based member
+ // ::= 3 <basis> # based const member
+ // ::= 4 <basis> # based volatile member
+ // ::= 5 <basis> # based const volatile member
+ // ::= 6 # near function (pointers only)
+ // ::= 7 # far function (pointers only)
+ // ::= 8 # near method (pointers only)
+ // ::= 9 # far method (pointers only)
+ // ::= _A <basis> # based function (pointers only)
+ // ::= _B <basis> # based function (far?) (pointers only)
+ // ::= _C <basis> # based method (pointers only)
+ // ::= _D <basis> # based method (far?) (pointers only)
+ // ::= _E # block (Clang)
+ // <basis> ::= 0 # __based(void)
+ // ::= 1 # __based(segment)?
+ // ::= 2 <name> # __based(name)
+ // ::= 3 # ?
+ // ::= 4 # ?
+ // ::= 5 # not really based
+ bool HasConst = Quals.hasConst(),
+ HasVolatile = Quals.hasVolatile();
+ if (!IsMember) {
+ if (HasConst && HasVolatile) {
+ Out << 'D';
+ } else if (HasVolatile) {
+ Out << 'C';
+ } else if (HasConst) {
+ Out << 'B';
+ } else {
+ Out << 'A';
+ }
+ } else {
+ if (HasConst && HasVolatile) {
+ Out << 'T';
+ } else if (HasVolatile) {
+ Out << 'S';
+ } else if (HasConst) {
+ Out << 'R';
+ } else {
+ Out << 'Q';
+ }
+ }
+
+ // FIXME: For now, just drop all extension qualifiers on the floor.
+}
+
+void MicrosoftCXXNameMangler::manglePointerQualifiers(Qualifiers Quals) {
+ // <pointer-cvr-qualifiers> ::= P # no qualifiers
+ // ::= Q # const
+ // ::= R # volatile
+ // ::= S # const volatile
+ bool HasConst = Quals.hasConst(),
+ HasVolatile = Quals.hasVolatile();
+ if (HasConst && HasVolatile) {
+ Out << 'S';
+ } else if (HasVolatile) {
+ Out << 'R';
+ } else if (HasConst) {
+ Out << 'Q';
+ } else {
+ Out << 'P';
+ }
+}
+
+void MicrosoftCXXNameMangler::mangleArgumentType(QualType T,
+ SourceRange Range) {
+ void *TypePtr = getASTContext().getCanonicalType(T).getAsOpaquePtr();
+ ArgBackRefMap::iterator Found = TypeBackReferences.find(TypePtr);
+
+ if (Found == TypeBackReferences.end()) {
+ size_t OutSizeBefore = Out.GetNumBytesInBuffer();
+
+ mangleType(T, Range, false);
+
+ // See if it's worth creating a back reference.
+ // Only types longer than 1 character are considered
+ // and only 10 back references slots are available:
+ bool LongerThanOneChar = (Out.GetNumBytesInBuffer() - OutSizeBefore > 1);
+ if (LongerThanOneChar && TypeBackReferences.size() < 10) {
+ size_t Size = TypeBackReferences.size();
+ TypeBackReferences[TypePtr] = Size;
+ }
+ } else {
+ Out << Found->second;
+ }
+}
+
+void MicrosoftCXXNameMangler::mangleType(QualType T, SourceRange Range,
+ bool MangleQualifiers) {
+ // Only operate on the canonical type!
+ T = getASTContext().getCanonicalType(T);
+
+ Qualifiers Quals = T.getLocalQualifiers();
+ // We have to mangle these now, while we still have enough information.
+ if (T->isAnyPointerType() || T->isMemberPointerType() ||
+ T->isBlockPointerType()) {
+ manglePointerQualifiers(Quals);
+ } else if (Quals && MangleQualifiers) {
+ mangleQualifiers(Quals, false);
+ }
+
+ SplitQualType split = T.split();
+ const Type *ty = split.Ty;
+
+ // If we're mangling a qualified array type, push the qualifiers to
+ // the element type.
+ if (split.Quals && isa<ArrayType>(T)) {
+ ty = Context.getASTContext().getAsArrayType(T);
+ }
+
+ switch (ty->getTypeClass()) {
+#define ABSTRACT_TYPE(CLASS, PARENT)
+#define NON_CANONICAL_TYPE(CLASS, PARENT) \
+ case Type::CLASS: \
+ llvm_unreachable("can't mangle non-canonical type " #CLASS "Type"); \
+ return;
+#define TYPE(CLASS, PARENT) \
+ case Type::CLASS: \
+ mangleType(cast<CLASS##Type>(ty), Range); \
+ break;
+#include "clang/AST/TypeNodes.def"
+#undef ABSTRACT_TYPE
+#undef NON_CANONICAL_TYPE
+#undef TYPE
+ }
+}
+
+void MicrosoftCXXNameMangler::mangleType(const BuiltinType *T,
+ SourceRange Range) {
+ // <type> ::= <builtin-type>
+ // <builtin-type> ::= X # void
+ // ::= C # signed char
+ // ::= D # char
+ // ::= E # unsigned char
+ // ::= F # short
+ // ::= G # unsigned short (or wchar_t if it's not a builtin)
+ // ::= H # int
+ // ::= I # unsigned int
+ // ::= J # long
+ // ::= K # unsigned long
+ // L # <none>
+ // ::= M # float
+ // ::= N # double
+ // ::= O # long double (__float80 is mangled differently)
+ // ::= _J # long long, __int64
+ // ::= _K # unsigned long long, __int64
+ // ::= _L # __int128
+ // ::= _M # unsigned __int128
+ // ::= _N # bool
+ // _O # <array in parameter>
+ // ::= _T # __float80 (Intel)
+ // ::= _W # wchar_t
+ // ::= _Z # __float80 (Digital Mars)
+ switch (T->getKind()) {
+ case BuiltinType::Void: Out << 'X'; break;
+ case BuiltinType::SChar: Out << 'C'; break;
+ case BuiltinType::Char_U: case BuiltinType::Char_S: Out << 'D'; break;
+ case BuiltinType::UChar: Out << 'E'; break;
+ case BuiltinType::Short: Out << 'F'; break;
+ case BuiltinType::UShort: Out << 'G'; break;
+ case BuiltinType::Int: Out << 'H'; break;
+ case BuiltinType::UInt: Out << 'I'; break;
+ case BuiltinType::Long: Out << 'J'; break;
+ case BuiltinType::ULong: Out << 'K'; break;
+ case BuiltinType::Float: Out << 'M'; break;
+ case BuiltinType::Double: Out << 'N'; break;
+ // TODO: Determine size and mangle accordingly
+ case BuiltinType::LongDouble: Out << 'O'; break;
+ case BuiltinType::LongLong: Out << "_J"; break;
+ case BuiltinType::ULongLong: Out << "_K"; break;
+ case BuiltinType::Int128: Out << "_L"; break;
+ case BuiltinType::UInt128: Out << "_M"; break;
+ case BuiltinType::Bool: Out << "_N"; break;
+ case BuiltinType::WChar_S:
+ case BuiltinType::WChar_U: Out << "_W"; break;
+
+#define BUILTIN_TYPE(Id, SingletonId)
+#define PLACEHOLDER_TYPE(Id, SingletonId) \
+ case BuiltinType::Id:
+#include "clang/AST/BuiltinTypes.def"
+ case BuiltinType::Dependent:
+ llvm_unreachable("placeholder types shouldn't get to name mangling");
+
+ case BuiltinType::ObjCId: Out << "PAUobjc_object@@"; break;
+ case BuiltinType::ObjCClass: Out << "PAUobjc_class@@"; break;
+ case BuiltinType::ObjCSel: Out << "PAUobjc_selector@@"; break;
+
+ case BuiltinType::OCLImage1d: Out << "PAUocl_image1d@@"; break;
+ case BuiltinType::OCLImage1dArray: Out << "PAUocl_image1darray@@"; break;
+ case BuiltinType::OCLImage1dBuffer: Out << "PAUocl_image1dbuffer@@"; break;
+ case BuiltinType::OCLImage2d: Out << "PAUocl_image2d@@"; break;
+ case BuiltinType::OCLImage2dArray: Out << "PAUocl_image2darray@@"; break;
+ case BuiltinType::OCLImage3d: Out << "PAUocl_image3d@@"; break;
+
+ case BuiltinType::NullPtr: Out << "$$T"; break;
+
+ case BuiltinType::Char16:
+ case BuiltinType::Char32:
+ case BuiltinType::Half: {
+ DiagnosticsEngine &Diags = Context.getDiags();
+ unsigned DiagID = Diags.getCustomDiagID(DiagnosticsEngine::Error,
+ "cannot mangle this built-in %0 type yet");
+ Diags.Report(Range.getBegin(), DiagID)
+ << T->getName(Context.getASTContext().getPrintingPolicy())
+ << Range;
+ break;
+ }
+ }
+}
+
+// <type> ::= <function-type>
+void MicrosoftCXXNameMangler::mangleType(const FunctionProtoType *T,
+ SourceRange) {
+ // Structors only appear in decls, so at this point we know it's not a
+ // structor type.
+ // FIXME: This may not be lambda-friendly.
+ Out << "$$A6";
+ mangleType(T, NULL, false, false);
+}
+void MicrosoftCXXNameMangler::mangleType(const FunctionNoProtoType *T,
+ SourceRange) {
+ llvm_unreachable("Can't mangle K&R function prototypes");
+}
+
+void MicrosoftCXXNameMangler::mangleType(const FunctionType *T,
+ const FunctionDecl *D,
+ bool IsStructor,
+ bool IsInstMethod) {
+ // <function-type> ::= <this-cvr-qualifiers> <calling-convention>
+ // <return-type> <argument-list> <throw-spec>
+ const FunctionProtoType *Proto = cast<FunctionProtoType>(T);
+
+ // If this is a C++ instance method, mangle the CVR qualifiers for the
+ // this pointer.
+ if (IsInstMethod)
+ mangleQualifiers(Qualifiers::fromCVRMask(Proto->getTypeQuals()), false);
+
+ mangleCallingConvention(T, IsInstMethod);
+
+ // <return-type> ::= <type>
+ // ::= @ # structors (they have no declared return type)
+ if (IsStructor)
+ Out << '@';
+ else {
+ QualType Result = Proto->getResultType();
+ const Type* RT = Result.getTypePtr();
+ if (!RT->isAnyPointerType() && !RT->isReferenceType()) {
+ if (Result.hasQualifiers() || !RT->isBuiltinType())
+ Out << '?';
+ if (!RT->isBuiltinType() && !Result.hasQualifiers()) {
+ // Lack of qualifiers for user types is mangled as 'A'.
+ Out << 'A';
+ }
+ }
+
+ // FIXME: Get the source range for the result type. Or, better yet,
+ // implement the unimplemented stuff so we don't need accurate source
+ // location info anymore :).
+ mangleType(Result, SourceRange());
+ }
+
+ // <argument-list> ::= X # void
+ // ::= <type>+ @
+ // ::= <type>* Z # varargs
+ if (Proto->getNumArgs() == 0 && !Proto->isVariadic()) {
+ Out << 'X';
+ } else {
+ if (D) {
+ // If we got a decl, use the type-as-written to make sure arrays
+ // get mangled right. Note that we can't rely on the TSI
+ // existing if (for example) the parameter was synthesized.
+ for (FunctionDecl::param_const_iterator Parm = D->param_begin(),
+ ParmEnd = D->param_end(); Parm != ParmEnd; ++Parm) {
+ TypeSourceInfo *TSI = (*Parm)->getTypeSourceInfo();
+ QualType Type = TSI ? TSI->getType() : (*Parm)->getType();
+ mangleArgumentType(Type, (*Parm)->getSourceRange());
+ }
+ } else {
+ // Happens for function pointer type arguments for example.
+ for (FunctionProtoType::arg_type_iterator Arg = Proto->arg_type_begin(),
+ ArgEnd = Proto->arg_type_end();
+ Arg != ArgEnd; ++Arg)
+ mangleArgumentType(*Arg, SourceRange());
+ }
+ // <builtin-type> ::= Z # ellipsis
+ if (Proto->isVariadic())
+ Out << 'Z';
+ else
+ Out << '@';
+ }
+
+ mangleThrowSpecification(Proto);
+}
+
+void MicrosoftCXXNameMangler::mangleFunctionClass(const FunctionDecl *FD) {
+ // <function-class> ::= A # private: near
+ // ::= B # private: far
+ // ::= C # private: static near
+ // ::= D # private: static far
+ // ::= E # private: virtual near
+ // ::= F # private: virtual far
+ // ::= G # private: thunk near
+ // ::= H # private: thunk far
+ // ::= I # protected: near
+ // ::= J # protected: far
+ // ::= K # protected: static near
+ // ::= L # protected: static far
+ // ::= M # protected: virtual near
+ // ::= N # protected: virtual far
+ // ::= O # protected: thunk near
+ // ::= P # protected: thunk far
+ // ::= Q # public: near
+ // ::= R # public: far
+ // ::= S # public: static near
+ // ::= T # public: static far
+ // ::= U # public: virtual near
+ // ::= V # public: virtual far
+ // ::= W # public: thunk near
+ // ::= X # public: thunk far
+ // ::= Y # global near
+ // ::= Z # global far
+ if (const CXXMethodDecl *MD = dyn_cast<CXXMethodDecl>(FD)) {
+ switch (MD->getAccess()) {
+ default:
+ case AS_private:
+ if (MD->isStatic())
+ Out << 'C';
+ else if (MD->isVirtual())
+ Out << 'E';
+ else
+ Out << 'A';
+ break;
+ case AS_protected:
+ if (MD->isStatic())
+ Out << 'K';
+ else if (MD->isVirtual())
+ Out << 'M';
+ else
+ Out << 'I';
+ break;
+ case AS_public:
+ if (MD->isStatic())
+ Out << 'S';
+ else if (MD->isVirtual())
+ Out << 'U';
+ else
+ Out << 'Q';
+ }
+ } else
+ Out << 'Y';
+}
+void MicrosoftCXXNameMangler::mangleCallingConvention(const FunctionType *T,
+ bool IsInstMethod) {
+ // <calling-convention> ::= A # __cdecl
+ // ::= B # __export __cdecl
+ // ::= C # __pascal
+ // ::= D # __export __pascal
+ // ::= E # __thiscall
+ // ::= F # __export __thiscall
+ // ::= G # __stdcall
+ // ::= H # __export __stdcall
+ // ::= I # __fastcall
+ // ::= J # __export __fastcall
+ // The 'export' calling conventions are from a bygone era
+ // (*cough*Win16*cough*) when functions were declared for export with
+ // that keyword. (It didn't actually export them, it just made them so
+ // that they could be in a DLL and somebody from another module could call
+ // them.)
+ CallingConv CC = T->getCallConv();
+ if (CC == CC_Default) {
+ if (IsInstMethod) {
+ const FunctionProtoType *FPT =
+ T->getCanonicalTypeUnqualified().castAs<FunctionProtoType>();
+ bool isVariadic = FPT->isVariadic();
+ CC = getASTContext().getDefaultCXXMethodCallConv(isVariadic);
+ } else {
+ CC = CC_C;
+ }
+ }
+ switch (CC) {
+ default:
+ llvm_unreachable("Unsupported CC for mangling");
+ case CC_Default:
+ case CC_C: Out << 'A'; break;
+ case CC_X86Pascal: Out << 'C'; break;
+ case CC_X86ThisCall: Out << 'E'; break;
+ case CC_X86StdCall: Out << 'G'; break;
+ case CC_X86FastCall: Out << 'I'; break;
+ }
+}
+void MicrosoftCXXNameMangler::mangleThrowSpecification(
+ const FunctionProtoType *FT) {
+ // <throw-spec> ::= Z # throw(...) (default)
+ // ::= @ # throw() or __declspec/__attribute__((nothrow))
+ // ::= <type>+
+ // NOTE: Since the Microsoft compiler ignores throw specifications, they are
+ // all actually mangled as 'Z'. (They're ignored because their associated
+ // functionality isn't implemented, and probably never will be.)
+ Out << 'Z';
+}
+
+void MicrosoftCXXNameMangler::mangleType(const UnresolvedUsingType *T,
+ SourceRange Range) {
+ // Probably should be mangled as a template instantiation; need to see what
+ // VC does first.
+ DiagnosticsEngine &Diags = Context.getDiags();
+ unsigned DiagID = Diags.getCustomDiagID(DiagnosticsEngine::Error,
+ "cannot mangle this unresolved dependent type yet");
+ Diags.Report(Range.getBegin(), DiagID)
+ << Range;
+}
+
+// <type> ::= <union-type> | <struct-type> | <class-type> | <enum-type>
+// <union-type> ::= T <name>
+// <struct-type> ::= U <name>
+// <class-type> ::= V <name>
+// <enum-type> ::= W <size> <name>
+void MicrosoftCXXNameMangler::mangleType(const EnumType *T, SourceRange) {
+ mangleType(cast<TagType>(T));
+}
+void MicrosoftCXXNameMangler::mangleType(const RecordType *T, SourceRange) {
+ mangleType(cast<TagType>(T));
+}
+void MicrosoftCXXNameMangler::mangleType(const TagType *T) {
+ switch (T->getDecl()->getTagKind()) {
+ case TTK_Union:
+ Out << 'T';
+ break;
+ case TTK_Struct:
+ case TTK_Interface:
+ Out << 'U';
+ break;
+ case TTK_Class:
+ Out << 'V';
+ break;
+ case TTK_Enum:
+ Out << 'W';
+ Out << getASTContext().getTypeSizeInChars(
+ cast<EnumDecl>(T->getDecl())->getIntegerType()).getQuantity();
+ break;
+ }
+ mangleName(T->getDecl());
+}
+
+// <type> ::= <array-type>
+// <array-type> ::= <pointer-cvr-qualifiers> <cvr-qualifiers>
+// [Y <dimension-count> <dimension>+]
+// <element-type> # as global
+// ::= Q <cvr-qualifiers> [Y <dimension-count> <dimension>+]
+// <element-type> # as param
+// It's supposed to be the other way around, but for some strange reason, it
+// isn't. Today this behavior is retained for the sole purpose of backwards
+// compatibility.
+void MicrosoftCXXNameMangler::mangleType(const ArrayType *T, bool IsGlobal) {
+ // This isn't a recursive mangling, so now we have to do it all in this
+ // one call.
+ if (IsGlobal) {
+ manglePointerQualifiers(T->getElementType().getQualifiers());
+ } else {
+ Out << 'Q';
+ }
+ mangleExtraDimensions(T->getElementType());
+}
+void MicrosoftCXXNameMangler::mangleType(const ConstantArrayType *T,
+ SourceRange) {
+ mangleType(cast<ArrayType>(T), false);
+}
+void MicrosoftCXXNameMangler::mangleType(const VariableArrayType *T,
+ SourceRange) {
+ mangleType(cast<ArrayType>(T), false);
+}
+void MicrosoftCXXNameMangler::mangleType(const DependentSizedArrayType *T,
+ SourceRange) {
+ mangleType(cast<ArrayType>(T), false);
+}
+void MicrosoftCXXNameMangler::mangleType(const IncompleteArrayType *T,
+ SourceRange) {
+ mangleType(cast<ArrayType>(T), false);
+}
+void MicrosoftCXXNameMangler::mangleExtraDimensions(QualType ElementTy) {
+ SmallVector<llvm::APInt, 3> Dimensions;
+ for (;;) {
+ if (const ConstantArrayType *CAT =
+ getASTContext().getAsConstantArrayType(ElementTy)) {
+ Dimensions.push_back(CAT->getSize());
+ ElementTy = CAT->getElementType();
+ } else if (ElementTy->isVariableArrayType()) {
+ const VariableArrayType *VAT =
+ getASTContext().getAsVariableArrayType(ElementTy);
+ DiagnosticsEngine &Diags = Context.getDiags();
+ unsigned DiagID = Diags.getCustomDiagID(DiagnosticsEngine::Error,
+ "cannot mangle this variable-length array yet");
+ Diags.Report(VAT->getSizeExpr()->getExprLoc(), DiagID)
+ << VAT->getBracketsRange();
+ return;
+ } else if (ElementTy->isDependentSizedArrayType()) {
+ // The dependent expression has to be folded into a constant (TODO).
+ const DependentSizedArrayType *DSAT =
+ getASTContext().getAsDependentSizedArrayType(ElementTy);
+ DiagnosticsEngine &Diags = Context.getDiags();
+ unsigned DiagID = Diags.getCustomDiagID(DiagnosticsEngine::Error,
+ "cannot mangle this dependent-length array yet");
+ Diags.Report(DSAT->getSizeExpr()->getExprLoc(), DiagID)
+ << DSAT->getBracketsRange();
+ return;
+ } else if (ElementTy->isIncompleteArrayType()) continue;
+ else break;
+ }
+ mangleQualifiers(ElementTy.getQualifiers(), false);
+ // If there are any additional dimensions, mangle them now.
+ if (Dimensions.size() > 0) {
+ Out << 'Y';
+ // <dimension-count> ::= <number> # number of extra dimensions
+ mangleNumber(Dimensions.size());
+ for (unsigned Dim = 0; Dim < Dimensions.size(); ++Dim) {
+ mangleNumber(Dimensions[Dim].getLimitedValue());
+ }
+ }
+ mangleType(ElementTy.getLocalUnqualifiedType(), SourceRange());
+}
+
+// <type> ::= <pointer-to-member-type>
+// <pointer-to-member-type> ::= <pointer-cvr-qualifiers> <cvr-qualifiers>
+// <class name> <type>
+void MicrosoftCXXNameMangler::mangleType(const MemberPointerType *T,
+ SourceRange Range) {
+ QualType PointeeType = T->getPointeeType();
+ if (const FunctionProtoType *FPT = PointeeType->getAs<FunctionProtoType>()) {
+ Out << '8';
+ mangleName(T->getClass()->castAs<RecordType>()->getDecl());
+ mangleType(FPT, NULL, false, true);
+ } else {
+ mangleQualifiers(PointeeType.getQualifiers(), true);
+ mangleName(T->getClass()->castAs<RecordType>()->getDecl());
+ mangleType(PointeeType.getLocalUnqualifiedType(), Range);
+ }
+}
+
+void MicrosoftCXXNameMangler::mangleType(const TemplateTypeParmType *T,
+ SourceRange Range) {
+ DiagnosticsEngine &Diags = Context.getDiags();
+ unsigned DiagID = Diags.getCustomDiagID(DiagnosticsEngine::Error,
+ "cannot mangle this template type parameter type yet");
+ Diags.Report(Range.getBegin(), DiagID)
+ << Range;
+}
+
+void MicrosoftCXXNameMangler::mangleType(
+ const SubstTemplateTypeParmPackType *T,
+ SourceRange Range) {
+ DiagnosticsEngine &Diags = Context.getDiags();
+ unsigned DiagID = Diags.getCustomDiagID(DiagnosticsEngine::Error,
+ "cannot mangle this substituted parameter pack yet");
+ Diags.Report(Range.getBegin(), DiagID)
+ << Range;
+}
+
+// <type> ::= <pointer-type>
+// <pointer-type> ::= <pointer-cvr-qualifiers> <cvr-qualifiers> <type>
+void MicrosoftCXXNameMangler::mangleType(const PointerType *T,
+ SourceRange Range) {
+ QualType PointeeTy = T->getPointeeType();
+ if (PointeeTy->isArrayType()) {
+ // Pointers to arrays are mangled like arrays.
+ mangleExtraDimensions(PointeeTy);
+ } else if (const FunctionType *FT = PointeeTy->getAs<FunctionType>()) {
+ // Function pointers are special.
+ Out << '6';
+ mangleType(FT, NULL, false, false);
+ } else {
+ mangleQualifiers(PointeeTy.getQualifiers(), false);
+ mangleType(PointeeTy, Range, false);
+ }
+}
+void MicrosoftCXXNameMangler::mangleType(const ObjCObjectPointerType *T,
+ SourceRange Range) {
+ // Object pointers never have qualifiers.
+ Out << 'A';
+ mangleType(T->getPointeeType(), Range);
+}
+
+// <type> ::= <reference-type>
+// <reference-type> ::= A <cvr-qualifiers> <type>
+void MicrosoftCXXNameMangler::mangleType(const LValueReferenceType *T,
+ SourceRange Range) {
+ Out << 'A';
+ QualType PointeeTy = T->getPointeeType();
+ if (!PointeeTy.hasQualifiers())
+ // Lack of qualifiers is mangled as 'A'.
+ Out << 'A';
+ mangleType(PointeeTy, Range);
+}
+
+// <type> ::= <r-value-reference-type>
+// <r-value-reference-type> ::= $$Q <cvr-qualifiers> <type>
+void MicrosoftCXXNameMangler::mangleType(const RValueReferenceType *T,
+ SourceRange Range) {
+ Out << "$$Q";
+ QualType PointeeTy = T->getPointeeType();
+ if (!PointeeTy.hasQualifiers())
+ // Lack of qualifiers is mangled as 'A'.
+ Out << 'A';
+ mangleType(PointeeTy, Range);
+}
+
+void MicrosoftCXXNameMangler::mangleType(const ComplexType *T,
+ SourceRange Range) {
+ DiagnosticsEngine &Diags = Context.getDiags();
+ unsigned DiagID = Diags.getCustomDiagID(DiagnosticsEngine::Error,
+ "cannot mangle this complex number type yet");
+ Diags.Report(Range.getBegin(), DiagID)
+ << Range;
+}
+
+void MicrosoftCXXNameMangler::mangleType(const VectorType *T,
+ SourceRange Range) {
+ DiagnosticsEngine &Diags = Context.getDiags();
+ unsigned DiagID = Diags.getCustomDiagID(DiagnosticsEngine::Error,
+ "cannot mangle this vector type yet");
+ Diags.Report(Range.getBegin(), DiagID)
+ << Range;
+}
+void MicrosoftCXXNameMangler::mangleType(const ExtVectorType *T,
+ SourceRange Range) {
+ DiagnosticsEngine &Diags = Context.getDiags();
+ unsigned DiagID = Diags.getCustomDiagID(DiagnosticsEngine::Error,
+ "cannot mangle this extended vector type yet");
+ Diags.Report(Range.getBegin(), DiagID)
+ << Range;
+}
+void MicrosoftCXXNameMangler::mangleType(const DependentSizedExtVectorType *T,
+ SourceRange Range) {
+ DiagnosticsEngine &Diags = Context.getDiags();
+ unsigned DiagID = Diags.getCustomDiagID(DiagnosticsEngine::Error,
+ "cannot mangle this dependent-sized extended vector type yet");
+ Diags.Report(Range.getBegin(), DiagID)
+ << Range;
+}
+
+void MicrosoftCXXNameMangler::mangleType(const ObjCInterfaceType *T,
+ SourceRange) {
+ // ObjC interfaces have structs underlying them.
+ Out << 'U';
+ mangleName(T->getDecl());
+}
+
+void MicrosoftCXXNameMangler::mangleType(const ObjCObjectType *T,
+ SourceRange Range) {
+ // We don't allow overloading by different protocol qualification,
+ // so mangling them isn't necessary.
+ mangleType(T->getBaseType(), Range);
+}
+
+void MicrosoftCXXNameMangler::mangleType(const BlockPointerType *T,
+ SourceRange Range) {
+ Out << "_E";
+
+ QualType pointee = T->getPointeeType();
+ mangleType(pointee->castAs<FunctionProtoType>(), NULL, false, false);
+}
+
+void MicrosoftCXXNameMangler::mangleType(const InjectedClassNameType *T,
+ SourceRange Range) {
+ DiagnosticsEngine &Diags = Context.getDiags();
+ unsigned DiagID = Diags.getCustomDiagID(DiagnosticsEngine::Error,
+ "cannot mangle this injected class name type yet");
+ Diags.Report(Range.getBegin(), DiagID)
+ << Range;
+}
+
+void MicrosoftCXXNameMangler::mangleType(const TemplateSpecializationType *T,
+ SourceRange Range) {
+ DiagnosticsEngine &Diags = Context.getDiags();
+ unsigned DiagID = Diags.getCustomDiagID(DiagnosticsEngine::Error,
+ "cannot mangle this template specialization type yet");
+ Diags.Report(Range.getBegin(), DiagID)
+ << Range;
+}
+
+void MicrosoftCXXNameMangler::mangleType(const DependentNameType *T,
+ SourceRange Range) {
+ DiagnosticsEngine &Diags = Context.getDiags();
+ unsigned DiagID = Diags.getCustomDiagID(DiagnosticsEngine::Error,
+ "cannot mangle this dependent name type yet");
+ Diags.Report(Range.getBegin(), DiagID)
+ << Range;
+}
+
+void MicrosoftCXXNameMangler::mangleType(
+ const DependentTemplateSpecializationType *T,
+ SourceRange Range) {
+ DiagnosticsEngine &Diags = Context.getDiags();
+ unsigned DiagID = Diags.getCustomDiagID(DiagnosticsEngine::Error,
+ "cannot mangle this dependent template specialization type yet");
+ Diags.Report(Range.getBegin(), DiagID)
+ << Range;
+}
+
+void MicrosoftCXXNameMangler::mangleType(const PackExpansionType *T,
+ SourceRange Range) {
+ DiagnosticsEngine &Diags = Context.getDiags();
+ unsigned DiagID = Diags.getCustomDiagID(DiagnosticsEngine::Error,
+ "cannot mangle this pack expansion yet");
+ Diags.Report(Range.getBegin(), DiagID)
+ << Range;
+}
+
+void MicrosoftCXXNameMangler::mangleType(const TypeOfType *T,
+ SourceRange Range) {
+ DiagnosticsEngine &Diags = Context.getDiags();
+ unsigned DiagID = Diags.getCustomDiagID(DiagnosticsEngine::Error,
+ "cannot mangle this typeof(type) yet");
+ Diags.Report(Range.getBegin(), DiagID)
+ << Range;
+}
+
+void MicrosoftCXXNameMangler::mangleType(const TypeOfExprType *T,
+ SourceRange Range) {
+ DiagnosticsEngine &Diags = Context.getDiags();
+ unsigned DiagID = Diags.getCustomDiagID(DiagnosticsEngine::Error,
+ "cannot mangle this typeof(expression) yet");
+ Diags.Report(Range.getBegin(), DiagID)
+ << Range;
+}
+
+void MicrosoftCXXNameMangler::mangleType(const DecltypeType *T,
+ SourceRange Range) {
+ DiagnosticsEngine &Diags = Context.getDiags();
+ unsigned DiagID = Diags.getCustomDiagID(DiagnosticsEngine::Error,
+ "cannot mangle this decltype() yet");
+ Diags.Report(Range.getBegin(), DiagID)
+ << Range;
+}
+
+void MicrosoftCXXNameMangler::mangleType(const UnaryTransformType *T,
+ SourceRange Range) {
+ DiagnosticsEngine &Diags = Context.getDiags();
+ unsigned DiagID = Diags.getCustomDiagID(DiagnosticsEngine::Error,
+ "cannot mangle this unary transform type yet");
+ Diags.Report(Range.getBegin(), DiagID)
+ << Range;
+}
+
+void MicrosoftCXXNameMangler::mangleType(const AutoType *T, SourceRange Range) {
+ DiagnosticsEngine &Diags = Context.getDiags();
+ unsigned DiagID = Diags.getCustomDiagID(DiagnosticsEngine::Error,
+ "cannot mangle this 'auto' type yet");
+ Diags.Report(Range.getBegin(), DiagID)
+ << Range;
+}
+
+void MicrosoftCXXNameMangler::mangleType(const AtomicType *T,
+ SourceRange Range) {
+ DiagnosticsEngine &Diags = Context.getDiags();
+ unsigned DiagID = Diags.getCustomDiagID(DiagnosticsEngine::Error,
+ "cannot mangle this C11 atomic type yet");
+ Diags.Report(Range.getBegin(), DiagID)
+ << Range;
+}
+
+void MicrosoftMangleContext::mangleName(const NamedDecl *D,
+ raw_ostream &Out) {
+ assert((isa<FunctionDecl>(D) || isa<VarDecl>(D)) &&
+ "Invalid mangleName() call, argument is not a variable or function!");
+ assert(!isa<CXXConstructorDecl>(D) && !isa<CXXDestructorDecl>(D) &&
+ "Invalid mangleName() call on 'structor decl!");
+
+ PrettyStackTraceDecl CrashInfo(D, SourceLocation(),
+ getASTContext().getSourceManager(),
+ "Mangling declaration");
+
+ MicrosoftCXXNameMangler Mangler(*this, Out);
+ return Mangler.mangle(D);
+}
+void MicrosoftMangleContext::mangleThunk(const CXXMethodDecl *MD,
+ const ThunkInfo &Thunk,
+ raw_ostream &) {
+ unsigned DiagID = getDiags().getCustomDiagID(DiagnosticsEngine::Error,
+ "cannot mangle thunk for this method yet");
+ getDiags().Report(MD->getLocation(), DiagID);
+}
+void MicrosoftMangleContext::mangleCXXDtorThunk(const CXXDestructorDecl *DD,
+ CXXDtorType Type,
+ const ThisAdjustment &,
+ raw_ostream &) {
+ unsigned DiagID = getDiags().getCustomDiagID(DiagnosticsEngine::Error,
+ "cannot mangle thunk for this destructor yet");
+ getDiags().Report(DD->getLocation(), DiagID);
+}
+void MicrosoftMangleContext::mangleCXXVTable(const CXXRecordDecl *RD,
+ raw_ostream &Out) {
+ // <mangled-name> ::= ? <operator-name> <class-name> <storage-class>
+ // <cvr-qualifiers> [<name>] @
+ // <operator-name> ::= _7 # vftable
+ // ::= _8 # vbtable
+ // NOTE: <cvr-qualifiers> here is always 'B' (const). <storage-class>
+ // is always '6' for vftables and '7' for vbtables. (The difference is
+ // beyond me.)
+ // TODO: vbtables.
+ MicrosoftCXXNameMangler Mangler(*this, Out);
+ Mangler.getStream() << "\01??_7";
+ Mangler.mangleName(RD);
+ Mangler.getStream() << "6B";
+ // TODO: If the class has more than one vtable, mangle in the class it came
+ // from.
+ Mangler.getStream() << '@';
+}
+void MicrosoftMangleContext::mangleCXXVTT(const CXXRecordDecl *RD,
+ raw_ostream &) {
+ llvm_unreachable("The MS C++ ABI does not have virtual table tables!");
+}
+void MicrosoftMangleContext::mangleCXXCtorVTable(const CXXRecordDecl *RD,
+ int64_t Offset,
+ const CXXRecordDecl *Type,
+ raw_ostream &) {
+ llvm_unreachable("The MS C++ ABI does not have constructor vtables!");
+}
+void MicrosoftMangleContext::mangleCXXRTTI(QualType T,
+ raw_ostream &) {
+ // FIXME: Give a location...
+ unsigned DiagID = getDiags().getCustomDiagID(DiagnosticsEngine::Error,
+ "cannot mangle RTTI descriptors for type %0 yet");
+ getDiags().Report(DiagID)
+ << T.getBaseTypeIdentifier();
+}
+void MicrosoftMangleContext::mangleCXXRTTIName(QualType T,
+ raw_ostream &) {
+ // FIXME: Give a location...
+ unsigned DiagID = getDiags().getCustomDiagID(DiagnosticsEngine::Error,
+ "cannot mangle the name of type %0 into RTTI descriptors yet");
+ getDiags().Report(DiagID)
+ << T.getBaseTypeIdentifier();
+}
+void MicrosoftMangleContext::mangleCXXCtor(const CXXConstructorDecl *D,
+ CXXCtorType Type,
+ raw_ostream & Out) {
+ MicrosoftCXXNameMangler mangler(*this, Out);
+ mangler.mangle(D);
+}
+void MicrosoftMangleContext::mangleCXXDtor(const CXXDestructorDecl *D,
+ CXXDtorType Type,
+ raw_ostream & Out) {
+ MicrosoftCXXNameMangler mangler(*this, Out);
+ mangler.mangle(D);
+}
+void MicrosoftMangleContext::mangleReferenceTemporary(const clang::VarDecl *VD,
+ raw_ostream &) {
+ unsigned DiagID = getDiags().getCustomDiagID(DiagnosticsEngine::Error,
+ "cannot mangle this reference temporary yet");
+ getDiags().Report(VD->getLocation(), DiagID);
+}
+
+MangleContext *clang::createMicrosoftMangleContext(ASTContext &Context,
+ DiagnosticsEngine &Diags) {
+ return new MicrosoftMangleContext(Context, Diags);
+}
diff --git a/clang/lib/AST/NSAPI.cpp b/clang/lib/AST/NSAPI.cpp index 0837509194b..6218da20d81 100644 --- a/clang/lib/AST/NSAPI.cpp +++ b/clang/lib/AST/NSAPI.cpp @@ -1,414 +1,420 @@ -//===--- NSAPI.cpp - NSFoundation APIs ------------------------------------===// -// -// The LLVM Compiler Infrastructure -// -// This file is distributed under the University of Illinois Open Source -// License. See LICENSE.TXT for details. -// -//===----------------------------------------------------------------------===// - -#include "clang/AST/NSAPI.h" -#include "clang/AST/ASTContext.h" -#include "clang/AST/Expr.h" - -using namespace clang; - -NSAPI::NSAPI(ASTContext &ctx) - : Ctx(ctx), ClassIds(), BOOLId(0), NSIntegerId(0), NSUIntegerId(0), - NSASCIIStringEncodingId(0), NSUTF8StringEncodingId(0) { -} - -IdentifierInfo *NSAPI::getNSClassId(NSClassIdKindKind K) const { - static const char *ClassName[NumClassIds] = { - "NSObject", - "NSString", - "NSArray", - "NSMutableArray", - "NSDictionary", - "NSMutableDictionary", - "NSNumber" - }; - - if (!ClassIds[K]) - return (ClassIds[K] = &Ctx.Idents.get(ClassName[K])); - - return ClassIds[K]; -} - -Selector NSAPI::getNSStringSelector(NSStringMethodKind MK) const { - if (NSStringSelectors[MK].isNull()) { - Selector Sel; - switch (MK) { - case NSStr_stringWithString: - Sel = Ctx.Selectors.getUnarySelector(&Ctx.Idents.get("stringWithString")); - break; - case NSStr_stringWithUTF8String: - Sel = Ctx.Selectors.getUnarySelector( - &Ctx.Idents.get("stringWithUTF8String")); - break; - case NSStr_stringWithCStringEncoding: { - IdentifierInfo *KeyIdents[] = { - &Ctx.Idents.get("stringWithCString"), - &Ctx.Idents.get("encoding") - }; - Sel = Ctx.Selectors.getSelector(2, KeyIdents); - break; - } - case NSStr_stringWithCString: - Sel= Ctx.Selectors.getUnarySelector(&Ctx.Idents.get("stringWithCString")); - break; - case NSStr_initWithString: - Sel = Ctx.Selectors.getUnarySelector(&Ctx.Idents.get("initWithString")); - break; - } - return (NSStringSelectors[MK] = Sel); - } - - return NSStringSelectors[MK]; -} - -llvm::Optional<NSAPI::NSStringMethodKind> -NSAPI::getNSStringMethodKind(Selector Sel) const { - for (unsigned i = 0; i != NumNSStringMethods; ++i) { - NSStringMethodKind MK = NSStringMethodKind(i); - if (Sel == getNSStringSelector(MK)) - return MK; - } - - return llvm::Optional<NSStringMethodKind>(); -} - -Selector NSAPI::getNSArraySelector(NSArrayMethodKind MK) const { - if (NSArraySelectors[MK].isNull()) { - Selector Sel; - switch (MK) { - case NSArr_array: - Sel = Ctx.Selectors.getNullarySelector(&Ctx.Idents.get("array")); - break; - case NSArr_arrayWithArray: - Sel = Ctx.Selectors.getUnarySelector(&Ctx.Idents.get("arrayWithArray")); - break; - case NSArr_arrayWithObject: - Sel = Ctx.Selectors.getUnarySelector(&Ctx.Idents.get("arrayWithObject")); - break; - case NSArr_arrayWithObjects: - Sel = Ctx.Selectors.getUnarySelector(&Ctx.Idents.get("arrayWithObjects")); - break; - case NSArr_arrayWithObjectsCount: { - IdentifierInfo *KeyIdents[] = { - &Ctx.Idents.get("arrayWithObjects"), - &Ctx.Idents.get("count") - }; - Sel = Ctx.Selectors.getSelector(2, KeyIdents); - break; - } - case NSArr_initWithArray: - Sel = Ctx.Selectors.getUnarySelector(&Ctx.Idents.get("initWithArray")); - break; - case NSArr_initWithObjects: - Sel = Ctx.Selectors.getUnarySelector(&Ctx.Idents.get("initWithObjects")); - break; - case NSArr_objectAtIndex: - Sel = Ctx.Selectors.getUnarySelector(&Ctx.Idents.get("objectAtIndex")); - break; - case NSMutableArr_replaceObjectAtIndex: { - IdentifierInfo *KeyIdents[] = { - &Ctx.Idents.get("replaceObjectAtIndex"), - &Ctx.Idents.get("withObject") - }; - Sel = Ctx.Selectors.getSelector(2, KeyIdents); - break; - } - } - return (NSArraySelectors[MK] = Sel); - } - - return NSArraySelectors[MK]; -} - -llvm::Optional<NSAPI::NSArrayMethodKind> -NSAPI::getNSArrayMethodKind(Selector Sel) { - for (unsigned i = 0; i != NumNSArrayMethods; ++i) { - NSArrayMethodKind MK = NSArrayMethodKind(i); - if (Sel == getNSArraySelector(MK)) - return MK; - } - - return llvm::Optional<NSArrayMethodKind>(); -} - -Selector NSAPI::getNSDictionarySelector( - NSDictionaryMethodKind MK) const { - if (NSDictionarySelectors[MK].isNull()) { - Selector Sel; - switch (MK) { - case NSDict_dictionary: - Sel = Ctx.Selectors.getNullarySelector(&Ctx.Idents.get("dictionary")); - break; - case NSDict_dictionaryWithDictionary: - Sel = Ctx.Selectors.getUnarySelector( - &Ctx.Idents.get("dictionaryWithDictionary")); - break; - case NSDict_dictionaryWithObjectForKey: { - IdentifierInfo *KeyIdents[] = { - &Ctx.Idents.get("dictionaryWithObject"), - &Ctx.Idents.get("forKey") - }; - Sel = Ctx.Selectors.getSelector(2, KeyIdents); - break; - } - case NSDict_dictionaryWithObjectsForKeys: { - IdentifierInfo *KeyIdents[] = { - &Ctx.Idents.get("dictionaryWithObjects"), - &Ctx.Idents.get("forKeys") - }; - Sel = Ctx.Selectors.getSelector(2, KeyIdents); - break; - } - case NSDict_dictionaryWithObjectsForKeysCount: { - IdentifierInfo *KeyIdents[] = { - &Ctx.Idents.get("dictionaryWithObjects"), - &Ctx.Idents.get("forKeys"), - &Ctx.Idents.get("count") - }; - Sel = Ctx.Selectors.getSelector(3, KeyIdents); - break; - } - case NSDict_dictionaryWithObjectsAndKeys: - Sel = Ctx.Selectors.getUnarySelector( - &Ctx.Idents.get("dictionaryWithObjectsAndKeys")); - break; - case NSDict_initWithDictionary: - Sel = Ctx.Selectors.getUnarySelector( - &Ctx.Idents.get("initWithDictionary")); - break; - case NSDict_initWithObjectsAndKeys: - Sel = Ctx.Selectors.getUnarySelector( - &Ctx.Idents.get("initWithObjectsAndKeys")); - break; - case NSDict_objectForKey: - Sel = Ctx.Selectors.getUnarySelector(&Ctx.Idents.get("objectForKey")); - break; - case NSMutableDict_setObjectForKey: { - IdentifierInfo *KeyIdents[] = { - &Ctx.Idents.get("setObject"), - &Ctx.Idents.get("forKey") - }; - Sel = Ctx.Selectors.getSelector(2, KeyIdents); - break; - } - } - return (NSDictionarySelectors[MK] = Sel); - } - - return NSDictionarySelectors[MK]; -} - -llvm::Optional<NSAPI::NSDictionaryMethodKind> -NSAPI::getNSDictionaryMethodKind(Selector Sel) { - for (unsigned i = 0; i != NumNSDictionaryMethods; ++i) { - NSDictionaryMethodKind MK = NSDictionaryMethodKind(i); - if (Sel == getNSDictionarySelector(MK)) - return MK; - } - - return llvm::Optional<NSDictionaryMethodKind>(); -} - -Selector NSAPI::getNSNumberLiteralSelector(NSNumberLiteralMethodKind MK, - bool Instance) const { - static const char *ClassSelectorName[NumNSNumberLiteralMethods] = { - "numberWithChar", - "numberWithUnsignedChar", - "numberWithShort", - "numberWithUnsignedShort", - "numberWithInt", - "numberWithUnsignedInt", - "numberWithLong", - "numberWithUnsignedLong", - "numberWithLongLong", - "numberWithUnsignedLongLong", - "numberWithFloat", - "numberWithDouble", - "numberWithBool", - "numberWithInteger", - "numberWithUnsignedInteger" - }; - static const char *InstanceSelectorName[NumNSNumberLiteralMethods] = { - "initWithChar", - "initWithUnsignedChar", - "initWithShort", - "initWithUnsignedShort", - "initWithInt", - "initWithUnsignedInt", - "initWithLong", - "initWithUnsignedLong", - "initWithLongLong", - "initWithUnsignedLongLong", - "initWithFloat", - "initWithDouble", - "initWithBool", - "initWithInteger", - "initWithUnsignedInteger" - }; - - Selector *Sels; - const char **Names; - if (Instance) { - Sels = NSNumberInstanceSelectors; - Names = InstanceSelectorName; - } else { - Sels = NSNumberClassSelectors; - Names = ClassSelectorName; - } - - if (Sels[MK].isNull()) - Sels[MK] = Ctx.Selectors.getUnarySelector(&Ctx.Idents.get(Names[MK])); - return Sels[MK]; -} - -llvm::Optional<NSAPI::NSNumberLiteralMethodKind> -NSAPI::getNSNumberLiteralMethodKind(Selector Sel) const { - for (unsigned i = 0; i != NumNSNumberLiteralMethods; ++i) { - NSNumberLiteralMethodKind MK = NSNumberLiteralMethodKind(i); - if (isNSNumberLiteralSelector(MK, Sel)) - return MK; - } - - return llvm::Optional<NSNumberLiteralMethodKind>(); -} - -llvm::Optional<NSAPI::NSNumberLiteralMethodKind> -NSAPI::getNSNumberFactoryMethodKind(QualType T) const { - const BuiltinType *BT = T->getAs<BuiltinType>(); - if (!BT) - return llvm::Optional<NSAPI::NSNumberLiteralMethodKind>(); - - const TypedefType *TDT = T->getAs<TypedefType>(); - if (TDT) { - QualType TDTTy = QualType(TDT, 0); - if (isObjCBOOLType(TDTTy)) - return NSAPI::NSNumberWithBool; - if (isObjCNSIntegerType(TDTTy)) - return NSAPI::NSNumberWithInteger; - if (isObjCNSUIntegerType(TDTTy)) - return NSAPI::NSNumberWithUnsignedInteger; - } - - switch (BT->getKind()) { - case BuiltinType::Char_S: - case BuiltinType::SChar: - return NSAPI::NSNumberWithChar; - case BuiltinType::Char_U: - case BuiltinType::UChar: - return NSAPI::NSNumberWithUnsignedChar; - case BuiltinType::Short: - return NSAPI::NSNumberWithShort; - case BuiltinType::UShort: - return NSAPI::NSNumberWithUnsignedShort; - case BuiltinType::Int: - return NSAPI::NSNumberWithInt; - case BuiltinType::UInt: - return NSAPI::NSNumberWithUnsignedInt; - case BuiltinType::Long: - return NSAPI::NSNumberWithLong; - case BuiltinType::ULong: - return NSAPI::NSNumberWithUnsignedLong; - case BuiltinType::LongLong: - return NSAPI::NSNumberWithLongLong; - case BuiltinType::ULongLong: - return NSAPI::NSNumberWithUnsignedLongLong; - case BuiltinType::Float: - return NSAPI::NSNumberWithFloat; - case BuiltinType::Double: - return NSAPI::NSNumberWithDouble; - case BuiltinType::Bool: - return NSAPI::NSNumberWithBool; - - case BuiltinType::Void: - case BuiltinType::WChar_U: - case BuiltinType::WChar_S: - case BuiltinType::Char16: - case BuiltinType::Char32: - case BuiltinType::Int128: - case BuiltinType::LongDouble: - case BuiltinType::UInt128: - case BuiltinType::NullPtr: - case BuiltinType::ObjCClass: - case BuiltinType::ObjCId: - case BuiltinType::ObjCSel: - case BuiltinType::BoundMember: - case BuiltinType::Dependent: - case BuiltinType::Overload: - case BuiltinType::UnknownAny: - case BuiltinType::ARCUnbridgedCast: - case BuiltinType::Half: - case BuiltinType::PseudoObject: - case BuiltinType::BuiltinFn: - break; - } - - return llvm::Optional<NSAPI::NSNumberLiteralMethodKind>(); -} - -/// \brief Returns true if \param T is a typedef of "BOOL" in objective-c. -bool NSAPI::isObjCBOOLType(QualType T) const { - return isObjCTypedef(T, "BOOL", BOOLId); -} -/// \brief Returns true if \param T is a typedef of "NSInteger" in objective-c. -bool NSAPI::isObjCNSIntegerType(QualType T) const { - return isObjCTypedef(T, "NSInteger", NSIntegerId); -} -/// \brief Returns true if \param T is a typedef of "NSUInteger" in objective-c. -bool NSAPI::isObjCNSUIntegerType(QualType T) const { - return isObjCTypedef(T, "NSUInteger", NSUIntegerId); -} - -bool NSAPI::isObjCTypedef(QualType T, - StringRef name, IdentifierInfo *&II) const { - if (!Ctx.getLangOpts().ObjC1) - return false; - if (T.isNull()) - return false; - - if (!II) - II = &Ctx.Idents.get(name); - - while (const TypedefType *TDT = T->getAs<TypedefType>()) { - if (TDT->getDecl()->getDeclName().getAsIdentifierInfo() == II) - return true; - T = TDT->desugar(); - } - - return false; -} - -bool NSAPI::isObjCEnumerator(const Expr *E, - StringRef name, IdentifierInfo *&II) const { - if (!Ctx.getLangOpts().ObjC1) - return false; - if (!E) - return false; - - if (!II) - II = &Ctx.Idents.get(name); - - if (const DeclRefExpr *DRE = dyn_cast<DeclRefExpr>(E->IgnoreParenImpCasts())) - if (const EnumConstantDecl * - EnumD = dyn_cast_or_null<EnumConstantDecl>(DRE->getDecl())) - return EnumD->getIdentifier() == II; - - return false; -} - -Selector NSAPI::getOrInitSelector(ArrayRef<StringRef> Ids, - Selector &Sel) const { - if (Sel.isNull()) { - SmallVector<IdentifierInfo *, 4> Idents; - for (ArrayRef<StringRef>::const_iterator - I = Ids.begin(), E = Ids.end(); I != E; ++I) - Idents.push_back(&Ctx.Idents.get(*I)); - Sel = Ctx.Selectors.getSelector(Idents.size(), Idents.data()); - } - return Sel; -} +//===--- NSAPI.cpp - NSFoundation APIs ------------------------------------===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#include "clang/AST/NSAPI.h"
+#include "clang/AST/ASTContext.h"
+#include "clang/AST/Expr.h"
+
+using namespace clang;
+
+NSAPI::NSAPI(ASTContext &ctx)
+ : Ctx(ctx), ClassIds(), BOOLId(0), NSIntegerId(0), NSUIntegerId(0),
+ NSASCIIStringEncodingId(0), NSUTF8StringEncodingId(0) {
+}
+
+IdentifierInfo *NSAPI::getNSClassId(NSClassIdKindKind K) const {
+ static const char *ClassName[NumClassIds] = {
+ "NSObject",
+ "NSString",
+ "NSArray",
+ "NSMutableArray",
+ "NSDictionary",
+ "NSMutableDictionary",
+ "NSNumber"
+ };
+
+ if (!ClassIds[K])
+ return (ClassIds[K] = &Ctx.Idents.get(ClassName[K]));
+
+ return ClassIds[K];
+}
+
+Selector NSAPI::getNSStringSelector(NSStringMethodKind MK) const {
+ if (NSStringSelectors[MK].isNull()) {
+ Selector Sel;
+ switch (MK) {
+ case NSStr_stringWithString:
+ Sel = Ctx.Selectors.getUnarySelector(&Ctx.Idents.get("stringWithString"));
+ break;
+ case NSStr_stringWithUTF8String:
+ Sel = Ctx.Selectors.getUnarySelector(
+ &Ctx.Idents.get("stringWithUTF8String"));
+ break;
+ case NSStr_stringWithCStringEncoding: {
+ IdentifierInfo *KeyIdents[] = {
+ &Ctx.Idents.get("stringWithCString"),
+ &Ctx.Idents.get("encoding")
+ };
+ Sel = Ctx.Selectors.getSelector(2, KeyIdents);
+ break;
+ }
+ case NSStr_stringWithCString:
+ Sel= Ctx.Selectors.getUnarySelector(&Ctx.Idents.get("stringWithCString"));
+ break;
+ case NSStr_initWithString:
+ Sel = Ctx.Selectors.getUnarySelector(&Ctx.Idents.get("initWithString"));
+ break;
+ }
+ return (NSStringSelectors[MK] = Sel);
+ }
+
+ return NSStringSelectors[MK];
+}
+
+llvm::Optional<NSAPI::NSStringMethodKind>
+NSAPI::getNSStringMethodKind(Selector Sel) const {
+ for (unsigned i = 0; i != NumNSStringMethods; ++i) {
+ NSStringMethodKind MK = NSStringMethodKind(i);
+ if (Sel == getNSStringSelector(MK))
+ return MK;
+ }
+
+ return llvm::Optional<NSStringMethodKind>();
+}
+
+Selector NSAPI::getNSArraySelector(NSArrayMethodKind MK) const {
+ if (NSArraySelectors[MK].isNull()) {
+ Selector Sel;
+ switch (MK) {
+ case NSArr_array:
+ Sel = Ctx.Selectors.getNullarySelector(&Ctx.Idents.get("array"));
+ break;
+ case NSArr_arrayWithArray:
+ Sel = Ctx.Selectors.getUnarySelector(&Ctx.Idents.get("arrayWithArray"));
+ break;
+ case NSArr_arrayWithObject:
+ Sel = Ctx.Selectors.getUnarySelector(&Ctx.Idents.get("arrayWithObject"));
+ break;
+ case NSArr_arrayWithObjects:
+ Sel = Ctx.Selectors.getUnarySelector(&Ctx.Idents.get("arrayWithObjects"));
+ break;
+ case NSArr_arrayWithObjectsCount: {
+ IdentifierInfo *KeyIdents[] = {
+ &Ctx.Idents.get("arrayWithObjects"),
+ &Ctx.Idents.get("count")
+ };
+ Sel = Ctx.Selectors.getSelector(2, KeyIdents);
+ break;
+ }
+ case NSArr_initWithArray:
+ Sel = Ctx.Selectors.getUnarySelector(&Ctx.Idents.get("initWithArray"));
+ break;
+ case NSArr_initWithObjects:
+ Sel = Ctx.Selectors.getUnarySelector(&Ctx.Idents.get("initWithObjects"));
+ break;
+ case NSArr_objectAtIndex:
+ Sel = Ctx.Selectors.getUnarySelector(&Ctx.Idents.get("objectAtIndex"));
+ break;
+ case NSMutableArr_replaceObjectAtIndex: {
+ IdentifierInfo *KeyIdents[] = {
+ &Ctx.Idents.get("replaceObjectAtIndex"),
+ &Ctx.Idents.get("withObject")
+ };
+ Sel = Ctx.Selectors.getSelector(2, KeyIdents);
+ break;
+ }
+ }
+ return (NSArraySelectors[MK] = Sel);
+ }
+
+ return NSArraySelectors[MK];
+}
+
+llvm::Optional<NSAPI::NSArrayMethodKind>
+NSAPI::getNSArrayMethodKind(Selector Sel) {
+ for (unsigned i = 0; i != NumNSArrayMethods; ++i) {
+ NSArrayMethodKind MK = NSArrayMethodKind(i);
+ if (Sel == getNSArraySelector(MK))
+ return MK;
+ }
+
+ return llvm::Optional<NSArrayMethodKind>();
+}
+
+Selector NSAPI::getNSDictionarySelector(
+ NSDictionaryMethodKind MK) const {
+ if (NSDictionarySelectors[MK].isNull()) {
+ Selector Sel;
+ switch (MK) {
+ case NSDict_dictionary:
+ Sel = Ctx.Selectors.getNullarySelector(&Ctx.Idents.get("dictionary"));
+ break;
+ case NSDict_dictionaryWithDictionary:
+ Sel = Ctx.Selectors.getUnarySelector(
+ &Ctx.Idents.get("dictionaryWithDictionary"));
+ break;
+ case NSDict_dictionaryWithObjectForKey: {
+ IdentifierInfo *KeyIdents[] = {
+ &Ctx.Idents.get("dictionaryWithObject"),
+ &Ctx.Idents.get("forKey")
+ };
+ Sel = Ctx.Selectors.getSelector(2, KeyIdents);
+ break;
+ }
+ case NSDict_dictionaryWithObjectsForKeys: {
+ IdentifierInfo *KeyIdents[] = {
+ &Ctx.Idents.get("dictionaryWithObjects"),
+ &Ctx.Idents.get("forKeys")
+ };
+ Sel = Ctx.Selectors.getSelector(2, KeyIdents);
+ break;
+ }
+ case NSDict_dictionaryWithObjectsForKeysCount: {
+ IdentifierInfo *KeyIdents[] = {
+ &Ctx.Idents.get("dictionaryWithObjects"),
+ &Ctx.Idents.get("forKeys"),
+ &Ctx.Idents.get("count")
+ };
+ Sel = Ctx.Selectors.getSelector(3, KeyIdents);
+ break;
+ }
+ case NSDict_dictionaryWithObjectsAndKeys:
+ Sel = Ctx.Selectors.getUnarySelector(
+ &Ctx.Idents.get("dictionaryWithObjectsAndKeys"));
+ break;
+ case NSDict_initWithDictionary:
+ Sel = Ctx.Selectors.getUnarySelector(
+ &Ctx.Idents.get("initWithDictionary"));
+ break;
+ case NSDict_initWithObjectsAndKeys:
+ Sel = Ctx.Selectors.getUnarySelector(
+ &Ctx.Idents.get("initWithObjectsAndKeys"));
+ break;
+ case NSDict_objectForKey:
+ Sel = Ctx.Selectors.getUnarySelector(&Ctx.Idents.get("objectForKey"));
+ break;
+ case NSMutableDict_setObjectForKey: {
+ IdentifierInfo *KeyIdents[] = {
+ &Ctx.Idents.get("setObject"),
+ &Ctx.Idents.get("forKey")
+ };
+ Sel = Ctx.Selectors.getSelector(2, KeyIdents);
+ break;
+ }
+ }
+ return (NSDictionarySelectors[MK] = Sel);
+ }
+
+ return NSDictionarySelectors[MK];
+}
+
+llvm::Optional<NSAPI::NSDictionaryMethodKind>
+NSAPI::getNSDictionaryMethodKind(Selector Sel) {
+ for (unsigned i = 0; i != NumNSDictionaryMethods; ++i) {
+ NSDictionaryMethodKind MK = NSDictionaryMethodKind(i);
+ if (Sel == getNSDictionarySelector(MK))
+ return MK;
+ }
+
+ return llvm::Optional<NSDictionaryMethodKind>();
+}
+
+Selector NSAPI::getNSNumberLiteralSelector(NSNumberLiteralMethodKind MK,
+ bool Instance) const {
+ static const char *ClassSelectorName[NumNSNumberLiteralMethods] = {
+ "numberWithChar",
+ "numberWithUnsignedChar",
+ "numberWithShort",
+ "numberWithUnsignedShort",
+ "numberWithInt",
+ "numberWithUnsignedInt",
+ "numberWithLong",
+ "numberWithUnsignedLong",
+ "numberWithLongLong",
+ "numberWithUnsignedLongLong",
+ "numberWithFloat",
+ "numberWithDouble",
+ "numberWithBool",
+ "numberWithInteger",
+ "numberWithUnsignedInteger"
+ };
+ static const char *InstanceSelectorName[NumNSNumberLiteralMethods] = {
+ "initWithChar",
+ "initWithUnsignedChar",
+ "initWithShort",
+ "initWithUnsignedShort",
+ "initWithInt",
+ "initWithUnsignedInt",
+ "initWithLong",
+ "initWithUnsignedLong",
+ "initWithLongLong",
+ "initWithUnsignedLongLong",
+ "initWithFloat",
+ "initWithDouble",
+ "initWithBool",
+ "initWithInteger",
+ "initWithUnsignedInteger"
+ };
+
+ Selector *Sels;
+ const char **Names;
+ if (Instance) {
+ Sels = NSNumberInstanceSelectors;
+ Names = InstanceSelectorName;
+ } else {
+ Sels = NSNumberClassSelectors;
+ Names = ClassSelectorName;
+ }
+
+ if (Sels[MK].isNull())
+ Sels[MK] = Ctx.Selectors.getUnarySelector(&Ctx.Idents.get(Names[MK]));
+ return Sels[MK];
+}
+
+llvm::Optional<NSAPI::NSNumberLiteralMethodKind>
+NSAPI::getNSNumberLiteralMethodKind(Selector Sel) const {
+ for (unsigned i = 0; i != NumNSNumberLiteralMethods; ++i) {
+ NSNumberLiteralMethodKind MK = NSNumberLiteralMethodKind(i);
+ if (isNSNumberLiteralSelector(MK, Sel))
+ return MK;
+ }
+
+ return llvm::Optional<NSNumberLiteralMethodKind>();
+}
+
+llvm::Optional<NSAPI::NSNumberLiteralMethodKind>
+NSAPI::getNSNumberFactoryMethodKind(QualType T) const {
+ const BuiltinType *BT = T->getAs<BuiltinType>();
+ if (!BT)
+ return llvm::Optional<NSAPI::NSNumberLiteralMethodKind>();
+
+ const TypedefType *TDT = T->getAs<TypedefType>();
+ if (TDT) {
+ QualType TDTTy = QualType(TDT, 0);
+ if (isObjCBOOLType(TDTTy))
+ return NSAPI::NSNumberWithBool;
+ if (isObjCNSIntegerType(TDTTy))
+ return NSAPI::NSNumberWithInteger;
+ if (isObjCNSUIntegerType(TDTTy))
+ return NSAPI::NSNumberWithUnsignedInteger;
+ }
+
+ switch (BT->getKind()) {
+ case BuiltinType::Char_S:
+ case BuiltinType::SChar:
+ return NSAPI::NSNumberWithChar;
+ case BuiltinType::Char_U:
+ case BuiltinType::UChar:
+ return NSAPI::NSNumberWithUnsignedChar;
+ case BuiltinType::Short:
+ return NSAPI::NSNumberWithShort;
+ case BuiltinType::UShort:
+ return NSAPI::NSNumberWithUnsignedShort;
+ case BuiltinType::Int:
+ return NSAPI::NSNumberWithInt;
+ case BuiltinType::UInt:
+ return NSAPI::NSNumberWithUnsignedInt;
+ case BuiltinType::Long:
+ return NSAPI::NSNumberWithLong;
+ case BuiltinType::ULong:
+ return NSAPI::NSNumberWithUnsignedLong;
+ case BuiltinType::LongLong:
+ return NSAPI::NSNumberWithLongLong;
+ case BuiltinType::ULongLong:
+ return NSAPI::NSNumberWithUnsignedLongLong;
+ case BuiltinType::Float:
+ return NSAPI::NSNumberWithFloat;
+ case BuiltinType::Double:
+ return NSAPI::NSNumberWithDouble;
+ case BuiltinType::Bool:
+ return NSAPI::NSNumberWithBool;
+
+ case BuiltinType::Void:
+ case BuiltinType::WChar_U:
+ case BuiltinType::WChar_S:
+ case BuiltinType::Char16:
+ case BuiltinType::Char32:
+ case BuiltinType::Int128:
+ case BuiltinType::LongDouble:
+ case BuiltinType::UInt128:
+ case BuiltinType::NullPtr:
+ case BuiltinType::ObjCClass:
+ case BuiltinType::ObjCId:
+ case BuiltinType::ObjCSel:
+ case BuiltinType::OCLImage1d:
+ case BuiltinType::OCLImage1dArray:
+ case BuiltinType::OCLImage1dBuffer:
+ case BuiltinType::OCLImage2d:
+ case BuiltinType::OCLImage2dArray:
+ case BuiltinType::OCLImage3d:
+ case BuiltinType::BoundMember:
+ case BuiltinType::Dependent:
+ case BuiltinType::Overload:
+ case BuiltinType::UnknownAny:
+ case BuiltinType::ARCUnbridgedCast:
+ case BuiltinType::Half:
+ case BuiltinType::PseudoObject:
+ case BuiltinType::BuiltinFn:
+ break;
+ }
+
+ return llvm::Optional<NSAPI::NSNumberLiteralMethodKind>();
+}
+
+/// \brief Returns true if \param T is a typedef of "BOOL" in objective-c.
+bool NSAPI::isObjCBOOLType(QualType T) const {
+ return isObjCTypedef(T, "BOOL", BOOLId);
+}
+/// \brief Returns true if \param T is a typedef of "NSInteger" in objective-c.
+bool NSAPI::isObjCNSIntegerType(QualType T) const {
+ return isObjCTypedef(T, "NSInteger", NSIntegerId);
+}
+/// \brief Returns true if \param T is a typedef of "NSUInteger" in objective-c.
+bool NSAPI::isObjCNSUIntegerType(QualType T) const {
+ return isObjCTypedef(T, "NSUInteger", NSUIntegerId);
+}
+
+bool NSAPI::isObjCTypedef(QualType T,
+ StringRef name, IdentifierInfo *&II) const {
+ if (!Ctx.getLangOpts().ObjC1)
+ return false;
+ if (T.isNull())
+ return false;
+
+ if (!II)
+ II = &Ctx.Idents.get(name);
+
+ while (const TypedefType *TDT = T->getAs<TypedefType>()) {
+ if (TDT->getDecl()->getDeclName().getAsIdentifierInfo() == II)
+ return true;
+ T = TDT->desugar();
+ }
+
+ return false;
+}
+
+bool NSAPI::isObjCEnumerator(const Expr *E,
+ StringRef name, IdentifierInfo *&II) const {
+ if (!Ctx.getLangOpts().ObjC1)
+ return false;
+ if (!E)
+ return false;
+
+ if (!II)
+ II = &Ctx.Idents.get(name);
+
+ if (const DeclRefExpr *DRE = dyn_cast<DeclRefExpr>(E->IgnoreParenImpCasts()))
+ if (const EnumConstantDecl *
+ EnumD = dyn_cast_or_null<EnumConstantDecl>(DRE->getDecl()))
+ return EnumD->getIdentifier() == II;
+
+ return false;
+}
+
+Selector NSAPI::getOrInitSelector(ArrayRef<StringRef> Ids,
+ Selector &Sel) const {
+ if (Sel.isNull()) {
+ SmallVector<IdentifierInfo *, 4> Idents;
+ for (ArrayRef<StringRef>::const_iterator
+ I = Ids.begin(), E = Ids.end(); I != E; ++I)
+ Idents.push_back(&Ctx.Idents.get(*I));
+ Sel = Ctx.Selectors.getSelector(Idents.size(), Idents.data());
+ }
+ return Sel;
+}
diff --git a/clang/lib/AST/Type.cpp b/clang/lib/AST/Type.cpp index 97448eee81e..26eee2d74a1 100644 --- a/clang/lib/AST/Type.cpp +++ b/clang/lib/AST/Type.cpp @@ -1512,6 +1512,12 @@ StringRef BuiltinType::getName(const PrintingPolicy &Policy) const { case ObjCId: return "id"; case ObjCClass: return "Class"; case ObjCSel: return "SEL"; + case OCLImage1d: return "image1d_t"; + case OCLImage1dArray: return "image1d_array_t"; + case OCLImage1dBuffer: return "image1d_buffer_t"; + case OCLImage2d: return "image2d_t"; + case OCLImage2dArray: return "image2d_array_t"; + case OCLImage3d: return "image3d_t"; } llvm_unreachable("Invalid builtin type."); diff --git a/clang/lib/AST/TypeLoc.cpp b/clang/lib/AST/TypeLoc.cpp index c021cf886b3..b86d2260a0c 100644 --- a/clang/lib/AST/TypeLoc.cpp +++ b/clang/lib/AST/TypeLoc.cpp @@ -1,361 +1,367 @@ -//===--- TypeLoc.cpp - Type Source Info Wrapper -----------------*- C++ -*-===// -// -// The LLVM Compiler Infrastructure -// -// This file is distributed under the University of Illinois Open Source -// License. See LICENSE.TXT for details. -// -//===----------------------------------------------------------------------===// -// -// This file defines the TypeLoc subclasses implementations. -// -//===----------------------------------------------------------------------===// - -#include "clang/AST/TypeLoc.h" -#include "clang/AST/ASTContext.h" -#include "clang/AST/Expr.h" -#include "clang/AST/TypeLocVisitor.h" -#include "llvm/Support/ErrorHandling.h" -#include "llvm/Support/raw_ostream.h" -using namespace clang; - -//===----------------------------------------------------------------------===// -// TypeLoc Implementation -//===----------------------------------------------------------------------===// - -namespace { - class TypeLocRanger : public TypeLocVisitor<TypeLocRanger, SourceRange> { - public: -#define ABSTRACT_TYPELOC(CLASS, PARENT) -#define TYPELOC(CLASS, PARENT) \ - SourceRange Visit##CLASS##TypeLoc(CLASS##TypeLoc TyLoc) { \ - return TyLoc.getLocalSourceRange(); \ - } -#include "clang/AST/TypeLocNodes.def" - }; -} - -SourceRange TypeLoc::getLocalSourceRangeImpl(TypeLoc TL) { - if (TL.isNull()) return SourceRange(); - return TypeLocRanger().Visit(TL); -} - -namespace { - class TypeSizer : public TypeLocVisitor<TypeSizer, unsigned> { - public: -#define ABSTRACT_TYPELOC(CLASS, PARENT) -#define TYPELOC(CLASS, PARENT) \ - unsigned Visit##CLASS##TypeLoc(CLASS##TypeLoc TyLoc) { \ - return TyLoc.getFullDataSize(); \ - } -#include "clang/AST/TypeLocNodes.def" - }; -} - -/// \brief Returns the size of the type source info data block. -unsigned TypeLoc::getFullDataSizeForType(QualType Ty) { - if (Ty.isNull()) return 0; - return TypeSizer().Visit(TypeLoc(Ty, 0)); -} - -namespace { - class NextLoc : public TypeLocVisitor<NextLoc, TypeLoc> { - public: -#define ABSTRACT_TYPELOC(CLASS, PARENT) -#define TYPELOC(CLASS, PARENT) \ - TypeLoc Visit##CLASS##TypeLoc(CLASS##TypeLoc TyLoc) { \ - return TyLoc.getNextTypeLoc(); \ - } -#include "clang/AST/TypeLocNodes.def" - }; -} - -/// \brief Get the next TypeLoc pointed by this TypeLoc, e.g for "int*" the -/// TypeLoc is a PointerLoc and next TypeLoc is for "int". -TypeLoc TypeLoc::getNextTypeLocImpl(TypeLoc TL) { - return NextLoc().Visit(TL); -} - -/// \brief Initializes a type location, and all of its children -/// recursively, as if the entire tree had been written in the -/// given location. -void TypeLoc::initializeImpl(ASTContext &Context, TypeLoc TL, - SourceLocation Loc) { - while (true) { - switch (TL.getTypeLocClass()) { -#define ABSTRACT_TYPELOC(CLASS, PARENT) -#define TYPELOC(CLASS, PARENT) \ - case CLASS: { \ - CLASS##TypeLoc TLCasted = cast<CLASS##TypeLoc>(TL); \ - TLCasted.initializeLocal(Context, Loc); \ - TL = TLCasted.getNextTypeLoc(); \ - if (!TL) return; \ - continue; \ - } -#include "clang/AST/TypeLocNodes.def" - } - } -} - -SourceLocation TypeLoc::getBeginLoc() const { - TypeLoc Cur = *this; - TypeLoc LeftMost = Cur; - while (true) { - switch (Cur.getTypeLocClass()) { - case Elaborated: - LeftMost = Cur; - break; - case FunctionProto: - if (cast<FunctionProtoTypeLoc>(&Cur)->getTypePtr()->hasTrailingReturn()) { - LeftMost = Cur; - break; - } - /* Fall through */ - case FunctionNoProto: - case ConstantArray: - case DependentSizedArray: - case IncompleteArray: - case VariableArray: - // FIXME: Currently QualifiedTypeLoc does not have a source range - case Qualified: - Cur = Cur.getNextTypeLoc(); - continue; - default: - if (!Cur.getLocalSourceRange().getBegin().isInvalid()) - LeftMost = Cur; - Cur = Cur.getNextTypeLoc(); - if (Cur.isNull()) - break; - continue; - } // switch - break; - } // while - return LeftMost.getLocalSourceRange().getBegin(); -} - -SourceLocation TypeLoc::getEndLoc() const { - TypeLoc Cur = *this; - TypeLoc Last; - while (true) { - switch (Cur.getTypeLocClass()) { - default: - if (!Last) - Last = Cur; - return Last.getLocalSourceRange().getEnd(); - case Paren: - case ConstantArray: - case DependentSizedArray: - case IncompleteArray: - case VariableArray: - case FunctionNoProto: - Last = Cur; - break; - case FunctionProto: - if (cast<FunctionProtoTypeLoc>(&Cur)->getTypePtr()->hasTrailingReturn()) - Last = TypeLoc(); - else - Last = Cur; - break; - case Pointer: - case BlockPointer: - case MemberPointer: - case LValueReference: - case RValueReference: - case PackExpansion: - if (!Last) - Last = Cur; - break; - case Qualified: - case Elaborated: - break; - } - Cur = Cur.getNextTypeLoc(); - } -} - - -namespace { - struct TSTChecker : public TypeLocVisitor<TSTChecker, bool> { - // Overload resolution does the real work for us. - static bool isTypeSpec(TypeSpecTypeLoc _) { return true; } - static bool isTypeSpec(TypeLoc _) { return false; } - -#define ABSTRACT_TYPELOC(CLASS, PARENT) -#define TYPELOC(CLASS, PARENT) \ - bool Visit##CLASS##TypeLoc(CLASS##TypeLoc TyLoc) { \ - return isTypeSpec(TyLoc); \ - } -#include "clang/AST/TypeLocNodes.def" - }; -} - - -/// \brief Determines if the given type loc corresponds to a -/// TypeSpecTypeLoc. Since there is not actually a TypeSpecType in -/// the type hierarchy, this is made somewhat complicated. -/// -/// There are a lot of types that currently use TypeSpecTypeLoc -/// because it's a convenient base class. Ideally we would not accept -/// those here, but ideally we would have better implementations for -/// them. -bool TypeSpecTypeLoc::classof(const TypeLoc *TL) { - if (TL->getType().hasLocalQualifiers()) return false; - return TSTChecker().Visit(*TL); -} - -// Reimplemented to account for GNU/C++ extension -// typeof unary-expression -// where there are no parentheses. -SourceRange TypeOfExprTypeLoc::getLocalSourceRange() const { - if (getRParenLoc().isValid()) - return SourceRange(getTypeofLoc(), getRParenLoc()); - else - return SourceRange(getTypeofLoc(), - getUnderlyingExpr()->getSourceRange().getEnd()); -} - - -TypeSpecifierType BuiltinTypeLoc::getWrittenTypeSpec() const { - if (needsExtraLocalData()) - return static_cast<TypeSpecifierType>(getWrittenBuiltinSpecs().Type); - switch (getTypePtr()->getKind()) { - case BuiltinType::Void: - return TST_void; - case BuiltinType::Bool: - return TST_bool; - case BuiltinType::Char_U: - case BuiltinType::Char_S: - return TST_char; - case BuiltinType::Char16: - return TST_char16; - case BuiltinType::Char32: - return TST_char32; - case BuiltinType::WChar_S: - case BuiltinType::WChar_U: - return TST_wchar; - case BuiltinType::UChar: - case BuiltinType::UShort: - case BuiltinType::UInt: - case BuiltinType::ULong: - case BuiltinType::ULongLong: - case BuiltinType::UInt128: - case BuiltinType::SChar: - case BuiltinType::Short: - case BuiltinType::Int: - case BuiltinType::Long: - case BuiltinType::LongLong: - case BuiltinType::Int128: - case BuiltinType::Half: - case BuiltinType::Float: - case BuiltinType::Double: - case BuiltinType::LongDouble: - llvm_unreachable("Builtin type needs extra local data!"); - // Fall through, if the impossible happens. - - case BuiltinType::NullPtr: - case BuiltinType::Overload: - case BuiltinType::Dependent: - case BuiltinType::BoundMember: - case BuiltinType::UnknownAny: - case BuiltinType::ARCUnbridgedCast: - case BuiltinType::PseudoObject: - case BuiltinType::ObjCId: - case BuiltinType::ObjCClass: - case BuiltinType::ObjCSel: - case BuiltinType::BuiltinFn: - return TST_unspecified; - } - - llvm_unreachable("Invalid BuiltinType Kind!"); -} - -TypeLoc TypeLoc::IgnoreParensImpl(TypeLoc TL) { - while (ParenTypeLoc* PTL = dyn_cast<ParenTypeLoc>(&TL)) - TL = PTL->getInnerLoc(); - return TL; -} - -void ElaboratedTypeLoc::initializeLocal(ASTContext &Context, - SourceLocation Loc) { - setElaboratedKeywordLoc(Loc); - NestedNameSpecifierLocBuilder Builder; - Builder.MakeTrivial(Context, getTypePtr()->getQualifier(), Loc); - setQualifierLoc(Builder.getWithLocInContext(Context)); -} - -void DependentNameTypeLoc::initializeLocal(ASTContext &Context, - SourceLocation Loc) { - setElaboratedKeywordLoc(Loc); - NestedNameSpecifierLocBuilder Builder; - Builder.MakeTrivial(Context, getTypePtr()->getQualifier(), Loc); - setQualifierLoc(Builder.getWithLocInContext(Context)); - setNameLoc(Loc); -} - -void -DependentTemplateSpecializationTypeLoc::initializeLocal(ASTContext &Context, - SourceLocation Loc) { - setElaboratedKeywordLoc(Loc); - if (getTypePtr()->getQualifier()) { - NestedNameSpecifierLocBuilder Builder; - Builder.MakeTrivial(Context, getTypePtr()->getQualifier(), Loc); - setQualifierLoc(Builder.getWithLocInContext(Context)); - } else { - setQualifierLoc(NestedNameSpecifierLoc()); - } - setTemplateKeywordLoc(Loc); - setTemplateNameLoc(Loc); - setLAngleLoc(Loc); - setRAngleLoc(Loc); - TemplateSpecializationTypeLoc::initializeArgLocs(Context, getNumArgs(), - getTypePtr()->getArgs(), - getArgInfos(), Loc); -} - -void TemplateSpecializationTypeLoc::initializeArgLocs(ASTContext &Context, - unsigned NumArgs, - const TemplateArgument *Args, - TemplateArgumentLocInfo *ArgInfos, - SourceLocation Loc) { - for (unsigned i = 0, e = NumArgs; i != e; ++i) { - switch (Args[i].getKind()) { - case TemplateArgument::Null: - case TemplateArgument::Declaration: - case TemplateArgument::Integral: - case TemplateArgument::NullPtr: - llvm_unreachable("Impossible TemplateArgument"); - - case TemplateArgument::Expression: - ArgInfos[i] = TemplateArgumentLocInfo(Args[i].getAsExpr()); - break; - - case TemplateArgument::Type: - ArgInfos[i] = TemplateArgumentLocInfo( - Context.getTrivialTypeSourceInfo(Args[i].getAsType(), - Loc)); - break; - - case TemplateArgument::Template: - case TemplateArgument::TemplateExpansion: { - NestedNameSpecifierLocBuilder Builder; - TemplateName Template = Args[i].getAsTemplate(); - if (DependentTemplateName *DTN = Template.getAsDependentTemplateName()) - Builder.MakeTrivial(Context, DTN->getQualifier(), Loc); - else if (QualifiedTemplateName *QTN = Template.getAsQualifiedTemplateName()) - Builder.MakeTrivial(Context, QTN->getQualifier(), Loc); - - ArgInfos[i] = TemplateArgumentLocInfo( - Builder.getWithLocInContext(Context), - Loc, - Args[i].getKind() == TemplateArgument::Template - ? SourceLocation() - : Loc); - break; - } - - case TemplateArgument::Pack: - ArgInfos[i] = TemplateArgumentLocInfo(); - break; - } - } -} +//===--- TypeLoc.cpp - Type Source Info Wrapper -----------------*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+//
+// This file defines the TypeLoc subclasses implementations.
+//
+//===----------------------------------------------------------------------===//
+
+#include "clang/AST/TypeLoc.h"
+#include "clang/AST/ASTContext.h"
+#include "clang/AST/Expr.h"
+#include "clang/AST/TypeLocVisitor.h"
+#include "llvm/Support/ErrorHandling.h"
+#include "llvm/Support/raw_ostream.h"
+using namespace clang;
+
+//===----------------------------------------------------------------------===//
+// TypeLoc Implementation
+//===----------------------------------------------------------------------===//
+
+namespace {
+ class TypeLocRanger : public TypeLocVisitor<TypeLocRanger, SourceRange> {
+ public:
+#define ABSTRACT_TYPELOC(CLASS, PARENT)
+#define TYPELOC(CLASS, PARENT) \
+ SourceRange Visit##CLASS##TypeLoc(CLASS##TypeLoc TyLoc) { \
+ return TyLoc.getLocalSourceRange(); \
+ }
+#include "clang/AST/TypeLocNodes.def"
+ };
+}
+
+SourceRange TypeLoc::getLocalSourceRangeImpl(TypeLoc TL) {
+ if (TL.isNull()) return SourceRange();
+ return TypeLocRanger().Visit(TL);
+}
+
+namespace {
+ class TypeSizer : public TypeLocVisitor<TypeSizer, unsigned> {
+ public:
+#define ABSTRACT_TYPELOC(CLASS, PARENT)
+#define TYPELOC(CLASS, PARENT) \
+ unsigned Visit##CLASS##TypeLoc(CLASS##TypeLoc TyLoc) { \
+ return TyLoc.getFullDataSize(); \
+ }
+#include "clang/AST/TypeLocNodes.def"
+ };
+}
+
+/// \brief Returns the size of the type source info data block.
+unsigned TypeLoc::getFullDataSizeForType(QualType Ty) {
+ if (Ty.isNull()) return 0;
+ return TypeSizer().Visit(TypeLoc(Ty, 0));
+}
+
+namespace {
+ class NextLoc : public TypeLocVisitor<NextLoc, TypeLoc> {
+ public:
+#define ABSTRACT_TYPELOC(CLASS, PARENT)
+#define TYPELOC(CLASS, PARENT) \
+ TypeLoc Visit##CLASS##TypeLoc(CLASS##TypeLoc TyLoc) { \
+ return TyLoc.getNextTypeLoc(); \
+ }
+#include "clang/AST/TypeLocNodes.def"
+ };
+}
+
+/// \brief Get the next TypeLoc pointed by this TypeLoc, e.g for "int*" the
+/// TypeLoc is a PointerLoc and next TypeLoc is for "int".
+TypeLoc TypeLoc::getNextTypeLocImpl(TypeLoc TL) {
+ return NextLoc().Visit(TL);
+}
+
+/// \brief Initializes a type location, and all of its children
+/// recursively, as if the entire tree had been written in the
+/// given location.
+void TypeLoc::initializeImpl(ASTContext &Context, TypeLoc TL,
+ SourceLocation Loc) {
+ while (true) {
+ switch (TL.getTypeLocClass()) {
+#define ABSTRACT_TYPELOC(CLASS, PARENT)
+#define TYPELOC(CLASS, PARENT) \
+ case CLASS: { \
+ CLASS##TypeLoc TLCasted = cast<CLASS##TypeLoc>(TL); \
+ TLCasted.initializeLocal(Context, Loc); \
+ TL = TLCasted.getNextTypeLoc(); \
+ if (!TL) return; \
+ continue; \
+ }
+#include "clang/AST/TypeLocNodes.def"
+ }
+ }
+}
+
+SourceLocation TypeLoc::getBeginLoc() const {
+ TypeLoc Cur = *this;
+ TypeLoc LeftMost = Cur;
+ while (true) {
+ switch (Cur.getTypeLocClass()) {
+ case Elaborated:
+ LeftMost = Cur;
+ break;
+ case FunctionProto:
+ if (cast<FunctionProtoTypeLoc>(&Cur)->getTypePtr()->hasTrailingReturn()) {
+ LeftMost = Cur;
+ break;
+ }
+ /* Fall through */
+ case FunctionNoProto:
+ case ConstantArray:
+ case DependentSizedArray:
+ case IncompleteArray:
+ case VariableArray:
+ // FIXME: Currently QualifiedTypeLoc does not have a source range
+ case Qualified:
+ Cur = Cur.getNextTypeLoc();
+ continue;
+ default:
+ if (!Cur.getLocalSourceRange().getBegin().isInvalid())
+ LeftMost = Cur;
+ Cur = Cur.getNextTypeLoc();
+ if (Cur.isNull())
+ break;
+ continue;
+ } // switch
+ break;
+ } // while
+ return LeftMost.getLocalSourceRange().getBegin();
+}
+
+SourceLocation TypeLoc::getEndLoc() const {
+ TypeLoc Cur = *this;
+ TypeLoc Last;
+ while (true) {
+ switch (Cur.getTypeLocClass()) {
+ default:
+ if (!Last)
+ Last = Cur;
+ return Last.getLocalSourceRange().getEnd();
+ case Paren:
+ case ConstantArray:
+ case DependentSizedArray:
+ case IncompleteArray:
+ case VariableArray:
+ case FunctionNoProto:
+ Last = Cur;
+ break;
+ case FunctionProto:
+ if (cast<FunctionProtoTypeLoc>(&Cur)->getTypePtr()->hasTrailingReturn())
+ Last = TypeLoc();
+ else
+ Last = Cur;
+ break;
+ case Pointer:
+ case BlockPointer:
+ case MemberPointer:
+ case LValueReference:
+ case RValueReference:
+ case PackExpansion:
+ if (!Last)
+ Last = Cur;
+ break;
+ case Qualified:
+ case Elaborated:
+ break;
+ }
+ Cur = Cur.getNextTypeLoc();
+ }
+}
+
+
+namespace {
+ struct TSTChecker : public TypeLocVisitor<TSTChecker, bool> {
+ // Overload resolution does the real work for us.
+ static bool isTypeSpec(TypeSpecTypeLoc _) { return true; }
+ static bool isTypeSpec(TypeLoc _) { return false; }
+
+#define ABSTRACT_TYPELOC(CLASS, PARENT)
+#define TYPELOC(CLASS, PARENT) \
+ bool Visit##CLASS##TypeLoc(CLASS##TypeLoc TyLoc) { \
+ return isTypeSpec(TyLoc); \
+ }
+#include "clang/AST/TypeLocNodes.def"
+ };
+}
+
+
+/// \brief Determines if the given type loc corresponds to a
+/// TypeSpecTypeLoc. Since there is not actually a TypeSpecType in
+/// the type hierarchy, this is made somewhat complicated.
+///
+/// There are a lot of types that currently use TypeSpecTypeLoc
+/// because it's a convenient base class. Ideally we would not accept
+/// those here, but ideally we would have better implementations for
+/// them.
+bool TypeSpecTypeLoc::classof(const TypeLoc *TL) {
+ if (TL->getType().hasLocalQualifiers()) return false;
+ return TSTChecker().Visit(*TL);
+}
+
+// Reimplemented to account for GNU/C++ extension
+// typeof unary-expression
+// where there are no parentheses.
+SourceRange TypeOfExprTypeLoc::getLocalSourceRange() const {
+ if (getRParenLoc().isValid())
+ return SourceRange(getTypeofLoc(), getRParenLoc());
+ else
+ return SourceRange(getTypeofLoc(),
+ getUnderlyingExpr()->getSourceRange().getEnd());
+}
+
+
+TypeSpecifierType BuiltinTypeLoc::getWrittenTypeSpec() const {
+ if (needsExtraLocalData())
+ return static_cast<TypeSpecifierType>(getWrittenBuiltinSpecs().Type);
+ switch (getTypePtr()->getKind()) {
+ case BuiltinType::Void:
+ return TST_void;
+ case BuiltinType::Bool:
+ return TST_bool;
+ case BuiltinType::Char_U:
+ case BuiltinType::Char_S:
+ return TST_char;
+ case BuiltinType::Char16:
+ return TST_char16;
+ case BuiltinType::Char32:
+ return TST_char32;
+ case BuiltinType::WChar_S:
+ case BuiltinType::WChar_U:
+ return TST_wchar;
+ case BuiltinType::UChar:
+ case BuiltinType::UShort:
+ case BuiltinType::UInt:
+ case BuiltinType::ULong:
+ case BuiltinType::ULongLong:
+ case BuiltinType::UInt128:
+ case BuiltinType::SChar:
+ case BuiltinType::Short:
+ case BuiltinType::Int:
+ case BuiltinType::Long:
+ case BuiltinType::LongLong:
+ case BuiltinType::Int128:
+ case BuiltinType::Half:
+ case BuiltinType::Float:
+ case BuiltinType::Double:
+ case BuiltinType::LongDouble:
+ llvm_unreachable("Builtin type needs extra local data!");
+ // Fall through, if the impossible happens.
+
+ case BuiltinType::NullPtr:
+ case BuiltinType::Overload:
+ case BuiltinType::Dependent:
+ case BuiltinType::BoundMember:
+ case BuiltinType::UnknownAny:
+ case BuiltinType::ARCUnbridgedCast:
+ case BuiltinType::PseudoObject:
+ case BuiltinType::ObjCId:
+ case BuiltinType::ObjCClass:
+ case BuiltinType::ObjCSel:
+ case BuiltinType::OCLImage1d:
+ case BuiltinType::OCLImage1dArray:
+ case BuiltinType::OCLImage1dBuffer:
+ case BuiltinType::OCLImage2d:
+ case BuiltinType::OCLImage2dArray:
+ case BuiltinType::OCLImage3d:
+ case BuiltinType::BuiltinFn:
+ return TST_unspecified;
+ }
+
+ llvm_unreachable("Invalid BuiltinType Kind!");
+}
+
+TypeLoc TypeLoc::IgnoreParensImpl(TypeLoc TL) {
+ while (ParenTypeLoc* PTL = dyn_cast<ParenTypeLoc>(&TL))
+ TL = PTL->getInnerLoc();
+ return TL;
+}
+
+void ElaboratedTypeLoc::initializeLocal(ASTContext &Context,
+ SourceLocation Loc) {
+ setElaboratedKeywordLoc(Loc);
+ NestedNameSpecifierLocBuilder Builder;
+ Builder.MakeTrivial(Context, getTypePtr()->getQualifier(), Loc);
+ setQualifierLoc(Builder.getWithLocInContext(Context));
+}
+
+void DependentNameTypeLoc::initializeLocal(ASTContext &Context,
+ SourceLocation Loc) {
+ setElaboratedKeywordLoc(Loc);
+ NestedNameSpecifierLocBuilder Builder;
+ Builder.MakeTrivial(Context, getTypePtr()->getQualifier(), Loc);
+ setQualifierLoc(Builder.getWithLocInContext(Context));
+ setNameLoc(Loc);
+}
+
+void
+DependentTemplateSpecializationTypeLoc::initializeLocal(ASTContext &Context,
+ SourceLocation Loc) {
+ setElaboratedKeywordLoc(Loc);
+ if (getTypePtr()->getQualifier()) {
+ NestedNameSpecifierLocBuilder Builder;
+ Builder.MakeTrivial(Context, getTypePtr()->getQualifier(), Loc);
+ setQualifierLoc(Builder.getWithLocInContext(Context));
+ } else {
+ setQualifierLoc(NestedNameSpecifierLoc());
+ }
+ setTemplateKeywordLoc(Loc);
+ setTemplateNameLoc(Loc);
+ setLAngleLoc(Loc);
+ setRAngleLoc(Loc);
+ TemplateSpecializationTypeLoc::initializeArgLocs(Context, getNumArgs(),
+ getTypePtr()->getArgs(),
+ getArgInfos(), Loc);
+}
+
+void TemplateSpecializationTypeLoc::initializeArgLocs(ASTContext &Context,
+ unsigned NumArgs,
+ const TemplateArgument *Args,
+ TemplateArgumentLocInfo *ArgInfos,
+ SourceLocation Loc) {
+ for (unsigned i = 0, e = NumArgs; i != e; ++i) {
+ switch (Args[i].getKind()) {
+ case TemplateArgument::Null:
+ case TemplateArgument::Declaration:
+ case TemplateArgument::Integral:
+ case TemplateArgument::NullPtr:
+ llvm_unreachable("Impossible TemplateArgument");
+
+ case TemplateArgument::Expression:
+ ArgInfos[i] = TemplateArgumentLocInfo(Args[i].getAsExpr());
+ break;
+
+ case TemplateArgument::Type:
+ ArgInfos[i] = TemplateArgumentLocInfo(
+ Context.getTrivialTypeSourceInfo(Args[i].getAsType(),
+ Loc));
+ break;
+
+ case TemplateArgument::Template:
+ case TemplateArgument::TemplateExpansion: {
+ NestedNameSpecifierLocBuilder Builder;
+ TemplateName Template = Args[i].getAsTemplate();
+ if (DependentTemplateName *DTN = Template.getAsDependentTemplateName())
+ Builder.MakeTrivial(Context, DTN->getQualifier(), Loc);
+ else if (QualifiedTemplateName *QTN = Template.getAsQualifiedTemplateName())
+ Builder.MakeTrivial(Context, QTN->getQualifier(), Loc);
+
+ ArgInfos[i] = TemplateArgumentLocInfo(
+ Builder.getWithLocInContext(Context),
+ Loc,
+ Args[i].getKind() == TemplateArgument::Template
+ ? SourceLocation()
+ : Loc);
+ break;
+ }
+
+ case TemplateArgument::Pack:
+ ArgInfos[i] = TemplateArgumentLocInfo();
+ break;
+ }
+ }
+}
diff --git a/clang/lib/CodeGen/CGDebugInfo.cpp b/clang/lib/CodeGen/CGDebugInfo.cpp index 844514be27c..c16081fb985 100644 --- a/clang/lib/CodeGen/CGDebugInfo.cpp +++ b/clang/lib/CodeGen/CGDebugInfo.cpp @@ -1,2802 +1,2834 @@ -//===--- CGDebugInfo.cpp - Emit Debug Information for a Module ------------===// -// -// The LLVM Compiler Infrastructure -// -// This file is distributed under the University of Illinois Open Source -// License. See LICENSE.TXT for details. -// -//===----------------------------------------------------------------------===// -// -// This coordinates the debug information generation while generating code. -// -//===----------------------------------------------------------------------===// - -#include "CGDebugInfo.h" -#include "CGBlocks.h" -#include "CGObjCRuntime.h" -#include "CodeGenFunction.h" -#include "CodeGenModule.h" -#include "clang/AST/ASTContext.h" -#include "clang/AST/DeclFriend.h" -#include "clang/AST/DeclObjC.h" -#include "clang/AST/DeclTemplate.h" -#include "clang/AST/Expr.h" -#include "clang/AST/RecordLayout.h" -#include "clang/Basic/FileManager.h" -#include "clang/Basic/SourceManager.h" -#include "clang/Basic/Version.h" -#include "clang/Frontend/CodeGenOptions.h" -#include "llvm/ADT/SmallVector.h" -#include "llvm/ADT/StringExtras.h" -#include "llvm/Constants.h" -#include "llvm/DataLayout.h" -#include "llvm/DerivedTypes.h" -#include "llvm/Instructions.h" -#include "llvm/Intrinsics.h" -#include "llvm/Module.h" -#include "llvm/Support/Dwarf.h" -#include "llvm/Support/FileSystem.h" -using namespace clang; -using namespace clang::CodeGen; - -CGDebugInfo::CGDebugInfo(CodeGenModule &CGM) - : CGM(CGM), DBuilder(CGM.getModule()), - BlockLiteralGenericSet(false) { - CreateCompileUnit(); -} - -CGDebugInfo::~CGDebugInfo() { - assert(LexicalBlockStack.empty() && - "Region stack mismatch, stack not empty!"); -} - -void CGDebugInfo::setLocation(SourceLocation Loc) { - // If the new location isn't valid return. - if (!Loc.isValid()) return; - - CurLoc = CGM.getContext().getSourceManager().getExpansionLoc(Loc); - - // If we've changed files in the middle of a lexical scope go ahead - // and create a new lexical scope with file node if it's different - // from the one in the scope. - if (LexicalBlockStack.empty()) return; - - SourceManager &SM = CGM.getContext().getSourceManager(); - PresumedLoc PCLoc = SM.getPresumedLoc(CurLoc); - PresumedLoc PPLoc = SM.getPresumedLoc(PrevLoc); - - if (PCLoc.isInvalid() || PPLoc.isInvalid() || - !strcmp(PPLoc.getFilename(), PCLoc.getFilename())) - return; - - llvm::MDNode *LB = LexicalBlockStack.back(); - llvm::DIScope Scope = llvm::DIScope(LB); - if (Scope.isLexicalBlockFile()) { - llvm::DILexicalBlockFile LBF = llvm::DILexicalBlockFile(LB); - llvm::DIDescriptor D - = DBuilder.createLexicalBlockFile(LBF.getScope(), - getOrCreateFile(CurLoc)); - llvm::MDNode *N = D; - LexicalBlockStack.pop_back(); - LexicalBlockStack.push_back(N); - } else if (Scope.isLexicalBlock()) { - llvm::DIDescriptor D - = DBuilder.createLexicalBlockFile(Scope, getOrCreateFile(CurLoc)); - llvm::MDNode *N = D; - LexicalBlockStack.pop_back(); - LexicalBlockStack.push_back(N); - } -} - -/// getContextDescriptor - Get context info for the decl. -llvm::DIDescriptor CGDebugInfo::getContextDescriptor(const Decl *Context) { - if (!Context) - return TheCU; - - llvm::DenseMap<const Decl *, llvm::WeakVH>::iterator - I = RegionMap.find(Context); - if (I != RegionMap.end()) { - llvm::Value *V = I->second; - return llvm::DIDescriptor(dyn_cast_or_null<llvm::MDNode>(V)); - } - - // Check namespace. - if (const NamespaceDecl *NSDecl = dyn_cast<NamespaceDecl>(Context)) - return llvm::DIDescriptor(getOrCreateNameSpace(NSDecl)); - - if (const RecordDecl *RDecl = dyn_cast<RecordDecl>(Context)) { - if (!RDecl->isDependentType()) { - llvm::DIType Ty = getOrCreateType(CGM.getContext().getTypeDeclType(RDecl), - getOrCreateMainFile()); - return llvm::DIDescriptor(Ty); - } - } - return TheCU; -} - -/// getFunctionName - Get function name for the given FunctionDecl. If the -/// name is constructred on demand (e.g. C++ destructor) then the name -/// is stored on the side. -StringRef CGDebugInfo::getFunctionName(const FunctionDecl *FD) { - assert (FD && "Invalid FunctionDecl!"); - IdentifierInfo *FII = FD->getIdentifier(); - FunctionTemplateSpecializationInfo *Info - = FD->getTemplateSpecializationInfo(); - if (!Info && FII) - return FII->getName(); - - // Otherwise construct human readable name for debug info. - std::string NS = FD->getNameAsString(); - - // Add any template specialization args. - if (Info) { - const TemplateArgumentList *TArgs = Info->TemplateArguments; - const TemplateArgument *Args = TArgs->data(); - unsigned NumArgs = TArgs->size(); - PrintingPolicy Policy(CGM.getLangOpts()); - NS += TemplateSpecializationType::PrintTemplateArgumentList(Args, - NumArgs, - Policy); - } - - // Copy this name on the side and use its reference. - char *StrPtr = DebugInfoNames.Allocate<char>(NS.length()); - memcpy(StrPtr, NS.data(), NS.length()); - return StringRef(StrPtr, NS.length()); -} - -StringRef CGDebugInfo::getObjCMethodName(const ObjCMethodDecl *OMD) { - SmallString<256> MethodName; - llvm::raw_svector_ostream OS(MethodName); - OS << (OMD->isInstanceMethod() ? '-' : '+') << '['; - const DeclContext *DC = OMD->getDeclContext(); - if (const ObjCImplementationDecl *OID = - dyn_cast<const ObjCImplementationDecl>(DC)) { - OS << OID->getName(); - } else if (const ObjCInterfaceDecl *OID = - dyn_cast<const ObjCInterfaceDecl>(DC)) { - OS << OID->getName(); - } else if (const ObjCCategoryImplDecl *OCD = - dyn_cast<const ObjCCategoryImplDecl>(DC)){ - OS << ((const NamedDecl *)OCD)->getIdentifier()->getNameStart() << '(' << - OCD->getIdentifier()->getNameStart() << ')'; - } - OS << ' ' << OMD->getSelector().getAsString() << ']'; - - char *StrPtr = DebugInfoNames.Allocate<char>(OS.tell()); - memcpy(StrPtr, MethodName.begin(), OS.tell()); - return StringRef(StrPtr, OS.tell()); -} - -/// getSelectorName - Return selector name. This is used for debugging -/// info. -StringRef CGDebugInfo::getSelectorName(Selector S) { - const std::string &SName = S.getAsString(); - char *StrPtr = DebugInfoNames.Allocate<char>(SName.size()); - memcpy(StrPtr, SName.data(), SName.size()); - return StringRef(StrPtr, SName.size()); -} - -/// getClassName - Get class name including template argument list. -StringRef -CGDebugInfo::getClassName(const RecordDecl *RD) { - const ClassTemplateSpecializationDecl *Spec - = dyn_cast<ClassTemplateSpecializationDecl>(RD); - if (!Spec) - return RD->getName(); - - const TemplateArgument *Args; - unsigned NumArgs; - if (TypeSourceInfo *TAW = Spec->getTypeAsWritten()) { - const TemplateSpecializationType *TST = - cast<TemplateSpecializationType>(TAW->getType()); - Args = TST->getArgs(); - NumArgs = TST->getNumArgs(); - } else { - const TemplateArgumentList &TemplateArgs = Spec->getTemplateArgs(); - Args = TemplateArgs.data(); - NumArgs = TemplateArgs.size(); - } - StringRef Name = RD->getIdentifier()->getName(); - PrintingPolicy Policy(CGM.getLangOpts()); - std::string TemplateArgList = - TemplateSpecializationType::PrintTemplateArgumentList(Args, NumArgs, Policy); - - // Copy this name on the side and use its reference. - size_t Length = Name.size() + TemplateArgList.size(); - char *StrPtr = DebugInfoNames.Allocate<char>(Length); - memcpy(StrPtr, Name.data(), Name.size()); - memcpy(StrPtr + Name.size(), TemplateArgList.data(), TemplateArgList.size()); - return StringRef(StrPtr, Length); -} - -/// getOrCreateFile - Get the file debug info descriptor for the input location. -llvm::DIFile CGDebugInfo::getOrCreateFile(SourceLocation Loc) { - if (!Loc.isValid()) - // If Location is not valid then use main input file. - return DBuilder.createFile(TheCU.getFilename(), TheCU.getDirectory()); - - SourceManager &SM = CGM.getContext().getSourceManager(); - PresumedLoc PLoc = SM.getPresumedLoc(Loc); - - if (PLoc.isInvalid() || StringRef(PLoc.getFilename()).empty()) - // If the location is not valid then use main input file. - return DBuilder.createFile(TheCU.getFilename(), TheCU.getDirectory()); - - // Cache the results. - const char *fname = PLoc.getFilename(); - llvm::DenseMap<const char *, llvm::WeakVH>::iterator it = - DIFileCache.find(fname); - - if (it != DIFileCache.end()) { - // Verify that the information still exists. - if (llvm::Value *V = it->second) - return llvm::DIFile(cast<llvm::MDNode>(V)); - } - - llvm::DIFile F = DBuilder.createFile(PLoc.getFilename(), getCurrentDirname()); - - DIFileCache[fname] = F; - return F; -} - -/// getOrCreateMainFile - Get the file info for main compile unit. -llvm::DIFile CGDebugInfo::getOrCreateMainFile() { - return DBuilder.createFile(TheCU.getFilename(), TheCU.getDirectory()); -} - -/// getLineNumber - Get line number for the location. If location is invalid -/// then use current location. -unsigned CGDebugInfo::getLineNumber(SourceLocation Loc) { - if (Loc.isInvalid() && CurLoc.isInvalid()) - return 0; - SourceManager &SM = CGM.getContext().getSourceManager(); - PresumedLoc PLoc = SM.getPresumedLoc(Loc.isValid() ? Loc : CurLoc); - return PLoc.isValid()? PLoc.getLine() : 0; -} - -/// getColumnNumber - Get column number for the location. -unsigned CGDebugInfo::getColumnNumber(SourceLocation Loc) { - // We may not want column information at all. - if (!CGM.getCodeGenOpts().DebugColumnInfo) - return 0; - - // If the location is invalid then use the current column. - if (Loc.isInvalid() && CurLoc.isInvalid()) - return 0; - SourceManager &SM = CGM.getContext().getSourceManager(); - PresumedLoc PLoc = SM.getPresumedLoc(Loc.isValid() ? Loc : CurLoc); - return PLoc.isValid()? PLoc.getColumn() : 0; -} - -StringRef CGDebugInfo::getCurrentDirname() { - if (!CGM.getCodeGenOpts().DebugCompilationDir.empty()) - return CGM.getCodeGenOpts().DebugCompilationDir; - - if (!CWDName.empty()) - return CWDName; - SmallString<256> CWD; - llvm::sys::fs::current_path(CWD); - char *CompDirnamePtr = DebugInfoNames.Allocate<char>(CWD.size()); - memcpy(CompDirnamePtr, CWD.data(), CWD.size()); - return CWDName = StringRef(CompDirnamePtr, CWD.size()); -} - -/// CreateCompileUnit - Create new compile unit. -void CGDebugInfo::CreateCompileUnit() { - - // Get absolute path name. - SourceManager &SM = CGM.getContext().getSourceManager(); - std::string MainFileName = CGM.getCodeGenOpts().MainFileName; - if (MainFileName.empty()) - MainFileName = "<unknown>"; - - // The main file name provided via the "-main-file-name" option contains just - // the file name itself with no path information. This file name may have had - // a relative path, so we look into the actual file entry for the main - // file to determine the real absolute path for the file. - std::string MainFileDir; - if (const FileEntry *MainFile = SM.getFileEntryForID(SM.getMainFileID())) { - MainFileDir = MainFile->getDir()->getName(); - if (MainFileDir != ".") - MainFileName = MainFileDir + "/" + MainFileName; - } - - // Save filename string. - char *FilenamePtr = DebugInfoNames.Allocate<char>(MainFileName.length()); - memcpy(FilenamePtr, MainFileName.c_str(), MainFileName.length()); - StringRef Filename(FilenamePtr, MainFileName.length()); - - unsigned LangTag; - const LangOptions &LO = CGM.getLangOpts(); - if (LO.CPlusPlus) { - if (LO.ObjC1) - LangTag = llvm::dwarf::DW_LANG_ObjC_plus_plus; - else - LangTag = llvm::dwarf::DW_LANG_C_plus_plus; - } else if (LO.ObjC1) { - LangTag = llvm::dwarf::DW_LANG_ObjC; - } else if (LO.C99) { - LangTag = llvm::dwarf::DW_LANG_C99; - } else { - LangTag = llvm::dwarf::DW_LANG_C89; - } - - std::string Producer = getClangFullVersion(); - - // Figure out which version of the ObjC runtime we have. - unsigned RuntimeVers = 0; - if (LO.ObjC1) - RuntimeVers = LO.ObjCRuntime.isNonFragile() ? 2 : 1; - - // Create new compile unit. - DBuilder.createCompileUnit( - LangTag, Filename, getCurrentDirname(), - Producer, - LO.Optimize, CGM.getCodeGenOpts().DwarfDebugFlags, RuntimeVers); - // FIXME - Eliminate TheCU. - TheCU = llvm::DICompileUnit(DBuilder.getCU()); -} - -/// CreateType - Get the Basic type from the cache or create a new -/// one if necessary. -llvm::DIType CGDebugInfo::CreateType(const BuiltinType *BT) { - unsigned Encoding = 0; - StringRef BTName; - switch (BT->getKind()) { -#define BUILTIN_TYPE(Id, SingletonId) -#define PLACEHOLDER_TYPE(Id, SingletonId) \ - case BuiltinType::Id: -#include "clang/AST/BuiltinTypes.def" - case BuiltinType::Dependent: - llvm_unreachable("Unexpected builtin type"); - case BuiltinType::NullPtr: - return DBuilder. - createNullPtrType(BT->getName(CGM.getLangOpts())); - case BuiltinType::Void: - return llvm::DIType(); - case BuiltinType::ObjCClass: - if (ClassTy.Verify()) - return ClassTy; - ClassTy = DBuilder.createForwardDecl(llvm::dwarf::DW_TAG_structure_type, - "objc_class", TheCU, - getOrCreateMainFile(), 0); - return ClassTy; - case BuiltinType::ObjCId: { - // typedef struct objc_class *Class; - // typedef struct objc_object { - // Class isa; - // } *id; - - if (ObjTy.Verify()) - return ObjTy; - - if (!ClassTy.Verify()) - ClassTy = DBuilder.createForwardDecl(llvm::dwarf::DW_TAG_structure_type, - "objc_class", TheCU, - getOrCreateMainFile(), 0); - - unsigned Size = CGM.getContext().getTypeSize(CGM.getContext().VoidPtrTy); - - llvm::DIType ISATy = DBuilder.createPointerType(ClassTy, Size); - - llvm::DIType FwdTy = DBuilder.createStructType(TheCU, "objc_object", - getOrCreateMainFile(), - 0, 0, 0, 0, - llvm::DIArray()); - - llvm::TrackingVH<llvm::MDNode> ObjNode(FwdTy); - SmallVector<llvm::Value *, 1> EltTys; - llvm::DIType FieldTy = - DBuilder.createMemberType(llvm::DIDescriptor(ObjNode), "isa", - getOrCreateMainFile(), 0, Size, - 0, 0, 0, ISATy); - EltTys.push_back(FieldTy); - llvm::DIArray Elements = DBuilder.getOrCreateArray(EltTys); - - ObjNode->replaceOperandWith(10, Elements); - ObjTy = llvm::DIType(ObjNode); - return ObjTy; - } - case BuiltinType::ObjCSel: { - if (SelTy.Verify()) - return SelTy; - SelTy = - DBuilder.createForwardDecl(llvm::dwarf::DW_TAG_structure_type, - "objc_selector", TheCU, getOrCreateMainFile(), - 0); - return SelTy; - } - case BuiltinType::UChar: - case BuiltinType::Char_U: Encoding = llvm::dwarf::DW_ATE_unsigned_char; break; - case BuiltinType::Char_S: - case BuiltinType::SChar: Encoding = llvm::dwarf::DW_ATE_signed_char; break; - case BuiltinType::Char16: - case BuiltinType::Char32: Encoding = llvm::dwarf::DW_ATE_UTF; break; - case BuiltinType::UShort: - case BuiltinType::UInt: - case BuiltinType::UInt128: - case BuiltinType::ULong: - case BuiltinType::WChar_U: - case BuiltinType::ULongLong: Encoding = llvm::dwarf::DW_ATE_unsigned; break; - case BuiltinType::Short: - case BuiltinType::Int: - case BuiltinType::Int128: - case BuiltinType::Long: - case BuiltinType::WChar_S: - case BuiltinType::LongLong: Encoding = llvm::dwarf::DW_ATE_signed; break; - case BuiltinType::Bool: Encoding = llvm::dwarf::DW_ATE_boolean; break; - case BuiltinType::Half: - case BuiltinType::Float: - case BuiltinType::LongDouble: - case BuiltinType::Double: Encoding = llvm::dwarf::DW_ATE_float; break; - } - - switch (BT->getKind()) { - case BuiltinType::Long: BTName = "long int"; break; - case BuiltinType::LongLong: BTName = "long long int"; break; - case BuiltinType::ULong: BTName = "long unsigned int"; break; - case BuiltinType::ULongLong: BTName = "long long unsigned int"; break; - default: - BTName = BT->getName(CGM.getLangOpts()); - break; - } - // Bit size, align and offset of the type. - uint64_t Size = CGM.getContext().getTypeSize(BT); - uint64_t Align = CGM.getContext().getTypeAlign(BT); - llvm::DIType DbgTy = - DBuilder.createBasicType(BTName, Size, Align, Encoding); - return DbgTy; -} - -llvm::DIType CGDebugInfo::CreateType(const ComplexType *Ty) { - // Bit size, align and offset of the type. - unsigned Encoding = llvm::dwarf::DW_ATE_complex_float; - if (Ty->isComplexIntegerType()) - Encoding = llvm::dwarf::DW_ATE_lo_user; - - uint64_t Size = CGM.getContext().getTypeSize(Ty); - uint64_t Align = CGM.getContext().getTypeAlign(Ty); - llvm::DIType DbgTy = - DBuilder.createBasicType("complex", Size, Align, Encoding); - - return DbgTy; -} - -/// CreateCVRType - Get the qualified type from the cache or create -/// a new one if necessary. -llvm::DIType CGDebugInfo::CreateQualifiedType(QualType Ty, llvm::DIFile Unit) { - QualifierCollector Qc; - const Type *T = Qc.strip(Ty); - - // Ignore these qualifiers for now. - Qc.removeObjCGCAttr(); - Qc.removeAddressSpace(); - Qc.removeObjCLifetime(); - - // We will create one Derived type for one qualifier and recurse to handle any - // additional ones. - unsigned Tag; - if (Qc.hasConst()) { - Tag = llvm::dwarf::DW_TAG_const_type; - Qc.removeConst(); - } else if (Qc.hasVolatile()) { - Tag = llvm::dwarf::DW_TAG_volatile_type; - Qc.removeVolatile(); - } else if (Qc.hasRestrict()) { - Tag = llvm::dwarf::DW_TAG_restrict_type; - Qc.removeRestrict(); - } else { - assert(Qc.empty() && "Unknown type qualifier for debug info"); - return getOrCreateType(QualType(T, 0), Unit); - } - - llvm::DIType FromTy = getOrCreateType(Qc.apply(CGM.getContext(), T), Unit); - - // No need to fill in the Name, Line, Size, Alignment, Offset in case of - // CVR derived types. - llvm::DIType DbgTy = DBuilder.createQualifiedType(Tag, FromTy); - - return DbgTy; -} - -llvm::DIType CGDebugInfo::CreateType(const ObjCObjectPointerType *Ty, - llvm::DIFile Unit) { - llvm::DIType DbgTy = - CreatePointerLikeType(llvm::dwarf::DW_TAG_pointer_type, Ty, - Ty->getPointeeType(), Unit); - return DbgTy; -} - -llvm::DIType CGDebugInfo::CreateType(const PointerType *Ty, - llvm::DIFile Unit) { - return CreatePointerLikeType(llvm::dwarf::DW_TAG_pointer_type, Ty, - Ty->getPointeeType(), Unit); -} - -// Creates a forward declaration for a RecordDecl in the given context. -llvm::DIType CGDebugInfo::createRecordFwdDecl(const RecordDecl *RD, - llvm::DIDescriptor Ctx) { - llvm::DIFile DefUnit = getOrCreateFile(RD->getLocation()); - unsigned Line = getLineNumber(RD->getLocation()); - StringRef RDName = getClassName(RD); - - unsigned Tag = 0; - if (RD->isStruct() || RD->isInterface()) - Tag = llvm::dwarf::DW_TAG_structure_type; - else if (RD->isUnion()) - Tag = llvm::dwarf::DW_TAG_union_type; - else { - assert(RD->isClass()); - Tag = llvm::dwarf::DW_TAG_class_type; - } - - // Create the type. - return DBuilder.createForwardDecl(Tag, RDName, Ctx, DefUnit, Line); -} - -// Walk up the context chain and create forward decls for record decls, -// and normal descriptors for namespaces. -llvm::DIDescriptor CGDebugInfo::createContextChain(const Decl *Context) { - if (!Context) - return TheCU; - - // See if we already have the parent. - llvm::DenseMap<const Decl *, llvm::WeakVH>::iterator - I = RegionMap.find(Context); - if (I != RegionMap.end()) { - llvm::Value *V = I->second; - return llvm::DIDescriptor(dyn_cast_or_null<llvm::MDNode>(V)); - } - - // Check namespace. - if (const NamespaceDecl *NSDecl = dyn_cast<NamespaceDecl>(Context)) - return llvm::DIDescriptor(getOrCreateNameSpace(NSDecl)); - - if (const RecordDecl *RD = dyn_cast<RecordDecl>(Context)) { - if (!RD->isDependentType()) { - llvm::DIType Ty = getOrCreateLimitedType(CGM.getContext().getTypeDeclType(RD), - getOrCreateMainFile()); - return llvm::DIDescriptor(Ty); - } - } - return TheCU; -} - -/// CreatePointeeType - Create Pointee type. If Pointee is a record -/// then emit record's fwd if debug info size reduction is enabled. -llvm::DIType CGDebugInfo::CreatePointeeType(QualType PointeeTy, - llvm::DIFile Unit) { - if (CGM.getCodeGenOpts().getDebugInfo() != CodeGenOptions::LimitedDebugInfo) - return getOrCreateType(PointeeTy, Unit); - - // Limit debug info for the pointee type. - - // If we have an existing type, use that, it's still smaller than creating - // a new type. - llvm::DIType Ty = getTypeOrNull(PointeeTy); - if (Ty.Verify()) return Ty; - - // Handle qualifiers. - if (PointeeTy.hasLocalQualifiers()) - return CreateQualifiedType(PointeeTy, Unit); - - if (const RecordType *RTy = dyn_cast<RecordType>(PointeeTy)) { - RecordDecl *RD = RTy->getDecl(); - llvm::DIDescriptor FDContext = - getContextDescriptor(cast<Decl>(RD->getDeclContext())); - llvm::DIType RetTy = createRecordFwdDecl(RD, FDContext); - TypeCache[QualType(RTy, 0).getAsOpaquePtr()] = RetTy; - return RetTy; - } - return getOrCreateType(PointeeTy, Unit); - -} - -llvm::DIType CGDebugInfo::CreatePointerLikeType(unsigned Tag, - const Type *Ty, - QualType PointeeTy, - llvm::DIFile Unit) { - if (Tag == llvm::dwarf::DW_TAG_reference_type || - Tag == llvm::dwarf::DW_TAG_rvalue_reference_type) - return DBuilder.createReferenceType(Tag, - CreatePointeeType(PointeeTy, Unit)); - - // Bit size, align and offset of the type. - // Size is always the size of a pointer. We can't use getTypeSize here - // because that does not return the correct value for references. - unsigned AS = CGM.getContext().getTargetAddressSpace(PointeeTy); - uint64_t Size = CGM.getContext().getTargetInfo().getPointerWidth(AS); - uint64_t Align = CGM.getContext().getTypeAlign(Ty); - - return DBuilder.createPointerType(CreatePointeeType(PointeeTy, Unit), - Size, Align); -} - -llvm::DIType CGDebugInfo::CreateType(const BlockPointerType *Ty, - llvm::DIFile Unit) { - if (BlockLiteralGenericSet) - return BlockLiteralGeneric; - - SmallVector<llvm::Value *, 8> EltTys; - llvm::DIType FieldTy; - QualType FType; - uint64_t FieldSize, FieldOffset; - unsigned FieldAlign; - llvm::DIArray Elements; - llvm::DIType EltTy, DescTy; - - FieldOffset = 0; - FType = CGM.getContext().UnsignedLongTy; - EltTys.push_back(CreateMemberType(Unit, FType, "reserved", &FieldOffset)); - EltTys.push_back(CreateMemberType(Unit, FType, "Size", &FieldOffset)); - - Elements = DBuilder.getOrCreateArray(EltTys); - EltTys.clear(); - - unsigned Flags = llvm::DIDescriptor::FlagAppleBlock; - unsigned LineNo = getLineNumber(CurLoc); - - EltTy = DBuilder.createStructType(Unit, "__block_descriptor", - Unit, LineNo, FieldOffset, 0, - Flags, Elements); - - // Bit size, align and offset of the type. - uint64_t Size = CGM.getContext().getTypeSize(Ty); - - DescTy = DBuilder.createPointerType(EltTy, Size); - - FieldOffset = 0; - FType = CGM.getContext().getPointerType(CGM.getContext().VoidTy); - EltTys.push_back(CreateMemberType(Unit, FType, "__isa", &FieldOffset)); - FType = CGM.getContext().IntTy; - EltTys.push_back(CreateMemberType(Unit, FType, "__flags", &FieldOffset)); - EltTys.push_back(CreateMemberType(Unit, FType, "__reserved", &FieldOffset)); - FType = CGM.getContext().getPointerType(CGM.getContext().VoidTy); - EltTys.push_back(CreateMemberType(Unit, FType, "__FuncPtr", &FieldOffset)); - - FType = CGM.getContext().getPointerType(CGM.getContext().VoidTy); - FieldTy = DescTy; - FieldSize = CGM.getContext().getTypeSize(Ty); - FieldAlign = CGM.getContext().getTypeAlign(Ty); - FieldTy = DBuilder.createMemberType(Unit, "__descriptor", Unit, - LineNo, FieldSize, FieldAlign, - FieldOffset, 0, FieldTy); - EltTys.push_back(FieldTy); - - FieldOffset += FieldSize; - Elements = DBuilder.getOrCreateArray(EltTys); - - EltTy = DBuilder.createStructType(Unit, "__block_literal_generic", - Unit, LineNo, FieldOffset, 0, - Flags, Elements); - - BlockLiteralGenericSet = true; - BlockLiteralGeneric = DBuilder.createPointerType(EltTy, Size); - return BlockLiteralGeneric; -} - -llvm::DIType CGDebugInfo::CreateType(const TypedefType *Ty, llvm::DIFile Unit) { - // Typedefs are derived from some other type. If we have a typedef of a - // typedef, make sure to emit the whole chain. - llvm::DIType Src = getOrCreateType(Ty->getDecl()->getUnderlyingType(), Unit); - if (!Src.Verify()) - return llvm::DIType(); - // We don't set size information, but do specify where the typedef was - // declared. - unsigned Line = getLineNumber(Ty->getDecl()->getLocation()); - const TypedefNameDecl *TyDecl = Ty->getDecl(); - - llvm::DIDescriptor TypedefContext = - getContextDescriptor(cast<Decl>(Ty->getDecl()->getDeclContext())); - - return - DBuilder.createTypedef(Src, TyDecl->getName(), Unit, Line, TypedefContext); -} - -llvm::DIType CGDebugInfo::CreateType(const FunctionType *Ty, - llvm::DIFile Unit) { - SmallVector<llvm::Value *, 16> EltTys; - - // Add the result type at least. - EltTys.push_back(getOrCreateType(Ty->getResultType(), Unit)); - - // Set up remainder of arguments if there is a prototype. - // FIXME: IF NOT, HOW IS THIS REPRESENTED? llvm-gcc doesn't represent '...'! - if (isa<FunctionNoProtoType>(Ty)) - EltTys.push_back(DBuilder.createUnspecifiedParameter()); - else if (const FunctionProtoType *FPT = dyn_cast<FunctionProtoType>(Ty)) { - for (unsigned i = 0, e = FPT->getNumArgs(); i != e; ++i) - EltTys.push_back(getOrCreateType(FPT->getArgType(i), Unit)); - } - - llvm::DIArray EltTypeArray = DBuilder.getOrCreateArray(EltTys); - return DBuilder.createSubroutineType(Unit, EltTypeArray); -} - - -void CGDebugInfo:: -CollectRecordStaticVars(const RecordDecl *RD, llvm::DIType FwdDecl) { - - for (RecordDecl::decl_iterator I = RD->decls_begin(), E = RD->decls_end(); - I != E; ++I) - if (const VarDecl *V = dyn_cast<VarDecl>(*I)) { - if (V->getInit()) { - const APValue *Value = V->evaluateValue(); - if (Value && Value->isInt()) { - llvm::ConstantInt *CI - = llvm::ConstantInt::get(CGM.getLLVMContext(), Value->getInt()); - - // Create the descriptor for static variable. - llvm::DIFile VUnit = getOrCreateFile(V->getLocation()); - StringRef VName = V->getName(); - llvm::DIType VTy = getOrCreateType(V->getType(), VUnit); - // Do not use DIGlobalVariable for enums. - if (VTy.getTag() != llvm::dwarf::DW_TAG_enumeration_type) { - DBuilder.createStaticVariable(FwdDecl, VName, VName, VUnit, - getLineNumber(V->getLocation()), - VTy, true, CI); - } - } - } - } -} - -llvm::DIType CGDebugInfo::createFieldType(StringRef name, - QualType type, - uint64_t sizeInBitsOverride, - SourceLocation loc, - AccessSpecifier AS, - uint64_t offsetInBits, - llvm::DIFile tunit, - llvm::DIDescriptor scope) { - llvm::DIType debugType = getOrCreateType(type, tunit); - - // Get the location for the field. - llvm::DIFile file = getOrCreateFile(loc); - unsigned line = getLineNumber(loc); - - uint64_t sizeInBits = 0; - unsigned alignInBits = 0; - if (!type->isIncompleteArrayType()) { - llvm::tie(sizeInBits, alignInBits) = CGM.getContext().getTypeInfo(type); - - if (sizeInBitsOverride) - sizeInBits = sizeInBitsOverride; - } - - unsigned flags = 0; - if (AS == clang::AS_private) - flags |= llvm::DIDescriptor::FlagPrivate; - else if (AS == clang::AS_protected) - flags |= llvm::DIDescriptor::FlagProtected; - - return DBuilder.createMemberType(scope, name, file, line, sizeInBits, - alignInBits, offsetInBits, flags, debugType); -} - -/// CollectRecordFields - A helper function to collect debug info for -/// record fields. This is used while creating debug info entry for a Record. -void CGDebugInfo:: -CollectRecordFields(const RecordDecl *record, llvm::DIFile tunit, - SmallVectorImpl<llvm::Value *> &elements, - llvm::DIType RecordTy) { - unsigned fieldNo = 0; - const ASTRecordLayout &layout = CGM.getContext().getASTRecordLayout(record); - const CXXRecordDecl *CXXDecl = dyn_cast<CXXRecordDecl>(record); - - // For C++11 Lambdas a Field will be the same as a Capture, but the Capture - // has the name and the location of the variable so we should iterate over - // both concurrently. - if (CXXDecl && CXXDecl->isLambda()) { - RecordDecl::field_iterator Field = CXXDecl->field_begin(); - unsigned fieldno = 0; - for (CXXRecordDecl::capture_const_iterator I = CXXDecl->captures_begin(), - E = CXXDecl->captures_end(); I != E; ++I, ++Field, ++fieldno) { - const LambdaExpr::Capture C = *I; - if (C.capturesVariable()) { - VarDecl *V = C.getCapturedVar(); - llvm::DIFile VUnit = getOrCreateFile(C.getLocation()); - StringRef VName = V->getName(); - uint64_t SizeInBitsOverride = 0; - if (Field->isBitField()) { - SizeInBitsOverride = Field->getBitWidthValue(CGM.getContext()); - assert(SizeInBitsOverride && "found named 0-width bitfield"); - } - llvm::DIType fieldType - = createFieldType(VName, Field->getType(), SizeInBitsOverride, C.getLocation(), - Field->getAccess(), layout.getFieldOffset(fieldno), - VUnit, RecordTy); - elements.push_back(fieldType); - } else { - // TODO: Need to handle 'this' in some way by probably renaming the - // this of the lambda class and having a field member of 'this' or - // by using AT_object_pointer for the function and having that be - // used as 'this' for semantic references. - assert(C.capturesThis() && "Field that isn't captured and isn't this?"); - FieldDecl *f = *Field; - llvm::DIFile VUnit = getOrCreateFile(f->getLocation()); - QualType type = f->getType(); - llvm::DIType fieldType - = createFieldType("this", type, 0, f->getLocation(), f->getAccess(), - layout.getFieldOffset(fieldNo), VUnit, RecordTy); - - elements.push_back(fieldType); - } - } - } else { - bool IsMsStruct = record->isMsStruct(CGM.getContext()); - const FieldDecl *LastFD = 0; - for (RecordDecl::field_iterator I = record->field_begin(), - E = record->field_end(); - I != E; ++I, ++fieldNo) { - FieldDecl *field = *I; - - if (IsMsStruct) { - // Zero-length bitfields following non-bitfield members are ignored - if (CGM.getContext().ZeroBitfieldFollowsNonBitfield((field), LastFD)) { - --fieldNo; - continue; - } - LastFD = field; - } - - StringRef name = field->getName(); - QualType type = field->getType(); - - // Ignore unnamed fields unless they're anonymous structs/unions. - if (name.empty() && !type->isRecordType()) { - LastFD = field; - continue; - } - - uint64_t SizeInBitsOverride = 0; - if (field->isBitField()) { - SizeInBitsOverride = field->getBitWidthValue(CGM.getContext()); - assert(SizeInBitsOverride && "found named 0-width bitfield"); - } - - llvm::DIType fieldType - = createFieldType(name, type, SizeInBitsOverride, - field->getLocation(), field->getAccess(), - layout.getFieldOffset(fieldNo), tunit, RecordTy); - - elements.push_back(fieldType); - } - } -} - -/// getOrCreateMethodType - CXXMethodDecl's type is a FunctionType. This -/// function type is not updated to include implicit "this" pointer. Use this -/// routine to get a method type which includes "this" pointer. -llvm::DIType -CGDebugInfo::getOrCreateMethodType(const CXXMethodDecl *Method, - llvm::DIFile Unit) { - llvm::DIType FnTy - = getOrCreateType(QualType(Method->getType()->getAs<FunctionProtoType>(), - 0), - Unit); - - // Add "this" pointer. - llvm::DIArray Args = llvm::DICompositeType(FnTy).getTypeArray(); - assert (Args.getNumElements() && "Invalid number of arguments!"); - - SmallVector<llvm::Value *, 16> Elts; - - // First element is always return type. For 'void' functions it is NULL. - Elts.push_back(Args.getElement(0)); - - if (!Method->isStatic()) { - // "this" pointer is always first argument. - QualType ThisPtr = Method->getThisType(CGM.getContext()); - - const CXXRecordDecl *RD = Method->getParent(); - if (isa<ClassTemplateSpecializationDecl>(RD)) { - // Create pointer type directly in this case. - const PointerType *ThisPtrTy = cast<PointerType>(ThisPtr); - QualType PointeeTy = ThisPtrTy->getPointeeType(); - unsigned AS = CGM.getContext().getTargetAddressSpace(PointeeTy); - uint64_t Size = CGM.getContext().getTargetInfo().getPointerWidth(AS); - uint64_t Align = CGM.getContext().getTypeAlign(ThisPtrTy); - llvm::DIType PointeeType = getOrCreateType(PointeeTy, Unit); - llvm::DIType ThisPtrType = DBuilder.createPointerType(PointeeType, Size, Align); - TypeCache[ThisPtr.getAsOpaquePtr()] = ThisPtrType; - // TODO: This and the artificial type below are misleading, the - // types aren't artificial the argument is, but the current - // metadata doesn't represent that. - ThisPtrType = DBuilder.createObjectPointerType(ThisPtrType); - Elts.push_back(ThisPtrType); - } else { - llvm::DIType ThisPtrType = getOrCreateType(ThisPtr, Unit); - TypeCache[ThisPtr.getAsOpaquePtr()] = ThisPtrType; - ThisPtrType = DBuilder.createObjectPointerType(ThisPtrType); - Elts.push_back(ThisPtrType); - } - } - - // Copy rest of the arguments. - for (unsigned i = 1, e = Args.getNumElements(); i != e; ++i) - Elts.push_back(Args.getElement(i)); - - llvm::DIArray EltTypeArray = DBuilder.getOrCreateArray(Elts); - - return DBuilder.createSubroutineType(Unit, EltTypeArray); -} - -/// isFunctionLocalClass - Return true if CXXRecordDecl is defined -/// inside a function. -static bool isFunctionLocalClass(const CXXRecordDecl *RD) { - if (const CXXRecordDecl *NRD = dyn_cast<CXXRecordDecl>(RD->getDeclContext())) - return isFunctionLocalClass(NRD); - if (isa<FunctionDecl>(RD->getDeclContext())) - return true; - return false; -} - -/// CreateCXXMemberFunction - A helper function to create a DISubprogram for -/// a single member function GlobalDecl. -llvm::DISubprogram -CGDebugInfo::CreateCXXMemberFunction(const CXXMethodDecl *Method, - llvm::DIFile Unit, - llvm::DIType RecordTy) { - bool IsCtorOrDtor = - isa<CXXConstructorDecl>(Method) || isa<CXXDestructorDecl>(Method); - - StringRef MethodName = getFunctionName(Method); - llvm::DIType MethodTy = getOrCreateMethodType(Method, Unit); - - // Since a single ctor/dtor corresponds to multiple functions, it doesn't - // make sense to give a single ctor/dtor a linkage name. - StringRef MethodLinkageName; - if (!IsCtorOrDtor && !isFunctionLocalClass(Method->getParent())) - MethodLinkageName = CGM.getMangledName(Method); - - // Get the location for the method. - llvm::DIFile MethodDefUnit = getOrCreateFile(Method->getLocation()); - unsigned MethodLine = getLineNumber(Method->getLocation()); - - // Collect virtual method info. - llvm::DIType ContainingType; - unsigned Virtuality = 0; - unsigned VIndex = 0; - - if (Method->isVirtual()) { - if (Method->isPure()) - Virtuality = llvm::dwarf::DW_VIRTUALITY_pure_virtual; - else - Virtuality = llvm::dwarf::DW_VIRTUALITY_virtual; - - // It doesn't make sense to give a virtual destructor a vtable index, - // since a single destructor has two entries in the vtable. - if (!isa<CXXDestructorDecl>(Method)) - VIndex = CGM.getVTableContext().getMethodVTableIndex(Method); - ContainingType = RecordTy; - } - - unsigned Flags = 0; - if (Method->isImplicit()) - Flags |= llvm::DIDescriptor::FlagArtificial; - AccessSpecifier Access = Method->getAccess(); - if (Access == clang::AS_private) - Flags |= llvm::DIDescriptor::FlagPrivate; - else if (Access == clang::AS_protected) - Flags |= llvm::DIDescriptor::FlagProtected; - if (const CXXConstructorDecl *CXXC = dyn_cast<CXXConstructorDecl>(Method)) { - if (CXXC->isExplicit()) - Flags |= llvm::DIDescriptor::FlagExplicit; - } else if (const CXXConversionDecl *CXXC = - dyn_cast<CXXConversionDecl>(Method)) { - if (CXXC->isExplicit()) - Flags |= llvm::DIDescriptor::FlagExplicit; - } - if (Method->hasPrototype()) - Flags |= llvm::DIDescriptor::FlagPrototyped; - - llvm::DIArray TParamsArray = CollectFunctionTemplateParams(Method, Unit); - llvm::DISubprogram SP = - DBuilder.createMethod(RecordTy, MethodName, MethodLinkageName, - MethodDefUnit, MethodLine, - MethodTy, /*isLocalToUnit=*/false, - /* isDefinition=*/ false, - Virtuality, VIndex, ContainingType, - Flags, CGM.getLangOpts().Optimize, NULL, - TParamsArray); - - SPCache[Method->getCanonicalDecl()] = llvm::WeakVH(SP); - - return SP; -} - -/// CollectCXXMemberFunctions - A helper function to collect debug info for -/// C++ member functions. This is used while creating debug info entry for -/// a Record. -void CGDebugInfo:: -CollectCXXMemberFunctions(const CXXRecordDecl *RD, llvm::DIFile Unit, - SmallVectorImpl<llvm::Value *> &EltTys, - llvm::DIType RecordTy) { - - // Since we want more than just the individual member decls if we - // have templated functions iterate over every declaration to gather - // the functions. - for(DeclContext::decl_iterator I = RD->decls_begin(), - E = RD->decls_end(); I != E; ++I) { - Decl *D = *I; - if (D->isImplicit() && !D->isUsed()) - continue; - - if (const CXXMethodDecl *Method = dyn_cast<CXXMethodDecl>(D)) - EltTys.push_back(CreateCXXMemberFunction(Method, Unit, RecordTy)); - else if (FunctionTemplateDecl *FTD = dyn_cast<FunctionTemplateDecl>(D)) - for (FunctionTemplateDecl::spec_iterator SI = FTD->spec_begin(), - SE = FTD->spec_end(); SI != SE; ++SI) - EltTys.push_back(CreateCXXMemberFunction(cast<CXXMethodDecl>(*SI), Unit, - RecordTy)); - } -} - -/// CollectCXXFriends - A helper function to collect debug info for -/// C++ base classes. This is used while creating debug info entry for -/// a Record. -void CGDebugInfo:: -CollectCXXFriends(const CXXRecordDecl *RD, llvm::DIFile Unit, - SmallVectorImpl<llvm::Value *> &EltTys, - llvm::DIType RecordTy) { - for (CXXRecordDecl::friend_iterator BI = RD->friend_begin(), - BE = RD->friend_end(); BI != BE; ++BI) { - if ((*BI)->isUnsupportedFriend()) - continue; - if (TypeSourceInfo *TInfo = (*BI)->getFriendType()) - EltTys.push_back(DBuilder.createFriend(RecordTy, - getOrCreateType(TInfo->getType(), - Unit))); - } -} - -/// CollectCXXBases - A helper function to collect debug info for -/// C++ base classes. This is used while creating debug info entry for -/// a Record. -void CGDebugInfo:: -CollectCXXBases(const CXXRecordDecl *RD, llvm::DIFile Unit, - SmallVectorImpl<llvm::Value *> &EltTys, - llvm::DIType RecordTy) { - - const ASTRecordLayout &RL = CGM.getContext().getASTRecordLayout(RD); - for (CXXRecordDecl::base_class_const_iterator BI = RD->bases_begin(), - BE = RD->bases_end(); BI != BE; ++BI) { - unsigned BFlags = 0; - uint64_t BaseOffset; - - const CXXRecordDecl *Base = - cast<CXXRecordDecl>(BI->getType()->getAs<RecordType>()->getDecl()); - - if (BI->isVirtual()) { - // virtual base offset offset is -ve. The code generator emits dwarf - // expression where it expects +ve number. - BaseOffset = - 0 - CGM.getVTableContext() - .getVirtualBaseOffsetOffset(RD, Base).getQuantity(); - BFlags = llvm::DIDescriptor::FlagVirtual; - } else - BaseOffset = CGM.getContext().toBits(RL.getBaseClassOffset(Base)); - // FIXME: Inconsistent units for BaseOffset. It is in bytes when - // BI->isVirtual() and bits when not. - - AccessSpecifier Access = BI->getAccessSpecifier(); - if (Access == clang::AS_private) - BFlags |= llvm::DIDescriptor::FlagPrivate; - else if (Access == clang::AS_protected) - BFlags |= llvm::DIDescriptor::FlagProtected; - - llvm::DIType DTy = - DBuilder.createInheritance(RecordTy, - getOrCreateType(BI->getType(), Unit), - BaseOffset, BFlags); - EltTys.push_back(DTy); - } -} - -/// CollectTemplateParams - A helper function to collect template parameters. -llvm::DIArray CGDebugInfo:: -CollectTemplateParams(const TemplateParameterList *TPList, - const TemplateArgumentList &TAList, - llvm::DIFile Unit) { - SmallVector<llvm::Value *, 16> TemplateParams; - for (unsigned i = 0, e = TAList.size(); i != e; ++i) { - const TemplateArgument &TA = TAList[i]; - const NamedDecl *ND = TPList->getParam(i); - if (TA.getKind() == TemplateArgument::Type) { - llvm::DIType TTy = getOrCreateType(TA.getAsType(), Unit); - llvm::DITemplateTypeParameter TTP = - DBuilder.createTemplateTypeParameter(TheCU, ND->getName(), TTy); - TemplateParams.push_back(TTP); - } else if (TA.getKind() == TemplateArgument::Integral) { - llvm::DIType TTy = getOrCreateType(TA.getIntegralType(), Unit); - llvm::DITemplateValueParameter TVP = - DBuilder.createTemplateValueParameter(TheCU, ND->getName(), TTy, - TA.getAsIntegral().getZExtValue()); - TemplateParams.push_back(TVP); - } - } - return DBuilder.getOrCreateArray(TemplateParams); -} - -/// CollectFunctionTemplateParams - A helper function to collect debug -/// info for function template parameters. -llvm::DIArray CGDebugInfo:: -CollectFunctionTemplateParams(const FunctionDecl *FD, llvm::DIFile Unit) { - if (FD->getTemplatedKind() == - FunctionDecl::TK_FunctionTemplateSpecialization) { - const TemplateParameterList *TList = - FD->getTemplateSpecializationInfo()->getTemplate() - ->getTemplateParameters(); - return - CollectTemplateParams(TList, *FD->getTemplateSpecializationArgs(), Unit); - } - return llvm::DIArray(); -} - -/// CollectCXXTemplateParams - A helper function to collect debug info for -/// template parameters. -llvm::DIArray CGDebugInfo:: -CollectCXXTemplateParams(const ClassTemplateSpecializationDecl *TSpecial, - llvm::DIFile Unit) { - llvm::PointerUnion<ClassTemplateDecl *, - ClassTemplatePartialSpecializationDecl *> - PU = TSpecial->getSpecializedTemplateOrPartial(); - - TemplateParameterList *TPList = PU.is<ClassTemplateDecl *>() ? - PU.get<ClassTemplateDecl *>()->getTemplateParameters() : - PU.get<ClassTemplatePartialSpecializationDecl *>()->getTemplateParameters(); - const TemplateArgumentList &TAList = TSpecial->getTemplateInstantiationArgs(); - return CollectTemplateParams(TPList, TAList, Unit); -} - -/// getOrCreateVTablePtrType - Return debug info descriptor for vtable. -llvm::DIType CGDebugInfo::getOrCreateVTablePtrType(llvm::DIFile Unit) { - if (VTablePtrType.isValid()) - return VTablePtrType; - - ASTContext &Context = CGM.getContext(); - - /* Function type */ - llvm::Value *STy = getOrCreateType(Context.IntTy, Unit); - llvm::DIArray SElements = DBuilder.getOrCreateArray(STy); - llvm::DIType SubTy = DBuilder.createSubroutineType(Unit, SElements); - unsigned Size = Context.getTypeSize(Context.VoidPtrTy); - llvm::DIType vtbl_ptr_type = DBuilder.createPointerType(SubTy, Size, 0, - "__vtbl_ptr_type"); - VTablePtrType = DBuilder.createPointerType(vtbl_ptr_type, Size); - return VTablePtrType; -} - -/// getVTableName - Get vtable name for the given Class. -StringRef CGDebugInfo::getVTableName(const CXXRecordDecl *RD) { - // Construct gdb compatible name name. - std::string Name = "_vptr$" + RD->getNameAsString(); - - // Copy this name on the side and use its reference. - char *StrPtr = DebugInfoNames.Allocate<char>(Name.length()); - memcpy(StrPtr, Name.data(), Name.length()); - return StringRef(StrPtr, Name.length()); -} - - -/// CollectVTableInfo - If the C++ class has vtable info then insert appropriate -/// debug info entry in EltTys vector. -void CGDebugInfo:: -CollectVTableInfo(const CXXRecordDecl *RD, llvm::DIFile Unit, - SmallVectorImpl<llvm::Value *> &EltTys) { - const ASTRecordLayout &RL = CGM.getContext().getASTRecordLayout(RD); - - // If there is a primary base then it will hold vtable info. - if (RL.getPrimaryBase()) - return; - - // If this class is not dynamic then there is not any vtable info to collect. - if (!RD->isDynamicClass()) - return; - - unsigned Size = CGM.getContext().getTypeSize(CGM.getContext().VoidPtrTy); - llvm::DIType VPTR - = DBuilder.createMemberType(Unit, getVTableName(RD), Unit, - 0, Size, 0, 0, llvm::DIDescriptor::FlagArtificial, - getOrCreateVTablePtrType(Unit)); - EltTys.push_back(VPTR); -} - -/// getOrCreateRecordType - Emit record type's standalone debug info. -llvm::DIType CGDebugInfo::getOrCreateRecordType(QualType RTy, - SourceLocation Loc) { - assert(CGM.getCodeGenOpts().getDebugInfo() >= CodeGenOptions::LimitedDebugInfo); - llvm::DIType T = getOrCreateType(RTy, getOrCreateFile(Loc)); - return T; -} - -/// getOrCreateInterfaceType - Emit an objective c interface type standalone -/// debug info. -llvm::DIType CGDebugInfo::getOrCreateInterfaceType(QualType D, - SourceLocation Loc) { - assert(CGM.getCodeGenOpts().getDebugInfo() >= CodeGenOptions::LimitedDebugInfo); - llvm::DIType T = getOrCreateType(D, getOrCreateFile(Loc)); - DBuilder.retainType(T); - return T; -} - -/// CreateType - get structure or union type. -llvm::DIType CGDebugInfo::CreateType(const RecordType *Ty) { - RecordDecl *RD = Ty->getDecl(); - - // Get overall information about the record type for the debug info. - llvm::DIFile DefUnit = getOrCreateFile(RD->getLocation()); - - // Records and classes and unions can all be recursive. To handle them, we - // first generate a debug descriptor for the struct as a forward declaration. - // Then (if it is a definition) we go through and get debug info for all of - // its members. Finally, we create a descriptor for the complete type (which - // may refer to the forward decl if the struct is recursive) and replace all - // uses of the forward declaration with the final definition. - - llvm::DIType FwdDecl = getOrCreateLimitedType(QualType(Ty, 0), DefUnit); - - if (FwdDecl.isForwardDecl()) - return FwdDecl; - - llvm::TrackingVH<llvm::MDNode> FwdDeclNode(FwdDecl); - - // Push the struct on region stack. - LexicalBlockStack.push_back(FwdDeclNode); - RegionMap[Ty->getDecl()] = llvm::WeakVH(FwdDecl); - - // Add this to the completed types cache since we're completing it. - CompletedTypeCache[QualType(Ty, 0).getAsOpaquePtr()] = FwdDecl; - - // Convert all the elements. - SmallVector<llvm::Value *, 16> EltTys; - - // Note: The split of CXXDecl information here is intentional, the - // gdb tests will depend on a certain ordering at printout. The debug - // information offsets are still correct if we merge them all together - // though. - const CXXRecordDecl *CXXDecl = dyn_cast<CXXRecordDecl>(RD); - if (CXXDecl) { - CollectCXXBases(CXXDecl, DefUnit, EltTys, FwdDecl); - CollectVTableInfo(CXXDecl, DefUnit, EltTys); - } - - // Collect static variables with initializers and other fields. - CollectRecordStaticVars(RD, FwdDecl); - CollectRecordFields(RD, DefUnit, EltTys, FwdDecl); - llvm::DIArray TParamsArray; - if (CXXDecl) { - CollectCXXMemberFunctions(CXXDecl, DefUnit, EltTys, FwdDecl); - CollectCXXFriends(CXXDecl, DefUnit, EltTys, FwdDecl); - if (const ClassTemplateSpecializationDecl *TSpecial - = dyn_cast<ClassTemplateSpecializationDecl>(RD)) - TParamsArray = CollectCXXTemplateParams(TSpecial, DefUnit); - } - - LexicalBlockStack.pop_back(); - RegionMap.erase(Ty->getDecl()); - - llvm::DIArray Elements = DBuilder.getOrCreateArray(EltTys); - // FIXME: Magic numbers ahoy! These should be changed when we - // get some enums in llvm/Analysis/DebugInfo.h to refer to - // them. - if (RD->isUnion()) - FwdDeclNode->replaceOperandWith(10, Elements); - else if (CXXDecl) { - FwdDeclNode->replaceOperandWith(10, Elements); - FwdDeclNode->replaceOperandWith(13, TParamsArray); - } else - FwdDeclNode->replaceOperandWith(10, Elements); - - RegionMap[Ty->getDecl()] = llvm::WeakVH(FwdDeclNode); - return llvm::DIType(FwdDeclNode); -} - -/// CreateType - get objective-c object type. -llvm::DIType CGDebugInfo::CreateType(const ObjCObjectType *Ty, - llvm::DIFile Unit) { - // Ignore protocols. - return getOrCreateType(Ty->getBaseType(), Unit); -} - -/// CreateType - get objective-c interface type. -llvm::DIType CGDebugInfo::CreateType(const ObjCInterfaceType *Ty, - llvm::DIFile Unit) { - ObjCInterfaceDecl *ID = Ty->getDecl(); - if (!ID) - return llvm::DIType(); - - // Get overall information about the record type for the debug info. - llvm::DIFile DefUnit = getOrCreateFile(ID->getLocation()); - unsigned Line = getLineNumber(ID->getLocation()); - unsigned RuntimeLang = TheCU.getLanguage(); - - // If this is just a forward declaration return a special forward-declaration - // debug type since we won't be able to lay out the entire type. - ObjCInterfaceDecl *Def = ID->getDefinition(); - if (!Def) { - llvm::DIType FwdDecl = - DBuilder.createForwardDecl(llvm::dwarf::DW_TAG_structure_type, - ID->getName(), TheCU, DefUnit, Line, - RuntimeLang); - return FwdDecl; - } - - ID = Def; - - // Bit size, align and offset of the type. - uint64_t Size = CGM.getContext().getTypeSize(Ty); - uint64_t Align = CGM.getContext().getTypeAlign(Ty); - - unsigned Flags = 0; - if (ID->getImplementation()) - Flags |= llvm::DIDescriptor::FlagObjcClassComplete; - - llvm::DIType RealDecl = - DBuilder.createStructType(Unit, ID->getName(), DefUnit, - Line, Size, Align, Flags, - llvm::DIArray(), RuntimeLang); - - // Otherwise, insert it into the CompletedTypeCache so that recursive uses - // will find it and we're emitting the complete type. - CompletedTypeCache[QualType(Ty, 0).getAsOpaquePtr()] = RealDecl; - // Push the struct on region stack. - llvm::TrackingVH<llvm::MDNode> FwdDeclNode(RealDecl); - - LexicalBlockStack.push_back(FwdDeclNode); - RegionMap[Ty->getDecl()] = llvm::WeakVH(RealDecl); - - // Convert all the elements. - SmallVector<llvm::Value *, 16> EltTys; - - ObjCInterfaceDecl *SClass = ID->getSuperClass(); - if (SClass) { - llvm::DIType SClassTy = - getOrCreateType(CGM.getContext().getObjCInterfaceType(SClass), Unit); - if (!SClassTy.isValid()) - return llvm::DIType(); - - llvm::DIType InhTag = - DBuilder.createInheritance(RealDecl, SClassTy, 0, 0); - EltTys.push_back(InhTag); - } - - for (ObjCContainerDecl::prop_iterator I = ID->prop_begin(), - E = ID->prop_end(); I != E; ++I) { - const ObjCPropertyDecl *PD = *I; - SourceLocation Loc = PD->getLocation(); - llvm::DIFile PUnit = getOrCreateFile(Loc); - unsigned PLine = getLineNumber(Loc); - ObjCMethodDecl *Getter = PD->getGetterMethodDecl(); - ObjCMethodDecl *Setter = PD->getSetterMethodDecl(); - llvm::MDNode *PropertyNode = - DBuilder.createObjCProperty(PD->getName(), - PUnit, PLine, - (Getter && Getter->isImplicit()) ? "" : - getSelectorName(PD->getGetterName()), - (Setter && Setter->isImplicit()) ? "" : - getSelectorName(PD->getSetterName()), - PD->getPropertyAttributes(), - getOrCreateType(PD->getType(), PUnit)); - EltTys.push_back(PropertyNode); - } - - const ASTRecordLayout &RL = CGM.getContext().getASTObjCInterfaceLayout(ID); - unsigned FieldNo = 0; - for (ObjCIvarDecl *Field = ID->all_declared_ivar_begin(); Field; - Field = Field->getNextIvar(), ++FieldNo) { - llvm::DIType FieldTy = getOrCreateType(Field->getType(), Unit); - if (!FieldTy.isValid()) - return llvm::DIType(); - - StringRef FieldName = Field->getName(); - - // Ignore unnamed fields. - if (FieldName.empty()) - continue; - - // Get the location for the field. - llvm::DIFile FieldDefUnit = getOrCreateFile(Field->getLocation()); - unsigned FieldLine = getLineNumber(Field->getLocation()); - QualType FType = Field->getType(); - uint64_t FieldSize = 0; - unsigned FieldAlign = 0; - - if (!FType->isIncompleteArrayType()) { - - // Bit size, align and offset of the type. - FieldSize = Field->isBitField() - ? Field->getBitWidthValue(CGM.getContext()) - : CGM.getContext().getTypeSize(FType); - FieldAlign = CGM.getContext().getTypeAlign(FType); - } - - uint64_t FieldOffset; - if (CGM.getLangOpts().ObjCRuntime.isNonFragile()) { - // We don't know the runtime offset of an ivar if we're using the - // non-fragile ABI. For bitfields, use the bit offset into the first - // byte of storage of the bitfield. For other fields, use zero. - if (Field->isBitField()) { - FieldOffset = CGM.getObjCRuntime().ComputeBitfieldBitOffset( - CGM, ID, Field); - FieldOffset %= CGM.getContext().getCharWidth(); - } else { - FieldOffset = 0; - } - } else { - FieldOffset = RL.getFieldOffset(FieldNo); - } - - unsigned Flags = 0; - if (Field->getAccessControl() == ObjCIvarDecl::Protected) - Flags = llvm::DIDescriptor::FlagProtected; - else if (Field->getAccessControl() == ObjCIvarDecl::Private) - Flags = llvm::DIDescriptor::FlagPrivate; - - llvm::MDNode *PropertyNode = NULL; - if (ObjCImplementationDecl *ImpD = ID->getImplementation()) { - if (ObjCPropertyImplDecl *PImpD = - ImpD->FindPropertyImplIvarDecl(Field->getIdentifier())) { - if (ObjCPropertyDecl *PD = PImpD->getPropertyDecl()) { - SourceLocation Loc = PD->getLocation(); - llvm::DIFile PUnit = getOrCreateFile(Loc); - unsigned PLine = getLineNumber(Loc); - ObjCMethodDecl *Getter = PD->getGetterMethodDecl(); - ObjCMethodDecl *Setter = PD->getSetterMethodDecl(); - PropertyNode = - DBuilder.createObjCProperty(PD->getName(), - PUnit, PLine, - (Getter && Getter->isImplicit()) ? "" : - getSelectorName(PD->getGetterName()), - (Setter && Setter->isImplicit()) ? "" : - getSelectorName(PD->getSetterName()), - PD->getPropertyAttributes(), - getOrCreateType(PD->getType(), PUnit)); - } - } - } - FieldTy = DBuilder.createObjCIVar(FieldName, FieldDefUnit, - FieldLine, FieldSize, FieldAlign, - FieldOffset, Flags, FieldTy, - PropertyNode); - EltTys.push_back(FieldTy); - } - - llvm::DIArray Elements = DBuilder.getOrCreateArray(EltTys); - FwdDeclNode->replaceOperandWith(10, Elements); - - LexicalBlockStack.pop_back(); - return llvm::DIType(FwdDeclNode); -} - -llvm::DIType CGDebugInfo::CreateType(const VectorType *Ty, llvm::DIFile Unit) { - llvm::DIType ElementTy = getOrCreateType(Ty->getElementType(), Unit); - int64_t Count = Ty->getNumElements(); - if (Count == 0) - // If number of elements are not known then this is an unbounded array. - // Use Count == -1 to express such arrays. - Count = -1; - - llvm::Value *Subscript = DBuilder.getOrCreateSubrange(0, Count); - llvm::DIArray SubscriptArray = DBuilder.getOrCreateArray(Subscript); - - uint64_t Size = CGM.getContext().getTypeSize(Ty); - uint64_t Align = CGM.getContext().getTypeAlign(Ty); - - return DBuilder.createVectorType(Size, Align, ElementTy, SubscriptArray); -} - -llvm::DIType CGDebugInfo::CreateType(const ArrayType *Ty, - llvm::DIFile Unit) { - uint64_t Size; - uint64_t Align; - - // FIXME: make getTypeAlign() aware of VLAs and incomplete array types - if (const VariableArrayType *VAT = dyn_cast<VariableArrayType>(Ty)) { - Size = 0; - Align = - CGM.getContext().getTypeAlign(CGM.getContext().getBaseElementType(VAT)); - } else if (Ty->isIncompleteArrayType()) { - Size = 0; - if (Ty->getElementType()->isIncompleteType()) - Align = 0; - else - Align = CGM.getContext().getTypeAlign(Ty->getElementType()); - } else if (Ty->isDependentSizedArrayType() || Ty->isIncompleteType()) { - Size = 0; - Align = 0; - } else { - // Size and align of the whole array, not the element type. - Size = CGM.getContext().getTypeSize(Ty); - Align = CGM.getContext().getTypeAlign(Ty); - } - - // Add the dimensions of the array. FIXME: This loses CV qualifiers from - // interior arrays, do we care? Why aren't nested arrays represented the - // obvious/recursive way? - SmallVector<llvm::Value *, 8> Subscripts; - QualType EltTy(Ty, 0); - while ((Ty = dyn_cast<ArrayType>(EltTy))) { - // If the number of elements is known, then count is that number. Otherwise, - // it's -1. This allows us to represent a subrange with an array of 0 - // elements, like this: - // - // struct foo { - // int x[0]; - // }; - int64_t Count = -1; // Count == -1 is an unbounded array. - if (const ConstantArrayType *CAT = dyn_cast<ConstantArrayType>(Ty)) - Count = CAT->getSize().getZExtValue(); - - // FIXME: Verify this is right for VLAs. - Subscripts.push_back(DBuilder.getOrCreateSubrange(0, Count)); - EltTy = Ty->getElementType(); - } - - llvm::DIArray SubscriptArray = DBuilder.getOrCreateArray(Subscripts); - - llvm::DIType DbgTy = - DBuilder.createArrayType(Size, Align, getOrCreateType(EltTy, Unit), - SubscriptArray); - return DbgTy; -} - -llvm::DIType CGDebugInfo::CreateType(const LValueReferenceType *Ty, - llvm::DIFile Unit) { - return CreatePointerLikeType(llvm::dwarf::DW_TAG_reference_type, - Ty, Ty->getPointeeType(), Unit); -} - -llvm::DIType CGDebugInfo::CreateType(const RValueReferenceType *Ty, - llvm::DIFile Unit) { - return CreatePointerLikeType(llvm::dwarf::DW_TAG_rvalue_reference_type, - Ty, Ty->getPointeeType(), Unit); -} - -llvm::DIType CGDebugInfo::CreateType(const MemberPointerType *Ty, - llvm::DIFile U) { - QualType PointerDiffTy = CGM.getContext().getPointerDiffType(); - llvm::DIType PointerDiffDITy = getOrCreateType(PointerDiffTy, U); - - if (!Ty->getPointeeType()->isFunctionType()) { - // We have a data member pointer type. - return PointerDiffDITy; - } - - // We have a member function pointer type. Treat it as a struct with two - // ptrdiff_t members. - std::pair<uint64_t, unsigned> Info = CGM.getContext().getTypeInfo(Ty); - - uint64_t FieldOffset = 0; - llvm::Value *ElementTypes[2]; - - // FIXME: This should be a DW_TAG_pointer_to_member type. - ElementTypes[0] = - DBuilder.createMemberType(U, "ptr", U, 0, - Info.first, Info.second, FieldOffset, 0, - PointerDiffDITy); - FieldOffset += Info.first; - - ElementTypes[1] = - DBuilder.createMemberType(U, "ptr", U, 0, - Info.first, Info.second, FieldOffset, 0, - PointerDiffDITy); - - llvm::DIArray Elements = DBuilder.getOrCreateArray(ElementTypes); - - return DBuilder.createStructType(U, StringRef("test"), - U, 0, FieldOffset, - 0, 0, Elements); -} - -llvm::DIType CGDebugInfo::CreateType(const AtomicType *Ty, - llvm::DIFile U) { - // Ignore the atomic wrapping - // FIXME: What is the correct representation? - return getOrCreateType(Ty->getValueType(), U); -} - -/// CreateEnumType - get enumeration type. -llvm::DIType CGDebugInfo::CreateEnumType(const EnumDecl *ED) { - uint64_t Size = 0; - uint64_t Align = 0; - if (!ED->getTypeForDecl()->isIncompleteType()) { - Size = CGM.getContext().getTypeSize(ED->getTypeForDecl()); - Align = CGM.getContext().getTypeAlign(ED->getTypeForDecl()); - } - - // If this is just a forward declaration, construct an appropriately - // marked node and just return it. - if (!ED->getDefinition()) { - llvm::DIDescriptor EDContext; - EDContext = getContextDescriptor(cast<Decl>(ED->getDeclContext())); - llvm::DIFile DefUnit = getOrCreateFile(ED->getLocation()); - unsigned Line = getLineNumber(ED->getLocation()); - StringRef EDName = ED->getName(); - return DBuilder.createForwardDecl(llvm::dwarf::DW_TAG_enumeration_type, - EDName, EDContext, DefUnit, Line, 0, - Size, Align); - } - - // Create DIEnumerator elements for each enumerator. - SmallVector<llvm::Value *, 16> Enumerators; - ED = ED->getDefinition(); - for (EnumDecl::enumerator_iterator - Enum = ED->enumerator_begin(), EnumEnd = ED->enumerator_end(); - Enum != EnumEnd; ++Enum) { - Enumerators.push_back( - DBuilder.createEnumerator(Enum->getName(), - Enum->getInitVal().getZExtValue())); - } - - // Return a CompositeType for the enum itself. - llvm::DIArray EltArray = DBuilder.getOrCreateArray(Enumerators); - - llvm::DIFile DefUnit = getOrCreateFile(ED->getLocation()); - unsigned Line = getLineNumber(ED->getLocation()); - llvm::DIDescriptor EnumContext = - getContextDescriptor(cast<Decl>(ED->getDeclContext())); - llvm::DIType ClassTy = ED->isScopedUsingClassTag() ? - getOrCreateType(ED->getIntegerType(), DefUnit) : llvm::DIType(); - llvm::DIType DbgTy = - DBuilder.createEnumerationType(EnumContext, ED->getName(), DefUnit, Line, - Size, Align, EltArray, - ClassTy); - return DbgTy; -} - -static QualType UnwrapTypeForDebugInfo(QualType T) { - do { - QualType LastT = T; - switch (T->getTypeClass()) { - default: - return T; - case Type::TemplateSpecialization: - T = cast<TemplateSpecializationType>(T)->desugar(); - break; - case Type::TypeOfExpr: - T = cast<TypeOfExprType>(T)->getUnderlyingExpr()->getType(); - break; - case Type::TypeOf: - T = cast<TypeOfType>(T)->getUnderlyingType(); - break; - case Type::Decltype: - T = cast<DecltypeType>(T)->getUnderlyingType(); - break; - case Type::UnaryTransform: - T = cast<UnaryTransformType>(T)->getUnderlyingType(); - break; - case Type::Attributed: - T = cast<AttributedType>(T)->getEquivalentType(); - break; - case Type::Elaborated: - T = cast<ElaboratedType>(T)->getNamedType(); - break; - case Type::Paren: - T = cast<ParenType>(T)->getInnerType(); - break; - case Type::SubstTemplateTypeParm: { - // We need to keep the qualifiers handy since getReplacementType() - // will strip them away. - unsigned Quals = T.getLocalFastQualifiers(); - T = cast<SubstTemplateTypeParmType>(T)->getReplacementType(); - T.addFastQualifiers(Quals); - } - break; - case Type::Auto: - T = cast<AutoType>(T)->getDeducedType(); - break; - } - - assert(T != LastT && "Type unwrapping failed to unwrap!"); - if (T == LastT) - return T; - } while (true); -} - -/// getType - Get the type from the cache or return null type if it doesn't exist. -llvm::DIType CGDebugInfo::getTypeOrNull(QualType Ty) { - - // Unwrap the type as needed for debug information. - Ty = UnwrapTypeForDebugInfo(Ty); - - // Check for existing entry. - llvm::DenseMap<void *, llvm::WeakVH>::iterator it = - TypeCache.find(Ty.getAsOpaquePtr()); - if (it != TypeCache.end()) { - // Verify that the debug info still exists. - if (llvm::Value *V = it->second) - return llvm::DIType(cast<llvm::MDNode>(V)); - } - - return llvm::DIType(); -} - -/// getCompletedTypeOrNull - Get the type from the cache or return null if it -/// doesn't exist. -llvm::DIType CGDebugInfo::getCompletedTypeOrNull(QualType Ty) { - - // Unwrap the type as needed for debug information. - Ty = UnwrapTypeForDebugInfo(Ty); - - // Check for existing entry. - llvm::DenseMap<void *, llvm::WeakVH>::iterator it = - CompletedTypeCache.find(Ty.getAsOpaquePtr()); - if (it != CompletedTypeCache.end()) { - // Verify that the debug info still exists. - if (llvm::Value *V = it->second) - return llvm::DIType(cast<llvm::MDNode>(V)); - } - - return llvm::DIType(); -} - - -/// getOrCreateType - Get the type from the cache or create a new -/// one if necessary. -llvm::DIType CGDebugInfo::getOrCreateType(QualType Ty, llvm::DIFile Unit) { - if (Ty.isNull()) - return llvm::DIType(); - - // Unwrap the type as needed for debug information. - Ty = UnwrapTypeForDebugInfo(Ty); - - llvm::DIType T = getCompletedTypeOrNull(Ty); - - if (T.Verify()) - return T; - - // Otherwise create the type. - llvm::DIType Res = CreateTypeNode(Ty, Unit); - - llvm::DIType TC = getTypeOrNull(Ty); - if (TC.Verify() && TC.isForwardDecl()) - ReplaceMap.push_back(std::make_pair(Ty.getAsOpaquePtr(), - static_cast<llvm::Value*>(TC))); - - // And update the type cache. - TypeCache[Ty.getAsOpaquePtr()] = Res; - - if (!Res.isForwardDecl()) - CompletedTypeCache[Ty.getAsOpaquePtr()] = Res; - - return Res; -} - -/// CreateTypeNode - Create a new debug type node. -llvm::DIType CGDebugInfo::CreateTypeNode(QualType Ty, llvm::DIFile Unit) { - // Handle qualifiers, which recursively handles what they refer to. - if (Ty.hasLocalQualifiers()) - return CreateQualifiedType(Ty, Unit); - - const char *Diag = 0; - - // Work out details of type. - switch (Ty->getTypeClass()) { -#define TYPE(Class, Base) -#define ABSTRACT_TYPE(Class, Base) -#define NON_CANONICAL_TYPE(Class, Base) -#define DEPENDENT_TYPE(Class, Base) case Type::Class: -#include "clang/AST/TypeNodes.def" - llvm_unreachable("Dependent types cannot show up in debug information"); - - case Type::ExtVector: - case Type::Vector: - return CreateType(cast<VectorType>(Ty), Unit); - case Type::ObjCObjectPointer: - return CreateType(cast<ObjCObjectPointerType>(Ty), Unit); - case Type::ObjCObject: - return CreateType(cast<ObjCObjectType>(Ty), Unit); - case Type::ObjCInterface: - return CreateType(cast<ObjCInterfaceType>(Ty), Unit); - case Type::Builtin: - return CreateType(cast<BuiltinType>(Ty)); - case Type::Complex: - return CreateType(cast<ComplexType>(Ty)); - case Type::Pointer: - return CreateType(cast<PointerType>(Ty), Unit); - case Type::BlockPointer: - return CreateType(cast<BlockPointerType>(Ty), Unit); - case Type::Typedef: - return CreateType(cast<TypedefType>(Ty), Unit); - case Type::Record: - return CreateType(cast<RecordType>(Ty)); - case Type::Enum: - return CreateEnumType(cast<EnumType>(Ty)->getDecl()); - case Type::FunctionProto: - case Type::FunctionNoProto: - return CreateType(cast<FunctionType>(Ty), Unit); - case Type::ConstantArray: - case Type::VariableArray: - case Type::IncompleteArray: - return CreateType(cast<ArrayType>(Ty), Unit); - - case Type::LValueReference: - return CreateType(cast<LValueReferenceType>(Ty), Unit); - case Type::RValueReference: - return CreateType(cast<RValueReferenceType>(Ty), Unit); - - case Type::MemberPointer: - return CreateType(cast<MemberPointerType>(Ty), Unit); - - case Type::Atomic: - return CreateType(cast<AtomicType>(Ty), Unit); - - case Type::Attributed: - case Type::TemplateSpecialization: - case Type::Elaborated: - case Type::Paren: - case Type::SubstTemplateTypeParm: - case Type::TypeOfExpr: - case Type::TypeOf: - case Type::Decltype: - case Type::UnaryTransform: - case Type::Auto: - llvm_unreachable("type should have been unwrapped!"); - } - - assert(Diag && "Fall through without a diagnostic?"); - unsigned DiagID = CGM.getDiags().getCustomDiagID(DiagnosticsEngine::Error, - "debug information for %0 is not yet supported"); - CGM.getDiags().Report(DiagID) - << Diag; - return llvm::DIType(); -} - -/// getOrCreateLimitedType - Get the type from the cache or create a new -/// limited type if necessary. -llvm::DIType CGDebugInfo::getOrCreateLimitedType(QualType Ty, - llvm::DIFile Unit) { - if (Ty.isNull()) - return llvm::DIType(); - - // Unwrap the type as needed for debug information. - Ty = UnwrapTypeForDebugInfo(Ty); - - llvm::DIType T = getTypeOrNull(Ty); - - // We may have cached a forward decl when we could have created - // a non-forward decl. Go ahead and create a non-forward decl - // now. - if (T.Verify() && !T.isForwardDecl()) return T; - - // Otherwise create the type. - llvm::DIType Res = CreateLimitedTypeNode(Ty, Unit); - - if (T.Verify() && T.isForwardDecl()) - ReplaceMap.push_back(std::make_pair(Ty.getAsOpaquePtr(), - static_cast<llvm::Value*>(T))); - - // And update the type cache. - TypeCache[Ty.getAsOpaquePtr()] = Res; - return Res; -} - -// TODO: Currently used for context chains when limiting debug info. -llvm::DIType CGDebugInfo::CreateLimitedType(const RecordType *Ty) { - RecordDecl *RD = Ty->getDecl(); - - // Get overall information about the record type for the debug info. - llvm::DIFile DefUnit = getOrCreateFile(RD->getLocation()); - unsigned Line = getLineNumber(RD->getLocation()); - StringRef RDName = getClassName(RD); - - llvm::DIDescriptor RDContext; - if (CGM.getCodeGenOpts().getDebugInfo() == CodeGenOptions::LimitedDebugInfo) - RDContext = createContextChain(cast<Decl>(RD->getDeclContext())); - else - RDContext = getContextDescriptor(cast<Decl>(RD->getDeclContext())); - - // If this is just a forward declaration, construct an appropriately - // marked node and just return it. - if (!RD->getDefinition()) - return createRecordFwdDecl(RD, RDContext); - - uint64_t Size = CGM.getContext().getTypeSize(Ty); - uint64_t Align = CGM.getContext().getTypeAlign(Ty); - const CXXRecordDecl *CXXDecl = dyn_cast<CXXRecordDecl>(RD); - llvm::TrackingVH<llvm::MDNode> RealDecl; - - if (RD->isUnion()) - RealDecl = DBuilder.createUnionType(RDContext, RDName, DefUnit, Line, - Size, Align, 0, llvm::DIArray()); - else if (RD->isClass()) { - // FIXME: This could be a struct type giving a default visibility different - // than C++ class type, but needs llvm metadata changes first. - RealDecl = DBuilder.createClassType(RDContext, RDName, DefUnit, Line, - Size, Align, 0, 0, llvm::DIType(), - llvm::DIArray(), llvm::DIType(), - llvm::DIArray()); - } else - RealDecl = DBuilder.createStructType(RDContext, RDName, DefUnit, Line, - Size, Align, 0, llvm::DIArray()); - - RegionMap[Ty->getDecl()] = llvm::WeakVH(RealDecl); - TypeCache[QualType(Ty, 0).getAsOpaquePtr()] = llvm::DIType(RealDecl); - - if (CXXDecl) { - // A class's primary base or the class itself contains the vtable. - llvm::MDNode *ContainingType = NULL; - const ASTRecordLayout &RL = CGM.getContext().getASTRecordLayout(RD); - if (const CXXRecordDecl *PBase = RL.getPrimaryBase()) { - // Seek non virtual primary base root. - while (1) { - const ASTRecordLayout &BRL = CGM.getContext().getASTRecordLayout(PBase); - const CXXRecordDecl *PBT = BRL.getPrimaryBase(); - if (PBT && !BRL.isPrimaryBaseVirtual()) - PBase = PBT; - else - break; - } - ContainingType = - getOrCreateType(QualType(PBase->getTypeForDecl(), 0), DefUnit); - } - else if (CXXDecl->isDynamicClass()) - ContainingType = RealDecl; - - RealDecl->replaceOperandWith(12, ContainingType); - } - return llvm::DIType(RealDecl); -} - -/// CreateLimitedTypeNode - Create a new debug type node, but only forward -/// declare composite types that haven't been processed yet. -llvm::DIType CGDebugInfo::CreateLimitedTypeNode(QualType Ty,llvm::DIFile Unit) { - - // Work out details of type. - switch (Ty->getTypeClass()) { -#define TYPE(Class, Base) -#define ABSTRACT_TYPE(Class, Base) -#define NON_CANONICAL_TYPE(Class, Base) -#define DEPENDENT_TYPE(Class, Base) case Type::Class: - #include "clang/AST/TypeNodes.def" - llvm_unreachable("Dependent types cannot show up in debug information"); - - case Type::Record: - return CreateLimitedType(cast<RecordType>(Ty)); - default: - return CreateTypeNode(Ty, Unit); - } -} - -/// CreateMemberType - Create new member and increase Offset by FType's size. -llvm::DIType CGDebugInfo::CreateMemberType(llvm::DIFile Unit, QualType FType, - StringRef Name, - uint64_t *Offset) { - llvm::DIType FieldTy = CGDebugInfo::getOrCreateType(FType, Unit); - uint64_t FieldSize = CGM.getContext().getTypeSize(FType); - unsigned FieldAlign = CGM.getContext().getTypeAlign(FType); - llvm::DIType Ty = DBuilder.createMemberType(Unit, Name, Unit, 0, - FieldSize, FieldAlign, - *Offset, 0, FieldTy); - *Offset += FieldSize; - return Ty; -} - -/// getFunctionDeclaration - Return debug info descriptor to describe method -/// declaration for the given method definition. -llvm::DISubprogram CGDebugInfo::getFunctionDeclaration(const Decl *D) { - const FunctionDecl *FD = dyn_cast<FunctionDecl>(D); - if (!FD) return llvm::DISubprogram(); - - // Setup context. - getContextDescriptor(cast<Decl>(D->getDeclContext())); - - llvm::DenseMap<const FunctionDecl *, llvm::WeakVH>::iterator - MI = SPCache.find(FD->getCanonicalDecl()); - if (MI != SPCache.end()) { - llvm::Value *V = MI->second; - llvm::DISubprogram SP(dyn_cast_or_null<llvm::MDNode>(V)); - if (SP.isSubprogram() && !llvm::DISubprogram(SP).isDefinition()) - return SP; - } - - for (FunctionDecl::redecl_iterator I = FD->redecls_begin(), - E = FD->redecls_end(); I != E; ++I) { - const FunctionDecl *NextFD = *I; - llvm::DenseMap<const FunctionDecl *, llvm::WeakVH>::iterator - MI = SPCache.find(NextFD->getCanonicalDecl()); - if (MI != SPCache.end()) { - llvm::Value *V = MI->second; - llvm::DISubprogram SP(dyn_cast_or_null<llvm::MDNode>(V)); - if (SP.isSubprogram() && !llvm::DISubprogram(SP).isDefinition()) - return SP; - } - } - return llvm::DISubprogram(); -} - -// getOrCreateFunctionType - Construct DIType. If it is a c++ method, include -// implicit parameter "this". -llvm::DIType CGDebugInfo::getOrCreateFunctionType(const Decl *D, - QualType FnType, - llvm::DIFile F) { - - if (const CXXMethodDecl *Method = dyn_cast<CXXMethodDecl>(D)) - return getOrCreateMethodType(Method, F); - if (const ObjCMethodDecl *OMethod = dyn_cast<ObjCMethodDecl>(D)) { - // Add "self" and "_cmd" - SmallVector<llvm::Value *, 16> Elts; - - // First element is always return type. For 'void' functions it is NULL. - Elts.push_back(getOrCreateType(OMethod->getResultType(), F)); - // "self" pointer is always first argument. - llvm::DIType SelfTy = getOrCreateType(OMethod->getSelfDecl()->getType(), F); - Elts.push_back(DBuilder.createObjectPointerType(SelfTy)); - // "_cmd" pointer is always second argument. - llvm::DIType CmdTy = getOrCreateType(OMethod->getCmdDecl()->getType(), F); - Elts.push_back(DBuilder.createArtificialType(CmdTy)); - // Get rest of the arguments. - for (ObjCMethodDecl::param_const_iterator PI = OMethod->param_begin(), - PE = OMethod->param_end(); PI != PE; ++PI) - Elts.push_back(getOrCreateType((*PI)->getType(), F)); - - llvm::DIArray EltTypeArray = DBuilder.getOrCreateArray(Elts); - return DBuilder.createSubroutineType(F, EltTypeArray); - } - return getOrCreateType(FnType, F); -} - -/// EmitFunctionStart - Constructs the debug code for entering a function. -void CGDebugInfo::EmitFunctionStart(GlobalDecl GD, QualType FnType, - llvm::Function *Fn, - CGBuilderTy &Builder) { - - StringRef Name; - StringRef LinkageName; - - FnBeginRegionCount.push_back(LexicalBlockStack.size()); - - const Decl *D = GD.getDecl(); - // Function may lack declaration in source code if it is created by Clang - // CodeGen (examples: _GLOBAL__I_a, __cxx_global_array_dtor, thunk). - bool HasDecl = (D != 0); - // Use the location of the declaration. - SourceLocation Loc; - if (HasDecl) - Loc = D->getLocation(); - - unsigned Flags = 0; - llvm::DIFile Unit = getOrCreateFile(Loc); - llvm::DIDescriptor FDContext(Unit); - llvm::DIArray TParamsArray; - if (!HasDecl) { - // Use llvm function name. - Name = Fn->getName(); - } else if (const FunctionDecl *FD = dyn_cast<FunctionDecl>(D)) { - // If there is a DISubprogram for this function available then use it. - llvm::DenseMap<const FunctionDecl *, llvm::WeakVH>::iterator - FI = SPCache.find(FD->getCanonicalDecl()); - if (FI != SPCache.end()) { - llvm::Value *V = FI->second; - llvm::DIDescriptor SP(dyn_cast_or_null<llvm::MDNode>(V)); - if (SP.isSubprogram() && llvm::DISubprogram(SP).isDefinition()) { - llvm::MDNode *SPN = SP; - LexicalBlockStack.push_back(SPN); - RegionMap[D] = llvm::WeakVH(SP); - return; - } - } - Name = getFunctionName(FD); - // Use mangled name as linkage name for c/c++ functions. - if (FD->hasPrototype()) { - LinkageName = CGM.getMangledName(GD); - Flags |= llvm::DIDescriptor::FlagPrototyped; - } - if (LinkageName == Name || - CGM.getCodeGenOpts().getDebugInfo() <= CodeGenOptions::DebugLineTablesOnly) - LinkageName = StringRef(); - - if (CGM.getCodeGenOpts().getDebugInfo() >= CodeGenOptions::LimitedDebugInfo) { - if (const NamespaceDecl *NSDecl = - dyn_cast_or_null<NamespaceDecl>(FD->getDeclContext())) - FDContext = getOrCreateNameSpace(NSDecl); - else if (const RecordDecl *RDecl = - dyn_cast_or_null<RecordDecl>(FD->getDeclContext())) - FDContext = getContextDescriptor(cast<Decl>(RDecl->getDeclContext())); - - // Collect template parameters. - TParamsArray = CollectFunctionTemplateParams(FD, Unit); - } - } else if (const ObjCMethodDecl *OMD = dyn_cast<ObjCMethodDecl>(D)) { - Name = getObjCMethodName(OMD); - Flags |= llvm::DIDescriptor::FlagPrototyped; - } else { - // Use llvm function name. - Name = Fn->getName(); - Flags |= llvm::DIDescriptor::FlagPrototyped; - } - if (!Name.empty() && Name[0] == '\01') - Name = Name.substr(1); - - unsigned LineNo = getLineNumber(Loc); - if (!HasDecl || D->isImplicit()) - Flags |= llvm::DIDescriptor::FlagArtificial; - - llvm::DIType DIFnType; - llvm::DISubprogram SPDecl; - if (HasDecl && - CGM.getCodeGenOpts().getDebugInfo() >= CodeGenOptions::LimitedDebugInfo) { - DIFnType = getOrCreateFunctionType(D, FnType, Unit); - SPDecl = getFunctionDeclaration(D); - } else { - // Create fake but valid subroutine type. Otherwise - // llvm::DISubprogram::Verify() would return false, and - // subprogram DIE will miss DW_AT_decl_file and - // DW_AT_decl_line fields. - SmallVector<llvm::Value*, 16> Elts; - llvm::DIArray EltTypeArray = DBuilder.getOrCreateArray(Elts); - DIFnType = DBuilder.createSubroutineType(Unit, EltTypeArray); - } - llvm::DISubprogram SP; - SP = DBuilder.createFunction(FDContext, Name, LinkageName, Unit, - LineNo, DIFnType, - Fn->hasInternalLinkage(), true/*definition*/, - getLineNumber(CurLoc), Flags, - CGM.getLangOpts().Optimize, - Fn, TParamsArray, SPDecl); - - // Push function on region stack. - llvm::MDNode *SPN = SP; - LexicalBlockStack.push_back(SPN); - if (HasDecl) - RegionMap[D] = llvm::WeakVH(SP); -} - -/// EmitLocation - Emit metadata to indicate a change in line/column -/// information in the source file. -void CGDebugInfo::EmitLocation(CGBuilderTy &Builder, SourceLocation Loc) { - - // Update our current location - setLocation(Loc); - - if (CurLoc.isInvalid() || CurLoc.isMacroID()) return; - - // Don't bother if things are the same as last time. - SourceManager &SM = CGM.getContext().getSourceManager(); - if (CurLoc == PrevLoc || - SM.getExpansionLoc(CurLoc) == SM.getExpansionLoc(PrevLoc)) - // New Builder may not be in sync with CGDebugInfo. - if (!Builder.getCurrentDebugLocation().isUnknown()) - return; - - // Update last state. - PrevLoc = CurLoc; - - llvm::MDNode *Scope = LexicalBlockStack.back(); - Builder.SetCurrentDebugLocation(llvm::DebugLoc::get(getLineNumber(CurLoc), - getColumnNumber(CurLoc), - Scope)); -} - -/// CreateLexicalBlock - Creates a new lexical block node and pushes it on -/// the stack. -void CGDebugInfo::CreateLexicalBlock(SourceLocation Loc) { - llvm::DIDescriptor D = - DBuilder.createLexicalBlock(LexicalBlockStack.empty() ? - llvm::DIDescriptor() : - llvm::DIDescriptor(LexicalBlockStack.back()), - getOrCreateFile(CurLoc), - getLineNumber(CurLoc), - getColumnNumber(CurLoc)); - llvm::MDNode *DN = D; - LexicalBlockStack.push_back(DN); -} - -/// EmitLexicalBlockStart - Constructs the debug code for entering a declarative -/// region - beginning of a DW_TAG_lexical_block. -void CGDebugInfo::EmitLexicalBlockStart(CGBuilderTy &Builder, SourceLocation Loc) { - // Set our current location. - setLocation(Loc); - - // Create a new lexical block and push it on the stack. - CreateLexicalBlock(Loc); - - // Emit a line table change for the current location inside the new scope. - Builder.SetCurrentDebugLocation(llvm::DebugLoc::get(getLineNumber(Loc), - getColumnNumber(Loc), - LexicalBlockStack.back())); -} - -/// EmitLexicalBlockEnd - Constructs the debug code for exiting a declarative -/// region - end of a DW_TAG_lexical_block. -void CGDebugInfo::EmitLexicalBlockEnd(CGBuilderTy &Builder, SourceLocation Loc) { - assert(!LexicalBlockStack.empty() && "Region stack mismatch, stack empty!"); - - // Provide an entry in the line table for the end of the block. - EmitLocation(Builder, Loc); - - LexicalBlockStack.pop_back(); -} - -/// EmitFunctionEnd - Constructs the debug code for exiting a function. -void CGDebugInfo::EmitFunctionEnd(CGBuilderTy &Builder) { - assert(!LexicalBlockStack.empty() && "Region stack mismatch, stack empty!"); - unsigned RCount = FnBeginRegionCount.back(); - assert(RCount <= LexicalBlockStack.size() && "Region stack mismatch"); - - // Pop all regions for this function. - while (LexicalBlockStack.size() != RCount) - EmitLexicalBlockEnd(Builder, CurLoc); - FnBeginRegionCount.pop_back(); -} - -// EmitTypeForVarWithBlocksAttr - Build up structure info for the byref. -// See BuildByRefType. -llvm::DIType CGDebugInfo::EmitTypeForVarWithBlocksAttr(const VarDecl *VD, - uint64_t *XOffset) { - - SmallVector<llvm::Value *, 5> EltTys; - QualType FType; - uint64_t FieldSize, FieldOffset; - unsigned FieldAlign; - - llvm::DIFile Unit = getOrCreateFile(VD->getLocation()); - QualType Type = VD->getType(); - - FieldOffset = 0; - FType = CGM.getContext().getPointerType(CGM.getContext().VoidTy); - EltTys.push_back(CreateMemberType(Unit, FType, "__isa", &FieldOffset)); - EltTys.push_back(CreateMemberType(Unit, FType, "__forwarding", &FieldOffset)); - FType = CGM.getContext().IntTy; - EltTys.push_back(CreateMemberType(Unit, FType, "__flags", &FieldOffset)); - EltTys.push_back(CreateMemberType(Unit, FType, "__size", &FieldOffset)); - - bool HasCopyAndDispose = CGM.getContext().BlockRequiresCopying(Type, VD); - if (HasCopyAndDispose) { - FType = CGM.getContext().getPointerType(CGM.getContext().VoidTy); - EltTys.push_back(CreateMemberType(Unit, FType, "__copy_helper", - &FieldOffset)); - EltTys.push_back(CreateMemberType(Unit, FType, "__destroy_helper", - &FieldOffset)); - } - bool HasByrefExtendedLayout; - Qualifiers::ObjCLifetime Lifetime; - if (CGM.getContext().getByrefLifetime(Type, - Lifetime, HasByrefExtendedLayout) - && HasByrefExtendedLayout) - EltTys.push_back(CreateMemberType(Unit, FType, - "__byref_variable_layout", - &FieldOffset)); - - CharUnits Align = CGM.getContext().getDeclAlign(VD); - if (Align > CGM.getContext().toCharUnitsFromBits( - CGM.getContext().getTargetInfo().getPointerAlign(0))) { - CharUnits FieldOffsetInBytes - = CGM.getContext().toCharUnitsFromBits(FieldOffset); - CharUnits AlignedOffsetInBytes - = FieldOffsetInBytes.RoundUpToAlignment(Align); - CharUnits NumPaddingBytes - = AlignedOffsetInBytes - FieldOffsetInBytes; - - if (NumPaddingBytes.isPositive()) { - llvm::APInt pad(32, NumPaddingBytes.getQuantity()); - FType = CGM.getContext().getConstantArrayType(CGM.getContext().CharTy, - pad, ArrayType::Normal, 0); - EltTys.push_back(CreateMemberType(Unit, FType, "", &FieldOffset)); - } - } - - FType = Type; - llvm::DIType FieldTy = CGDebugInfo::getOrCreateType(FType, Unit); - FieldSize = CGM.getContext().getTypeSize(FType); - FieldAlign = CGM.getContext().toBits(Align); - - *XOffset = FieldOffset; - FieldTy = DBuilder.createMemberType(Unit, VD->getName(), Unit, - 0, FieldSize, FieldAlign, - FieldOffset, 0, FieldTy); - EltTys.push_back(FieldTy); - FieldOffset += FieldSize; - - llvm::DIArray Elements = DBuilder.getOrCreateArray(EltTys); - - unsigned Flags = llvm::DIDescriptor::FlagBlockByrefStruct; - - return DBuilder.createStructType(Unit, "", Unit, 0, FieldOffset, 0, Flags, - Elements); -} - -/// EmitDeclare - Emit local variable declaration debug info. -void CGDebugInfo::EmitDeclare(const VarDecl *VD, unsigned Tag, - llvm::Value *Storage, - unsigned ArgNo, CGBuilderTy &Builder) { - assert(CGM.getCodeGenOpts().getDebugInfo() >= CodeGenOptions::LimitedDebugInfo); - assert(!LexicalBlockStack.empty() && "Region stack mismatch, stack empty!"); - - llvm::DIFile Unit = getOrCreateFile(VD->getLocation()); - llvm::DIType Ty; - uint64_t XOffset = 0; - if (VD->hasAttr<BlocksAttr>()) - Ty = EmitTypeForVarWithBlocksAttr(VD, &XOffset); - else - Ty = getOrCreateType(VD->getType(), Unit); - - // If there is no debug info for this type then do not emit debug info - // for this variable. - if (!Ty) - return; - - if (llvm::Argument *Arg = dyn_cast<llvm::Argument>(Storage)) { - // If Storage is an aggregate returned as 'sret' then let debugger know - // about this. - if (Arg->hasStructRetAttr()) - Ty = DBuilder.createReferenceType(llvm::dwarf::DW_TAG_reference_type, Ty); - else if (CXXRecordDecl *Record = VD->getType()->getAsCXXRecordDecl()) { - // If an aggregate variable has non trivial destructor or non trivial copy - // constructor than it is pass indirectly. Let debug info know about this - // by using reference of the aggregate type as a argument type. - if (Record->hasNonTrivialCopyConstructor() || - !Record->hasTrivialDestructor()) - Ty = DBuilder.createReferenceType(llvm::dwarf::DW_TAG_reference_type, Ty); - } - } - - // Get location information. - unsigned Line = getLineNumber(VD->getLocation()); - unsigned Column = getColumnNumber(VD->getLocation()); - unsigned Flags = 0; - if (VD->isImplicit()) - Flags |= llvm::DIDescriptor::FlagArtificial; - // If this is the first argument and it is implicit then - // give it an object pointer flag. - // FIXME: There has to be a better way to do this, but for static - // functions there won't be an implicit param at arg1 and - // otherwise it is 'self' or 'this'. - if (isa<ImplicitParamDecl>(VD) && ArgNo == 1) - Flags |= llvm::DIDescriptor::FlagObjectPointer; - - llvm::MDNode *Scope = LexicalBlockStack.back(); - - StringRef Name = VD->getName(); - if (!Name.empty()) { - if (VD->hasAttr<BlocksAttr>()) { - CharUnits offset = CharUnits::fromQuantity(32); - SmallVector<llvm::Value *, 9> addr; - llvm::Type *Int64Ty = CGM.Int64Ty; - addr.push_back(llvm::ConstantInt::get(Int64Ty, llvm::DIBuilder::OpPlus)); - // offset of __forwarding field - offset = CGM.getContext().toCharUnitsFromBits( - CGM.getContext().getTargetInfo().getPointerWidth(0)); - addr.push_back(llvm::ConstantInt::get(Int64Ty, offset.getQuantity())); - addr.push_back(llvm::ConstantInt::get(Int64Ty, llvm::DIBuilder::OpDeref)); - addr.push_back(llvm::ConstantInt::get(Int64Ty, llvm::DIBuilder::OpPlus)); - // offset of x field - offset = CGM.getContext().toCharUnitsFromBits(XOffset); - addr.push_back(llvm::ConstantInt::get(Int64Ty, offset.getQuantity())); - - // Create the descriptor for the variable. - llvm::DIVariable D = - DBuilder.createComplexVariable(Tag, - llvm::DIDescriptor(Scope), - VD->getName(), Unit, Line, Ty, - addr, ArgNo); - - // Insert an llvm.dbg.declare into the current block. - llvm::Instruction *Call = - DBuilder.insertDeclare(Storage, D, Builder.GetInsertBlock()); - Call->setDebugLoc(llvm::DebugLoc::get(Line, Column, Scope)); - return; - } else if (isa<VariableArrayType>(VD->getType())) { - // These are "complex" variables in that they need an op_deref. - // Create the descriptor for the variable. - llvm::Value *Addr = llvm::ConstantInt::get(CGM.Int64Ty, - llvm::DIBuilder::OpDeref); - llvm::DIVariable D = - DBuilder.createComplexVariable(Tag, - llvm::DIDescriptor(Scope), - Name, Unit, Line, Ty, - Addr, ArgNo); - - // Insert an llvm.dbg.declare into the current block. - llvm::Instruction *Call = - DBuilder.insertDeclare(Storage, D, Builder.GetInsertBlock()); - Call->setDebugLoc(llvm::DebugLoc::get(Line, Column, Scope)); - return; - } - - // Create the descriptor for the variable. - llvm::DIVariable D = - DBuilder.createLocalVariable(Tag, llvm::DIDescriptor(Scope), - Name, Unit, Line, Ty, - CGM.getLangOpts().Optimize, Flags, ArgNo); - - // Insert an llvm.dbg.declare into the current block. - llvm::Instruction *Call = - DBuilder.insertDeclare(Storage, D, Builder.GetInsertBlock()); - Call->setDebugLoc(llvm::DebugLoc::get(Line, Column, Scope)); - return; - } - - // If VD is an anonymous union then Storage represents value for - // all union fields. - if (const RecordType *RT = dyn_cast<RecordType>(VD->getType())) { - const RecordDecl *RD = cast<RecordDecl>(RT->getDecl()); - if (RD->isUnion()) { - for (RecordDecl::field_iterator I = RD->field_begin(), - E = RD->field_end(); - I != E; ++I) { - FieldDecl *Field = *I; - llvm::DIType FieldTy = getOrCreateType(Field->getType(), Unit); - StringRef FieldName = Field->getName(); - - // Ignore unnamed fields. Do not ignore unnamed records. - if (FieldName.empty() && !isa<RecordType>(Field->getType())) - continue; - - // Use VarDecl's Tag, Scope and Line number. - llvm::DIVariable D = - DBuilder.createLocalVariable(Tag, llvm::DIDescriptor(Scope), - FieldName, Unit, Line, FieldTy, - CGM.getLangOpts().Optimize, Flags, - ArgNo); - - // Insert an llvm.dbg.declare into the current block. - llvm::Instruction *Call = - DBuilder.insertDeclare(Storage, D, Builder.GetInsertBlock()); - Call->setDebugLoc(llvm::DebugLoc::get(Line, Column, Scope)); - } - } - } -} - -void CGDebugInfo::EmitDeclareOfAutoVariable(const VarDecl *VD, - llvm::Value *Storage, - CGBuilderTy &Builder) { - assert(CGM.getCodeGenOpts().getDebugInfo() >= CodeGenOptions::LimitedDebugInfo); - EmitDeclare(VD, llvm::dwarf::DW_TAG_auto_variable, Storage, 0, Builder); -} - -void CGDebugInfo::EmitDeclareOfBlockDeclRefVariable(const VarDecl *VD, - llvm::Value *Storage, - CGBuilderTy &Builder, - const CGBlockInfo &blockInfo) { - assert(CGM.getCodeGenOpts().getDebugInfo() >= CodeGenOptions::LimitedDebugInfo); - assert(!LexicalBlockStack.empty() && "Region stack mismatch, stack empty!"); - - if (Builder.GetInsertBlock() == 0) - return; - - bool isByRef = VD->hasAttr<BlocksAttr>(); - - uint64_t XOffset = 0; - llvm::DIFile Unit = getOrCreateFile(VD->getLocation()); - llvm::DIType Ty; - if (isByRef) - Ty = EmitTypeForVarWithBlocksAttr(VD, &XOffset); - else - Ty = getOrCreateType(VD->getType(), Unit); - - // Self is passed along as an implicit non-arg variable in a - // block. Mark it as the object pointer. - if (isa<ImplicitParamDecl>(VD) && VD->getName() == "self") - Ty = DBuilder.createObjectPointerType(Ty); - - // Get location information. - unsigned Line = getLineNumber(VD->getLocation()); - unsigned Column = getColumnNumber(VD->getLocation()); - - const llvm::DataLayout &target = CGM.getDataLayout(); - - CharUnits offset = CharUnits::fromQuantity( - target.getStructLayout(blockInfo.StructureType) - ->getElementOffset(blockInfo.getCapture(VD).getIndex())); - - SmallVector<llvm::Value *, 9> addr; - llvm::Type *Int64Ty = CGM.Int64Ty; - addr.push_back(llvm::ConstantInt::get(Int64Ty, llvm::DIBuilder::OpPlus)); - addr.push_back(llvm::ConstantInt::get(Int64Ty, offset.getQuantity())); - if (isByRef) { - addr.push_back(llvm::ConstantInt::get(Int64Ty, llvm::DIBuilder::OpDeref)); - addr.push_back(llvm::ConstantInt::get(Int64Ty, llvm::DIBuilder::OpPlus)); - // offset of __forwarding field - offset = CGM.getContext() - .toCharUnitsFromBits(target.getPointerSizeInBits(0)); - addr.push_back(llvm::ConstantInt::get(Int64Ty, offset.getQuantity())); - addr.push_back(llvm::ConstantInt::get(Int64Ty, llvm::DIBuilder::OpDeref)); - addr.push_back(llvm::ConstantInt::get(Int64Ty, llvm::DIBuilder::OpPlus)); - // offset of x field - offset = CGM.getContext().toCharUnitsFromBits(XOffset); - addr.push_back(llvm::ConstantInt::get(Int64Ty, offset.getQuantity())); - } - - // Create the descriptor for the variable. - llvm::DIVariable D = - DBuilder.createComplexVariable(llvm::dwarf::DW_TAG_auto_variable, - llvm::DIDescriptor(LexicalBlockStack.back()), - VD->getName(), Unit, Line, Ty, addr); - // Insert an llvm.dbg.declare into the current block. - llvm::Instruction *Call = - DBuilder.insertDeclare(Storage, D, Builder.GetInsertPoint()); - Call->setDebugLoc(llvm::DebugLoc::get(Line, Column, - LexicalBlockStack.back())); -} - -/// EmitDeclareOfArgVariable - Emit call to llvm.dbg.declare for an argument -/// variable declaration. -void CGDebugInfo::EmitDeclareOfArgVariable(const VarDecl *VD, llvm::Value *AI, - unsigned ArgNo, - CGBuilderTy &Builder) { - assert(CGM.getCodeGenOpts().getDebugInfo() >= CodeGenOptions::LimitedDebugInfo); - EmitDeclare(VD, llvm::dwarf::DW_TAG_arg_variable, AI, ArgNo, Builder); -} - -namespace { - struct BlockLayoutChunk { - uint64_t OffsetInBits; - const BlockDecl::Capture *Capture; - }; - bool operator<(const BlockLayoutChunk &l, const BlockLayoutChunk &r) { - return l.OffsetInBits < r.OffsetInBits; - } -} - -void CGDebugInfo::EmitDeclareOfBlockLiteralArgVariable(const CGBlockInfo &block, - llvm::Value *addr, - CGBuilderTy &Builder) { - assert(CGM.getCodeGenOpts().getDebugInfo() >= CodeGenOptions::LimitedDebugInfo); - ASTContext &C = CGM.getContext(); - const BlockDecl *blockDecl = block.getBlockDecl(); - - // Collect some general information about the block's location. - SourceLocation loc = blockDecl->getCaretLocation(); - llvm::DIFile tunit = getOrCreateFile(loc); - unsigned line = getLineNumber(loc); - unsigned column = getColumnNumber(loc); - - // Build the debug-info type for the block literal. - getContextDescriptor(cast<Decl>(blockDecl->getDeclContext())); - - const llvm::StructLayout *blockLayout = - CGM.getDataLayout().getStructLayout(block.StructureType); - - SmallVector<llvm::Value*, 16> fields; - fields.push_back(createFieldType("__isa", C.VoidPtrTy, 0, loc, AS_public, - blockLayout->getElementOffsetInBits(0), - tunit, tunit)); - fields.push_back(createFieldType("__flags", C.IntTy, 0, loc, AS_public, - blockLayout->getElementOffsetInBits(1), - tunit, tunit)); - fields.push_back(createFieldType("__reserved", C.IntTy, 0, loc, AS_public, - blockLayout->getElementOffsetInBits(2), - tunit, tunit)); - fields.push_back(createFieldType("__FuncPtr", C.VoidPtrTy, 0, loc, AS_public, - blockLayout->getElementOffsetInBits(3), - tunit, tunit)); - fields.push_back(createFieldType("__descriptor", - C.getPointerType(block.NeedsCopyDispose ? - C.getBlockDescriptorExtendedType() : - C.getBlockDescriptorType()), - 0, loc, AS_public, - blockLayout->getElementOffsetInBits(4), - tunit, tunit)); - - // We want to sort the captures by offset, not because DWARF - // requires this, but because we're paranoid about debuggers. - SmallVector<BlockLayoutChunk, 8> chunks; - - // 'this' capture. - if (blockDecl->capturesCXXThis()) { - BlockLayoutChunk chunk; - chunk.OffsetInBits = - blockLayout->getElementOffsetInBits(block.CXXThisIndex); - chunk.Capture = 0; - chunks.push_back(chunk); - } - - // Variable captures. - for (BlockDecl::capture_const_iterator - i = blockDecl->capture_begin(), e = blockDecl->capture_end(); - i != e; ++i) { - const BlockDecl::Capture &capture = *i; - const VarDecl *variable = capture.getVariable(); - const CGBlockInfo::Capture &captureInfo = block.getCapture(variable); - - // Ignore constant captures. - if (captureInfo.isConstant()) - continue; - - BlockLayoutChunk chunk; - chunk.OffsetInBits = - blockLayout->getElementOffsetInBits(captureInfo.getIndex()); - chunk.Capture = &capture; - chunks.push_back(chunk); - } - - // Sort by offset. - llvm::array_pod_sort(chunks.begin(), chunks.end()); - - for (SmallVectorImpl<BlockLayoutChunk>::iterator - i = chunks.begin(), e = chunks.end(); i != e; ++i) { - uint64_t offsetInBits = i->OffsetInBits; - const BlockDecl::Capture *capture = i->Capture; - - // If we have a null capture, this must be the C++ 'this' capture. - if (!capture) { - const CXXMethodDecl *method = - cast<CXXMethodDecl>(blockDecl->getNonClosureContext()); - QualType type = method->getThisType(C); - - fields.push_back(createFieldType("this", type, 0, loc, AS_public, - offsetInBits, tunit, tunit)); - continue; - } - - const VarDecl *variable = capture->getVariable(); - StringRef name = variable->getName(); - - llvm::DIType fieldType; - if (capture->isByRef()) { - std::pair<uint64_t,unsigned> ptrInfo = C.getTypeInfo(C.VoidPtrTy); - - // FIXME: this creates a second copy of this type! - uint64_t xoffset; - fieldType = EmitTypeForVarWithBlocksAttr(variable, &xoffset); - fieldType = DBuilder.createPointerType(fieldType, ptrInfo.first); - fieldType = DBuilder.createMemberType(tunit, name, tunit, line, - ptrInfo.first, ptrInfo.second, - offsetInBits, 0, fieldType); - } else { - fieldType = createFieldType(name, variable->getType(), 0, - loc, AS_public, offsetInBits, tunit, tunit); - } - fields.push_back(fieldType); - } - - SmallString<36> typeName; - llvm::raw_svector_ostream(typeName) - << "__block_literal_" << CGM.getUniqueBlockCount(); - - llvm::DIArray fieldsArray = DBuilder.getOrCreateArray(fields); - - llvm::DIType type = - DBuilder.createStructType(tunit, typeName.str(), tunit, line, - CGM.getContext().toBits(block.BlockSize), - CGM.getContext().toBits(block.BlockAlign), - 0, fieldsArray); - type = DBuilder.createPointerType(type, CGM.PointerWidthInBits); - - // Get overall information about the block. - unsigned flags = llvm::DIDescriptor::FlagArtificial; - llvm::MDNode *scope = LexicalBlockStack.back(); - StringRef name = ".block_descriptor"; - - // Create the descriptor for the parameter. - llvm::DIVariable debugVar = - DBuilder.createLocalVariable(llvm::dwarf::DW_TAG_arg_variable, - llvm::DIDescriptor(scope), - name, tunit, line, type, - CGM.getLangOpts().Optimize, flags, - cast<llvm::Argument>(addr)->getArgNo() + 1); - - // Insert an llvm.dbg.value into the current block. - llvm::Instruction *declare = - DBuilder.insertDbgValueIntrinsic(addr, 0, debugVar, - Builder.GetInsertBlock()); - declare->setDebugLoc(llvm::DebugLoc::get(line, column, scope)); -} - -/// EmitGlobalVariable - Emit information about a global variable. -void CGDebugInfo::EmitGlobalVariable(llvm::GlobalVariable *Var, - const VarDecl *D) { - assert(CGM.getCodeGenOpts().getDebugInfo() >= CodeGenOptions::LimitedDebugInfo); - // Create global variable debug descriptor. - llvm::DIFile Unit = getOrCreateFile(D->getLocation()); - unsigned LineNo = getLineNumber(D->getLocation()); - - setLocation(D->getLocation()); - - QualType T = D->getType(); - if (T->isIncompleteArrayType()) { - - // CodeGen turns int[] into int[1] so we'll do the same here. - llvm::APInt ConstVal(32, 1); - QualType ET = CGM.getContext().getAsArrayType(T)->getElementType(); - - T = CGM.getContext().getConstantArrayType(ET, ConstVal, - ArrayType::Normal, 0); - } - StringRef DeclName = D->getName(); - StringRef LinkageName; - if (D->getDeclContext() && !isa<FunctionDecl>(D->getDeclContext()) - && !isa<ObjCMethodDecl>(D->getDeclContext())) - LinkageName = Var->getName(); - if (LinkageName == DeclName) - LinkageName = StringRef(); - llvm::DIDescriptor DContext = - getContextDescriptor(dyn_cast<Decl>(D->getDeclContext())); - DBuilder.createStaticVariable(DContext, DeclName, LinkageName, - Unit, LineNo, getOrCreateType(T, Unit), - Var->hasInternalLinkage(), Var); -} - -/// EmitGlobalVariable - Emit information about an objective-c interface. -void CGDebugInfo::EmitGlobalVariable(llvm::GlobalVariable *Var, - ObjCInterfaceDecl *ID) { - assert(CGM.getCodeGenOpts().getDebugInfo() >= CodeGenOptions::LimitedDebugInfo); - // Create global variable debug descriptor. - llvm::DIFile Unit = getOrCreateFile(ID->getLocation()); - unsigned LineNo = getLineNumber(ID->getLocation()); - - StringRef Name = ID->getName(); - - QualType T = CGM.getContext().getObjCInterfaceType(ID); - if (T->isIncompleteArrayType()) { - - // CodeGen turns int[] into int[1] so we'll do the same here. - llvm::APInt ConstVal(32, 1); - QualType ET = CGM.getContext().getAsArrayType(T)->getElementType(); - - T = CGM.getContext().getConstantArrayType(ET, ConstVal, - ArrayType::Normal, 0); - } - - DBuilder.createGlobalVariable(Name, Unit, LineNo, - getOrCreateType(T, Unit), - Var->hasInternalLinkage(), Var); -} - -/// EmitGlobalVariable - Emit global variable's debug info. -void CGDebugInfo::EmitGlobalVariable(const ValueDecl *VD, - llvm::Constant *Init) { - assert(CGM.getCodeGenOpts().getDebugInfo() >= CodeGenOptions::LimitedDebugInfo); - // Create the descriptor for the variable. - llvm::DIFile Unit = getOrCreateFile(VD->getLocation()); - StringRef Name = VD->getName(); - llvm::DIType Ty = getOrCreateType(VD->getType(), Unit); - if (const EnumConstantDecl *ECD = dyn_cast<EnumConstantDecl>(VD)) { - const EnumDecl *ED = cast<EnumDecl>(ECD->getDeclContext()); - assert(isa<EnumType>(ED->getTypeForDecl()) && "Enum without EnumType?"); - Ty = getOrCreateType(QualType(ED->getTypeForDecl(), 0), Unit); - } - // Do not use DIGlobalVariable for enums. - if (Ty.getTag() == llvm::dwarf::DW_TAG_enumeration_type) - return; - DBuilder.createStaticVariable(Unit, Name, Name, Unit, - getLineNumber(VD->getLocation()), - Ty, true, Init); -} - -/// getOrCreateNamesSpace - Return namespace descriptor for the given -/// namespace decl. -llvm::DINameSpace -CGDebugInfo::getOrCreateNameSpace(const NamespaceDecl *NSDecl) { - llvm::DenseMap<const NamespaceDecl *, llvm::WeakVH>::iterator I = - NameSpaceCache.find(NSDecl); - if (I != NameSpaceCache.end()) - return llvm::DINameSpace(cast<llvm::MDNode>(I->second)); - - unsigned LineNo = getLineNumber(NSDecl->getLocation()); - llvm::DIFile FileD = getOrCreateFile(NSDecl->getLocation()); - llvm::DIDescriptor Context = - getContextDescriptor(dyn_cast<Decl>(NSDecl->getDeclContext())); - llvm::DINameSpace NS = - DBuilder.createNameSpace(Context, NSDecl->getName(), FileD, LineNo); - NameSpaceCache[NSDecl] = llvm::WeakVH(NS); - return NS; -} - -void CGDebugInfo::finalize() { - for (std::vector<std::pair<void *, llvm::WeakVH> >::const_iterator VI - = ReplaceMap.begin(), VE = ReplaceMap.end(); VI != VE; ++VI) { - llvm::DIType Ty, RepTy; - // Verify that the debug info still exists. - if (llvm::Value *V = VI->second) - Ty = llvm::DIType(cast<llvm::MDNode>(V)); - - llvm::DenseMap<void *, llvm::WeakVH>::iterator it = - TypeCache.find(VI->first); - if (it != TypeCache.end()) { - // Verify that the debug info still exists. - if (llvm::Value *V = it->second) - RepTy = llvm::DIType(cast<llvm::MDNode>(V)); - } - - if (Ty.Verify() && Ty.isForwardDecl() && RepTy.Verify()) { - Ty.replaceAllUsesWith(RepTy); - } - } - DBuilder.finalize(); -} +//===--- CGDebugInfo.cpp - Emit Debug Information for a Module ------------===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+//
+// This coordinates the debug information generation while generating code.
+//
+//===----------------------------------------------------------------------===//
+
+#include "CGDebugInfo.h"
+#include "CGBlocks.h"
+#include "CGObjCRuntime.h"
+#include "CodeGenFunction.h"
+#include "CodeGenModule.h"
+#include "clang/AST/ASTContext.h"
+#include "clang/AST/DeclFriend.h"
+#include "clang/AST/DeclObjC.h"
+#include "clang/AST/DeclTemplate.h"
+#include "clang/AST/Expr.h"
+#include "clang/AST/RecordLayout.h"
+#include "clang/Basic/FileManager.h"
+#include "clang/Basic/SourceManager.h"
+#include "clang/Basic/Version.h"
+#include "clang/Frontend/CodeGenOptions.h"
+#include "llvm/ADT/SmallVector.h"
+#include "llvm/ADT/StringExtras.h"
+#include "llvm/Constants.h"
+#include "llvm/DataLayout.h"
+#include "llvm/DerivedTypes.h"
+#include "llvm/Instructions.h"
+#include "llvm/Intrinsics.h"
+#include "llvm/Module.h"
+#include "llvm/Support/Dwarf.h"
+#include "llvm/Support/FileSystem.h"
+using namespace clang;
+using namespace clang::CodeGen;
+
+CGDebugInfo::CGDebugInfo(CodeGenModule &CGM)
+ : CGM(CGM), DBuilder(CGM.getModule()),
+ BlockLiteralGenericSet(false) {
+ CreateCompileUnit();
+}
+
+CGDebugInfo::~CGDebugInfo() {
+ assert(LexicalBlockStack.empty() &&
+ "Region stack mismatch, stack not empty!");
+}
+
+void CGDebugInfo::setLocation(SourceLocation Loc) {
+ // If the new location isn't valid return.
+ if (!Loc.isValid()) return;
+
+ CurLoc = CGM.getContext().getSourceManager().getExpansionLoc(Loc);
+
+ // If we've changed files in the middle of a lexical scope go ahead
+ // and create a new lexical scope with file node if it's different
+ // from the one in the scope.
+ if (LexicalBlockStack.empty()) return;
+
+ SourceManager &SM = CGM.getContext().getSourceManager();
+ PresumedLoc PCLoc = SM.getPresumedLoc(CurLoc);
+ PresumedLoc PPLoc = SM.getPresumedLoc(PrevLoc);
+
+ if (PCLoc.isInvalid() || PPLoc.isInvalid() ||
+ !strcmp(PPLoc.getFilename(), PCLoc.getFilename()))
+ return;
+
+ llvm::MDNode *LB = LexicalBlockStack.back();
+ llvm::DIScope Scope = llvm::DIScope(LB);
+ if (Scope.isLexicalBlockFile()) {
+ llvm::DILexicalBlockFile LBF = llvm::DILexicalBlockFile(LB);
+ llvm::DIDescriptor D
+ = DBuilder.createLexicalBlockFile(LBF.getScope(),
+ getOrCreateFile(CurLoc));
+ llvm::MDNode *N = D;
+ LexicalBlockStack.pop_back();
+ LexicalBlockStack.push_back(N);
+ } else if (Scope.isLexicalBlock()) {
+ llvm::DIDescriptor D
+ = DBuilder.createLexicalBlockFile(Scope, getOrCreateFile(CurLoc));
+ llvm::MDNode *N = D;
+ LexicalBlockStack.pop_back();
+ LexicalBlockStack.push_back(N);
+ }
+}
+
+/// getContextDescriptor - Get context info for the decl.
+llvm::DIDescriptor CGDebugInfo::getContextDescriptor(const Decl *Context) {
+ if (!Context)
+ return TheCU;
+
+ llvm::DenseMap<const Decl *, llvm::WeakVH>::iterator
+ I = RegionMap.find(Context);
+ if (I != RegionMap.end()) {
+ llvm::Value *V = I->second;
+ return llvm::DIDescriptor(dyn_cast_or_null<llvm::MDNode>(V));
+ }
+
+ // Check namespace.
+ if (const NamespaceDecl *NSDecl = dyn_cast<NamespaceDecl>(Context))
+ return llvm::DIDescriptor(getOrCreateNameSpace(NSDecl));
+
+ if (const RecordDecl *RDecl = dyn_cast<RecordDecl>(Context)) {
+ if (!RDecl->isDependentType()) {
+ llvm::DIType Ty = getOrCreateType(CGM.getContext().getTypeDeclType(RDecl),
+ getOrCreateMainFile());
+ return llvm::DIDescriptor(Ty);
+ }
+ }
+ return TheCU;
+}
+
+/// getFunctionName - Get function name for the given FunctionDecl. If the
+/// name is constructred on demand (e.g. C++ destructor) then the name
+/// is stored on the side.
+StringRef CGDebugInfo::getFunctionName(const FunctionDecl *FD) {
+ assert (FD && "Invalid FunctionDecl!");
+ IdentifierInfo *FII = FD->getIdentifier();
+ FunctionTemplateSpecializationInfo *Info
+ = FD->getTemplateSpecializationInfo();
+ if (!Info && FII)
+ return FII->getName();
+
+ // Otherwise construct human readable name for debug info.
+ std::string NS = FD->getNameAsString();
+
+ // Add any template specialization args.
+ if (Info) {
+ const TemplateArgumentList *TArgs = Info->TemplateArguments;
+ const TemplateArgument *Args = TArgs->data();
+ unsigned NumArgs = TArgs->size();
+ PrintingPolicy Policy(CGM.getLangOpts());
+ NS += TemplateSpecializationType::PrintTemplateArgumentList(Args,
+ NumArgs,
+ Policy);
+ }
+
+ // Copy this name on the side and use its reference.
+ char *StrPtr = DebugInfoNames.Allocate<char>(NS.length());
+ memcpy(StrPtr, NS.data(), NS.length());
+ return StringRef(StrPtr, NS.length());
+}
+
+StringRef CGDebugInfo::getObjCMethodName(const ObjCMethodDecl *OMD) {
+ SmallString<256> MethodName;
+ llvm::raw_svector_ostream OS(MethodName);
+ OS << (OMD->isInstanceMethod() ? '-' : '+') << '[';
+ const DeclContext *DC = OMD->getDeclContext();
+ if (const ObjCImplementationDecl *OID =
+ dyn_cast<const ObjCImplementationDecl>(DC)) {
+ OS << OID->getName();
+ } else if (const ObjCInterfaceDecl *OID =
+ dyn_cast<const ObjCInterfaceDecl>(DC)) {
+ OS << OID->getName();
+ } else if (const ObjCCategoryImplDecl *OCD =
+ dyn_cast<const ObjCCategoryImplDecl>(DC)){
+ OS << ((const NamedDecl *)OCD)->getIdentifier()->getNameStart() << '(' <<
+ OCD->getIdentifier()->getNameStart() << ')';
+ }
+ OS << ' ' << OMD->getSelector().getAsString() << ']';
+
+ char *StrPtr = DebugInfoNames.Allocate<char>(OS.tell());
+ memcpy(StrPtr, MethodName.begin(), OS.tell());
+ return StringRef(StrPtr, OS.tell());
+}
+
+/// getSelectorName - Return selector name. This is used for debugging
+/// info.
+StringRef CGDebugInfo::getSelectorName(Selector S) {
+ const std::string &SName = S.getAsString();
+ char *StrPtr = DebugInfoNames.Allocate<char>(SName.size());
+ memcpy(StrPtr, SName.data(), SName.size());
+ return StringRef(StrPtr, SName.size());
+}
+
+/// getClassName - Get class name including template argument list.
+StringRef
+CGDebugInfo::getClassName(const RecordDecl *RD) {
+ const ClassTemplateSpecializationDecl *Spec
+ = dyn_cast<ClassTemplateSpecializationDecl>(RD);
+ if (!Spec)
+ return RD->getName();
+
+ const TemplateArgument *Args;
+ unsigned NumArgs;
+ if (TypeSourceInfo *TAW = Spec->getTypeAsWritten()) {
+ const TemplateSpecializationType *TST =
+ cast<TemplateSpecializationType>(TAW->getType());
+ Args = TST->getArgs();
+ NumArgs = TST->getNumArgs();
+ } else {
+ const TemplateArgumentList &TemplateArgs = Spec->getTemplateArgs();
+ Args = TemplateArgs.data();
+ NumArgs = TemplateArgs.size();
+ }
+ StringRef Name = RD->getIdentifier()->getName();
+ PrintingPolicy Policy(CGM.getLangOpts());
+ std::string TemplateArgList =
+ TemplateSpecializationType::PrintTemplateArgumentList(Args, NumArgs, Policy);
+
+ // Copy this name on the side and use its reference.
+ size_t Length = Name.size() + TemplateArgList.size();
+ char *StrPtr = DebugInfoNames.Allocate<char>(Length);
+ memcpy(StrPtr, Name.data(), Name.size());
+ memcpy(StrPtr + Name.size(), TemplateArgList.data(), TemplateArgList.size());
+ return StringRef(StrPtr, Length);
+}
+
+/// getOrCreateFile - Get the file debug info descriptor for the input location.
+llvm::DIFile CGDebugInfo::getOrCreateFile(SourceLocation Loc) {
+ if (!Loc.isValid())
+ // If Location is not valid then use main input file.
+ return DBuilder.createFile(TheCU.getFilename(), TheCU.getDirectory());
+
+ SourceManager &SM = CGM.getContext().getSourceManager();
+ PresumedLoc PLoc = SM.getPresumedLoc(Loc);
+
+ if (PLoc.isInvalid() || StringRef(PLoc.getFilename()).empty())
+ // If the location is not valid then use main input file.
+ return DBuilder.createFile(TheCU.getFilename(), TheCU.getDirectory());
+
+ // Cache the results.
+ const char *fname = PLoc.getFilename();
+ llvm::DenseMap<const char *, llvm::WeakVH>::iterator it =
+ DIFileCache.find(fname);
+
+ if (it != DIFileCache.end()) {
+ // Verify that the information still exists.
+ if (llvm::Value *V = it->second)
+ return llvm::DIFile(cast<llvm::MDNode>(V));
+ }
+
+ llvm::DIFile F = DBuilder.createFile(PLoc.getFilename(), getCurrentDirname());
+
+ DIFileCache[fname] = F;
+ return F;
+}
+
+/// getOrCreateMainFile - Get the file info for main compile unit.
+llvm::DIFile CGDebugInfo::getOrCreateMainFile() {
+ return DBuilder.createFile(TheCU.getFilename(), TheCU.getDirectory());
+}
+
+/// getLineNumber - Get line number for the location. If location is invalid
+/// then use current location.
+unsigned CGDebugInfo::getLineNumber(SourceLocation Loc) {
+ if (Loc.isInvalid() && CurLoc.isInvalid())
+ return 0;
+ SourceManager &SM = CGM.getContext().getSourceManager();
+ PresumedLoc PLoc = SM.getPresumedLoc(Loc.isValid() ? Loc : CurLoc);
+ return PLoc.isValid()? PLoc.getLine() : 0;
+}
+
+/// getColumnNumber - Get column number for the location.
+unsigned CGDebugInfo::getColumnNumber(SourceLocation Loc) {
+ // We may not want column information at all.
+ if (!CGM.getCodeGenOpts().DebugColumnInfo)
+ return 0;
+
+ // If the location is invalid then use the current column.
+ if (Loc.isInvalid() && CurLoc.isInvalid())
+ return 0;
+ SourceManager &SM = CGM.getContext().getSourceManager();
+ PresumedLoc PLoc = SM.getPresumedLoc(Loc.isValid() ? Loc : CurLoc);
+ return PLoc.isValid()? PLoc.getColumn() : 0;
+}
+
+StringRef CGDebugInfo::getCurrentDirname() {
+ if (!CGM.getCodeGenOpts().DebugCompilationDir.empty())
+ return CGM.getCodeGenOpts().DebugCompilationDir;
+
+ if (!CWDName.empty())
+ return CWDName;
+ SmallString<256> CWD;
+ llvm::sys::fs::current_path(CWD);
+ char *CompDirnamePtr = DebugInfoNames.Allocate<char>(CWD.size());
+ memcpy(CompDirnamePtr, CWD.data(), CWD.size());
+ return CWDName = StringRef(CompDirnamePtr, CWD.size());
+}
+
+/// CreateCompileUnit - Create new compile unit.
+void CGDebugInfo::CreateCompileUnit() {
+
+ // Get absolute path name.
+ SourceManager &SM = CGM.getContext().getSourceManager();
+ std::string MainFileName = CGM.getCodeGenOpts().MainFileName;
+ if (MainFileName.empty())
+ MainFileName = "<unknown>";
+
+ // The main file name provided via the "-main-file-name" option contains just
+ // the file name itself with no path information. This file name may have had
+ // a relative path, so we look into the actual file entry for the main
+ // file to determine the real absolute path for the file.
+ std::string MainFileDir;
+ if (const FileEntry *MainFile = SM.getFileEntryForID(SM.getMainFileID())) {
+ MainFileDir = MainFile->getDir()->getName();
+ if (MainFileDir != ".")
+ MainFileName = MainFileDir + "/" + MainFileName;
+ }
+
+ // Save filename string.
+ char *FilenamePtr = DebugInfoNames.Allocate<char>(MainFileName.length());
+ memcpy(FilenamePtr, MainFileName.c_str(), MainFileName.length());
+ StringRef Filename(FilenamePtr, MainFileName.length());
+
+ unsigned LangTag;
+ const LangOptions &LO = CGM.getLangOpts();
+ if (LO.CPlusPlus) {
+ if (LO.ObjC1)
+ LangTag = llvm::dwarf::DW_LANG_ObjC_plus_plus;
+ else
+ LangTag = llvm::dwarf::DW_LANG_C_plus_plus;
+ } else if (LO.ObjC1) {
+ LangTag = llvm::dwarf::DW_LANG_ObjC;
+ } else if (LO.C99) {
+ LangTag = llvm::dwarf::DW_LANG_C99;
+ } else {
+ LangTag = llvm::dwarf::DW_LANG_C89;
+ }
+
+ std::string Producer = getClangFullVersion();
+
+ // Figure out which version of the ObjC runtime we have.
+ unsigned RuntimeVers = 0;
+ if (LO.ObjC1)
+ RuntimeVers = LO.ObjCRuntime.isNonFragile() ? 2 : 1;
+
+ // Create new compile unit.
+ DBuilder.createCompileUnit(
+ LangTag, Filename, getCurrentDirname(),
+ Producer,
+ LO.Optimize, CGM.getCodeGenOpts().DwarfDebugFlags, RuntimeVers);
+ // FIXME - Eliminate TheCU.
+ TheCU = llvm::DICompileUnit(DBuilder.getCU());
+}
+
+/// CreateType - Get the Basic type from the cache or create a new
+/// one if necessary.
+llvm::DIType CGDebugInfo::CreateType(const BuiltinType *BT) {
+ unsigned Encoding = 0;
+ StringRef BTName;
+ switch (BT->getKind()) {
+#define BUILTIN_TYPE(Id, SingletonId)
+#define PLACEHOLDER_TYPE(Id, SingletonId) \
+ case BuiltinType::Id:
+#include "clang/AST/BuiltinTypes.def"
+ case BuiltinType::Dependent:
+ llvm_unreachable("Unexpected builtin type");
+ case BuiltinType::NullPtr:
+ return DBuilder.
+ createNullPtrType(BT->getName(CGM.getLangOpts()));
+ case BuiltinType::Void:
+ return llvm::DIType();
+ case BuiltinType::ObjCClass:
+ if (ClassTy.Verify())
+ return ClassTy;
+ ClassTy = DBuilder.createForwardDecl(llvm::dwarf::DW_TAG_structure_type,
+ "objc_class", TheCU,
+ getOrCreateMainFile(), 0);
+ return ClassTy;
+ case BuiltinType::ObjCId: {
+ // typedef struct objc_class *Class;
+ // typedef struct objc_object {
+ // Class isa;
+ // } *id;
+
+ if (ObjTy.Verify())
+ return ObjTy;
+
+ if (!ClassTy.Verify())
+ ClassTy = DBuilder.createForwardDecl(llvm::dwarf::DW_TAG_structure_type,
+ "objc_class", TheCU,
+ getOrCreateMainFile(), 0);
+
+ unsigned Size = CGM.getContext().getTypeSize(CGM.getContext().VoidPtrTy);
+
+ llvm::DIType ISATy = DBuilder.createPointerType(ClassTy, Size);
+
+ llvm::DIType FwdTy = DBuilder.createStructType(TheCU, "objc_object",
+ getOrCreateMainFile(),
+ 0, 0, 0, 0,
+ llvm::DIArray());
+
+ llvm::TrackingVH<llvm::MDNode> ObjNode(FwdTy);
+ SmallVector<llvm::Value *, 1> EltTys;
+ llvm::DIType FieldTy =
+ DBuilder.createMemberType(llvm::DIDescriptor(ObjNode), "isa",
+ getOrCreateMainFile(), 0, Size,
+ 0, 0, 0, ISATy);
+ EltTys.push_back(FieldTy);
+ llvm::DIArray Elements = DBuilder.getOrCreateArray(EltTys);
+
+ ObjNode->replaceOperandWith(10, Elements);
+ ObjTy = llvm::DIType(ObjNode);
+ return ObjTy;
+ }
+ case BuiltinType::ObjCSel: {
+ if (SelTy.Verify())
+ return SelTy;
+ SelTy =
+ DBuilder.createForwardDecl(llvm::dwarf::DW_TAG_structure_type,
+ "objc_selector", TheCU, getOrCreateMainFile(),
+ 0);
+ return SelTy;
+ }
+
+ case BuiltinType::OCLImage1d:
+ return getOrCreateStructPtrType("opencl_image1d_t",
+ OCLImage1dDITy);
+ case BuiltinType::OCLImage1dArray:
+ return getOrCreateStructPtrType("opencl_image1d_array_t",
+ OCLImage1dArrayDITy);
+ case BuiltinType::OCLImage1dBuffer:
+ return getOrCreateStructPtrType("opencl_image1d_buffer_t",
+ OCLImage1dBufferDITy);
+ case BuiltinType::OCLImage2d:
+ return getOrCreateStructPtrType("opencl_image2d_t",
+ OCLImage2dDITy);
+ case BuiltinType::OCLImage2dArray:
+ return getOrCreateStructPtrType("opencl_image2d_array_t",
+ OCLImage2dArrayDITy);
+ case BuiltinType::OCLImage3d:
+ return getOrCreateStructPtrType("opencl_image3d_t",
+ OCLImage3dDITy);
+
+ case BuiltinType::UChar:
+ case BuiltinType::Char_U: Encoding = llvm::dwarf::DW_ATE_unsigned_char; break;
+ case BuiltinType::Char_S:
+ case BuiltinType::SChar: Encoding = llvm::dwarf::DW_ATE_signed_char; break;
+ case BuiltinType::Char16:
+ case BuiltinType::Char32: Encoding = llvm::dwarf::DW_ATE_UTF; break;
+ case BuiltinType::UShort:
+ case BuiltinType::UInt:
+ case BuiltinType::UInt128:
+ case BuiltinType::ULong:
+ case BuiltinType::WChar_U:
+ case BuiltinType::ULongLong: Encoding = llvm::dwarf::DW_ATE_unsigned; break;
+ case BuiltinType::Short:
+ case BuiltinType::Int:
+ case BuiltinType::Int128:
+ case BuiltinType::Long:
+ case BuiltinType::WChar_S:
+ case BuiltinType::LongLong: Encoding = llvm::dwarf::DW_ATE_signed; break;
+ case BuiltinType::Bool: Encoding = llvm::dwarf::DW_ATE_boolean; break;
+ case BuiltinType::Half:
+ case BuiltinType::Float:
+ case BuiltinType::LongDouble:
+ case BuiltinType::Double: Encoding = llvm::dwarf::DW_ATE_float; break;
+ }
+
+ switch (BT->getKind()) {
+ case BuiltinType::Long: BTName = "long int"; break;
+ case BuiltinType::LongLong: BTName = "long long int"; break;
+ case BuiltinType::ULong: BTName = "long unsigned int"; break;
+ case BuiltinType::ULongLong: BTName = "long long unsigned int"; break;
+ default:
+ BTName = BT->getName(CGM.getLangOpts());
+ break;
+ }
+ // Bit size, align and offset of the type.
+ uint64_t Size = CGM.getContext().getTypeSize(BT);
+ uint64_t Align = CGM.getContext().getTypeAlign(BT);
+ llvm::DIType DbgTy =
+ DBuilder.createBasicType(BTName, Size, Align, Encoding);
+ return DbgTy;
+}
+
+llvm::DIType CGDebugInfo::CreateType(const ComplexType *Ty) {
+ // Bit size, align and offset of the type.
+ unsigned Encoding = llvm::dwarf::DW_ATE_complex_float;
+ if (Ty->isComplexIntegerType())
+ Encoding = llvm::dwarf::DW_ATE_lo_user;
+
+ uint64_t Size = CGM.getContext().getTypeSize(Ty);
+ uint64_t Align = CGM.getContext().getTypeAlign(Ty);
+ llvm::DIType DbgTy =
+ DBuilder.createBasicType("complex", Size, Align, Encoding);
+
+ return DbgTy;
+}
+
+/// CreateCVRType - Get the qualified type from the cache or create
+/// a new one if necessary.
+llvm::DIType CGDebugInfo::CreateQualifiedType(QualType Ty, llvm::DIFile Unit) {
+ QualifierCollector Qc;
+ const Type *T = Qc.strip(Ty);
+
+ // Ignore these qualifiers for now.
+ Qc.removeObjCGCAttr();
+ Qc.removeAddressSpace();
+ Qc.removeObjCLifetime();
+
+ // We will create one Derived type for one qualifier and recurse to handle any
+ // additional ones.
+ unsigned Tag;
+ if (Qc.hasConst()) {
+ Tag = llvm::dwarf::DW_TAG_const_type;
+ Qc.removeConst();
+ } else if (Qc.hasVolatile()) {
+ Tag = llvm::dwarf::DW_TAG_volatile_type;
+ Qc.removeVolatile();
+ } else if (Qc.hasRestrict()) {
+ Tag = llvm::dwarf::DW_TAG_restrict_type;
+ Qc.removeRestrict();
+ } else {
+ assert(Qc.empty() && "Unknown type qualifier for debug info");
+ return getOrCreateType(QualType(T, 0), Unit);
+ }
+
+ llvm::DIType FromTy = getOrCreateType(Qc.apply(CGM.getContext(), T), Unit);
+
+ // No need to fill in the Name, Line, Size, Alignment, Offset in case of
+ // CVR derived types.
+ llvm::DIType DbgTy = DBuilder.createQualifiedType(Tag, FromTy);
+
+ return DbgTy;
+}
+
+llvm::DIType CGDebugInfo::CreateType(const ObjCObjectPointerType *Ty,
+ llvm::DIFile Unit) {
+ llvm::DIType DbgTy =
+ CreatePointerLikeType(llvm::dwarf::DW_TAG_pointer_type, Ty,
+ Ty->getPointeeType(), Unit);
+ return DbgTy;
+}
+
+llvm::DIType CGDebugInfo::CreateType(const PointerType *Ty,
+ llvm::DIFile Unit) {
+ return CreatePointerLikeType(llvm::dwarf::DW_TAG_pointer_type, Ty,
+ Ty->getPointeeType(), Unit);
+}
+
+// Creates a forward declaration for a RecordDecl in the given context.
+llvm::DIType CGDebugInfo::createRecordFwdDecl(const RecordDecl *RD,
+ llvm::DIDescriptor Ctx) {
+ llvm::DIFile DefUnit = getOrCreateFile(RD->getLocation());
+ unsigned Line = getLineNumber(RD->getLocation());
+ StringRef RDName = getClassName(RD);
+
+ unsigned Tag = 0;
+ if (RD->isStruct() || RD->isInterface())
+ Tag = llvm::dwarf::DW_TAG_structure_type;
+ else if (RD->isUnion())
+ Tag = llvm::dwarf::DW_TAG_union_type;
+ else {
+ assert(RD->isClass());
+ Tag = llvm::dwarf::DW_TAG_class_type;
+ }
+
+ // Create the type.
+ return DBuilder.createForwardDecl(Tag, RDName, Ctx, DefUnit, Line);
+}
+
+// Walk up the context chain and create forward decls for record decls,
+// and normal descriptors for namespaces.
+llvm::DIDescriptor CGDebugInfo::createContextChain(const Decl *Context) {
+ if (!Context)
+ return TheCU;
+
+ // See if we already have the parent.
+ llvm::DenseMap<const Decl *, llvm::WeakVH>::iterator
+ I = RegionMap.find(Context);
+ if (I != RegionMap.end()) {
+ llvm::Value *V = I->second;
+ return llvm::DIDescriptor(dyn_cast_or_null<llvm::MDNode>(V));
+ }
+
+ // Check namespace.
+ if (const NamespaceDecl *NSDecl = dyn_cast<NamespaceDecl>(Context))
+ return llvm::DIDescriptor(getOrCreateNameSpace(NSDecl));
+
+ if (const RecordDecl *RD = dyn_cast<RecordDecl>(Context)) {
+ if (!RD->isDependentType()) {
+ llvm::DIType Ty = getOrCreateLimitedType(CGM.getContext().getTypeDeclType(RD),
+ getOrCreateMainFile());
+ return llvm::DIDescriptor(Ty);
+ }
+ }
+ return TheCU;
+}
+
+/// CreatePointeeType - Create Pointee type. If Pointee is a record
+/// then emit record's fwd if debug info size reduction is enabled.
+llvm::DIType CGDebugInfo::CreatePointeeType(QualType PointeeTy,
+ llvm::DIFile Unit) {
+ if (CGM.getCodeGenOpts().getDebugInfo() != CodeGenOptions::LimitedDebugInfo)
+ return getOrCreateType(PointeeTy, Unit);
+
+ // Limit debug info for the pointee type.
+
+ // If we have an existing type, use that, it's still smaller than creating
+ // a new type.
+ llvm::DIType Ty = getTypeOrNull(PointeeTy);
+ if (Ty.Verify()) return Ty;
+
+ // Handle qualifiers.
+ if (PointeeTy.hasLocalQualifiers())
+ return CreateQualifiedType(PointeeTy, Unit);
+
+ if (const RecordType *RTy = dyn_cast<RecordType>(PointeeTy)) {
+ RecordDecl *RD = RTy->getDecl();
+ llvm::DIDescriptor FDContext =
+ getContextDescriptor(cast<Decl>(RD->getDeclContext()));
+ llvm::DIType RetTy = createRecordFwdDecl(RD, FDContext);
+ TypeCache[QualType(RTy, 0).getAsOpaquePtr()] = RetTy;
+ return RetTy;
+ }
+ return getOrCreateType(PointeeTy, Unit);
+
+}
+
+llvm::DIType CGDebugInfo::CreatePointerLikeType(unsigned Tag,
+ const Type *Ty,
+ QualType PointeeTy,
+ llvm::DIFile Unit) {
+ if (Tag == llvm::dwarf::DW_TAG_reference_type ||
+ Tag == llvm::dwarf::DW_TAG_rvalue_reference_type)
+ return DBuilder.createReferenceType(Tag,
+ CreatePointeeType(PointeeTy, Unit));
+
+ // Bit size, align and offset of the type.
+ // Size is always the size of a pointer. We can't use getTypeSize here
+ // because that does not return the correct value for references.
+ unsigned AS = CGM.getContext().getTargetAddressSpace(PointeeTy);
+ uint64_t Size = CGM.getContext().getTargetInfo().getPointerWidth(AS);
+ uint64_t Align = CGM.getContext().getTypeAlign(Ty);
+
+ return DBuilder.createPointerType(CreatePointeeType(PointeeTy, Unit),
+ Size, Align);
+}
+
+llvm::DIType CGDebugInfo::getOrCreateStructPtrType(StringRef Name, llvm::DIType &Cache) {
+ if (Cache.Verify())
+ return Cache;
+ Cache =
+ DBuilder.createForwardDecl(llvm::dwarf::DW_TAG_structure_type,
+ Name, TheCU, getOrCreateMainFile(),
+ 0);
+ unsigned Size = CGM.getContext().getTypeSize(CGM.getContext().VoidPtrTy);
+ Cache = DBuilder.createPointerType(Cache, Size);
+ return Cache;
+}
+
+llvm::DIType CGDebugInfo::CreateType(const BlockPointerType *Ty,
+ llvm::DIFile Unit) {
+ if (BlockLiteralGenericSet)
+ return BlockLiteralGeneric;
+
+ SmallVector<llvm::Value *, 8> EltTys;
+ llvm::DIType FieldTy;
+ QualType FType;
+ uint64_t FieldSize, FieldOffset;
+ unsigned FieldAlign;
+ llvm::DIArray Elements;
+ llvm::DIType EltTy, DescTy;
+
+ FieldOffset = 0;
+ FType = CGM.getContext().UnsignedLongTy;
+ EltTys.push_back(CreateMemberType(Unit, FType, "reserved", &FieldOffset));
+ EltTys.push_back(CreateMemberType(Unit, FType, "Size", &FieldOffset));
+
+ Elements = DBuilder.getOrCreateArray(EltTys);
+ EltTys.clear();
+
+ unsigned Flags = llvm::DIDescriptor::FlagAppleBlock;
+ unsigned LineNo = getLineNumber(CurLoc);
+
+ EltTy = DBuilder.createStructType(Unit, "__block_descriptor",
+ Unit, LineNo, FieldOffset, 0,
+ Flags, Elements);
+
+ // Bit size, align and offset of the type.
+ uint64_t Size = CGM.getContext().getTypeSize(Ty);
+
+ DescTy = DBuilder.createPointerType(EltTy, Size);
+
+ FieldOffset = 0;
+ FType = CGM.getContext().getPointerType(CGM.getContext().VoidTy);
+ EltTys.push_back(CreateMemberType(Unit, FType, "__isa", &FieldOffset));
+ FType = CGM.getContext().IntTy;
+ EltTys.push_back(CreateMemberType(Unit, FType, "__flags", &FieldOffset));
+ EltTys.push_back(CreateMemberType(Unit, FType, "__reserved", &FieldOffset));
+ FType = CGM.getContext().getPointerType(CGM.getContext().VoidTy);
+ EltTys.push_back(CreateMemberType(Unit, FType, "__FuncPtr", &FieldOffset));
+
+ FType = CGM.getContext().getPointerType(CGM.getContext().VoidTy);
+ FieldTy = DescTy;
+ FieldSize = CGM.getContext().getTypeSize(Ty);
+ FieldAlign = CGM.getContext().getTypeAlign(Ty);
+ FieldTy = DBuilder.createMemberType(Unit, "__descriptor", Unit,
+ LineNo, FieldSize, FieldAlign,
+ FieldOffset, 0, FieldTy);
+ EltTys.push_back(FieldTy);
+
+ FieldOffset += FieldSize;
+ Elements = DBuilder.getOrCreateArray(EltTys);
+
+ EltTy = DBuilder.createStructType(Unit, "__block_literal_generic",
+ Unit, LineNo, FieldOffset, 0,
+ Flags, Elements);
+
+ BlockLiteralGenericSet = true;
+ BlockLiteralGeneric = DBuilder.createPointerType(EltTy, Size);
+ return BlockLiteralGeneric;
+}
+
+llvm::DIType CGDebugInfo::CreateType(const TypedefType *Ty, llvm::DIFile Unit) {
+ // Typedefs are derived from some other type. If we have a typedef of a
+ // typedef, make sure to emit the whole chain.
+ llvm::DIType Src = getOrCreateType(Ty->getDecl()->getUnderlyingType(), Unit);
+ if (!Src.Verify())
+ return llvm::DIType();
+ // We don't set size information, but do specify where the typedef was
+ // declared.
+ unsigned Line = getLineNumber(Ty->getDecl()->getLocation());
+ const TypedefNameDecl *TyDecl = Ty->getDecl();
+
+ llvm::DIDescriptor TypedefContext =
+ getContextDescriptor(cast<Decl>(Ty->getDecl()->getDeclContext()));
+
+ return
+ DBuilder.createTypedef(Src, TyDecl->getName(), Unit, Line, TypedefContext);
+}
+
+llvm::DIType CGDebugInfo::CreateType(const FunctionType *Ty,
+ llvm::DIFile Unit) {
+ SmallVector<llvm::Value *, 16> EltTys;
+
+ // Add the result type at least.
+ EltTys.push_back(getOrCreateType(Ty->getResultType(), Unit));
+
+ // Set up remainder of arguments if there is a prototype.
+ // FIXME: IF NOT, HOW IS THIS REPRESENTED? llvm-gcc doesn't represent '...'!
+ if (isa<FunctionNoProtoType>(Ty))
+ EltTys.push_back(DBuilder.createUnspecifiedParameter());
+ else if (const FunctionProtoType *FPT = dyn_cast<FunctionProtoType>(Ty)) {
+ for (unsigned i = 0, e = FPT->getNumArgs(); i != e; ++i)
+ EltTys.push_back(getOrCreateType(FPT->getArgType(i), Unit));
+ }
+
+ llvm::DIArray EltTypeArray = DBuilder.getOrCreateArray(EltTys);
+ return DBuilder.createSubroutineType(Unit, EltTypeArray);
+}
+
+
+void CGDebugInfo::
+CollectRecordStaticVars(const RecordDecl *RD, llvm::DIType FwdDecl) {
+
+ for (RecordDecl::decl_iterator I = RD->decls_begin(), E = RD->decls_end();
+ I != E; ++I)
+ if (const VarDecl *V = dyn_cast<VarDecl>(*I)) {
+ if (V->getInit()) {
+ const APValue *Value = V->evaluateValue();
+ if (Value && Value->isInt()) {
+ llvm::ConstantInt *CI
+ = llvm::ConstantInt::get(CGM.getLLVMContext(), Value->getInt());
+
+ // Create the descriptor for static variable.
+ llvm::DIFile VUnit = getOrCreateFile(V->getLocation());
+ StringRef VName = V->getName();
+ llvm::DIType VTy = getOrCreateType(V->getType(), VUnit);
+ // Do not use DIGlobalVariable for enums.
+ if (VTy.getTag() != llvm::dwarf::DW_TAG_enumeration_type) {
+ DBuilder.createStaticVariable(FwdDecl, VName, VName, VUnit,
+ getLineNumber(V->getLocation()),
+ VTy, true, CI);
+ }
+ }
+ }
+ }
+}
+
+llvm::DIType CGDebugInfo::createFieldType(StringRef name,
+ QualType type,
+ uint64_t sizeInBitsOverride,
+ SourceLocation loc,
+ AccessSpecifier AS,
+ uint64_t offsetInBits,
+ llvm::DIFile tunit,
+ llvm::DIDescriptor scope) {
+ llvm::DIType debugType = getOrCreateType(type, tunit);
+
+ // Get the location for the field.
+ llvm::DIFile file = getOrCreateFile(loc);
+ unsigned line = getLineNumber(loc);
+
+ uint64_t sizeInBits = 0;
+ unsigned alignInBits = 0;
+ if (!type->isIncompleteArrayType()) {
+ llvm::tie(sizeInBits, alignInBits) = CGM.getContext().getTypeInfo(type);
+
+ if (sizeInBitsOverride)
+ sizeInBits = sizeInBitsOverride;
+ }
+
+ unsigned flags = 0;
+ if (AS == clang::AS_private)
+ flags |= llvm::DIDescriptor::FlagPrivate;
+ else if (AS == clang::AS_protected)
+ flags |= llvm::DIDescriptor::FlagProtected;
+
+ return DBuilder.createMemberType(scope, name, file, line, sizeInBits,
+ alignInBits, offsetInBits, flags, debugType);
+}
+
+/// CollectRecordFields - A helper function to collect debug info for
+/// record fields. This is used while creating debug info entry for a Record.
+void CGDebugInfo::
+CollectRecordFields(const RecordDecl *record, llvm::DIFile tunit,
+ SmallVectorImpl<llvm::Value *> &elements,
+ llvm::DIType RecordTy) {
+ unsigned fieldNo = 0;
+ const ASTRecordLayout &layout = CGM.getContext().getASTRecordLayout(record);
+ const CXXRecordDecl *CXXDecl = dyn_cast<CXXRecordDecl>(record);
+
+ // For C++11 Lambdas a Field will be the same as a Capture, but the Capture
+ // has the name and the location of the variable so we should iterate over
+ // both concurrently.
+ if (CXXDecl && CXXDecl->isLambda()) {
+ RecordDecl::field_iterator Field = CXXDecl->field_begin();
+ unsigned fieldno = 0;
+ for (CXXRecordDecl::capture_const_iterator I = CXXDecl->captures_begin(),
+ E = CXXDecl->captures_end(); I != E; ++I, ++Field, ++fieldno) {
+ const LambdaExpr::Capture C = *I;
+ if (C.capturesVariable()) {
+ VarDecl *V = C.getCapturedVar();
+ llvm::DIFile VUnit = getOrCreateFile(C.getLocation());
+ StringRef VName = V->getName();
+ uint64_t SizeInBitsOverride = 0;
+ if (Field->isBitField()) {
+ SizeInBitsOverride = Field->getBitWidthValue(CGM.getContext());
+ assert(SizeInBitsOverride && "found named 0-width bitfield");
+ }
+ llvm::DIType fieldType
+ = createFieldType(VName, Field->getType(), SizeInBitsOverride, C.getLocation(),
+ Field->getAccess(), layout.getFieldOffset(fieldno),
+ VUnit, RecordTy);
+ elements.push_back(fieldType);
+ } else {
+ // TODO: Need to handle 'this' in some way by probably renaming the
+ // this of the lambda class and having a field member of 'this' or
+ // by using AT_object_pointer for the function and having that be
+ // used as 'this' for semantic references.
+ assert(C.capturesThis() && "Field that isn't captured and isn't this?");
+ FieldDecl *f = *Field;
+ llvm::DIFile VUnit = getOrCreateFile(f->getLocation());
+ QualType type = f->getType();
+ llvm::DIType fieldType
+ = createFieldType("this", type, 0, f->getLocation(), f->getAccess(),
+ layout.getFieldOffset(fieldNo), VUnit, RecordTy);
+
+ elements.push_back(fieldType);
+ }
+ }
+ } else {
+ bool IsMsStruct = record->isMsStruct(CGM.getContext());
+ const FieldDecl *LastFD = 0;
+ for (RecordDecl::field_iterator I = record->field_begin(),
+ E = record->field_end();
+ I != E; ++I, ++fieldNo) {
+ FieldDecl *field = *I;
+
+ if (IsMsStruct) {
+ // Zero-length bitfields following non-bitfield members are ignored
+ if (CGM.getContext().ZeroBitfieldFollowsNonBitfield((field), LastFD)) {
+ --fieldNo;
+ continue;
+ }
+ LastFD = field;
+ }
+
+ StringRef name = field->getName();
+ QualType type = field->getType();
+
+ // Ignore unnamed fields unless they're anonymous structs/unions.
+ if (name.empty() && !type->isRecordType()) {
+ LastFD = field;
+ continue;
+ }
+
+ uint64_t SizeInBitsOverride = 0;
+ if (field->isBitField()) {
+ SizeInBitsOverride = field->getBitWidthValue(CGM.getContext());
+ assert(SizeInBitsOverride && "found named 0-width bitfield");
+ }
+
+ llvm::DIType fieldType
+ = createFieldType(name, type, SizeInBitsOverride,
+ field->getLocation(), field->getAccess(),
+ layout.getFieldOffset(fieldNo), tunit, RecordTy);
+
+ elements.push_back(fieldType);
+ }
+ }
+}
+
+/// getOrCreateMethodType - CXXMethodDecl's type is a FunctionType. This
+/// function type is not updated to include implicit "this" pointer. Use this
+/// routine to get a method type which includes "this" pointer.
+llvm::DIType
+CGDebugInfo::getOrCreateMethodType(const CXXMethodDecl *Method,
+ llvm::DIFile Unit) {
+ llvm::DIType FnTy
+ = getOrCreateType(QualType(Method->getType()->getAs<FunctionProtoType>(),
+ 0),
+ Unit);
+
+ // Add "this" pointer.
+ llvm::DIArray Args = llvm::DICompositeType(FnTy).getTypeArray();
+ assert (Args.getNumElements() && "Invalid number of arguments!");
+
+ SmallVector<llvm::Value *, 16> Elts;
+
+ // First element is always return type. For 'void' functions it is NULL.
+ Elts.push_back(Args.getElement(0));
+
+ if (!Method->isStatic()) {
+ // "this" pointer is always first argument.
+ QualType ThisPtr = Method->getThisType(CGM.getContext());
+
+ const CXXRecordDecl *RD = Method->getParent();
+ if (isa<ClassTemplateSpecializationDecl>(RD)) {
+ // Create pointer type directly in this case.
+ const PointerType *ThisPtrTy = cast<PointerType>(ThisPtr);
+ QualType PointeeTy = ThisPtrTy->getPointeeType();
+ unsigned AS = CGM.getContext().getTargetAddressSpace(PointeeTy);
+ uint64_t Size = CGM.getContext().getTargetInfo().getPointerWidth(AS);
+ uint64_t Align = CGM.getContext().getTypeAlign(ThisPtrTy);
+ llvm::DIType PointeeType = getOrCreateType(PointeeTy, Unit);
+ llvm::DIType ThisPtrType = DBuilder.createPointerType(PointeeType, Size, Align);
+ TypeCache[ThisPtr.getAsOpaquePtr()] = ThisPtrType;
+ // TODO: This and the artificial type below are misleading, the
+ // types aren't artificial the argument is, but the current
+ // metadata doesn't represent that.
+ ThisPtrType = DBuilder.createObjectPointerType(ThisPtrType);
+ Elts.push_back(ThisPtrType);
+ } else {
+ llvm::DIType ThisPtrType = getOrCreateType(ThisPtr, Unit);
+ TypeCache[ThisPtr.getAsOpaquePtr()] = ThisPtrType;
+ ThisPtrType = DBuilder.createObjectPointerType(ThisPtrType);
+ Elts.push_back(ThisPtrType);
+ }
+ }
+
+ // Copy rest of the arguments.
+ for (unsigned i = 1, e = Args.getNumElements(); i != e; ++i)
+ Elts.push_back(Args.getElement(i));
+
+ llvm::DIArray EltTypeArray = DBuilder.getOrCreateArray(Elts);
+
+ return DBuilder.createSubroutineType(Unit, EltTypeArray);
+}
+
+/// isFunctionLocalClass - Return true if CXXRecordDecl is defined
+/// inside a function.
+static bool isFunctionLocalClass(const CXXRecordDecl *RD) {
+ if (const CXXRecordDecl *NRD = dyn_cast<CXXRecordDecl>(RD->getDeclContext()))
+ return isFunctionLocalClass(NRD);
+ if (isa<FunctionDecl>(RD->getDeclContext()))
+ return true;
+ return false;
+}
+
+/// CreateCXXMemberFunction - A helper function to create a DISubprogram for
+/// a single member function GlobalDecl.
+llvm::DISubprogram
+CGDebugInfo::CreateCXXMemberFunction(const CXXMethodDecl *Method,
+ llvm::DIFile Unit,
+ llvm::DIType RecordTy) {
+ bool IsCtorOrDtor =
+ isa<CXXConstructorDecl>(Method) || isa<CXXDestructorDecl>(Method);
+
+ StringRef MethodName = getFunctionName(Method);
+ llvm::DIType MethodTy = getOrCreateMethodType(Method, Unit);
+
+ // Since a single ctor/dtor corresponds to multiple functions, it doesn't
+ // make sense to give a single ctor/dtor a linkage name.
+ StringRef MethodLinkageName;
+ if (!IsCtorOrDtor && !isFunctionLocalClass(Method->getParent()))
+ MethodLinkageName = CGM.getMangledName(Method);
+
+ // Get the location for the method.
+ llvm::DIFile MethodDefUnit = getOrCreateFile(Method->getLocation());
+ unsigned MethodLine = getLineNumber(Method->getLocation());
+
+ // Collect virtual method info.
+ llvm::DIType ContainingType;
+ unsigned Virtuality = 0;
+ unsigned VIndex = 0;
+
+ if (Method->isVirtual()) {
+ if (Method->isPure())
+ Virtuality = llvm::dwarf::DW_VIRTUALITY_pure_virtual;
+ else
+ Virtuality = llvm::dwarf::DW_VIRTUALITY_virtual;
+
+ // It doesn't make sense to give a virtual destructor a vtable index,
+ // since a single destructor has two entries in the vtable.
+ if (!isa<CXXDestructorDecl>(Method))
+ VIndex = CGM.getVTableContext().getMethodVTableIndex(Method);
+ ContainingType = RecordTy;
+ }
+
+ unsigned Flags = 0;
+ if (Method->isImplicit())
+ Flags |= llvm::DIDescriptor::FlagArtificial;
+ AccessSpecifier Access = Method->getAccess();
+ if (Access == clang::AS_private)
+ Flags |= llvm::DIDescriptor::FlagPrivate;
+ else if (Access == clang::AS_protected)
+ Flags |= llvm::DIDescriptor::FlagProtected;
+ if (const CXXConstructorDecl *CXXC = dyn_cast<CXXConstructorDecl>(Method)) {
+ if (CXXC->isExplicit())
+ Flags |= llvm::DIDescriptor::FlagExplicit;
+ } else if (const CXXConversionDecl *CXXC =
+ dyn_cast<CXXConversionDecl>(Method)) {
+ if (CXXC->isExplicit())
+ Flags |= llvm::DIDescriptor::FlagExplicit;
+ }
+ if (Method->hasPrototype())
+ Flags |= llvm::DIDescriptor::FlagPrototyped;
+
+ llvm::DIArray TParamsArray = CollectFunctionTemplateParams(Method, Unit);
+ llvm::DISubprogram SP =
+ DBuilder.createMethod(RecordTy, MethodName, MethodLinkageName,
+ MethodDefUnit, MethodLine,
+ MethodTy, /*isLocalToUnit=*/false,
+ /* isDefinition=*/ false,
+ Virtuality, VIndex, ContainingType,
+ Flags, CGM.getLangOpts().Optimize, NULL,
+ TParamsArray);
+
+ SPCache[Method->getCanonicalDecl()] = llvm::WeakVH(SP);
+
+ return SP;
+}
+
+/// CollectCXXMemberFunctions - A helper function to collect debug info for
+/// C++ member functions. This is used while creating debug info entry for
+/// a Record.
+void CGDebugInfo::
+CollectCXXMemberFunctions(const CXXRecordDecl *RD, llvm::DIFile Unit,
+ SmallVectorImpl<llvm::Value *> &EltTys,
+ llvm::DIType RecordTy) {
+
+ // Since we want more than just the individual member decls if we
+ // have templated functions iterate over every declaration to gather
+ // the functions.
+ for(DeclContext::decl_iterator I = RD->decls_begin(),
+ E = RD->decls_end(); I != E; ++I) {
+ Decl *D = *I;
+ if (D->isImplicit() && !D->isUsed())
+ continue;
+
+ if (const CXXMethodDecl *Method = dyn_cast<CXXMethodDecl>(D))
+ EltTys.push_back(CreateCXXMemberFunction(Method, Unit, RecordTy));
+ else if (FunctionTemplateDecl *FTD = dyn_cast<FunctionTemplateDecl>(D))
+ for (FunctionTemplateDecl::spec_iterator SI = FTD->spec_begin(),
+ SE = FTD->spec_end(); SI != SE; ++SI)
+ EltTys.push_back(CreateCXXMemberFunction(cast<CXXMethodDecl>(*SI), Unit,
+ RecordTy));
+ }
+}
+
+/// CollectCXXFriends - A helper function to collect debug info for
+/// C++ base classes. This is used while creating debug info entry for
+/// a Record.
+void CGDebugInfo::
+CollectCXXFriends(const CXXRecordDecl *RD, llvm::DIFile Unit,
+ SmallVectorImpl<llvm::Value *> &EltTys,
+ llvm::DIType RecordTy) {
+ for (CXXRecordDecl::friend_iterator BI = RD->friend_begin(),
+ BE = RD->friend_end(); BI != BE; ++BI) {
+ if ((*BI)->isUnsupportedFriend())
+ continue;
+ if (TypeSourceInfo *TInfo = (*BI)->getFriendType())
+ EltTys.push_back(DBuilder.createFriend(RecordTy,
+ getOrCreateType(TInfo->getType(),
+ Unit)));
+ }
+}
+
+/// CollectCXXBases - A helper function to collect debug info for
+/// C++ base classes. This is used while creating debug info entry for
+/// a Record.
+void CGDebugInfo::
+CollectCXXBases(const CXXRecordDecl *RD, llvm::DIFile Unit,
+ SmallVectorImpl<llvm::Value *> &EltTys,
+ llvm::DIType RecordTy) {
+
+ const ASTRecordLayout &RL = CGM.getContext().getASTRecordLayout(RD);
+ for (CXXRecordDecl::base_class_const_iterator BI = RD->bases_begin(),
+ BE = RD->bases_end(); BI != BE; ++BI) {
+ unsigned BFlags = 0;
+ uint64_t BaseOffset;
+
+ const CXXRecordDecl *Base =
+ cast<CXXRecordDecl>(BI->getType()->getAs<RecordType>()->getDecl());
+
+ if (BI->isVirtual()) {
+ // virtual base offset offset is -ve. The code generator emits dwarf
+ // expression where it expects +ve number.
+ BaseOffset =
+ 0 - CGM.getVTableContext()
+ .getVirtualBaseOffsetOffset(RD, Base).getQuantity();
+ BFlags = llvm::DIDescriptor::FlagVirtual;
+ } else
+ BaseOffset = CGM.getContext().toBits(RL.getBaseClassOffset(Base));
+ // FIXME: Inconsistent units for BaseOffset. It is in bytes when
+ // BI->isVirtual() and bits when not.
+
+ AccessSpecifier Access = BI->getAccessSpecifier();
+ if (Access == clang::AS_private)
+ BFlags |= llvm::DIDescriptor::FlagPrivate;
+ else if (Access == clang::AS_protected)
+ BFlags |= llvm::DIDescriptor::FlagProtected;
+
+ llvm::DIType DTy =
+ DBuilder.createInheritance(RecordTy,
+ getOrCreateType(BI->getType(), Unit),
+ BaseOffset, BFlags);
+ EltTys.push_back(DTy);
+ }
+}
+
+/// CollectTemplateParams - A helper function to collect template parameters.
+llvm::DIArray CGDebugInfo::
+CollectTemplateParams(const TemplateParameterList *TPList,
+ const TemplateArgumentList &TAList,
+ llvm::DIFile Unit) {
+ SmallVector<llvm::Value *, 16> TemplateParams;
+ for (unsigned i = 0, e = TAList.size(); i != e; ++i) {
+ const TemplateArgument &TA = TAList[i];
+ const NamedDecl *ND = TPList->getParam(i);
+ if (TA.getKind() == TemplateArgument::Type) {
+ llvm::DIType TTy = getOrCreateType(TA.getAsType(), Unit);
+ llvm::DITemplateTypeParameter TTP =
+ DBuilder.createTemplateTypeParameter(TheCU, ND->getName(), TTy);
+ TemplateParams.push_back(TTP);
+ } else if (TA.getKind() == TemplateArgument::Integral) {
+ llvm::DIType TTy = getOrCreateType(TA.getIntegralType(), Unit);
+ llvm::DITemplateValueParameter TVP =
+ DBuilder.createTemplateValueParameter(TheCU, ND->getName(), TTy,
+ TA.getAsIntegral().getZExtValue());
+ TemplateParams.push_back(TVP);
+ }
+ }
+ return DBuilder.getOrCreateArray(TemplateParams);
+}
+
+/// CollectFunctionTemplateParams - A helper function to collect debug
+/// info for function template parameters.
+llvm::DIArray CGDebugInfo::
+CollectFunctionTemplateParams(const FunctionDecl *FD, llvm::DIFile Unit) {
+ if (FD->getTemplatedKind() ==
+ FunctionDecl::TK_FunctionTemplateSpecialization) {
+ const TemplateParameterList *TList =
+ FD->getTemplateSpecializationInfo()->getTemplate()
+ ->getTemplateParameters();
+ return
+ CollectTemplateParams(TList, *FD->getTemplateSpecializationArgs(), Unit);
+ }
+ return llvm::DIArray();
+}
+
+/// CollectCXXTemplateParams - A helper function to collect debug info for
+/// template parameters.
+llvm::DIArray CGDebugInfo::
+CollectCXXTemplateParams(const ClassTemplateSpecializationDecl *TSpecial,
+ llvm::DIFile Unit) {
+ llvm::PointerUnion<ClassTemplateDecl *,
+ ClassTemplatePartialSpecializationDecl *>
+ PU = TSpecial->getSpecializedTemplateOrPartial();
+
+ TemplateParameterList *TPList = PU.is<ClassTemplateDecl *>() ?
+ PU.get<ClassTemplateDecl *>()->getTemplateParameters() :
+ PU.get<ClassTemplatePartialSpecializationDecl *>()->getTemplateParameters();
+ const TemplateArgumentList &TAList = TSpecial->getTemplateInstantiationArgs();
+ return CollectTemplateParams(TPList, TAList, Unit);
+}
+
+/// getOrCreateVTablePtrType - Return debug info descriptor for vtable.
+llvm::DIType CGDebugInfo::getOrCreateVTablePtrType(llvm::DIFile Unit) {
+ if (VTablePtrType.isValid())
+ return VTablePtrType;
+
+ ASTContext &Context = CGM.getContext();
+
+ /* Function type */
+ llvm::Value *STy = getOrCreateType(Context.IntTy, Unit);
+ llvm::DIArray SElements = DBuilder.getOrCreateArray(STy);
+ llvm::DIType SubTy = DBuilder.createSubroutineType(Unit, SElements);
+ unsigned Size = Context.getTypeSize(Context.VoidPtrTy);
+ llvm::DIType vtbl_ptr_type = DBuilder.createPointerType(SubTy, Size, 0,
+ "__vtbl_ptr_type");
+ VTablePtrType = DBuilder.createPointerType(vtbl_ptr_type, Size);
+ return VTablePtrType;
+}
+
+/// getVTableName - Get vtable name for the given Class.
+StringRef CGDebugInfo::getVTableName(const CXXRecordDecl *RD) {
+ // Construct gdb compatible name name.
+ std::string Name = "_vptr$" + RD->getNameAsString();
+
+ // Copy this name on the side and use its reference.
+ char *StrPtr = DebugInfoNames.Allocate<char>(Name.length());
+ memcpy(StrPtr, Name.data(), Name.length());
+ return StringRef(StrPtr, Name.length());
+}
+
+
+/// CollectVTableInfo - If the C++ class has vtable info then insert appropriate
+/// debug info entry in EltTys vector.
+void CGDebugInfo::
+CollectVTableInfo(const CXXRecordDecl *RD, llvm::DIFile Unit,
+ SmallVectorImpl<llvm::Value *> &EltTys) {
+ const ASTRecordLayout &RL = CGM.getContext().getASTRecordLayout(RD);
+
+ // If there is a primary base then it will hold vtable info.
+ if (RL.getPrimaryBase())
+ return;
+
+ // If this class is not dynamic then there is not any vtable info to collect.
+ if (!RD->isDynamicClass())
+ return;
+
+ unsigned Size = CGM.getContext().getTypeSize(CGM.getContext().VoidPtrTy);
+ llvm::DIType VPTR
+ = DBuilder.createMemberType(Unit, getVTableName(RD), Unit,
+ 0, Size, 0, 0, llvm::DIDescriptor::FlagArtificial,
+ getOrCreateVTablePtrType(Unit));
+ EltTys.push_back(VPTR);
+}
+
+/// getOrCreateRecordType - Emit record type's standalone debug info.
+llvm::DIType CGDebugInfo::getOrCreateRecordType(QualType RTy,
+ SourceLocation Loc) {
+ assert(CGM.getCodeGenOpts().getDebugInfo() >= CodeGenOptions::LimitedDebugInfo);
+ llvm::DIType T = getOrCreateType(RTy, getOrCreateFile(Loc));
+ return T;
+}
+
+/// getOrCreateInterfaceType - Emit an objective c interface type standalone
+/// debug info.
+llvm::DIType CGDebugInfo::getOrCreateInterfaceType(QualType D,
+ SourceLocation Loc) {
+ assert(CGM.getCodeGenOpts().getDebugInfo() >= CodeGenOptions::LimitedDebugInfo);
+ llvm::DIType T = getOrCreateType(D, getOrCreateFile(Loc));
+ DBuilder.retainType(T);
+ return T;
+}
+
+/// CreateType - get structure or union type.
+llvm::DIType CGDebugInfo::CreateType(const RecordType *Ty) {
+ RecordDecl *RD = Ty->getDecl();
+
+ // Get overall information about the record type for the debug info.
+ llvm::DIFile DefUnit = getOrCreateFile(RD->getLocation());
+
+ // Records and classes and unions can all be recursive. To handle them, we
+ // first generate a debug descriptor for the struct as a forward declaration.
+ // Then (if it is a definition) we go through and get debug info for all of
+ // its members. Finally, we create a descriptor for the complete type (which
+ // may refer to the forward decl if the struct is recursive) and replace all
+ // uses of the forward declaration with the final definition.
+
+ llvm::DIType FwdDecl = getOrCreateLimitedType(QualType(Ty, 0), DefUnit);
+
+ if (FwdDecl.isForwardDecl())
+ return FwdDecl;
+
+ llvm::TrackingVH<llvm::MDNode> FwdDeclNode(FwdDecl);
+
+ // Push the struct on region stack.
+ LexicalBlockStack.push_back(FwdDeclNode);
+ RegionMap[Ty->getDecl()] = llvm::WeakVH(FwdDecl);
+
+ // Add this to the completed types cache since we're completing it.
+ CompletedTypeCache[QualType(Ty, 0).getAsOpaquePtr()] = FwdDecl;
+
+ // Convert all the elements.
+ SmallVector<llvm::Value *, 16> EltTys;
+
+ // Note: The split of CXXDecl information here is intentional, the
+ // gdb tests will depend on a certain ordering at printout. The debug
+ // information offsets are still correct if we merge them all together
+ // though.
+ const CXXRecordDecl *CXXDecl = dyn_cast<CXXRecordDecl>(RD);
+ if (CXXDecl) {
+ CollectCXXBases(CXXDecl, DefUnit, EltTys, FwdDecl);
+ CollectVTableInfo(CXXDecl, DefUnit, EltTys);
+ }
+
+ // Collect static variables with initializers and other fields.
+ CollectRecordStaticVars(RD, FwdDecl);
+ CollectRecordFields(RD, DefUnit, EltTys, FwdDecl);
+ llvm::DIArray TParamsArray;
+ if (CXXDecl) {
+ CollectCXXMemberFunctions(CXXDecl, DefUnit, EltTys, FwdDecl);
+ CollectCXXFriends(CXXDecl, DefUnit, EltTys, FwdDecl);
+ if (const ClassTemplateSpecializationDecl *TSpecial
+ = dyn_cast<ClassTemplateSpecializationDecl>(RD))
+ TParamsArray = CollectCXXTemplateParams(TSpecial, DefUnit);
+ }
+
+ LexicalBlockStack.pop_back();
+ RegionMap.erase(Ty->getDecl());
+
+ llvm::DIArray Elements = DBuilder.getOrCreateArray(EltTys);
+ // FIXME: Magic numbers ahoy! These should be changed when we
+ // get some enums in llvm/Analysis/DebugInfo.h to refer to
+ // them.
+ if (RD->isUnion())
+ FwdDeclNode->replaceOperandWith(10, Elements);
+ else if (CXXDecl) {
+ FwdDeclNode->replaceOperandWith(10, Elements);
+ FwdDeclNode->replaceOperandWith(13, TParamsArray);
+ } else
+ FwdDeclNode->replaceOperandWith(10, Elements);
+
+ RegionMap[Ty->getDecl()] = llvm::WeakVH(FwdDeclNode);
+ return llvm::DIType(FwdDeclNode);
+}
+
+/// CreateType - get objective-c object type.
+llvm::DIType CGDebugInfo::CreateType(const ObjCObjectType *Ty,
+ llvm::DIFile Unit) {
+ // Ignore protocols.
+ return getOrCreateType(Ty->getBaseType(), Unit);
+}
+
+/// CreateType - get objective-c interface type.
+llvm::DIType CGDebugInfo::CreateType(const ObjCInterfaceType *Ty,
+ llvm::DIFile Unit) {
+ ObjCInterfaceDecl *ID = Ty->getDecl();
+ if (!ID)
+ return llvm::DIType();
+
+ // Get overall information about the record type for the debug info.
+ llvm::DIFile DefUnit = getOrCreateFile(ID->getLocation());
+ unsigned Line = getLineNumber(ID->getLocation());
+ unsigned RuntimeLang = TheCU.getLanguage();
+
+ // If this is just a forward declaration return a special forward-declaration
+ // debug type since we won't be able to lay out the entire type.
+ ObjCInterfaceDecl *Def = ID->getDefinition();
+ if (!Def) {
+ llvm::DIType FwdDecl =
+ DBuilder.createForwardDecl(llvm::dwarf::DW_TAG_structure_type,
+ ID->getName(), TheCU, DefUnit, Line,
+ RuntimeLang);
+ return FwdDecl;
+ }
+
+ ID = Def;
+
+ // Bit size, align and offset of the type.
+ uint64_t Size = CGM.getContext().getTypeSize(Ty);
+ uint64_t Align = CGM.getContext().getTypeAlign(Ty);
+
+ unsigned Flags = 0;
+ if (ID->getImplementation())
+ Flags |= llvm::DIDescriptor::FlagObjcClassComplete;
+
+ llvm::DIType RealDecl =
+ DBuilder.createStructType(Unit, ID->getName(), DefUnit,
+ Line, Size, Align, Flags,
+ llvm::DIArray(), RuntimeLang);
+
+ // Otherwise, insert it into the CompletedTypeCache so that recursive uses
+ // will find it and we're emitting the complete type.
+ CompletedTypeCache[QualType(Ty, 0).getAsOpaquePtr()] = RealDecl;
+ // Push the struct on region stack.
+ llvm::TrackingVH<llvm::MDNode> FwdDeclNode(RealDecl);
+
+ LexicalBlockStack.push_back(FwdDeclNode);
+ RegionMap[Ty->getDecl()] = llvm::WeakVH(RealDecl);
+
+ // Convert all the elements.
+ SmallVector<llvm::Value *, 16> EltTys;
+
+ ObjCInterfaceDecl *SClass = ID->getSuperClass();
+ if (SClass) {
+ llvm::DIType SClassTy =
+ getOrCreateType(CGM.getContext().getObjCInterfaceType(SClass), Unit);
+ if (!SClassTy.isValid())
+ return llvm::DIType();
+
+ llvm::DIType InhTag =
+ DBuilder.createInheritance(RealDecl, SClassTy, 0, 0);
+ EltTys.push_back(InhTag);
+ }
+
+ for (ObjCContainerDecl::prop_iterator I = ID->prop_begin(),
+ E = ID->prop_end(); I != E; ++I) {
+ const ObjCPropertyDecl *PD = *I;
+ SourceLocation Loc = PD->getLocation();
+ llvm::DIFile PUnit = getOrCreateFile(Loc);
+ unsigned PLine = getLineNumber(Loc);
+ ObjCMethodDecl *Getter = PD->getGetterMethodDecl();
+ ObjCMethodDecl *Setter = PD->getSetterMethodDecl();
+ llvm::MDNode *PropertyNode =
+ DBuilder.createObjCProperty(PD->getName(),
+ PUnit, PLine,
+ (Getter && Getter->isImplicit()) ? "" :
+ getSelectorName(PD->getGetterName()),
+ (Setter && Setter->isImplicit()) ? "" :
+ getSelectorName(PD->getSetterName()),
+ PD->getPropertyAttributes(),
+ getOrCreateType(PD->getType(), PUnit));
+ EltTys.push_back(PropertyNode);
+ }
+
+ const ASTRecordLayout &RL = CGM.getContext().getASTObjCInterfaceLayout(ID);
+ unsigned FieldNo = 0;
+ for (ObjCIvarDecl *Field = ID->all_declared_ivar_begin(); Field;
+ Field = Field->getNextIvar(), ++FieldNo) {
+ llvm::DIType FieldTy = getOrCreateType(Field->getType(), Unit);
+ if (!FieldTy.isValid())
+ return llvm::DIType();
+
+ StringRef FieldName = Field->getName();
+
+ // Ignore unnamed fields.
+ if (FieldName.empty())
+ continue;
+
+ // Get the location for the field.
+ llvm::DIFile FieldDefUnit = getOrCreateFile(Field->getLocation());
+ unsigned FieldLine = getLineNumber(Field->getLocation());
+ QualType FType = Field->getType();
+ uint64_t FieldSize = 0;
+ unsigned FieldAlign = 0;
+
+ if (!FType->isIncompleteArrayType()) {
+
+ // Bit size, align and offset of the type.
+ FieldSize = Field->isBitField()
+ ? Field->getBitWidthValue(CGM.getContext())
+ : CGM.getContext().getTypeSize(FType);
+ FieldAlign = CGM.getContext().getTypeAlign(FType);
+ }
+
+ uint64_t FieldOffset;
+ if (CGM.getLangOpts().ObjCRuntime.isNonFragile()) {
+ // We don't know the runtime offset of an ivar if we're using the
+ // non-fragile ABI. For bitfields, use the bit offset into the first
+ // byte of storage of the bitfield. For other fields, use zero.
+ if (Field->isBitField()) {
+ FieldOffset = CGM.getObjCRuntime().ComputeBitfieldBitOffset(
+ CGM, ID, Field);
+ FieldOffset %= CGM.getContext().getCharWidth();
+ } else {
+ FieldOffset = 0;
+ }
+ } else {
+ FieldOffset = RL.getFieldOffset(FieldNo);
+ }
+
+ unsigned Flags = 0;
+ if (Field->getAccessControl() == ObjCIvarDecl::Protected)
+ Flags = llvm::DIDescriptor::FlagProtected;
+ else if (Field->getAccessControl() == ObjCIvarDecl::Private)
+ Flags = llvm::DIDescriptor::FlagPrivate;
+
+ llvm::MDNode *PropertyNode = NULL;
+ if (ObjCImplementationDecl *ImpD = ID->getImplementation()) {
+ if (ObjCPropertyImplDecl *PImpD =
+ ImpD->FindPropertyImplIvarDecl(Field->getIdentifier())) {
+ if (ObjCPropertyDecl *PD = PImpD->getPropertyDecl()) {
+ SourceLocation Loc = PD->getLocation();
+ llvm::DIFile PUnit = getOrCreateFile(Loc);
+ unsigned PLine = getLineNumber(Loc);
+ ObjCMethodDecl *Getter = PD->getGetterMethodDecl();
+ ObjCMethodDecl *Setter = PD->getSetterMethodDecl();
+ PropertyNode =
+ DBuilder.createObjCProperty(PD->getName(),
+ PUnit, PLine,
+ (Getter && Getter->isImplicit()) ? "" :
+ getSelectorName(PD->getGetterName()),
+ (Setter && Setter->isImplicit()) ? "" :
+ getSelectorName(PD->getSetterName()),
+ PD->getPropertyAttributes(),
+ getOrCreateType(PD->getType(), PUnit));
+ }
+ }
+ }
+ FieldTy = DBuilder.createObjCIVar(FieldName, FieldDefUnit,
+ FieldLine, FieldSize, FieldAlign,
+ FieldOffset, Flags, FieldTy,
+ PropertyNode);
+ EltTys.push_back(FieldTy);
+ }
+
+ llvm::DIArray Elements = DBuilder.getOrCreateArray(EltTys);
+ FwdDeclNode->replaceOperandWith(10, Elements);
+
+ LexicalBlockStack.pop_back();
+ return llvm::DIType(FwdDeclNode);
+}
+
+llvm::DIType CGDebugInfo::CreateType(const VectorType *Ty, llvm::DIFile Unit) {
+ llvm::DIType ElementTy = getOrCreateType(Ty->getElementType(), Unit);
+ int64_t Count = Ty->getNumElements();
+ if (Count == 0)
+ // If number of elements are not known then this is an unbounded array.
+ // Use Count == -1 to express such arrays.
+ Count = -1;
+
+ llvm::Value *Subscript = DBuilder.getOrCreateSubrange(0, Count);
+ llvm::DIArray SubscriptArray = DBuilder.getOrCreateArray(Subscript);
+
+ uint64_t Size = CGM.getContext().getTypeSize(Ty);
+ uint64_t Align = CGM.getContext().getTypeAlign(Ty);
+
+ return DBuilder.createVectorType(Size, Align, ElementTy, SubscriptArray);
+}
+
+llvm::DIType CGDebugInfo::CreateType(const ArrayType *Ty,
+ llvm::DIFile Unit) {
+ uint64_t Size;
+ uint64_t Align;
+
+ // FIXME: make getTypeAlign() aware of VLAs and incomplete array types
+ if (const VariableArrayType *VAT = dyn_cast<VariableArrayType>(Ty)) {
+ Size = 0;
+ Align =
+ CGM.getContext().getTypeAlign(CGM.getContext().getBaseElementType(VAT));
+ } else if (Ty->isIncompleteArrayType()) {
+ Size = 0;
+ if (Ty->getElementType()->isIncompleteType())
+ Align = 0;
+ else
+ Align = CGM.getContext().getTypeAlign(Ty->getElementType());
+ } else if (Ty->isDependentSizedArrayType() || Ty->isIncompleteType()) {
+ Size = 0;
+ Align = 0;
+ } else {
+ // Size and align of the whole array, not the element type.
+ Size = CGM.getContext().getTypeSize(Ty);
+ Align = CGM.getContext().getTypeAlign(Ty);
+ }
+
+ // Add the dimensions of the array. FIXME: This loses CV qualifiers from
+ // interior arrays, do we care? Why aren't nested arrays represented the
+ // obvious/recursive way?
+ SmallVector<llvm::Value *, 8> Subscripts;
+ QualType EltTy(Ty, 0);
+ while ((Ty = dyn_cast<ArrayType>(EltTy))) {
+ // If the number of elements is known, then count is that number. Otherwise,
+ // it's -1. This allows us to represent a subrange with an array of 0
+ // elements, like this:
+ //
+ // struct foo {
+ // int x[0];
+ // };
+ int64_t Count = -1; // Count == -1 is an unbounded array.
+ if (const ConstantArrayType *CAT = dyn_cast<ConstantArrayType>(Ty))
+ Count = CAT->getSize().getZExtValue();
+
+ // FIXME: Verify this is right for VLAs.
+ Subscripts.push_back(DBuilder.getOrCreateSubrange(0, Count));
+ EltTy = Ty->getElementType();
+ }
+
+ llvm::DIArray SubscriptArray = DBuilder.getOrCreateArray(Subscripts);
+
+ llvm::DIType DbgTy =
+ DBuilder.createArrayType(Size, Align, getOrCreateType(EltTy, Unit),
+ SubscriptArray);
+ return DbgTy;
+}
+
+llvm::DIType CGDebugInfo::CreateType(const LValueReferenceType *Ty,
+ llvm::DIFile Unit) {
+ return CreatePointerLikeType(llvm::dwarf::DW_TAG_reference_type,
+ Ty, Ty->getPointeeType(), Unit);
+}
+
+llvm::DIType CGDebugInfo::CreateType(const RValueReferenceType *Ty,
+ llvm::DIFile Unit) {
+ return CreatePointerLikeType(llvm::dwarf::DW_TAG_rvalue_reference_type,
+ Ty, Ty->getPointeeType(), Unit);
+}
+
+llvm::DIType CGDebugInfo::CreateType(const MemberPointerType *Ty,
+ llvm::DIFile U) {
+ QualType PointerDiffTy = CGM.getContext().getPointerDiffType();
+ llvm::DIType PointerDiffDITy = getOrCreateType(PointerDiffTy, U);
+
+ if (!Ty->getPointeeType()->isFunctionType()) {
+ // We have a data member pointer type.
+ return PointerDiffDITy;
+ }
+
+ // We have a member function pointer type. Treat it as a struct with two
+ // ptrdiff_t members.
+ std::pair<uint64_t, unsigned> Info = CGM.getContext().getTypeInfo(Ty);
+
+ uint64_t FieldOffset = 0;
+ llvm::Value *ElementTypes[2];
+
+ // FIXME: This should be a DW_TAG_pointer_to_member type.
+ ElementTypes[0] =
+ DBuilder.createMemberType(U, "ptr", U, 0,
+ Info.first, Info.second, FieldOffset, 0,
+ PointerDiffDITy);
+ FieldOffset += Info.first;
+
+ ElementTypes[1] =
+ DBuilder.createMemberType(U, "ptr", U, 0,
+ Info.first, Info.second, FieldOffset, 0,
+ PointerDiffDITy);
+
+ llvm::DIArray Elements = DBuilder.getOrCreateArray(ElementTypes);
+
+ return DBuilder.createStructType(U, StringRef("test"),
+ U, 0, FieldOffset,
+ 0, 0, Elements);
+}
+
+llvm::DIType CGDebugInfo::CreateType(const AtomicType *Ty,
+ llvm::DIFile U) {
+ // Ignore the atomic wrapping
+ // FIXME: What is the correct representation?
+ return getOrCreateType(Ty->getValueType(), U);
+}
+
+/// CreateEnumType - get enumeration type.
+llvm::DIType CGDebugInfo::CreateEnumType(const EnumDecl *ED) {
+ uint64_t Size = 0;
+ uint64_t Align = 0;
+ if (!ED->getTypeForDecl()->isIncompleteType()) {
+ Size = CGM.getContext().getTypeSize(ED->getTypeForDecl());
+ Align = CGM.getContext().getTypeAlign(ED->getTypeForDecl());
+ }
+
+ // If this is just a forward declaration, construct an appropriately
+ // marked node and just return it.
+ if (!ED->getDefinition()) {
+ llvm::DIDescriptor EDContext;
+ EDContext = getContextDescriptor(cast<Decl>(ED->getDeclContext()));
+ llvm::DIFile DefUnit = getOrCreateFile(ED->getLocation());
+ unsigned Line = getLineNumber(ED->getLocation());
+ StringRef EDName = ED->getName();
+ return DBuilder.createForwardDecl(llvm::dwarf::DW_TAG_enumeration_type,
+ EDName, EDContext, DefUnit, Line, 0,
+ Size, Align);
+ }
+
+ // Create DIEnumerator elements for each enumerator.
+ SmallVector<llvm::Value *, 16> Enumerators;
+ ED = ED->getDefinition();
+ for (EnumDecl::enumerator_iterator
+ Enum = ED->enumerator_begin(), EnumEnd = ED->enumerator_end();
+ Enum != EnumEnd; ++Enum) {
+ Enumerators.push_back(
+ DBuilder.createEnumerator(Enum->getName(),
+ Enum->getInitVal().getZExtValue()));
+ }
+
+ // Return a CompositeType for the enum itself.
+ llvm::DIArray EltArray = DBuilder.getOrCreateArray(Enumerators);
+
+ llvm::DIFile DefUnit = getOrCreateFile(ED->getLocation());
+ unsigned Line = getLineNumber(ED->getLocation());
+ llvm::DIDescriptor EnumContext =
+ getContextDescriptor(cast<Decl>(ED->getDeclContext()));
+ llvm::DIType ClassTy = ED->isScopedUsingClassTag() ?
+ getOrCreateType(ED->getIntegerType(), DefUnit) : llvm::DIType();
+ llvm::DIType DbgTy =
+ DBuilder.createEnumerationType(EnumContext, ED->getName(), DefUnit, Line,
+ Size, Align, EltArray,
+ ClassTy);
+ return DbgTy;
+}
+
+static QualType UnwrapTypeForDebugInfo(QualType T) {
+ do {
+ QualType LastT = T;
+ switch (T->getTypeClass()) {
+ default:
+ return T;
+ case Type::TemplateSpecialization:
+ T = cast<TemplateSpecializationType>(T)->desugar();
+ break;
+ case Type::TypeOfExpr:
+ T = cast<TypeOfExprType>(T)->getUnderlyingExpr()->getType();
+ break;
+ case Type::TypeOf:
+ T = cast<TypeOfType>(T)->getUnderlyingType();
+ break;
+ case Type::Decltype:
+ T = cast<DecltypeType>(T)->getUnderlyingType();
+ break;
+ case Type::UnaryTransform:
+ T = cast<UnaryTransformType>(T)->getUnderlyingType();
+ break;
+ case Type::Attributed:
+ T = cast<AttributedType>(T)->getEquivalentType();
+ break;
+ case Type::Elaborated:
+ T = cast<ElaboratedType>(T)->getNamedType();
+ break;
+ case Type::Paren:
+ T = cast<ParenType>(T)->getInnerType();
+ break;
+ case Type::SubstTemplateTypeParm: {
+ // We need to keep the qualifiers handy since getReplacementType()
+ // will strip them away.
+ unsigned Quals = T.getLocalFastQualifiers();
+ T = cast<SubstTemplateTypeParmType>(T)->getReplacementType();
+ T.addFastQualifiers(Quals);
+ }
+ break;
+ case Type::Auto:
+ T = cast<AutoType>(T)->getDeducedType();
+ break;
+ }
+
+ assert(T != LastT && "Type unwrapping failed to unwrap!");
+ if (T == LastT)
+ return T;
+ } while (true);
+}
+
+/// getType - Get the type from the cache or return null type if it doesn't exist.
+llvm::DIType CGDebugInfo::getTypeOrNull(QualType Ty) {
+
+ // Unwrap the type as needed for debug information.
+ Ty = UnwrapTypeForDebugInfo(Ty);
+
+ // Check for existing entry.
+ llvm::DenseMap<void *, llvm::WeakVH>::iterator it =
+ TypeCache.find(Ty.getAsOpaquePtr());
+ if (it != TypeCache.end()) {
+ // Verify that the debug info still exists.
+ if (llvm::Value *V = it->second)
+ return llvm::DIType(cast<llvm::MDNode>(V));
+ }
+
+ return llvm::DIType();
+}
+
+/// getCompletedTypeOrNull - Get the type from the cache or return null if it
+/// doesn't exist.
+llvm::DIType CGDebugInfo::getCompletedTypeOrNull(QualType Ty) {
+
+ // Unwrap the type as needed for debug information.
+ Ty = UnwrapTypeForDebugInfo(Ty);
+
+ // Check for existing entry.
+ llvm::DenseMap<void *, llvm::WeakVH>::iterator it =
+ CompletedTypeCache.find(Ty.getAsOpaquePtr());
+ if (it != CompletedTypeCache.end()) {
+ // Verify that the debug info still exists.
+ if (llvm::Value *V = it->second)
+ return llvm::DIType(cast<llvm::MDNode>(V));
+ }
+
+ return llvm::DIType();
+}
+
+
+/// getOrCreateType - Get the type from the cache or create a new
+/// one if necessary.
+llvm::DIType CGDebugInfo::getOrCreateType(QualType Ty, llvm::DIFile Unit) {
+ if (Ty.isNull())
+ return llvm::DIType();
+
+ // Unwrap the type as needed for debug information.
+ Ty = UnwrapTypeForDebugInfo(Ty);
+
+ llvm::DIType T = getCompletedTypeOrNull(Ty);
+
+ if (T.Verify())
+ return T;
+
+ // Otherwise create the type.
+ llvm::DIType Res = CreateTypeNode(Ty, Unit);
+
+ llvm::DIType TC = getTypeOrNull(Ty);
+ if (TC.Verify() && TC.isForwardDecl())
+ ReplaceMap.push_back(std::make_pair(Ty.getAsOpaquePtr(),
+ static_cast<llvm::Value*>(TC)));
+
+ // And update the type cache.
+ TypeCache[Ty.getAsOpaquePtr()] = Res;
+
+ if (!Res.isForwardDecl())
+ CompletedTypeCache[Ty.getAsOpaquePtr()] = Res;
+
+ return Res;
+}
+
+/// CreateTypeNode - Create a new debug type node.
+llvm::DIType CGDebugInfo::CreateTypeNode(QualType Ty, llvm::DIFile Unit) {
+ // Handle qualifiers, which recursively handles what they refer to.
+ if (Ty.hasLocalQualifiers())
+ return CreateQualifiedType(Ty, Unit);
+
+ const char *Diag = 0;
+
+ // Work out details of type.
+ switch (Ty->getTypeClass()) {
+#define TYPE(Class, Base)
+#define ABSTRACT_TYPE(Class, Base)
+#define NON_CANONICAL_TYPE(Class, Base)
+#define DEPENDENT_TYPE(Class, Base) case Type::Class:
+#include "clang/AST/TypeNodes.def"
+ llvm_unreachable("Dependent types cannot show up in debug information");
+
+ case Type::ExtVector:
+ case Type::Vector:
+ return CreateType(cast<VectorType>(Ty), Unit);
+ case Type::ObjCObjectPointer:
+ return CreateType(cast<ObjCObjectPointerType>(Ty), Unit);
+ case Type::ObjCObject:
+ return CreateType(cast<ObjCObjectType>(Ty), Unit);
+ case Type::ObjCInterface:
+ return CreateType(cast<ObjCInterfaceType>(Ty), Unit);
+ case Type::Builtin:
+ return CreateType(cast<BuiltinType>(Ty));
+ case Type::Complex:
+ return CreateType(cast<ComplexType>(Ty));
+ case Type::Pointer:
+ return CreateType(cast<PointerType>(Ty), Unit);
+ case Type::BlockPointer:
+ return CreateType(cast<BlockPointerType>(Ty), Unit);
+ case Type::Typedef:
+ return CreateType(cast<TypedefType>(Ty), Unit);
+ case Type::Record:
+ return CreateType(cast<RecordType>(Ty));
+ case Type::Enum:
+ return CreateEnumType(cast<EnumType>(Ty)->getDecl());
+ case Type::FunctionProto:
+ case Type::FunctionNoProto:
+ return CreateType(cast<FunctionType>(Ty), Unit);
+ case Type::ConstantArray:
+ case Type::VariableArray:
+ case Type::IncompleteArray:
+ return CreateType(cast<ArrayType>(Ty), Unit);
+
+ case Type::LValueReference:
+ return CreateType(cast<LValueReferenceType>(Ty), Unit);
+ case Type::RValueReference:
+ return CreateType(cast<RValueReferenceType>(Ty), Unit);
+
+ case Type::MemberPointer:
+ return CreateType(cast<MemberPointerType>(Ty), Unit);
+
+ case Type::Atomic:
+ return CreateType(cast<AtomicType>(Ty), Unit);
+
+ case Type::Attributed:
+ case Type::TemplateSpecialization:
+ case Type::Elaborated:
+ case Type::Paren:
+ case Type::SubstTemplateTypeParm:
+ case Type::TypeOfExpr:
+ case Type::TypeOf:
+ case Type::Decltype:
+ case Type::UnaryTransform:
+ case Type::Auto:
+ llvm_unreachable("type should have been unwrapped!");
+ }
+
+ assert(Diag && "Fall through without a diagnostic?");
+ unsigned DiagID = CGM.getDiags().getCustomDiagID(DiagnosticsEngine::Error,
+ "debug information for %0 is not yet supported");
+ CGM.getDiags().Report(DiagID)
+ << Diag;
+ return llvm::DIType();
+}
+
+/// getOrCreateLimitedType - Get the type from the cache or create a new
+/// limited type if necessary.
+llvm::DIType CGDebugInfo::getOrCreateLimitedType(QualType Ty,
+ llvm::DIFile Unit) {
+ if (Ty.isNull())
+ return llvm::DIType();
+
+ // Unwrap the type as needed for debug information.
+ Ty = UnwrapTypeForDebugInfo(Ty);
+
+ llvm::DIType T = getTypeOrNull(Ty);
+
+ // We may have cached a forward decl when we could have created
+ // a non-forward decl. Go ahead and create a non-forward decl
+ // now.
+ if (T.Verify() && !T.isForwardDecl()) return T;
+
+ // Otherwise create the type.
+ llvm::DIType Res = CreateLimitedTypeNode(Ty, Unit);
+
+ if (T.Verify() && T.isForwardDecl())
+ ReplaceMap.push_back(std::make_pair(Ty.getAsOpaquePtr(),
+ static_cast<llvm::Value*>(T)));
+
+ // And update the type cache.
+ TypeCache[Ty.getAsOpaquePtr()] = Res;
+ return Res;
+}
+
+// TODO: Currently used for context chains when limiting debug info.
+llvm::DIType CGDebugInfo::CreateLimitedType(const RecordType *Ty) {
+ RecordDecl *RD = Ty->getDecl();
+
+ // Get overall information about the record type for the debug info.
+ llvm::DIFile DefUnit = getOrCreateFile(RD->getLocation());
+ unsigned Line = getLineNumber(RD->getLocation());
+ StringRef RDName = getClassName(RD);
+
+ llvm::DIDescriptor RDContext;
+ if (CGM.getCodeGenOpts().getDebugInfo() == CodeGenOptions::LimitedDebugInfo)
+ RDContext = createContextChain(cast<Decl>(RD->getDeclContext()));
+ else
+ RDContext = getContextDescriptor(cast<Decl>(RD->getDeclContext()));
+
+ // If this is just a forward declaration, construct an appropriately
+ // marked node and just return it.
+ if (!RD->getDefinition())
+ return createRecordFwdDecl(RD, RDContext);
+
+ uint64_t Size = CGM.getContext().getTypeSize(Ty);
+ uint64_t Align = CGM.getContext().getTypeAlign(Ty);
+ const CXXRecordDecl *CXXDecl = dyn_cast<CXXRecordDecl>(RD);
+ llvm::TrackingVH<llvm::MDNode> RealDecl;
+
+ if (RD->isUnion())
+ RealDecl = DBuilder.createUnionType(RDContext, RDName, DefUnit, Line,
+ Size, Align, 0, llvm::DIArray());
+ else if (RD->isClass()) {
+ // FIXME: This could be a struct type giving a default visibility different
+ // than C++ class type, but needs llvm metadata changes first.
+ RealDecl = DBuilder.createClassType(RDContext, RDName, DefUnit, Line,
+ Size, Align, 0, 0, llvm::DIType(),
+ llvm::DIArray(), llvm::DIType(),
+ llvm::DIArray());
+ } else
+ RealDecl = DBuilder.createStructType(RDContext, RDName, DefUnit, Line,
+ Size, Align, 0, llvm::DIArray());
+
+ RegionMap[Ty->getDecl()] = llvm::WeakVH(RealDecl);
+ TypeCache[QualType(Ty, 0).getAsOpaquePtr()] = llvm::DIType(RealDecl);
+
+ if (CXXDecl) {
+ // A class's primary base or the class itself contains the vtable.
+ llvm::MDNode *ContainingType = NULL;
+ const ASTRecordLayout &RL = CGM.getContext().getASTRecordLayout(RD);
+ if (const CXXRecordDecl *PBase = RL.getPrimaryBase()) {
+ // Seek non virtual primary base root.
+ while (1) {
+ const ASTRecordLayout &BRL = CGM.getContext().getASTRecordLayout(PBase);
+ const CXXRecordDecl *PBT = BRL.getPrimaryBase();
+ if (PBT && !BRL.isPrimaryBaseVirtual())
+ PBase = PBT;
+ else
+ break;
+ }
+ ContainingType =
+ getOrCreateType(QualType(PBase->getTypeForDecl(), 0), DefUnit);
+ }
+ else if (CXXDecl->isDynamicClass())
+ ContainingType = RealDecl;
+
+ RealDecl->replaceOperandWith(12, ContainingType);
+ }
+ return llvm::DIType(RealDecl);
+}
+
+/// CreateLimitedTypeNode - Create a new debug type node, but only forward
+/// declare composite types that haven't been processed yet.
+llvm::DIType CGDebugInfo::CreateLimitedTypeNode(QualType Ty,llvm::DIFile Unit) {
+
+ // Work out details of type.
+ switch (Ty->getTypeClass()) {
+#define TYPE(Class, Base)
+#define ABSTRACT_TYPE(Class, Base)
+#define NON_CANONICAL_TYPE(Class, Base)
+#define DEPENDENT_TYPE(Class, Base) case Type::Class:
+ #include "clang/AST/TypeNodes.def"
+ llvm_unreachable("Dependent types cannot show up in debug information");
+
+ case Type::Record:
+ return CreateLimitedType(cast<RecordType>(Ty));
+ default:
+ return CreateTypeNode(Ty, Unit);
+ }
+}
+
+/// CreateMemberType - Create new member and increase Offset by FType's size.
+llvm::DIType CGDebugInfo::CreateMemberType(llvm::DIFile Unit, QualType FType,
+ StringRef Name,
+ uint64_t *Offset) {
+ llvm::DIType FieldTy = CGDebugInfo::getOrCreateType(FType, Unit);
+ uint64_t FieldSize = CGM.getContext().getTypeSize(FType);
+ unsigned FieldAlign = CGM.getContext().getTypeAlign(FType);
+ llvm::DIType Ty = DBuilder.createMemberType(Unit, Name, Unit, 0,
+ FieldSize, FieldAlign,
+ *Offset, 0, FieldTy);
+ *Offset += FieldSize;
+ return Ty;
+}
+
+/// getFunctionDeclaration - Return debug info descriptor to describe method
+/// declaration for the given method definition.
+llvm::DISubprogram CGDebugInfo::getFunctionDeclaration(const Decl *D) {
+ const FunctionDecl *FD = dyn_cast<FunctionDecl>(D);
+ if (!FD) return llvm::DISubprogram();
+
+ // Setup context.
+ getContextDescriptor(cast<Decl>(D->getDeclContext()));
+
+ llvm::DenseMap<const FunctionDecl *, llvm::WeakVH>::iterator
+ MI = SPCache.find(FD->getCanonicalDecl());
+ if (MI != SPCache.end()) {
+ llvm::Value *V = MI->second;
+ llvm::DISubprogram SP(dyn_cast_or_null<llvm::MDNode>(V));
+ if (SP.isSubprogram() && !llvm::DISubprogram(SP).isDefinition())
+ return SP;
+ }
+
+ for (FunctionDecl::redecl_iterator I = FD->redecls_begin(),
+ E = FD->redecls_end(); I != E; ++I) {
+ const FunctionDecl *NextFD = *I;
+ llvm::DenseMap<const FunctionDecl *, llvm::WeakVH>::iterator
+ MI = SPCache.find(NextFD->getCanonicalDecl());
+ if (MI != SPCache.end()) {
+ llvm::Value *V = MI->second;
+ llvm::DISubprogram SP(dyn_cast_or_null<llvm::MDNode>(V));
+ if (SP.isSubprogram() && !llvm::DISubprogram(SP).isDefinition())
+ return SP;
+ }
+ }
+ return llvm::DISubprogram();
+}
+
+// getOrCreateFunctionType - Construct DIType. If it is a c++ method, include
+// implicit parameter "this".
+llvm::DIType CGDebugInfo::getOrCreateFunctionType(const Decl *D,
+ QualType FnType,
+ llvm::DIFile F) {
+
+ if (const CXXMethodDecl *Method = dyn_cast<CXXMethodDecl>(D))
+ return getOrCreateMethodType(Method, F);
+ if (const ObjCMethodDecl *OMethod = dyn_cast<ObjCMethodDecl>(D)) {
+ // Add "self" and "_cmd"
+ SmallVector<llvm::Value *, 16> Elts;
+
+ // First element is always return type. For 'void' functions it is NULL.
+ Elts.push_back(getOrCreateType(OMethod->getResultType(), F));
+ // "self" pointer is always first argument.
+ llvm::DIType SelfTy = getOrCreateType(OMethod->getSelfDecl()->getType(), F);
+ Elts.push_back(DBuilder.createObjectPointerType(SelfTy));
+ // "_cmd" pointer is always second argument.
+ llvm::DIType CmdTy = getOrCreateType(OMethod->getCmdDecl()->getType(), F);
+ Elts.push_back(DBuilder.createArtificialType(CmdTy));
+ // Get rest of the arguments.
+ for (ObjCMethodDecl::param_const_iterator PI = OMethod->param_begin(),
+ PE = OMethod->param_end(); PI != PE; ++PI)
+ Elts.push_back(getOrCreateType((*PI)->getType(), F));
+
+ llvm::DIArray EltTypeArray = DBuilder.getOrCreateArray(Elts);
+ return DBuilder.createSubroutineType(F, EltTypeArray);
+ }
+ return getOrCreateType(FnType, F);
+}
+
+/// EmitFunctionStart - Constructs the debug code for entering a function.
+void CGDebugInfo::EmitFunctionStart(GlobalDecl GD, QualType FnType,
+ llvm::Function *Fn,
+ CGBuilderTy &Builder) {
+
+ StringRef Name;
+ StringRef LinkageName;
+
+ FnBeginRegionCount.push_back(LexicalBlockStack.size());
+
+ const Decl *D = GD.getDecl();
+ // Function may lack declaration in source code if it is created by Clang
+ // CodeGen (examples: _GLOBAL__I_a, __cxx_global_array_dtor, thunk).
+ bool HasDecl = (D != 0);
+ // Use the location of the declaration.
+ SourceLocation Loc;
+ if (HasDecl)
+ Loc = D->getLocation();
+
+ unsigned Flags = 0;
+ llvm::DIFile Unit = getOrCreateFile(Loc);
+ llvm::DIDescriptor FDContext(Unit);
+ llvm::DIArray TParamsArray;
+ if (!HasDecl) {
+ // Use llvm function name.
+ Name = Fn->getName();
+ } else if (const FunctionDecl *FD = dyn_cast<FunctionDecl>(D)) {
+ // If there is a DISubprogram for this function available then use it.
+ llvm::DenseMap<const FunctionDecl *, llvm::WeakVH>::iterator
+ FI = SPCache.find(FD->getCanonicalDecl());
+ if (FI != SPCache.end()) {
+ llvm::Value *V = FI->second;
+ llvm::DIDescriptor SP(dyn_cast_or_null<llvm::MDNode>(V));
+ if (SP.isSubprogram() && llvm::DISubprogram(SP).isDefinition()) {
+ llvm::MDNode *SPN = SP;
+ LexicalBlockStack.push_back(SPN);
+ RegionMap[D] = llvm::WeakVH(SP);
+ return;
+ }
+ }
+ Name = getFunctionName(FD);
+ // Use mangled name as linkage name for c/c++ functions.
+ if (FD->hasPrototype()) {
+ LinkageName = CGM.getMangledName(GD);
+ Flags |= llvm::DIDescriptor::FlagPrototyped;
+ }
+ if (LinkageName == Name ||
+ CGM.getCodeGenOpts().getDebugInfo() <= CodeGenOptions::DebugLineTablesOnly)
+ LinkageName = StringRef();
+
+ if (CGM.getCodeGenOpts().getDebugInfo() >= CodeGenOptions::LimitedDebugInfo) {
+ if (const NamespaceDecl *NSDecl =
+ dyn_cast_or_null<NamespaceDecl>(FD->getDeclContext()))
+ FDContext = getOrCreateNameSpace(NSDecl);
+ else if (const RecordDecl *RDecl =
+ dyn_cast_or_null<RecordDecl>(FD->getDeclContext()))
+ FDContext = getContextDescriptor(cast<Decl>(RDecl->getDeclContext()));
+
+ // Collect template parameters.
+ TParamsArray = CollectFunctionTemplateParams(FD, Unit);
+ }
+ } else if (const ObjCMethodDecl *OMD = dyn_cast<ObjCMethodDecl>(D)) {
+ Name = getObjCMethodName(OMD);
+ Flags |= llvm::DIDescriptor::FlagPrototyped;
+ } else {
+ // Use llvm function name.
+ Name = Fn->getName();
+ Flags |= llvm::DIDescriptor::FlagPrototyped;
+ }
+ if (!Name.empty() && Name[0] == '\01')
+ Name = Name.substr(1);
+
+ unsigned LineNo = getLineNumber(Loc);
+ if (!HasDecl || D->isImplicit())
+ Flags |= llvm::DIDescriptor::FlagArtificial;
+
+ llvm::DIType DIFnType;
+ llvm::DISubprogram SPDecl;
+ if (HasDecl &&
+ CGM.getCodeGenOpts().getDebugInfo() >= CodeGenOptions::LimitedDebugInfo) {
+ DIFnType = getOrCreateFunctionType(D, FnType, Unit);
+ SPDecl = getFunctionDeclaration(D);
+ } else {
+ // Create fake but valid subroutine type. Otherwise
+ // llvm::DISubprogram::Verify() would return false, and
+ // subprogram DIE will miss DW_AT_decl_file and
+ // DW_AT_decl_line fields.
+ SmallVector<llvm::Value*, 16> Elts;
+ llvm::DIArray EltTypeArray = DBuilder.getOrCreateArray(Elts);
+ DIFnType = DBuilder.createSubroutineType(Unit, EltTypeArray);
+ }
+ llvm::DISubprogram SP;
+ SP = DBuilder.createFunction(FDContext, Name, LinkageName, Unit,
+ LineNo, DIFnType,
+ Fn->hasInternalLinkage(), true/*definition*/,
+ getLineNumber(CurLoc), Flags,
+ CGM.getLangOpts().Optimize,
+ Fn, TParamsArray, SPDecl);
+
+ // Push function on region stack.
+ llvm::MDNode *SPN = SP;
+ LexicalBlockStack.push_back(SPN);
+ if (HasDecl)
+ RegionMap[D] = llvm::WeakVH(SP);
+}
+
+/// EmitLocation - Emit metadata to indicate a change in line/column
+/// information in the source file.
+void CGDebugInfo::EmitLocation(CGBuilderTy &Builder, SourceLocation Loc) {
+
+ // Update our current location
+ setLocation(Loc);
+
+ if (CurLoc.isInvalid() || CurLoc.isMacroID()) return;
+
+ // Don't bother if things are the same as last time.
+ SourceManager &SM = CGM.getContext().getSourceManager();
+ if (CurLoc == PrevLoc ||
+ SM.getExpansionLoc(CurLoc) == SM.getExpansionLoc(PrevLoc))
+ // New Builder may not be in sync with CGDebugInfo.
+ if (!Builder.getCurrentDebugLocation().isUnknown())
+ return;
+
+ // Update last state.
+ PrevLoc = CurLoc;
+
+ llvm::MDNode *Scope = LexicalBlockStack.back();
+ Builder.SetCurrentDebugLocation(llvm::DebugLoc::get(getLineNumber(CurLoc),
+ getColumnNumber(CurLoc),
+ Scope));
+}
+
+/// CreateLexicalBlock - Creates a new lexical block node and pushes it on
+/// the stack.
+void CGDebugInfo::CreateLexicalBlock(SourceLocation Loc) {
+ llvm::DIDescriptor D =
+ DBuilder.createLexicalBlock(LexicalBlockStack.empty() ?
+ llvm::DIDescriptor() :
+ llvm::DIDescriptor(LexicalBlockStack.back()),
+ getOrCreateFile(CurLoc),
+ getLineNumber(CurLoc),
+ getColumnNumber(CurLoc));
+ llvm::MDNode *DN = D;
+ LexicalBlockStack.push_back(DN);
+}
+
+/// EmitLexicalBlockStart - Constructs the debug code for entering a declarative
+/// region - beginning of a DW_TAG_lexical_block.
+void CGDebugInfo::EmitLexicalBlockStart(CGBuilderTy &Builder, SourceLocation Loc) {
+ // Set our current location.
+ setLocation(Loc);
+
+ // Create a new lexical block and push it on the stack.
+ CreateLexicalBlock(Loc);
+
+ // Emit a line table change for the current location inside the new scope.
+ Builder.SetCurrentDebugLocation(llvm::DebugLoc::get(getLineNumber(Loc),
+ getColumnNumber(Loc),
+ LexicalBlockStack.back()));
+}
+
+/// EmitLexicalBlockEnd - Constructs the debug code for exiting a declarative
+/// region - end of a DW_TAG_lexical_block.
+void CGDebugInfo::EmitLexicalBlockEnd(CGBuilderTy &Builder, SourceLocation Loc) {
+ assert(!LexicalBlockStack.empty() && "Region stack mismatch, stack empty!");
+
+ // Provide an entry in the line table for the end of the block.
+ EmitLocation(Builder, Loc);
+
+ LexicalBlockStack.pop_back();
+}
+
+/// EmitFunctionEnd - Constructs the debug code for exiting a function.
+void CGDebugInfo::EmitFunctionEnd(CGBuilderTy &Builder) {
+ assert(!LexicalBlockStack.empty() && "Region stack mismatch, stack empty!");
+ unsigned RCount = FnBeginRegionCount.back();
+ assert(RCount <= LexicalBlockStack.size() && "Region stack mismatch");
+
+ // Pop all regions for this function.
+ while (LexicalBlockStack.size() != RCount)
+ EmitLexicalBlockEnd(Builder, CurLoc);
+ FnBeginRegionCount.pop_back();
+}
+
+// EmitTypeForVarWithBlocksAttr - Build up structure info for the byref.
+// See BuildByRefType.
+llvm::DIType CGDebugInfo::EmitTypeForVarWithBlocksAttr(const VarDecl *VD,
+ uint64_t *XOffset) {
+
+ SmallVector<llvm::Value *, 5> EltTys;
+ QualType FType;
+ uint64_t FieldSize, FieldOffset;
+ unsigned FieldAlign;
+
+ llvm::DIFile Unit = getOrCreateFile(VD->getLocation());
+ QualType Type = VD->getType();
+
+ FieldOffset = 0;
+ FType = CGM.getContext().getPointerType(CGM.getContext().VoidTy);
+ EltTys.push_back(CreateMemberType(Unit, FType, "__isa", &FieldOffset));
+ EltTys.push_back(CreateMemberType(Unit, FType, "__forwarding", &FieldOffset));
+ FType = CGM.getContext().IntTy;
+ EltTys.push_back(CreateMemberType(Unit, FType, "__flags", &FieldOffset));
+ EltTys.push_back(CreateMemberType(Unit, FType, "__size", &FieldOffset));
+
+ bool HasCopyAndDispose = CGM.getContext().BlockRequiresCopying(Type, VD);
+ if (HasCopyAndDispose) {
+ FType = CGM.getContext().getPointerType(CGM.getContext().VoidTy);
+ EltTys.push_back(CreateMemberType(Unit, FType, "__copy_helper",
+ &FieldOffset));
+ EltTys.push_back(CreateMemberType(Unit, FType, "__destroy_helper",
+ &FieldOffset));
+ }
+ bool HasByrefExtendedLayout;
+ Qualifiers::ObjCLifetime Lifetime;
+ if (CGM.getContext().getByrefLifetime(Type,
+ Lifetime, HasByrefExtendedLayout)
+ && HasByrefExtendedLayout)
+ EltTys.push_back(CreateMemberType(Unit, FType,
+ "__byref_variable_layout",
+ &FieldOffset));
+
+ CharUnits Align = CGM.getContext().getDeclAlign(VD);
+ if (Align > CGM.getContext().toCharUnitsFromBits(
+ CGM.getContext().getTargetInfo().getPointerAlign(0))) {
+ CharUnits FieldOffsetInBytes
+ = CGM.getContext().toCharUnitsFromBits(FieldOffset);
+ CharUnits AlignedOffsetInBytes
+ = FieldOffsetInBytes.RoundUpToAlignment(Align);
+ CharUnits NumPaddingBytes
+ = AlignedOffsetInBytes - FieldOffsetInBytes;
+
+ if (NumPaddingBytes.isPositive()) {
+ llvm::APInt pad(32, NumPaddingBytes.getQuantity());
+ FType = CGM.getContext().getConstantArrayType(CGM.getContext().CharTy,
+ pad, ArrayType::Normal, 0);
+ EltTys.push_back(CreateMemberType(Unit, FType, "", &FieldOffset));
+ }
+ }
+
+ FType = Type;
+ llvm::DIType FieldTy = CGDebugInfo::getOrCreateType(FType, Unit);
+ FieldSize = CGM.getContext().getTypeSize(FType);
+ FieldAlign = CGM.getContext().toBits(Align);
+
+ *XOffset = FieldOffset;
+ FieldTy = DBuilder.createMemberType(Unit, VD->getName(), Unit,
+ 0, FieldSize, FieldAlign,
+ FieldOffset, 0, FieldTy);
+ EltTys.push_back(FieldTy);
+ FieldOffset += FieldSize;
+
+ llvm::DIArray Elements = DBuilder.getOrCreateArray(EltTys);
+
+ unsigned Flags = llvm::DIDescriptor::FlagBlockByrefStruct;
+
+ return DBuilder.createStructType(Unit, "", Unit, 0, FieldOffset, 0, Flags,
+ Elements);
+}
+
+/// EmitDeclare - Emit local variable declaration debug info.
+void CGDebugInfo::EmitDeclare(const VarDecl *VD, unsigned Tag,
+ llvm::Value *Storage,
+ unsigned ArgNo, CGBuilderTy &Builder) {
+ assert(CGM.getCodeGenOpts().getDebugInfo() >= CodeGenOptions::LimitedDebugInfo);
+ assert(!LexicalBlockStack.empty() && "Region stack mismatch, stack empty!");
+
+ llvm::DIFile Unit = getOrCreateFile(VD->getLocation());
+ llvm::DIType Ty;
+ uint64_t XOffset = 0;
+ if (VD->hasAttr<BlocksAttr>())
+ Ty = EmitTypeForVarWithBlocksAttr(VD, &XOffset);
+ else
+ Ty = getOrCreateType(VD->getType(), Unit);
+
+ // If there is no debug info for this type then do not emit debug info
+ // for this variable.
+ if (!Ty)
+ return;
+
+ if (llvm::Argument *Arg = dyn_cast<llvm::Argument>(Storage)) {
+ // If Storage is an aggregate returned as 'sret' then let debugger know
+ // about this.
+ if (Arg->hasStructRetAttr())
+ Ty = DBuilder.createReferenceType(llvm::dwarf::DW_TAG_reference_type, Ty);
+ else if (CXXRecordDecl *Record = VD->getType()->getAsCXXRecordDecl()) {
+ // If an aggregate variable has non trivial destructor or non trivial copy
+ // constructor than it is pass indirectly. Let debug info know about this
+ // by using reference of the aggregate type as a argument type.
+ if (Record->hasNonTrivialCopyConstructor() ||
+ !Record->hasTrivialDestructor())
+ Ty = DBuilder.createReferenceType(llvm::dwarf::DW_TAG_reference_type, Ty);
+ }
+ }
+
+ // Get location information.
+ unsigned Line = getLineNumber(VD->getLocation());
+ unsigned Column = getColumnNumber(VD->getLocation());
+ unsigned Flags = 0;
+ if (VD->isImplicit())
+ Flags |= llvm::DIDescriptor::FlagArtificial;
+ // If this is the first argument and it is implicit then
+ // give it an object pointer flag.
+ // FIXME: There has to be a better way to do this, but for static
+ // functions there won't be an implicit param at arg1 and
+ // otherwise it is 'self' or 'this'.
+ if (isa<ImplicitParamDecl>(VD) && ArgNo == 1)
+ Flags |= llvm::DIDescriptor::FlagObjectPointer;
+
+ llvm::MDNode *Scope = LexicalBlockStack.back();
+
+ StringRef Name = VD->getName();
+ if (!Name.empty()) {
+ if (VD->hasAttr<BlocksAttr>()) {
+ CharUnits offset = CharUnits::fromQuantity(32);
+ SmallVector<llvm::Value *, 9> addr;
+ llvm::Type *Int64Ty = CGM.Int64Ty;
+ addr.push_back(llvm::ConstantInt::get(Int64Ty, llvm::DIBuilder::OpPlus));
+ // offset of __forwarding field
+ offset = CGM.getContext().toCharUnitsFromBits(
+ CGM.getContext().getTargetInfo().getPointerWidth(0));
+ addr.push_back(llvm::ConstantInt::get(Int64Ty, offset.getQuantity()));
+ addr.push_back(llvm::ConstantInt::get(Int64Ty, llvm::DIBuilder::OpDeref));
+ addr.push_back(llvm::ConstantInt::get(Int64Ty, llvm::DIBuilder::OpPlus));
+ // offset of x field
+ offset = CGM.getContext().toCharUnitsFromBits(XOffset);
+ addr.push_back(llvm::ConstantInt::get(Int64Ty, offset.getQuantity()));
+
+ // Create the descriptor for the variable.
+ llvm::DIVariable D =
+ DBuilder.createComplexVariable(Tag,
+ llvm::DIDescriptor(Scope),
+ VD->getName(), Unit, Line, Ty,
+ addr, ArgNo);
+
+ // Insert an llvm.dbg.declare into the current block.
+ llvm::Instruction *Call =
+ DBuilder.insertDeclare(Storage, D, Builder.GetInsertBlock());
+ Call->setDebugLoc(llvm::DebugLoc::get(Line, Column, Scope));
+ return;
+ } else if (isa<VariableArrayType>(VD->getType())) {
+ // These are "complex" variables in that they need an op_deref.
+ // Create the descriptor for the variable.
+ llvm::Value *Addr = llvm::ConstantInt::get(CGM.Int64Ty,
+ llvm::DIBuilder::OpDeref);
+ llvm::DIVariable D =
+ DBuilder.createComplexVariable(Tag,
+ llvm::DIDescriptor(Scope),
+ Name, Unit, Line, Ty,
+ Addr, ArgNo);
+
+ // Insert an llvm.dbg.declare into the current block.
+ llvm::Instruction *Call =
+ DBuilder.insertDeclare(Storage, D, Builder.GetInsertBlock());
+ Call->setDebugLoc(llvm::DebugLoc::get(Line, Column, Scope));
+ return;
+ }
+
+ // Create the descriptor for the variable.
+ llvm::DIVariable D =
+ DBuilder.createLocalVariable(Tag, llvm::DIDescriptor(Scope),
+ Name, Unit, Line, Ty,
+ CGM.getLangOpts().Optimize, Flags, ArgNo);
+
+ // Insert an llvm.dbg.declare into the current block.
+ llvm::Instruction *Call =
+ DBuilder.insertDeclare(Storage, D, Builder.GetInsertBlock());
+ Call->setDebugLoc(llvm::DebugLoc::get(Line, Column, Scope));
+ return;
+ }
+
+ // If VD is an anonymous union then Storage represents value for
+ // all union fields.
+ if (const RecordType *RT = dyn_cast<RecordType>(VD->getType())) {
+ const RecordDecl *RD = cast<RecordDecl>(RT->getDecl());
+ if (RD->isUnion()) {
+ for (RecordDecl::field_iterator I = RD->field_begin(),
+ E = RD->field_end();
+ I != E; ++I) {
+ FieldDecl *Field = *I;
+ llvm::DIType FieldTy = getOrCreateType(Field->getType(), Unit);
+ StringRef FieldName = Field->getName();
+
+ // Ignore unnamed fields. Do not ignore unnamed records.
+ if (FieldName.empty() && !isa<RecordType>(Field->getType()))
+ continue;
+
+ // Use VarDecl's Tag, Scope and Line number.
+ llvm::DIVariable D =
+ DBuilder.createLocalVariable(Tag, llvm::DIDescriptor(Scope),
+ FieldName, Unit, Line, FieldTy,
+ CGM.getLangOpts().Optimize, Flags,
+ ArgNo);
+
+ // Insert an llvm.dbg.declare into the current block.
+ llvm::Instruction *Call =
+ DBuilder.insertDeclare(Storage, D, Builder.GetInsertBlock());
+ Call->setDebugLoc(llvm::DebugLoc::get(Line, Column, Scope));
+ }
+ }
+ }
+}
+
+void CGDebugInfo::EmitDeclareOfAutoVariable(const VarDecl *VD,
+ llvm::Value *Storage,
+ CGBuilderTy &Builder) {
+ assert(CGM.getCodeGenOpts().getDebugInfo() >= CodeGenOptions::LimitedDebugInfo);
+ EmitDeclare(VD, llvm::dwarf::DW_TAG_auto_variable, Storage, 0, Builder);
+}
+
+void CGDebugInfo::EmitDeclareOfBlockDeclRefVariable(const VarDecl *VD,
+ llvm::Value *Storage,
+ CGBuilderTy &Builder,
+ const CGBlockInfo &blockInfo) {
+ assert(CGM.getCodeGenOpts().getDebugInfo() >= CodeGenOptions::LimitedDebugInfo);
+ assert(!LexicalBlockStack.empty() && "Region stack mismatch, stack empty!");
+
+ if (Builder.GetInsertBlock() == 0)
+ return;
+
+ bool isByRef = VD->hasAttr<BlocksAttr>();
+
+ uint64_t XOffset = 0;
+ llvm::DIFile Unit = getOrCreateFile(VD->getLocation());
+ llvm::DIType Ty;
+ if (isByRef)
+ Ty = EmitTypeForVarWithBlocksAttr(VD, &XOffset);
+ else
+ Ty = getOrCreateType(VD->getType(), Unit);
+
+ // Self is passed along as an implicit non-arg variable in a
+ // block. Mark it as the object pointer.
+ if (isa<ImplicitParamDecl>(VD) && VD->getName() == "self")
+ Ty = DBuilder.createObjectPointerType(Ty);
+
+ // Get location information.
+ unsigned Line = getLineNumber(VD->getLocation());
+ unsigned Column = getColumnNumber(VD->getLocation());
+
+ const llvm::DataLayout &target = CGM.getDataLayout();
+
+ CharUnits offset = CharUnits::fromQuantity(
+ target.getStructLayout(blockInfo.StructureType)
+ ->getElementOffset(blockInfo.getCapture(VD).getIndex()));
+
+ SmallVector<llvm::Value *, 9> addr;
+ llvm::Type *Int64Ty = CGM.Int64Ty;
+ addr.push_back(llvm::ConstantInt::get(Int64Ty, llvm::DIBuilder::OpPlus));
+ addr.push_back(llvm::ConstantInt::get(Int64Ty, offset.getQuantity()));
+ if (isByRef) {
+ addr.push_back(llvm::ConstantInt::get(Int64Ty, llvm::DIBuilder::OpDeref));
+ addr.push_back(llvm::ConstantInt::get(Int64Ty, llvm::DIBuilder::OpPlus));
+ // offset of __forwarding field
+ offset = CGM.getContext()
+ .toCharUnitsFromBits(target.getPointerSizeInBits(0));
+ addr.push_back(llvm::ConstantInt::get(Int64Ty, offset.getQuantity()));
+ addr.push_back(llvm::ConstantInt::get(Int64Ty, llvm::DIBuilder::OpDeref));
+ addr.push_back(llvm::ConstantInt::get(Int64Ty, llvm::DIBuilder::OpPlus));
+ // offset of x field
+ offset = CGM.getContext().toCharUnitsFromBits(XOffset);
+ addr.push_back(llvm::ConstantInt::get(Int64Ty, offset.getQuantity()));
+ }
+
+ // Create the descriptor for the variable.
+ llvm::DIVariable D =
+ DBuilder.createComplexVariable(llvm::dwarf::DW_TAG_auto_variable,
+ llvm::DIDescriptor(LexicalBlockStack.back()),
+ VD->getName(), Unit, Line, Ty, addr);
+ // Insert an llvm.dbg.declare into the current block.
+ llvm::Instruction *Call =
+ DBuilder.insertDeclare(Storage, D, Builder.GetInsertPoint());
+ Call->setDebugLoc(llvm::DebugLoc::get(Line, Column,
+ LexicalBlockStack.back()));
+}
+
+/// EmitDeclareOfArgVariable - Emit call to llvm.dbg.declare for an argument
+/// variable declaration.
+void CGDebugInfo::EmitDeclareOfArgVariable(const VarDecl *VD, llvm::Value *AI,
+ unsigned ArgNo,
+ CGBuilderTy &Builder) {
+ assert(CGM.getCodeGenOpts().getDebugInfo() >= CodeGenOptions::LimitedDebugInfo);
+ EmitDeclare(VD, llvm::dwarf::DW_TAG_arg_variable, AI, ArgNo, Builder);
+}
+
+namespace {
+ struct BlockLayoutChunk {
+ uint64_t OffsetInBits;
+ const BlockDecl::Capture *Capture;
+ };
+ bool operator<(const BlockLayoutChunk &l, const BlockLayoutChunk &r) {
+ return l.OffsetInBits < r.OffsetInBits;
+ }
+}
+
+void CGDebugInfo::EmitDeclareOfBlockLiteralArgVariable(const CGBlockInfo &block,
+ llvm::Value *addr,
+ CGBuilderTy &Builder) {
+ assert(CGM.getCodeGenOpts().getDebugInfo() >= CodeGenOptions::LimitedDebugInfo);
+ ASTContext &C = CGM.getContext();
+ const BlockDecl *blockDecl = block.getBlockDecl();
+
+ // Collect some general information about the block's location.
+ SourceLocation loc = blockDecl->getCaretLocation();
+ llvm::DIFile tunit = getOrCreateFile(loc);
+ unsigned line = getLineNumber(loc);
+ unsigned column = getColumnNumber(loc);
+
+ // Build the debug-info type for the block literal.
+ getContextDescriptor(cast<Decl>(blockDecl->getDeclContext()));
+
+ const llvm::StructLayout *blockLayout =
+ CGM.getDataLayout().getStructLayout(block.StructureType);
+
+ SmallVector<llvm::Value*, 16> fields;
+ fields.push_back(createFieldType("__isa", C.VoidPtrTy, 0, loc, AS_public,
+ blockLayout->getElementOffsetInBits(0),
+ tunit, tunit));
+ fields.push_back(createFieldType("__flags", C.IntTy, 0, loc, AS_public,
+ blockLayout->getElementOffsetInBits(1),
+ tunit, tunit));
+ fields.push_back(createFieldType("__reserved", C.IntTy, 0, loc, AS_public,
+ blockLayout->getElementOffsetInBits(2),
+ tunit, tunit));
+ fields.push_back(createFieldType("__FuncPtr", C.VoidPtrTy, 0, loc, AS_public,
+ blockLayout->getElementOffsetInBits(3),
+ tunit, tunit));
+ fields.push_back(createFieldType("__descriptor",
+ C.getPointerType(block.NeedsCopyDispose ?
+ C.getBlockDescriptorExtendedType() :
+ C.getBlockDescriptorType()),
+ 0, loc, AS_public,
+ blockLayout->getElementOffsetInBits(4),
+ tunit, tunit));
+
+ // We want to sort the captures by offset, not because DWARF
+ // requires this, but because we're paranoid about debuggers.
+ SmallVector<BlockLayoutChunk, 8> chunks;
+
+ // 'this' capture.
+ if (blockDecl->capturesCXXThis()) {
+ BlockLayoutChunk chunk;
+ chunk.OffsetInBits =
+ blockLayout->getElementOffsetInBits(block.CXXThisIndex);
+ chunk.Capture = 0;
+ chunks.push_back(chunk);
+ }
+
+ // Variable captures.
+ for (BlockDecl::capture_const_iterator
+ i = blockDecl->capture_begin(), e = blockDecl->capture_end();
+ i != e; ++i) {
+ const BlockDecl::Capture &capture = *i;
+ const VarDecl *variable = capture.getVariable();
+ const CGBlockInfo::Capture &captureInfo = block.getCapture(variable);
+
+ // Ignore constant captures.
+ if (captureInfo.isConstant())
+ continue;
+
+ BlockLayoutChunk chunk;
+ chunk.OffsetInBits =
+ blockLayout->getElementOffsetInBits(captureInfo.getIndex());
+ chunk.Capture = &capture;
+ chunks.push_back(chunk);
+ }
+
+ // Sort by offset.
+ llvm::array_pod_sort(chunks.begin(), chunks.end());
+
+ for (SmallVectorImpl<BlockLayoutChunk>::iterator
+ i = chunks.begin(), e = chunks.end(); i != e; ++i) {
+ uint64_t offsetInBits = i->OffsetInBits;
+ const BlockDecl::Capture *capture = i->Capture;
+
+ // If we have a null capture, this must be the C++ 'this' capture.
+ if (!capture) {
+ const CXXMethodDecl *method =
+ cast<CXXMethodDecl>(blockDecl->getNonClosureContext());
+ QualType type = method->getThisType(C);
+
+ fields.push_back(createFieldType("this", type, 0, loc, AS_public,
+ offsetInBits, tunit, tunit));
+ continue;
+ }
+
+ const VarDecl *variable = capture->getVariable();
+ StringRef name = variable->getName();
+
+ llvm::DIType fieldType;
+ if (capture->isByRef()) {
+ std::pair<uint64_t,unsigned> ptrInfo = C.getTypeInfo(C.VoidPtrTy);
+
+ // FIXME: this creates a second copy of this type!
+ uint64_t xoffset;
+ fieldType = EmitTypeForVarWithBlocksAttr(variable, &xoffset);
+ fieldType = DBuilder.createPointerType(fieldType, ptrInfo.first);
+ fieldType = DBuilder.createMemberType(tunit, name, tunit, line,
+ ptrInfo.first, ptrInfo.second,
+ offsetInBits, 0, fieldType);
+ } else {
+ fieldType = createFieldType(name, variable->getType(), 0,
+ loc, AS_public, offsetInBits, tunit, tunit);
+ }
+ fields.push_back(fieldType);
+ }
+
+ SmallString<36> typeName;
+ llvm::raw_svector_ostream(typeName)
+ << "__block_literal_" << CGM.getUniqueBlockCount();
+
+ llvm::DIArray fieldsArray = DBuilder.getOrCreateArray(fields);
+
+ llvm::DIType type =
+ DBuilder.createStructType(tunit, typeName.str(), tunit, line,
+ CGM.getContext().toBits(block.BlockSize),
+ CGM.getContext().toBits(block.BlockAlign),
+ 0, fieldsArray);
+ type = DBuilder.createPointerType(type, CGM.PointerWidthInBits);
+
+ // Get overall information about the block.
+ unsigned flags = llvm::DIDescriptor::FlagArtificial;
+ llvm::MDNode *scope = LexicalBlockStack.back();
+ StringRef name = ".block_descriptor";
+
+ // Create the descriptor for the parameter.
+ llvm::DIVariable debugVar =
+ DBuilder.createLocalVariable(llvm::dwarf::DW_TAG_arg_variable,
+ llvm::DIDescriptor(scope),
+ name, tunit, line, type,
+ CGM.getLangOpts().Optimize, flags,
+ cast<llvm::Argument>(addr)->getArgNo() + 1);
+
+ // Insert an llvm.dbg.value into the current block.
+ llvm::Instruction *declare =
+ DBuilder.insertDbgValueIntrinsic(addr, 0, debugVar,
+ Builder.GetInsertBlock());
+ declare->setDebugLoc(llvm::DebugLoc::get(line, column, scope));
+}
+
+/// EmitGlobalVariable - Emit information about a global variable.
+void CGDebugInfo::EmitGlobalVariable(llvm::GlobalVariable *Var,
+ const VarDecl *D) {
+ assert(CGM.getCodeGenOpts().getDebugInfo() >= CodeGenOptions::LimitedDebugInfo);
+ // Create global variable debug descriptor.
+ llvm::DIFile Unit = getOrCreateFile(D->getLocation());
+ unsigned LineNo = getLineNumber(D->getLocation());
+
+ setLocation(D->getLocation());
+
+ QualType T = D->getType();
+ if (T->isIncompleteArrayType()) {
+
+ // CodeGen turns int[] into int[1] so we'll do the same here.
+ llvm::APInt ConstVal(32, 1);
+ QualType ET = CGM.getContext().getAsArrayType(T)->getElementType();
+
+ T = CGM.getContext().getConstantArrayType(ET, ConstVal,
+ ArrayType::Normal, 0);
+ }
+ StringRef DeclName = D->getName();
+ StringRef LinkageName;
+ if (D->getDeclContext() && !isa<FunctionDecl>(D->getDeclContext())
+ && !isa<ObjCMethodDecl>(D->getDeclContext()))
+ LinkageName = Var->getName();
+ if (LinkageName == DeclName)
+ LinkageName = StringRef();
+ llvm::DIDescriptor DContext =
+ getContextDescriptor(dyn_cast<Decl>(D->getDeclContext()));
+ DBuilder.createStaticVariable(DContext, DeclName, LinkageName,
+ Unit, LineNo, getOrCreateType(T, Unit),
+ Var->hasInternalLinkage(), Var);
+}
+
+/// EmitGlobalVariable - Emit information about an objective-c interface.
+void CGDebugInfo::EmitGlobalVariable(llvm::GlobalVariable *Var,
+ ObjCInterfaceDecl *ID) {
+ assert(CGM.getCodeGenOpts().getDebugInfo() >= CodeGenOptions::LimitedDebugInfo);
+ // Create global variable debug descriptor.
+ llvm::DIFile Unit = getOrCreateFile(ID->getLocation());
+ unsigned LineNo = getLineNumber(ID->getLocation());
+
+ StringRef Name = ID->getName();
+
+ QualType T = CGM.getContext().getObjCInterfaceType(ID);
+ if (T->isIncompleteArrayType()) {
+
+ // CodeGen turns int[] into int[1] so we'll do the same here.
+ llvm::APInt ConstVal(32, 1);
+ QualType ET = CGM.getContext().getAsArrayType(T)->getElementType();
+
+ T = CGM.getContext().getConstantArrayType(ET, ConstVal,
+ ArrayType::Normal, 0);
+ }
+
+ DBuilder.createGlobalVariable(Name, Unit, LineNo,
+ getOrCreateType(T, Unit),
+ Var->hasInternalLinkage(), Var);
+}
+
+/// EmitGlobalVariable - Emit global variable's debug info.
+void CGDebugInfo::EmitGlobalVariable(const ValueDecl *VD,
+ llvm::Constant *Init) {
+ assert(CGM.getCodeGenOpts().getDebugInfo() >= CodeGenOptions::LimitedDebugInfo);
+ // Create the descriptor for the variable.
+ llvm::DIFile Unit = getOrCreateFile(VD->getLocation());
+ StringRef Name = VD->getName();
+ llvm::DIType Ty = getOrCreateType(VD->getType(), Unit);
+ if (const EnumConstantDecl *ECD = dyn_cast<EnumConstantDecl>(VD)) {
+ const EnumDecl *ED = cast<EnumDecl>(ECD->getDeclContext());
+ assert(isa<EnumType>(ED->getTypeForDecl()) && "Enum without EnumType?");
+ Ty = getOrCreateType(QualType(ED->getTypeForDecl(), 0), Unit);
+ }
+ // Do not use DIGlobalVariable for enums.
+ if (Ty.getTag() == llvm::dwarf::DW_TAG_enumeration_type)
+ return;
+ DBuilder.createStaticVariable(Unit, Name, Name, Unit,
+ getLineNumber(VD->getLocation()),
+ Ty, true, Init);
+}
+
+/// getOrCreateNamesSpace - Return namespace descriptor for the given
+/// namespace decl.
+llvm::DINameSpace
+CGDebugInfo::getOrCreateNameSpace(const NamespaceDecl *NSDecl) {
+ llvm::DenseMap<const NamespaceDecl *, llvm::WeakVH>::iterator I =
+ NameSpaceCache.find(NSDecl);
+ if (I != NameSpaceCache.end())
+ return llvm::DINameSpace(cast<llvm::MDNode>(I->second));
+
+ unsigned LineNo = getLineNumber(NSDecl->getLocation());
+ llvm::DIFile FileD = getOrCreateFile(NSDecl->getLocation());
+ llvm::DIDescriptor Context =
+ getContextDescriptor(dyn_cast<Decl>(NSDecl->getDeclContext()));
+ llvm::DINameSpace NS =
+ DBuilder.createNameSpace(Context, NSDecl->getName(), FileD, LineNo);
+ NameSpaceCache[NSDecl] = llvm::WeakVH(NS);
+ return NS;
+}
+
+void CGDebugInfo::finalize() {
+ for (std::vector<std::pair<void *, llvm::WeakVH> >::const_iterator VI
+ = ReplaceMap.begin(), VE = ReplaceMap.end(); VI != VE; ++VI) {
+ llvm::DIType Ty, RepTy;
+ // Verify that the debug info still exists.
+ if (llvm::Value *V = VI->second)
+ Ty = llvm::DIType(cast<llvm::MDNode>(V));
+
+ llvm::DenseMap<void *, llvm::WeakVH>::iterator it =
+ TypeCache.find(VI->first);
+ if (it != TypeCache.end()) {
+ // Verify that the debug info still exists.
+ if (llvm::Value *V = it->second)
+ RepTy = llvm::DIType(cast<llvm::MDNode>(V));
+ }
+
+ if (Ty.Verify() && Ty.isForwardDecl() && RepTy.Verify()) {
+ Ty.replaceAllUsesWith(RepTy);
+ }
+ }
+ DBuilder.finalize();
+}
diff --git a/clang/lib/CodeGen/CGDebugInfo.h b/clang/lib/CodeGen/CGDebugInfo.h index cb9ce8beef5..5a3b1221058 100644 --- a/clang/lib/CodeGen/CGDebugInfo.h +++ b/clang/lib/CodeGen/CGDebugInfo.h @@ -1,325 +1,330 @@ -//===--- CGDebugInfo.h - DebugInfo for LLVM CodeGen -------------*- C++ -*-===// -// -// The LLVM Compiler Infrastructure -// -// This file is distributed under the University of Illinois Open Source -// License. See LICENSE.TXT for details. -// -//===----------------------------------------------------------------------===// -// -// This is the source level debug info generator for llvm translation. -// -//===----------------------------------------------------------------------===// - -#ifndef CLANG_CODEGEN_CGDEBUGINFO_H -#define CLANG_CODEGEN_CGDEBUGINFO_H - -#include "CGBuilder.h" -#include "clang/AST/Expr.h" -#include "clang/AST/Type.h" -#include "clang/Basic/SourceLocation.h" -#include "llvm/ADT/DenseMap.h" -#include "llvm/DIBuilder.h" -#include "llvm/DebugInfo.h" -#include "llvm/Support/Allocator.h" -#include "llvm/Support/ValueHandle.h" - -namespace llvm { - class MDNode; -} - -namespace clang { - class CXXMethodDecl; - class VarDecl; - class ObjCInterfaceDecl; - class ClassTemplateSpecializationDecl; - class GlobalDecl; - -namespace CodeGen { - class CodeGenModule; - class CodeGenFunction; - class CGBlockInfo; - -/// CGDebugInfo - This class gathers all debug information during compilation -/// and is responsible for emitting to llvm globals or pass directly to -/// the backend. -class CGDebugInfo { - CodeGenModule &CGM; - llvm::DIBuilder DBuilder; - llvm::DICompileUnit TheCU; - SourceLocation CurLoc, PrevLoc; - llvm::DIType VTablePtrType; - llvm::DIType ClassTy; - llvm::DIType ObjTy; - llvm::DIType SelTy; - - /// TypeCache - Cache of previously constructed Types. - llvm::DenseMap<void *, llvm::WeakVH> TypeCache; - - /// CompleteTypeCache - Cache of previously constructed complete RecordTypes. - llvm::DenseMap<void *, llvm::WeakVH> CompletedTypeCache; - - /// ReplaceMap - Cache of forward declared types to RAUW at the end of - /// compilation. - std::vector<std::pair<void *, llvm::WeakVH> >ReplaceMap; - - bool BlockLiteralGenericSet; - llvm::DIType BlockLiteralGeneric; - - // LexicalBlockStack - Keep track of our current nested lexical block. - std::vector<llvm::TrackingVH<llvm::MDNode> > LexicalBlockStack; - llvm::DenseMap<const Decl *, llvm::WeakVH> RegionMap; - // FnBeginRegionCount - Keep track of LexicalBlockStack counter at the - // beginning of a function. This is used to pop unbalanced regions at - // the end of a function. - std::vector<unsigned> FnBeginRegionCount; - - /// DebugInfoNames - This is a storage for names that are - /// constructed on demand. For example, C++ destructors, C++ operators etc.. - llvm::BumpPtrAllocator DebugInfoNames; - StringRef CWDName; - - llvm::DenseMap<const char *, llvm::WeakVH> DIFileCache; - llvm::DenseMap<const FunctionDecl *, llvm::WeakVH> SPCache; - llvm::DenseMap<const NamespaceDecl *, llvm::WeakVH> NameSpaceCache; - - /// Helper functions for getOrCreateType. - llvm::DIType CreateType(const BuiltinType *Ty); - llvm::DIType CreateType(const ComplexType *Ty); - llvm::DIType CreateQualifiedType(QualType Ty, llvm::DIFile F); - llvm::DIType CreateType(const TypedefType *Ty, llvm::DIFile F); - llvm::DIType CreateType(const ObjCObjectPointerType *Ty, - llvm::DIFile F); - llvm::DIType CreateType(const PointerType *Ty, llvm::DIFile F); - llvm::DIType CreateType(const BlockPointerType *Ty, llvm::DIFile F); - llvm::DIType CreateType(const FunctionType *Ty, llvm::DIFile F); - llvm::DIType CreateType(const RecordType *Ty); - llvm::DIType CreateLimitedType(const RecordType *Ty); - llvm::DIType CreateType(const ObjCInterfaceType *Ty, llvm::DIFile F); - llvm::DIType CreateType(const ObjCObjectType *Ty, llvm::DIFile F); - llvm::DIType CreateType(const VectorType *Ty, llvm::DIFile F); - llvm::DIType CreateType(const ArrayType *Ty, llvm::DIFile F); - llvm::DIType CreateType(const LValueReferenceType *Ty, llvm::DIFile F); - llvm::DIType CreateType(const RValueReferenceType *Ty, llvm::DIFile Unit); - llvm::DIType CreateType(const MemberPointerType *Ty, llvm::DIFile F); - llvm::DIType CreateType(const AtomicType *Ty, llvm::DIFile F); - llvm::DIType CreateEnumType(const EnumDecl *ED); - llvm::DIType getTypeOrNull(const QualType); - llvm::DIType getCompletedTypeOrNull(const QualType); - llvm::DIType getOrCreateMethodType(const CXXMethodDecl *Method, - llvm::DIFile F); - llvm::DIType getOrCreateFunctionType(const Decl *D, QualType FnType, - llvm::DIFile F); - llvm::DIType getOrCreateVTablePtrType(llvm::DIFile F); - llvm::DINameSpace getOrCreateNameSpace(const NamespaceDecl *N); - llvm::DIType CreatePointeeType(QualType PointeeTy, llvm::DIFile F); - llvm::DIType CreatePointerLikeType(unsigned Tag, - const Type *Ty, QualType PointeeTy, - llvm::DIFile F); - - llvm::DISubprogram CreateCXXMemberFunction(const CXXMethodDecl *Method, - llvm::DIFile F, - llvm::DIType RecordTy); - - void CollectCXXMemberFunctions(const CXXRecordDecl *Decl, - llvm::DIFile F, - SmallVectorImpl<llvm::Value *> &E, - llvm::DIType T); - - void CollectCXXFriends(const CXXRecordDecl *Decl, - llvm::DIFile F, - SmallVectorImpl<llvm::Value *> &EltTys, - llvm::DIType RecordTy); - - void CollectCXXBases(const CXXRecordDecl *Decl, - llvm::DIFile F, - SmallVectorImpl<llvm::Value *> &EltTys, - llvm::DIType RecordTy); - - llvm::DIArray - CollectTemplateParams(const TemplateParameterList *TPList, - const TemplateArgumentList &TAList, - llvm::DIFile Unit); - llvm::DIArray - CollectFunctionTemplateParams(const FunctionDecl *FD, llvm::DIFile Unit); - llvm::DIArray - CollectCXXTemplateParams(const ClassTemplateSpecializationDecl *TS, - llvm::DIFile F); - - llvm::DIType createFieldType(StringRef name, QualType type, - uint64_t sizeInBitsOverride, SourceLocation loc, - AccessSpecifier AS, uint64_t offsetInBits, - llvm::DIFile tunit, - llvm::DIDescriptor scope); - void CollectRecordStaticVars(const RecordDecl *, llvm::DIType); - void CollectRecordFields(const RecordDecl *Decl, llvm::DIFile F, - SmallVectorImpl<llvm::Value *> &E, - llvm::DIType RecordTy); - - void CollectVTableInfo(const CXXRecordDecl *Decl, - llvm::DIFile F, - SmallVectorImpl<llvm::Value *> &EltTys); - - // CreateLexicalBlock - Create a new lexical block node and push it on - // the stack. - void CreateLexicalBlock(SourceLocation Loc); - -public: - CGDebugInfo(CodeGenModule &CGM); - ~CGDebugInfo(); - - void finalize(); - - /// setLocation - Update the current source location. If \arg loc is - /// invalid it is ignored. - void setLocation(SourceLocation Loc); - - /// EmitLocation - Emit metadata to indicate a change in line/column - /// information in the source file. - void EmitLocation(CGBuilderTy &Builder, SourceLocation Loc); - - /// EmitFunctionStart - Emit a call to llvm.dbg.function.start to indicate - /// start of a new function. - void EmitFunctionStart(GlobalDecl GD, QualType FnType, - llvm::Function *Fn, CGBuilderTy &Builder); - - /// EmitFunctionEnd - Constructs the debug code for exiting a function. - void EmitFunctionEnd(CGBuilderTy &Builder); - - /// EmitLexicalBlockStart - Emit metadata to indicate the beginning of a - /// new lexical block and push the block onto the stack. - void EmitLexicalBlockStart(CGBuilderTy &Builder, SourceLocation Loc); - - /// EmitLexicalBlockEnd - Emit metadata to indicate the end of a new lexical - /// block and pop the current block. - void EmitLexicalBlockEnd(CGBuilderTy &Builder, SourceLocation Loc); - - /// EmitDeclareOfAutoVariable - Emit call to llvm.dbg.declare for an automatic - /// variable declaration. - void EmitDeclareOfAutoVariable(const VarDecl *Decl, llvm::Value *AI, - CGBuilderTy &Builder); - - /// EmitDeclareOfBlockDeclRefVariable - Emit call to llvm.dbg.declare for an - /// imported variable declaration in a block. - void EmitDeclareOfBlockDeclRefVariable(const VarDecl *variable, - llvm::Value *storage, - CGBuilderTy &Builder, - const CGBlockInfo &blockInfo); - - /// EmitDeclareOfArgVariable - Emit call to llvm.dbg.declare for an argument - /// variable declaration. - void EmitDeclareOfArgVariable(const VarDecl *Decl, llvm::Value *AI, - unsigned ArgNo, CGBuilderTy &Builder); - - /// EmitDeclareOfBlockLiteralArgVariable - Emit call to - /// llvm.dbg.declare for the block-literal argument to a block - /// invocation function. - void EmitDeclareOfBlockLiteralArgVariable(const CGBlockInfo &block, - llvm::Value *addr, - CGBuilderTy &Builder); - - /// EmitGlobalVariable - Emit information about a global variable. - void EmitGlobalVariable(llvm::GlobalVariable *GV, const VarDecl *Decl); - - /// EmitGlobalVariable - Emit information about an objective-c interface. - void EmitGlobalVariable(llvm::GlobalVariable *GV, ObjCInterfaceDecl *Decl); - - /// EmitGlobalVariable - Emit global variable's debug info. - void EmitGlobalVariable(const ValueDecl *VD, llvm::Constant *Init); - - /// getOrCreateRecordType - Emit record type's standalone debug info. - llvm::DIType getOrCreateRecordType(QualType Ty, SourceLocation L); - - /// getOrCreateInterfaceType - Emit an objective c interface type standalone - /// debug info. - llvm::DIType getOrCreateInterfaceType(QualType Ty, - SourceLocation Loc); - -private: - /// EmitDeclare - Emit call to llvm.dbg.declare for a variable declaration. - void EmitDeclare(const VarDecl *decl, unsigned Tag, llvm::Value *AI, - unsigned ArgNo, CGBuilderTy &Builder); - - // EmitTypeForVarWithBlocksAttr - Build up structure info for the byref. - // See BuildByRefType. - llvm::DIType EmitTypeForVarWithBlocksAttr(const VarDecl *VD, - uint64_t *OffSet); - - /// getContextDescriptor - Get context info for the decl. - llvm::DIDescriptor getContextDescriptor(const Decl *Decl); - - /// createRecordFwdDecl - Create a forward decl for a RecordType in a given - /// context. - llvm::DIType createRecordFwdDecl(const RecordDecl *, llvm::DIDescriptor); - - /// createContextChain - Create a set of decls for the context chain. - llvm::DIDescriptor createContextChain(const Decl *Decl); - - /// getCurrentDirname - Return current directory name. - StringRef getCurrentDirname(); - - /// CreateCompileUnit - Create new compile unit. - void CreateCompileUnit(); - - /// getOrCreateFile - Get the file debug info descriptor for the input - /// location. - llvm::DIFile getOrCreateFile(SourceLocation Loc); - - /// getOrCreateMainFile - Get the file info for main compile unit. - llvm::DIFile getOrCreateMainFile(); - - /// getOrCreateType - Get the type from the cache or create a new type if - /// necessary. - llvm::DIType getOrCreateType(QualType Ty, llvm::DIFile F); - - /// getOrCreateLimitedType - Get the type from the cache or create a new - /// partial type if necessary. - llvm::DIType getOrCreateLimitedType(QualType Ty, llvm::DIFile F); - - /// CreateTypeNode - Create type metadata for a source language type. - llvm::DIType CreateTypeNode(QualType Ty, llvm::DIFile F); - - /// CreateLimitedTypeNode - Create type metadata for a source language - /// type, but only partial types for records. - llvm::DIType CreateLimitedTypeNode(QualType Ty, llvm::DIFile F); - - /// CreateMemberType - Create new member and increase Offset by FType's size. - llvm::DIType CreateMemberType(llvm::DIFile Unit, QualType FType, - StringRef Name, uint64_t *Offset); - - /// getFunctionDeclaration - Return debug info descriptor to describe method - /// declaration for the given method definition. - llvm::DISubprogram getFunctionDeclaration(const Decl *D); - - /// getFunctionName - Get function name for the given FunctionDecl. If the - /// name is constructred on demand (e.g. C++ destructor) then the name - /// is stored on the side. - StringRef getFunctionName(const FunctionDecl *FD); - - /// getObjCMethodName - Returns the unmangled name of an Objective-C method. - /// This is the display name for the debugging info. - StringRef getObjCMethodName(const ObjCMethodDecl *FD); - - /// getSelectorName - Return selector name. This is used for debugging - /// info. - StringRef getSelectorName(Selector S); - - /// getClassName - Get class name including template argument list. - StringRef getClassName(const RecordDecl *RD); - - /// getVTableName - Get vtable name for the given Class. - StringRef getVTableName(const CXXRecordDecl *Decl); - - /// getLineNumber - Get line number for the location. If location is invalid - /// then use current location. - unsigned getLineNumber(SourceLocation Loc); - - /// getColumnNumber - Get column number for the location. If location is - /// invalid then use current location. - unsigned getColumnNumber(SourceLocation Loc); -}; -} // namespace CodeGen -} // namespace clang - - -#endif +//===--- CGDebugInfo.h - DebugInfo for LLVM CodeGen -------------*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+//
+// This is the source level debug info generator for llvm translation.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef CLANG_CODEGEN_CGDEBUGINFO_H
+#define CLANG_CODEGEN_CGDEBUGINFO_H
+
+#include "CGBuilder.h"
+#include "clang/AST/Expr.h"
+#include "clang/AST/Type.h"
+#include "clang/Basic/SourceLocation.h"
+#include "llvm/ADT/DenseMap.h"
+#include "llvm/DIBuilder.h"
+#include "llvm/DebugInfo.h"
+#include "llvm/Support/Allocator.h"
+#include "llvm/Support/ValueHandle.h"
+
+namespace llvm {
+ class MDNode;
+}
+
+namespace clang {
+ class CXXMethodDecl;
+ class VarDecl;
+ class ObjCInterfaceDecl;
+ class ClassTemplateSpecializationDecl;
+ class GlobalDecl;
+
+namespace CodeGen {
+ class CodeGenModule;
+ class CodeGenFunction;
+ class CGBlockInfo;
+
+/// CGDebugInfo - This class gathers all debug information during compilation
+/// and is responsible for emitting to llvm globals or pass directly to
+/// the backend.
+class CGDebugInfo {
+ CodeGenModule &CGM;
+ llvm::DIBuilder DBuilder;
+ llvm::DICompileUnit TheCU;
+ SourceLocation CurLoc, PrevLoc;
+ llvm::DIType VTablePtrType;
+ llvm::DIType ClassTy;
+ llvm::DIType ObjTy;
+ llvm::DIType SelTy;
+ llvm::DIType OCLImage1dDITy, OCLImage1dArrayDITy, OCLImage1dBufferDITy;
+ llvm::DIType OCLImage2dDITy, OCLImage2dArrayDITy;
+ llvm::DIType OCLImage3dDITy;
+
+ /// TypeCache - Cache of previously constructed Types.
+ llvm::DenseMap<void *, llvm::WeakVH> TypeCache;
+
+ /// CompleteTypeCache - Cache of previously constructed complete RecordTypes.
+ llvm::DenseMap<void *, llvm::WeakVH> CompletedTypeCache;
+
+ /// ReplaceMap - Cache of forward declared types to RAUW at the end of
+ /// compilation.
+ std::vector<std::pair<void *, llvm::WeakVH> >ReplaceMap;
+
+ bool BlockLiteralGenericSet;
+ llvm::DIType BlockLiteralGeneric;
+
+ // LexicalBlockStack - Keep track of our current nested lexical block.
+ std::vector<llvm::TrackingVH<llvm::MDNode> > LexicalBlockStack;
+ llvm::DenseMap<const Decl *, llvm::WeakVH> RegionMap;
+ // FnBeginRegionCount - Keep track of LexicalBlockStack counter at the
+ // beginning of a function. This is used to pop unbalanced regions at
+ // the end of a function.
+ std::vector<unsigned> FnBeginRegionCount;
+
+ /// DebugInfoNames - This is a storage for names that are
+ /// constructed on demand. For example, C++ destructors, C++ operators etc..
+ llvm::BumpPtrAllocator DebugInfoNames;
+ StringRef CWDName;
+
+ llvm::DenseMap<const char *, llvm::WeakVH> DIFileCache;
+ llvm::DenseMap<const FunctionDecl *, llvm::WeakVH> SPCache;
+ llvm::DenseMap<const NamespaceDecl *, llvm::WeakVH> NameSpaceCache;
+
+ /// Helper functions for getOrCreateType.
+ llvm::DIType CreateType(const BuiltinType *Ty);
+ llvm::DIType CreateType(const ComplexType *Ty);
+ llvm::DIType CreateQualifiedType(QualType Ty, llvm::DIFile F);
+ llvm::DIType CreateType(const TypedefType *Ty, llvm::DIFile F);
+ llvm::DIType CreateType(const ObjCObjectPointerType *Ty,
+ llvm::DIFile F);
+ llvm::DIType CreateType(const PointerType *Ty, llvm::DIFile F);
+ llvm::DIType CreateType(const BlockPointerType *Ty, llvm::DIFile F);
+ llvm::DIType CreateType(const FunctionType *Ty, llvm::DIFile F);
+ llvm::DIType CreateType(const RecordType *Ty);
+ llvm::DIType CreateLimitedType(const RecordType *Ty);
+ llvm::DIType CreateType(const ObjCInterfaceType *Ty, llvm::DIFile F);
+ llvm::DIType CreateType(const ObjCObjectType *Ty, llvm::DIFile F);
+ llvm::DIType CreateType(const VectorType *Ty, llvm::DIFile F);
+ llvm::DIType CreateType(const ArrayType *Ty, llvm::DIFile F);
+ llvm::DIType CreateType(const LValueReferenceType *Ty, llvm::DIFile F);
+ llvm::DIType CreateType(const RValueReferenceType *Ty, llvm::DIFile Unit);
+ llvm::DIType CreateType(const MemberPointerType *Ty, llvm::DIFile F);
+ llvm::DIType CreateType(const AtomicType *Ty, llvm::DIFile F);
+ llvm::DIType CreateEnumType(const EnumDecl *ED);
+ llvm::DIType getTypeOrNull(const QualType);
+ llvm::DIType getCompletedTypeOrNull(const QualType);
+ llvm::DIType getOrCreateMethodType(const CXXMethodDecl *Method,
+ llvm::DIFile F);
+ llvm::DIType getOrCreateFunctionType(const Decl *D, QualType FnType,
+ llvm::DIFile F);
+ llvm::DIType getOrCreateVTablePtrType(llvm::DIFile F);
+ llvm::DINameSpace getOrCreateNameSpace(const NamespaceDecl *N);
+ llvm::DIType CreatePointeeType(QualType PointeeTy, llvm::DIFile F);
+ llvm::DIType CreatePointerLikeType(unsigned Tag,
+ const Type *Ty, QualType PointeeTy,
+ llvm::DIFile F);
+
+ llvm::DIType getOrCreateStructPtrType(StringRef Name, llvm::DIType &Cache);
+
+ llvm::DISubprogram CreateCXXMemberFunction(const CXXMethodDecl *Method,
+ llvm::DIFile F,
+ llvm::DIType RecordTy);
+
+ void CollectCXXMemberFunctions(const CXXRecordDecl *Decl,
+ llvm::DIFile F,
+ SmallVectorImpl<llvm::Value *> &E,
+ llvm::DIType T);
+
+ void CollectCXXFriends(const CXXRecordDecl *Decl,
+ llvm::DIFile F,
+ SmallVectorImpl<llvm::Value *> &EltTys,
+ llvm::DIType RecordTy);
+
+ void CollectCXXBases(const CXXRecordDecl *Decl,
+ llvm::DIFile F,
+ SmallVectorImpl<llvm::Value *> &EltTys,
+ llvm::DIType RecordTy);
+
+ llvm::DIArray
+ CollectTemplateParams(const TemplateParameterList *TPList,
+ const TemplateArgumentList &TAList,
+ llvm::DIFile Unit);
+ llvm::DIArray
+ CollectFunctionTemplateParams(const FunctionDecl *FD, llvm::DIFile Unit);
+ llvm::DIArray
+ CollectCXXTemplateParams(const ClassTemplateSpecializationDecl *TS,
+ llvm::DIFile F);
+
+ llvm::DIType createFieldType(StringRef name, QualType type,
+ uint64_t sizeInBitsOverride, SourceLocation loc,
+ AccessSpecifier AS, uint64_t offsetInBits,
+ llvm::DIFile tunit,
+ llvm::DIDescriptor scope);
+ void CollectRecordStaticVars(const RecordDecl *, llvm::DIType);
+ void CollectRecordFields(const RecordDecl *Decl, llvm::DIFile F,
+ SmallVectorImpl<llvm::Value *> &E,
+ llvm::DIType RecordTy);
+
+ void CollectVTableInfo(const CXXRecordDecl *Decl,
+ llvm::DIFile F,
+ SmallVectorImpl<llvm::Value *> &EltTys);
+
+ // CreateLexicalBlock - Create a new lexical block node and push it on
+ // the stack.
+ void CreateLexicalBlock(SourceLocation Loc);
+
+public:
+ CGDebugInfo(CodeGenModule &CGM);
+ ~CGDebugInfo();
+
+ void finalize();
+
+ /// setLocation - Update the current source location. If \arg loc is
+ /// invalid it is ignored.
+ void setLocation(SourceLocation Loc);
+
+ /// EmitLocation - Emit metadata to indicate a change in line/column
+ /// information in the source file.
+ void EmitLocation(CGBuilderTy &Builder, SourceLocation Loc);
+
+ /// EmitFunctionStart - Emit a call to llvm.dbg.function.start to indicate
+ /// start of a new function.
+ void EmitFunctionStart(GlobalDecl GD, QualType FnType,
+ llvm::Function *Fn, CGBuilderTy &Builder);
+
+ /// EmitFunctionEnd - Constructs the debug code for exiting a function.
+ void EmitFunctionEnd(CGBuilderTy &Builder);
+
+ /// EmitLexicalBlockStart - Emit metadata to indicate the beginning of a
+ /// new lexical block and push the block onto the stack.
+ void EmitLexicalBlockStart(CGBuilderTy &Builder, SourceLocation Loc);
+
+ /// EmitLexicalBlockEnd - Emit metadata to indicate the end of a new lexical
+ /// block and pop the current block.
+ void EmitLexicalBlockEnd(CGBuilderTy &Builder, SourceLocation Loc);
+
+ /// EmitDeclareOfAutoVariable - Emit call to llvm.dbg.declare for an automatic
+ /// variable declaration.
+ void EmitDeclareOfAutoVariable(const VarDecl *Decl, llvm::Value *AI,
+ CGBuilderTy &Builder);
+
+ /// EmitDeclareOfBlockDeclRefVariable - Emit call to llvm.dbg.declare for an
+ /// imported variable declaration in a block.
+ void EmitDeclareOfBlockDeclRefVariable(const VarDecl *variable,
+ llvm::Value *storage,
+ CGBuilderTy &Builder,
+ const CGBlockInfo &blockInfo);
+
+ /// EmitDeclareOfArgVariable - Emit call to llvm.dbg.declare for an argument
+ /// variable declaration.
+ void EmitDeclareOfArgVariable(const VarDecl *Decl, llvm::Value *AI,
+ unsigned ArgNo, CGBuilderTy &Builder);
+
+ /// EmitDeclareOfBlockLiteralArgVariable - Emit call to
+ /// llvm.dbg.declare for the block-literal argument to a block
+ /// invocation function.
+ void EmitDeclareOfBlockLiteralArgVariable(const CGBlockInfo &block,
+ llvm::Value *addr,
+ CGBuilderTy &Builder);
+
+ /// EmitGlobalVariable - Emit information about a global variable.
+ void EmitGlobalVariable(llvm::GlobalVariable *GV, const VarDecl *Decl);
+
+ /// EmitGlobalVariable - Emit information about an objective-c interface.
+ void EmitGlobalVariable(llvm::GlobalVariable *GV, ObjCInterfaceDecl *Decl);
+
+ /// EmitGlobalVariable - Emit global variable's debug info.
+ void EmitGlobalVariable(const ValueDecl *VD, llvm::Constant *Init);
+
+ /// getOrCreateRecordType - Emit record type's standalone debug info.
+ llvm::DIType getOrCreateRecordType(QualType Ty, SourceLocation L);
+
+ /// getOrCreateInterfaceType - Emit an objective c interface type standalone
+ /// debug info.
+ llvm::DIType getOrCreateInterfaceType(QualType Ty,
+ SourceLocation Loc);
+
+private:
+ /// EmitDeclare - Emit call to llvm.dbg.declare for a variable declaration.
+ void EmitDeclare(const VarDecl *decl, unsigned Tag, llvm::Value *AI,
+ unsigned ArgNo, CGBuilderTy &Builder);
+
+ // EmitTypeForVarWithBlocksAttr - Build up structure info for the byref.
+ // See BuildByRefType.
+ llvm::DIType EmitTypeForVarWithBlocksAttr(const VarDecl *VD,
+ uint64_t *OffSet);
+
+ /// getContextDescriptor - Get context info for the decl.
+ llvm::DIDescriptor getContextDescriptor(const Decl *Decl);
+
+ /// createRecordFwdDecl - Create a forward decl for a RecordType in a given
+ /// context.
+ llvm::DIType createRecordFwdDecl(const RecordDecl *, llvm::DIDescriptor);
+
+ /// createContextChain - Create a set of decls for the context chain.
+ llvm::DIDescriptor createContextChain(const Decl *Decl);
+
+ /// getCurrentDirname - Return current directory name.
+ StringRef getCurrentDirname();
+
+ /// CreateCompileUnit - Create new compile unit.
+ void CreateCompileUnit();
+
+ /// getOrCreateFile - Get the file debug info descriptor for the input
+ /// location.
+ llvm::DIFile getOrCreateFile(SourceLocation Loc);
+
+ /// getOrCreateMainFile - Get the file info for main compile unit.
+ llvm::DIFile getOrCreateMainFile();
+
+ /// getOrCreateType - Get the type from the cache or create a new type if
+ /// necessary.
+ llvm::DIType getOrCreateType(QualType Ty, llvm::DIFile F);
+
+ /// getOrCreateLimitedType - Get the type from the cache or create a new
+ /// partial type if necessary.
+ llvm::DIType getOrCreateLimitedType(QualType Ty, llvm::DIFile F);
+
+ /// CreateTypeNode - Create type metadata for a source language type.
+ llvm::DIType CreateTypeNode(QualType Ty, llvm::DIFile F);
+
+ /// CreateLimitedTypeNode - Create type metadata for a source language
+ /// type, but only partial types for records.
+ llvm::DIType CreateLimitedTypeNode(QualType Ty, llvm::DIFile F);
+
+ /// CreateMemberType - Create new member and increase Offset by FType's size.
+ llvm::DIType CreateMemberType(llvm::DIFile Unit, QualType FType,
+ StringRef Name, uint64_t *Offset);
+
+ /// getFunctionDeclaration - Return debug info descriptor to describe method
+ /// declaration for the given method definition.
+ llvm::DISubprogram getFunctionDeclaration(const Decl *D);
+
+ /// getFunctionName - Get function name for the given FunctionDecl. If the
+ /// name is constructred on demand (e.g. C++ destructor) then the name
+ /// is stored on the side.
+ StringRef getFunctionName(const FunctionDecl *FD);
+
+ /// getObjCMethodName - Returns the unmangled name of an Objective-C method.
+ /// This is the display name for the debugging info.
+ StringRef getObjCMethodName(const ObjCMethodDecl *FD);
+
+ /// getSelectorName - Return selector name. This is used for debugging
+ /// info.
+ StringRef getSelectorName(Selector S);
+
+ /// getClassName - Get class name including template argument list.
+ StringRef getClassName(const RecordDecl *RD);
+
+ /// getVTableName - Get vtable name for the given Class.
+ StringRef getVTableName(const CXXRecordDecl *Decl);
+
+ /// getLineNumber - Get line number for the location. If location is invalid
+ /// then use current location.
+ unsigned getLineNumber(SourceLocation Loc);
+
+ /// getColumnNumber - Get column number for the location. If location is
+ /// invalid then use current location.
+ unsigned getColumnNumber(SourceLocation Loc);
+};
+} // namespace CodeGen
+} // namespace clang
+
+
+#endif
diff --git a/clang/lib/CodeGen/CGOpenCLRuntime.cpp b/clang/lib/CodeGen/CGOpenCLRuntime.cpp index 3a0e116e5ab..61d62860d18 100644 --- a/clang/lib/CodeGen/CGOpenCLRuntime.cpp +++ b/clang/lib/CodeGen/CGOpenCLRuntime.cpp @@ -1,28 +1,59 @@ -//===----- CGOpenCLRuntime.cpp - Interface to OpenCL Runtimes -------------===// -// -// The LLVM Compiler Infrastructure -// -// This file is distributed under the University of Illinois Open Source -// License. See LICENSE.TXT for details. -// -//===----------------------------------------------------------------------===// -// -// This provides an abstract class for OpenCL code generation. Concrete -// subclasses of this implement code generation for specific OpenCL -// runtime libraries. -// -//===----------------------------------------------------------------------===// - -#include "CGOpenCLRuntime.h" -#include "CodeGenFunction.h" -#include "llvm/GlobalValue.h" - -using namespace clang; -using namespace CodeGen; - -CGOpenCLRuntime::~CGOpenCLRuntime() {} - -void CGOpenCLRuntime::EmitWorkGroupLocalVarDecl(CodeGenFunction &CGF, - const VarDecl &D) { - return CGF.EmitStaticVarDecl(D, llvm::GlobalValue::InternalLinkage); -} +//===----- CGOpenCLRuntime.cpp - Interface to OpenCL Runtimes -------------===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+//
+// This provides an abstract class for OpenCL code generation. Concrete
+// subclasses of this implement code generation for specific OpenCL
+// runtime libraries.
+//
+//===----------------------------------------------------------------------===//
+
+#include "CGOpenCLRuntime.h"
+#include "CodeGenFunction.h"
+#include "llvm/GlobalValue.h"
+#include "llvm/DerivedTypes.h"
+#include <assert.h>
+
+using namespace clang;
+using namespace CodeGen;
+
+CGOpenCLRuntime::~CGOpenCLRuntime() {}
+
+void CGOpenCLRuntime::EmitWorkGroupLocalVarDecl(CodeGenFunction &CGF,
+ const VarDecl &D) {
+ return CGF.EmitStaticVarDecl(D, llvm::GlobalValue::InternalLinkage);
+}
+
+llvm::Type *CGOpenCLRuntime::convertOpenCLSpecificType(const Type *T) {
+ assert(T->isOpenCLSpecificType() &&
+ "Not an OpenCL specific type!");
+
+ switch (cast<BuiltinType>(T)->getKind()) {
+ default:
+ llvm_unreachable("Unexpected opencl builtin type!");
+ return 0;
+ case BuiltinType::OCLImage1d:
+ return llvm::PointerType::get(llvm::StructType::create(
+ CGM.getLLVMContext(), "opencl.image1d_t"), 0);
+ case BuiltinType::OCLImage1dArray:
+ return llvm::PointerType::get(llvm::StructType::create(
+ CGM.getLLVMContext(), "opencl.image1d_array_t"), 0);
+ case BuiltinType::OCLImage1dBuffer:
+ return llvm::PointerType::get(llvm::StructType::create(
+ CGM.getLLVMContext(), "opencl.image1d_buffer_t"), 0);
+ case BuiltinType::OCLImage2d:
+ return llvm::PointerType::get(llvm::StructType::create(
+ CGM.getLLVMContext(), "opencl.image2d_t"), 0);
+ case BuiltinType::OCLImage2dArray:
+ return llvm::PointerType::get(llvm::StructType::create(
+ CGM.getLLVMContext(), "opencl.image2d_array_t"), 0);
+ case BuiltinType::OCLImage3d:
+ return llvm::PointerType::get(llvm::StructType::create(
+ CGM.getLLVMContext(), "opencl.image3d_t"), 0);
+ }
+}
diff --git a/clang/lib/CodeGen/CGOpenCLRuntime.h b/clang/lib/CodeGen/CGOpenCLRuntime.h index 9a8430fb750..7b33951c267 100644 --- a/clang/lib/CodeGen/CGOpenCLRuntime.h +++ b/clang/lib/CodeGen/CGOpenCLRuntime.h @@ -1,46 +1,52 @@ -//===----- CGOpenCLRuntime.h - Interface to OpenCL Runtimes -----*- C++ -*-===// -// -// The LLVM Compiler Infrastructure -// -// This file is distributed under the University of Illinois Open Source -// License. See LICENSE.TXT for details. -// -//===----------------------------------------------------------------------===// -// -// This provides an abstract class for OpenCL code generation. Concrete -// subclasses of this implement code generation for specific OpenCL -// runtime libraries. -// -//===----------------------------------------------------------------------===// - -#ifndef CLANG_CODEGEN_OPENCLRUNTIME_H -#define CLANG_CODEGEN_OPENCLRUNTIME_H - -namespace clang { - -class VarDecl; - -namespace CodeGen { - -class CodeGenFunction; -class CodeGenModule; - -class CGOpenCLRuntime { -protected: - CodeGenModule &CGM; - -public: - CGOpenCLRuntime(CodeGenModule &CGM) : CGM(CGM) {} - virtual ~CGOpenCLRuntime(); - - /// Emit the IR required for a work-group-local variable declaration, and add - /// an entry to CGF's LocalDeclMap for D. The base class does this using - /// CodeGenFunction::EmitStaticVarDecl to emit an internal global for D. - virtual void EmitWorkGroupLocalVarDecl(CodeGenFunction &CGF, - const VarDecl &D); -}; - -} -} - -#endif +//===----- CGOpenCLRuntime.h - Interface to OpenCL Runtimes -----*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+//
+// This provides an abstract class for OpenCL code generation. Concrete
+// subclasses of this implement code generation for specific OpenCL
+// runtime libraries.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef CLANG_CODEGEN_OPENCLRUNTIME_H
+#define CLANG_CODEGEN_OPENCLRUNTIME_H
+
+#include "clang/AST/Type.h"
+#include "llvm/Type.h"
+#include "llvm/Value.h"
+
+namespace clang {
+
+class VarDecl;
+
+namespace CodeGen {
+
+class CodeGenFunction;
+class CodeGenModule;
+
+class CGOpenCLRuntime {
+protected:
+ CodeGenModule &CGM;
+
+public:
+ CGOpenCLRuntime(CodeGenModule &CGM) : CGM(CGM) {}
+ virtual ~CGOpenCLRuntime();
+
+ /// Emit the IR required for a work-group-local variable declaration, and add
+ /// an entry to CGF's LocalDeclMap for D. The base class does this using
+ /// CodeGenFunction::EmitStaticVarDecl to emit an internal global for D.
+ virtual void EmitWorkGroupLocalVarDecl(CodeGenFunction &CGF,
+ const VarDecl &D);
+
+ virtual llvm::Type *convertOpenCLSpecificType(const Type *T);
+};
+
+}
+}
+
+#endif
diff --git a/clang/lib/CodeGen/CGRTTI.cpp b/clang/lib/CodeGen/CGRTTI.cpp index 53716a071f2..0a1fb4b02c6 100644 --- a/clang/lib/CodeGen/CGRTTI.cpp +++ b/clang/lib/CodeGen/CGRTTI.cpp @@ -1,1011 +1,1017 @@ -//===--- CGCXXRTTI.cpp - Emit LLVM Code for C++ RTTI descriptors ----------===// -// -// The LLVM Compiler Infrastructure -// -// This file is distributed under the University of Illinois Open Source -// License. See LICENSE.TXT for details. -// -//===----------------------------------------------------------------------===// -// -// This contains code dealing with C++ code generation of RTTI descriptors. -// -//===----------------------------------------------------------------------===// - -#include "CodeGenModule.h" -#include "CGCXXABI.h" -#include "CGObjCRuntime.h" -#include "clang/AST/RecordLayout.h" -#include "clang/AST/Type.h" -#include "clang/Frontend/CodeGenOptions.h" - -using namespace clang; -using namespace CodeGen; - -namespace { -class RTTIBuilder { - CodeGenModule &CGM; // Per-module state. - llvm::LLVMContext &VMContext; - - /// Fields - The fields of the RTTI descriptor currently being built. - SmallVector<llvm::Constant *, 16> Fields; - - /// GetAddrOfTypeName - Returns the mangled type name of the given type. - llvm::GlobalVariable * - GetAddrOfTypeName(QualType Ty, llvm::GlobalVariable::LinkageTypes Linkage); - - /// GetAddrOfExternalRTTIDescriptor - Returns the constant for the RTTI - /// descriptor of the given type. - llvm::Constant *GetAddrOfExternalRTTIDescriptor(QualType Ty); - - /// BuildVTablePointer - Build the vtable pointer for the given type. - void BuildVTablePointer(const Type *Ty); - - /// BuildSIClassTypeInfo - Build an abi::__si_class_type_info, used for single - /// inheritance, according to the Itanium C++ ABI, 2.9.5p6b. - void BuildSIClassTypeInfo(const CXXRecordDecl *RD); - - /// BuildVMIClassTypeInfo - Build an abi::__vmi_class_type_info, used for - /// classes with bases that do not satisfy the abi::__si_class_type_info - /// constraints, according ti the Itanium C++ ABI, 2.9.5p5c. - void BuildVMIClassTypeInfo(const CXXRecordDecl *RD); - - /// BuildPointerTypeInfo - Build an abi::__pointer_type_info struct, used - /// for pointer types. - void BuildPointerTypeInfo(QualType PointeeTy); - - /// BuildObjCObjectTypeInfo - Build the appropriate kind of - /// type_info for an object type. - void BuildObjCObjectTypeInfo(const ObjCObjectType *Ty); - - /// BuildPointerToMemberTypeInfo - Build an abi::__pointer_to_member_type_info - /// struct, used for member pointer types. - void BuildPointerToMemberTypeInfo(const MemberPointerType *Ty); - -public: - RTTIBuilder(CodeGenModule &CGM) : CGM(CGM), - VMContext(CGM.getModule().getContext()) { } - - // Pointer type info flags. - enum { - /// PTI_Const - Type has const qualifier. - PTI_Const = 0x1, - - /// PTI_Volatile - Type has volatile qualifier. - PTI_Volatile = 0x2, - - /// PTI_Restrict - Type has restrict qualifier. - PTI_Restrict = 0x4, - - /// PTI_Incomplete - Type is incomplete. - PTI_Incomplete = 0x8, - - /// PTI_ContainingClassIncomplete - Containing class is incomplete. - /// (in pointer to member). - PTI_ContainingClassIncomplete = 0x10 - }; - - // VMI type info flags. - enum { - /// VMI_NonDiamondRepeat - Class has non-diamond repeated inheritance. - VMI_NonDiamondRepeat = 0x1, - - /// VMI_DiamondShaped - Class is diamond shaped. - VMI_DiamondShaped = 0x2 - }; - - // Base class type info flags. - enum { - /// BCTI_Virtual - Base class is virtual. - BCTI_Virtual = 0x1, - - /// BCTI_Public - Base class is public. - BCTI_Public = 0x2 - }; - - /// BuildTypeInfo - Build the RTTI type info struct for the given type. - /// - /// \param Force - true to force the creation of this RTTI value - llvm::Constant *BuildTypeInfo(QualType Ty, bool Force = false); -}; -} - -llvm::GlobalVariable * -RTTIBuilder::GetAddrOfTypeName(QualType Ty, - llvm::GlobalVariable::LinkageTypes Linkage) { - SmallString<256> OutName; - llvm::raw_svector_ostream Out(OutName); - CGM.getCXXABI().getMangleContext().mangleCXXRTTIName(Ty, Out); - Out.flush(); - StringRef Name = OutName.str(); - - // We know that the mangled name of the type starts at index 4 of the - // mangled name of the typename, so we can just index into it in order to - // get the mangled name of the type. - llvm::Constant *Init = llvm::ConstantDataArray::getString(VMContext, - Name.substr(4)); - - llvm::GlobalVariable *GV = - CGM.CreateOrReplaceCXXRuntimeVariable(Name, Init->getType(), Linkage); - - GV->setInitializer(Init); - - return GV; -} - -llvm::Constant *RTTIBuilder::GetAddrOfExternalRTTIDescriptor(QualType Ty) { - // Mangle the RTTI name. - SmallString<256> OutName; - llvm::raw_svector_ostream Out(OutName); - CGM.getCXXABI().getMangleContext().mangleCXXRTTI(Ty, Out); - Out.flush(); - StringRef Name = OutName.str(); - - // Look for an existing global. - llvm::GlobalVariable *GV = CGM.getModule().getNamedGlobal(Name); - - if (!GV) { - // Create a new global variable. - GV = new llvm::GlobalVariable(CGM.getModule(), CGM.Int8PtrTy, - /*Constant=*/true, - llvm::GlobalValue::ExternalLinkage, 0, Name); - } - - return llvm::ConstantExpr::getBitCast(GV, CGM.Int8PtrTy); -} - -/// TypeInfoIsInStandardLibrary - Given a builtin type, returns whether the type -/// info for that type is defined in the standard library. -static bool TypeInfoIsInStandardLibrary(const BuiltinType *Ty) { - // Itanium C++ ABI 2.9.2: - // Basic type information (e.g. for "int", "bool", etc.) will be kept in - // the run-time support library. Specifically, the run-time support - // library should contain type_info objects for the types X, X* and - // X const*, for every X in: void, std::nullptr_t, bool, wchar_t, char, - // unsigned char, signed char, short, unsigned short, int, unsigned int, - // long, unsigned long, long long, unsigned long long, float, double, - // long double, char16_t, char32_t, and the IEEE 754r decimal and - // half-precision floating point types. - switch (Ty->getKind()) { - case BuiltinType::Void: - case BuiltinType::NullPtr: - case BuiltinType::Bool: - case BuiltinType::WChar_S: - case BuiltinType::WChar_U: - case BuiltinType::Char_U: - case BuiltinType::Char_S: - case BuiltinType::UChar: - case BuiltinType::SChar: - case BuiltinType::Short: - case BuiltinType::UShort: - case BuiltinType::Int: - case BuiltinType::UInt: - case BuiltinType::Long: - case BuiltinType::ULong: - case BuiltinType::LongLong: - case BuiltinType::ULongLong: - case BuiltinType::Half: - case BuiltinType::Float: - case BuiltinType::Double: - case BuiltinType::LongDouble: - case BuiltinType::Char16: - case BuiltinType::Char32: - case BuiltinType::Int128: - case BuiltinType::UInt128: - return true; - - case BuiltinType::Dependent: -#define BUILTIN_TYPE(Id, SingletonId) -#define PLACEHOLDER_TYPE(Id, SingletonId) \ - case BuiltinType::Id: -#include "clang/AST/BuiltinTypes.def" - llvm_unreachable("asking for RRTI for a placeholder type!"); - - case BuiltinType::ObjCId: - case BuiltinType::ObjCClass: - case BuiltinType::ObjCSel: - llvm_unreachable("FIXME: Objective-C types are unsupported!"); - } - - llvm_unreachable("Invalid BuiltinType Kind!"); -} - -static bool TypeInfoIsInStandardLibrary(const PointerType *PointerTy) { - QualType PointeeTy = PointerTy->getPointeeType(); - const BuiltinType *BuiltinTy = dyn_cast<BuiltinType>(PointeeTy); - if (!BuiltinTy) - return false; - - // Check the qualifiers. - Qualifiers Quals = PointeeTy.getQualifiers(); - Quals.removeConst(); - - if (!Quals.empty()) - return false; - - return TypeInfoIsInStandardLibrary(BuiltinTy); -} - -/// IsStandardLibraryRTTIDescriptor - Returns whether the type -/// information for the given type exists in the standard library. -static bool IsStandardLibraryRTTIDescriptor(QualType Ty) { - // Type info for builtin types is defined in the standard library. - if (const BuiltinType *BuiltinTy = dyn_cast<BuiltinType>(Ty)) - return TypeInfoIsInStandardLibrary(BuiltinTy); - - // Type info for some pointer types to builtin types is defined in the - // standard library. - if (const PointerType *PointerTy = dyn_cast<PointerType>(Ty)) - return TypeInfoIsInStandardLibrary(PointerTy); - - return false; -} - -/// ShouldUseExternalRTTIDescriptor - Returns whether the type information for -/// the given type exists somewhere else, and that we should not emit the type -/// information in this translation unit. Assumes that it is not a -/// standard-library type. -static bool ShouldUseExternalRTTIDescriptor(CodeGenModule &CGM, QualType Ty) { - ASTContext &Context = CGM.getContext(); - - // If RTTI is disabled, don't consider key functions. - if (!Context.getLangOpts().RTTI) return false; - - if (const RecordType *RecordTy = dyn_cast<RecordType>(Ty)) { - const CXXRecordDecl *RD = cast<CXXRecordDecl>(RecordTy->getDecl()); - if (!RD->hasDefinition()) - return false; - - if (!RD->isDynamicClass()) - return false; - - return !CGM.getVTables().ShouldEmitVTableInThisTU(RD); - } - - return false; -} - -/// IsIncompleteClassType - Returns whether the given record type is incomplete. -static bool IsIncompleteClassType(const RecordType *RecordTy) { - return !RecordTy->getDecl()->isCompleteDefinition(); -} - -/// ContainsIncompleteClassType - Returns whether the given type contains an -/// incomplete class type. This is true if -/// -/// * The given type is an incomplete class type. -/// * The given type is a pointer type whose pointee type contains an -/// incomplete class type. -/// * The given type is a member pointer type whose class is an incomplete -/// class type. -/// * The given type is a member pointer type whoise pointee type contains an -/// incomplete class type. -/// is an indirect or direct pointer to an incomplete class type. -static bool ContainsIncompleteClassType(QualType Ty) { - if (const RecordType *RecordTy = dyn_cast<RecordType>(Ty)) { - if (IsIncompleteClassType(RecordTy)) - return true; - } - - if (const PointerType *PointerTy = dyn_cast<PointerType>(Ty)) - return ContainsIncompleteClassType(PointerTy->getPointeeType()); - - if (const MemberPointerType *MemberPointerTy = - dyn_cast<MemberPointerType>(Ty)) { - // Check if the class type is incomplete. - const RecordType *ClassType = cast<RecordType>(MemberPointerTy->getClass()); - if (IsIncompleteClassType(ClassType)) - return true; - - return ContainsIncompleteClassType(MemberPointerTy->getPointeeType()); - } - - return false; -} - -/// getTypeInfoLinkage - Return the linkage that the type info and type info -/// name constants should have for the given type. -static llvm::GlobalVariable::LinkageTypes -getTypeInfoLinkage(CodeGenModule &CGM, QualType Ty) { - // Itanium C++ ABI 2.9.5p7: - // In addition, it and all of the intermediate abi::__pointer_type_info - // structs in the chain down to the abi::__class_type_info for the - // incomplete class type must be prevented from resolving to the - // corresponding type_info structs for the complete class type, possibly - // by making them local static objects. Finally, a dummy class RTTI is - // generated for the incomplete type that will not resolve to the final - // complete class RTTI (because the latter need not exist), possibly by - // making it a local static object. - if (ContainsIncompleteClassType(Ty)) - return llvm::GlobalValue::InternalLinkage; - - switch (Ty->getLinkage()) { - case NoLinkage: - case InternalLinkage: - case UniqueExternalLinkage: - return llvm::GlobalValue::InternalLinkage; - - case ExternalLinkage: - if (!CGM.getLangOpts().RTTI) { - // RTTI is not enabled, which means that this type info struct is going - // to be used for exception handling. Give it linkonce_odr linkage. - return llvm::GlobalValue::LinkOnceODRLinkage; - } - - if (const RecordType *Record = dyn_cast<RecordType>(Ty)) { - const CXXRecordDecl *RD = cast<CXXRecordDecl>(Record->getDecl()); - if (RD->hasAttr<WeakAttr>()) - return llvm::GlobalValue::WeakODRLinkage; - if (RD->isDynamicClass()) - return CGM.getVTableLinkage(RD); - } - - return llvm::GlobalValue::LinkOnceODRLinkage; - } - - llvm_unreachable("Invalid linkage!"); -} - -// CanUseSingleInheritance - Return whether the given record decl has a "single, -// public, non-virtual base at offset zero (i.e. the derived class is dynamic -// iff the base is)", according to Itanium C++ ABI, 2.95p6b. -static bool CanUseSingleInheritance(const CXXRecordDecl *RD) { - // Check the number of bases. - if (RD->getNumBases() != 1) - return false; - - // Get the base. - CXXRecordDecl::base_class_const_iterator Base = RD->bases_begin(); - - // Check that the base is not virtual. - if (Base->isVirtual()) - return false; - - // Check that the base is public. - if (Base->getAccessSpecifier() != AS_public) - return false; - - // Check that the class is dynamic iff the base is. - const CXXRecordDecl *BaseDecl = - cast<CXXRecordDecl>(Base->getType()->getAs<RecordType>()->getDecl()); - if (!BaseDecl->isEmpty() && - BaseDecl->isDynamicClass() != RD->isDynamicClass()) - return false; - - return true; -} - -void RTTIBuilder::BuildVTablePointer(const Type *Ty) { - // abi::__class_type_info. - static const char * const ClassTypeInfo = - "_ZTVN10__cxxabiv117__class_type_infoE"; - // abi::__si_class_type_info. - static const char * const SIClassTypeInfo = - "_ZTVN10__cxxabiv120__si_class_type_infoE"; - // abi::__vmi_class_type_info. - static const char * const VMIClassTypeInfo = - "_ZTVN10__cxxabiv121__vmi_class_type_infoE"; - - const char *VTableName = 0; - - switch (Ty->getTypeClass()) { -#define TYPE(Class, Base) -#define ABSTRACT_TYPE(Class, Base) -#define NON_CANONICAL_UNLESS_DEPENDENT_TYPE(Class, Base) case Type::Class: -#define NON_CANONICAL_TYPE(Class, Base) case Type::Class: -#define DEPENDENT_TYPE(Class, Base) case Type::Class: -#include "clang/AST/TypeNodes.def" - llvm_unreachable("Non-canonical and dependent types shouldn't get here"); - - case Type::LValueReference: - case Type::RValueReference: - llvm_unreachable("References shouldn't get here"); - - case Type::Builtin: - // GCC treats vector and complex types as fundamental types. - case Type::Vector: - case Type::ExtVector: - case Type::Complex: - case Type::Atomic: - // FIXME: GCC treats block pointers as fundamental types?! - case Type::BlockPointer: - // abi::__fundamental_type_info. - VTableName = "_ZTVN10__cxxabiv123__fundamental_type_infoE"; - break; - - case Type::ConstantArray: - case Type::IncompleteArray: - case Type::VariableArray: - // abi::__array_type_info. - VTableName = "_ZTVN10__cxxabiv117__array_type_infoE"; - break; - - case Type::FunctionNoProto: - case Type::FunctionProto: - // abi::__function_type_info. - VTableName = "_ZTVN10__cxxabiv120__function_type_infoE"; - break; - - case Type::Enum: - // abi::__enum_type_info. - VTableName = "_ZTVN10__cxxabiv116__enum_type_infoE"; - break; - - case Type::Record: { - const CXXRecordDecl *RD = - cast<CXXRecordDecl>(cast<RecordType>(Ty)->getDecl()); - - if (!RD->hasDefinition() || !RD->getNumBases()) { - VTableName = ClassTypeInfo; - } else if (CanUseSingleInheritance(RD)) { - VTableName = SIClassTypeInfo; - } else { - VTableName = VMIClassTypeInfo; - } - - break; - } - - case Type::ObjCObject: - // Ignore protocol qualifiers. - Ty = cast<ObjCObjectType>(Ty)->getBaseType().getTypePtr(); - - // Handle id and Class. - if (isa<BuiltinType>(Ty)) { - VTableName = ClassTypeInfo; - break; - } - - assert(isa<ObjCInterfaceType>(Ty)); - // Fall through. - - case Type::ObjCInterface: - if (cast<ObjCInterfaceType>(Ty)->getDecl()->getSuperClass()) { - VTableName = SIClassTypeInfo; - } else { - VTableName = ClassTypeInfo; - } - break; - - case Type::ObjCObjectPointer: - case Type::Pointer: - // abi::__pointer_type_info. - VTableName = "_ZTVN10__cxxabiv119__pointer_type_infoE"; - break; - - case Type::MemberPointer: - // abi::__pointer_to_member_type_info. - VTableName = "_ZTVN10__cxxabiv129__pointer_to_member_type_infoE"; - break; - } - - llvm::Constant *VTable = - CGM.getModule().getOrInsertGlobal(VTableName, CGM.Int8PtrTy); - - llvm::Type *PtrDiffTy = - CGM.getTypes().ConvertType(CGM.getContext().getPointerDiffType()); - - // The vtable address point is 2. - llvm::Constant *Two = llvm::ConstantInt::get(PtrDiffTy, 2); - VTable = llvm::ConstantExpr::getInBoundsGetElementPtr(VTable, Two); - VTable = llvm::ConstantExpr::getBitCast(VTable, CGM.Int8PtrTy); - - Fields.push_back(VTable); -} - -// maybeUpdateRTTILinkage - Will update the linkage of the RTTI data structures -// from available_externally to the correct linkage if necessary. An example of -// this is: -// -// struct A { -// virtual void f(); -// }; -// -// const std::type_info &g() { -// return typeid(A); -// } -// -// void A::f() { } -// -// When we're generating the typeid(A) expression, we do not yet know that -// A's key function is defined in this translation unit, so we will give the -// typeinfo and typename structures available_externally linkage. When A::f -// forces the vtable to be generated, we need to change the linkage of the -// typeinfo and typename structs, otherwise we'll end up with undefined -// externals when linking. -static void -maybeUpdateRTTILinkage(CodeGenModule &CGM, llvm::GlobalVariable *GV, - QualType Ty) { - // We're only interested in globals with available_externally linkage. - if (!GV->hasAvailableExternallyLinkage()) - return; - - // Get the real linkage for the type. - llvm::GlobalVariable::LinkageTypes Linkage = getTypeInfoLinkage(CGM, Ty); - - // If variable is supposed to have available_externally linkage, we don't - // need to do anything. - if (Linkage == llvm::GlobalVariable::AvailableExternallyLinkage) - return; - - // Update the typeinfo linkage. - GV->setLinkage(Linkage); - - // Get the typename global. - SmallString<256> OutName; - llvm::raw_svector_ostream Out(OutName); - CGM.getCXXABI().getMangleContext().mangleCXXRTTIName(Ty, Out); - Out.flush(); - StringRef Name = OutName.str(); - - llvm::GlobalVariable *TypeNameGV = CGM.getModule().getNamedGlobal(Name); - - assert(TypeNameGV->hasAvailableExternallyLinkage() && - "Type name has different linkage from type info!"); - - // And update its linkage. - TypeNameGV->setLinkage(Linkage); -} - -llvm::Constant *RTTIBuilder::BuildTypeInfo(QualType Ty, bool Force) { - // We want to operate on the canonical type. - Ty = CGM.getContext().getCanonicalType(Ty); - - // Check if we've already emitted an RTTI descriptor for this type. - SmallString<256> OutName; - llvm::raw_svector_ostream Out(OutName); - CGM.getCXXABI().getMangleContext().mangleCXXRTTI(Ty, Out); - Out.flush(); - StringRef Name = OutName.str(); - - llvm::GlobalVariable *OldGV = CGM.getModule().getNamedGlobal(Name); - if (OldGV && !OldGV->isDeclaration()) { - maybeUpdateRTTILinkage(CGM, OldGV, Ty); - - return llvm::ConstantExpr::getBitCast(OldGV, CGM.Int8PtrTy); - } - - // Check if there is already an external RTTI descriptor for this type. - bool IsStdLib = IsStandardLibraryRTTIDescriptor(Ty); - if (!Force && (IsStdLib || ShouldUseExternalRTTIDescriptor(CGM, Ty))) - return GetAddrOfExternalRTTIDescriptor(Ty); - - // Emit the standard library with external linkage. - llvm::GlobalVariable::LinkageTypes Linkage; - if (IsStdLib) - Linkage = llvm::GlobalValue::ExternalLinkage; - else - Linkage = getTypeInfoLinkage(CGM, Ty); - - // Add the vtable pointer. - BuildVTablePointer(cast<Type>(Ty)); - - // And the name. - llvm::GlobalVariable *TypeName = GetAddrOfTypeName(Ty, Linkage); - - Fields.push_back(llvm::ConstantExpr::getBitCast(TypeName, CGM.Int8PtrTy)); - - switch (Ty->getTypeClass()) { -#define TYPE(Class, Base) -#define ABSTRACT_TYPE(Class, Base) -#define NON_CANONICAL_UNLESS_DEPENDENT_TYPE(Class, Base) case Type::Class: -#define NON_CANONICAL_TYPE(Class, Base) case Type::Class: -#define DEPENDENT_TYPE(Class, Base) case Type::Class: -#include "clang/AST/TypeNodes.def" - llvm_unreachable("Non-canonical and dependent types shouldn't get here"); - - // GCC treats vector types as fundamental types. - case Type::Builtin: - case Type::Vector: - case Type::ExtVector: - case Type::Complex: - case Type::BlockPointer: - // Itanium C++ ABI 2.9.5p4: - // abi::__fundamental_type_info adds no data members to std::type_info. - break; - - case Type::LValueReference: - case Type::RValueReference: - llvm_unreachable("References shouldn't get here"); - - case Type::ConstantArray: - case Type::IncompleteArray: - case Type::VariableArray: - // Itanium C++ ABI 2.9.5p5: - // abi::__array_type_info adds no data members to std::type_info. - break; - - case Type::FunctionNoProto: - case Type::FunctionProto: - // Itanium C++ ABI 2.9.5p5: - // abi::__function_type_info adds no data members to std::type_info. - break; - - case Type::Enum: - // Itanium C++ ABI 2.9.5p5: - // abi::__enum_type_info adds no data members to std::type_info. - break; - - case Type::Record: { - const CXXRecordDecl *RD = - cast<CXXRecordDecl>(cast<RecordType>(Ty)->getDecl()); - if (!RD->hasDefinition() || !RD->getNumBases()) { - // We don't need to emit any fields. - break; - } - - if (CanUseSingleInheritance(RD)) - BuildSIClassTypeInfo(RD); - else - BuildVMIClassTypeInfo(RD); - - break; - } - - case Type::ObjCObject: - case Type::ObjCInterface: - BuildObjCObjectTypeInfo(cast<ObjCObjectType>(Ty)); - break; - - case Type::ObjCObjectPointer: - BuildPointerTypeInfo(cast<ObjCObjectPointerType>(Ty)->getPointeeType()); - break; - - case Type::Pointer: - BuildPointerTypeInfo(cast<PointerType>(Ty)->getPointeeType()); - break; - - case Type::MemberPointer: - BuildPointerToMemberTypeInfo(cast<MemberPointerType>(Ty)); - break; - - case Type::Atomic: - // No fields, at least for the moment. - break; - } - - llvm::Constant *Init = llvm::ConstantStruct::getAnon(Fields); - - llvm::GlobalVariable *GV = - new llvm::GlobalVariable(CGM.getModule(), Init->getType(), - /*Constant=*/true, Linkage, Init, Name); - - // If there's already an old global variable, replace it with the new one. - if (OldGV) { - GV->takeName(OldGV); - llvm::Constant *NewPtr = - llvm::ConstantExpr::getBitCast(GV, OldGV->getType()); - OldGV->replaceAllUsesWith(NewPtr); - OldGV->eraseFromParent(); - } - - // GCC only relies on the uniqueness of the type names, not the - // type_infos themselves, so we can emit these as hidden symbols. - // But don't do this if we're worried about strict visibility - // compatibility. - if (const RecordType *RT = dyn_cast<RecordType>(Ty)) { - const CXXRecordDecl *RD = cast<CXXRecordDecl>(RT->getDecl()); - - CGM.setTypeVisibility(GV, RD, CodeGenModule::TVK_ForRTTI); - CGM.setTypeVisibility(TypeName, RD, CodeGenModule::TVK_ForRTTIName); - } else { - Visibility TypeInfoVisibility = DefaultVisibility; - if (CGM.getCodeGenOpts().HiddenWeakVTables && - Linkage == llvm::GlobalValue::LinkOnceODRLinkage) - TypeInfoVisibility = HiddenVisibility; - - // The type name should have the same visibility as the type itself. - Visibility ExplicitVisibility = Ty->getVisibility(); - TypeName->setVisibility(CodeGenModule:: - GetLLVMVisibility(ExplicitVisibility)); - - TypeInfoVisibility = minVisibility(TypeInfoVisibility, Ty->getVisibility()); - GV->setVisibility(CodeGenModule::GetLLVMVisibility(TypeInfoVisibility)); - } - - GV->setUnnamedAddr(true); - - return llvm::ConstantExpr::getBitCast(GV, CGM.Int8PtrTy); -} - -/// ComputeQualifierFlags - Compute the pointer type info flags from the -/// given qualifier. -static unsigned ComputeQualifierFlags(Qualifiers Quals) { - unsigned Flags = 0; - - if (Quals.hasConst()) - Flags |= RTTIBuilder::PTI_Const; - if (Quals.hasVolatile()) - Flags |= RTTIBuilder::PTI_Volatile; - if (Quals.hasRestrict()) - Flags |= RTTIBuilder::PTI_Restrict; - - return Flags; -} - -/// BuildObjCObjectTypeInfo - Build the appropriate kind of type_info -/// for the given Objective-C object type. -void RTTIBuilder::BuildObjCObjectTypeInfo(const ObjCObjectType *OT) { - // Drop qualifiers. - const Type *T = OT->getBaseType().getTypePtr(); - assert(isa<BuiltinType>(T) || isa<ObjCInterfaceType>(T)); - - // The builtin types are abi::__class_type_infos and don't require - // extra fields. - if (isa<BuiltinType>(T)) return; - - ObjCInterfaceDecl *Class = cast<ObjCInterfaceType>(T)->getDecl(); - ObjCInterfaceDecl *Super = Class->getSuperClass(); - - // Root classes are also __class_type_info. - if (!Super) return; - - QualType SuperTy = CGM.getContext().getObjCInterfaceType(Super); - - // Everything else is single inheritance. - llvm::Constant *BaseTypeInfo = RTTIBuilder(CGM).BuildTypeInfo(SuperTy); - Fields.push_back(BaseTypeInfo); -} - -/// BuildSIClassTypeInfo - Build an abi::__si_class_type_info, used for single -/// inheritance, according to the Itanium C++ ABI, 2.95p6b. -void RTTIBuilder::BuildSIClassTypeInfo(const CXXRecordDecl *RD) { - // Itanium C++ ABI 2.9.5p6b: - // It adds to abi::__class_type_info a single member pointing to the - // type_info structure for the base type, - llvm::Constant *BaseTypeInfo = - RTTIBuilder(CGM).BuildTypeInfo(RD->bases_begin()->getType()); - Fields.push_back(BaseTypeInfo); -} - -namespace { - /// SeenBases - Contains virtual and non-virtual bases seen when traversing - /// a class hierarchy. - struct SeenBases { - llvm::SmallPtrSet<const CXXRecordDecl *, 16> NonVirtualBases; - llvm::SmallPtrSet<const CXXRecordDecl *, 16> VirtualBases; - }; -} - -/// ComputeVMIClassTypeInfoFlags - Compute the value of the flags member in -/// abi::__vmi_class_type_info. -/// -static unsigned ComputeVMIClassTypeInfoFlags(const CXXBaseSpecifier *Base, - SeenBases &Bases) { - - unsigned Flags = 0; - - const CXXRecordDecl *BaseDecl = - cast<CXXRecordDecl>(Base->getType()->getAs<RecordType>()->getDecl()); - - if (Base->isVirtual()) { - // Mark the virtual base as seen. - if (!Bases.VirtualBases.insert(BaseDecl)) { - // If this virtual base has been seen before, then the class is diamond - // shaped. - Flags |= RTTIBuilder::VMI_DiamondShaped; - } else { - if (Bases.NonVirtualBases.count(BaseDecl)) - Flags |= RTTIBuilder::VMI_NonDiamondRepeat; - } - } else { - // Mark the non-virtual base as seen. - if (!Bases.NonVirtualBases.insert(BaseDecl)) { - // If this non-virtual base has been seen before, then the class has non- - // diamond shaped repeated inheritance. - Flags |= RTTIBuilder::VMI_NonDiamondRepeat; - } else { - if (Bases.VirtualBases.count(BaseDecl)) - Flags |= RTTIBuilder::VMI_NonDiamondRepeat; - } - } - - // Walk all bases. - for (CXXRecordDecl::base_class_const_iterator I = BaseDecl->bases_begin(), - E = BaseDecl->bases_end(); I != E; ++I) - Flags |= ComputeVMIClassTypeInfoFlags(I, Bases); - - return Flags; -} - -static unsigned ComputeVMIClassTypeInfoFlags(const CXXRecordDecl *RD) { - unsigned Flags = 0; - SeenBases Bases; - - // Walk all bases. - for (CXXRecordDecl::base_class_const_iterator I = RD->bases_begin(), - E = RD->bases_end(); I != E; ++I) - Flags |= ComputeVMIClassTypeInfoFlags(I, Bases); - - return Flags; -} - -/// BuildVMIClassTypeInfo - Build an abi::__vmi_class_type_info, used for -/// classes with bases that do not satisfy the abi::__si_class_type_info -/// constraints, according ti the Itanium C++ ABI, 2.9.5p5c. -void RTTIBuilder::BuildVMIClassTypeInfo(const CXXRecordDecl *RD) { - llvm::Type *UnsignedIntLTy = - CGM.getTypes().ConvertType(CGM.getContext().UnsignedIntTy); - - // Itanium C++ ABI 2.9.5p6c: - // __flags is a word with flags describing details about the class - // structure, which may be referenced by using the __flags_masks - // enumeration. These flags refer to both direct and indirect bases. - unsigned Flags = ComputeVMIClassTypeInfoFlags(RD); - Fields.push_back(llvm::ConstantInt::get(UnsignedIntLTy, Flags)); - - // Itanium C++ ABI 2.9.5p6c: - // __base_count is a word with the number of direct proper base class - // descriptions that follow. - Fields.push_back(llvm::ConstantInt::get(UnsignedIntLTy, RD->getNumBases())); - - if (!RD->getNumBases()) - return; - - llvm::Type *LongLTy = - CGM.getTypes().ConvertType(CGM.getContext().LongTy); - - // Now add the base class descriptions. - - // Itanium C++ ABI 2.9.5p6c: - // __base_info[] is an array of base class descriptions -- one for every - // direct proper base. Each description is of the type: - // - // struct abi::__base_class_type_info { - // public: - // const __class_type_info *__base_type; - // long __offset_flags; - // - // enum __offset_flags_masks { - // __virtual_mask = 0x1, - // __public_mask = 0x2, - // __offset_shift = 8 - // }; - // }; - for (CXXRecordDecl::base_class_const_iterator I = RD->bases_begin(), - E = RD->bases_end(); I != E; ++I) { - const CXXBaseSpecifier *Base = I; - - // The __base_type member points to the RTTI for the base type. - Fields.push_back(RTTIBuilder(CGM).BuildTypeInfo(Base->getType())); - - const CXXRecordDecl *BaseDecl = - cast<CXXRecordDecl>(Base->getType()->getAs<RecordType>()->getDecl()); - - int64_t OffsetFlags = 0; - - // All but the lower 8 bits of __offset_flags are a signed offset. - // For a non-virtual base, this is the offset in the object of the base - // subobject. For a virtual base, this is the offset in the virtual table of - // the virtual base offset for the virtual base referenced (negative). - CharUnits Offset; - if (Base->isVirtual()) - Offset = - CGM.getVTableContext().getVirtualBaseOffsetOffset(RD, BaseDecl); - else { - const ASTRecordLayout &Layout = CGM.getContext().getASTRecordLayout(RD); - Offset = Layout.getBaseClassOffset(BaseDecl); - }; - - OffsetFlags = uint64_t(Offset.getQuantity()) << 8; - - // The low-order byte of __offset_flags contains flags, as given by the - // masks from the enumeration __offset_flags_masks. - if (Base->isVirtual()) - OffsetFlags |= BCTI_Virtual; - if (Base->getAccessSpecifier() == AS_public) - OffsetFlags |= BCTI_Public; - - Fields.push_back(llvm::ConstantInt::get(LongLTy, OffsetFlags)); - } -} - -/// BuildPointerTypeInfo - Build an abi::__pointer_type_info struct, -/// used for pointer types. -void RTTIBuilder::BuildPointerTypeInfo(QualType PointeeTy) { - Qualifiers Quals; - QualType UnqualifiedPointeeTy = - CGM.getContext().getUnqualifiedArrayType(PointeeTy, Quals); - - // Itanium C++ ABI 2.9.5p7: - // __flags is a flag word describing the cv-qualification and other - // attributes of the type pointed to - unsigned Flags = ComputeQualifierFlags(Quals); - - // Itanium C++ ABI 2.9.5p7: - // When the abi::__pbase_type_info is for a direct or indirect pointer to an - // incomplete class type, the incomplete target type flag is set. - if (ContainsIncompleteClassType(UnqualifiedPointeeTy)) - Flags |= PTI_Incomplete; - - llvm::Type *UnsignedIntLTy = - CGM.getTypes().ConvertType(CGM.getContext().UnsignedIntTy); - Fields.push_back(llvm::ConstantInt::get(UnsignedIntLTy, Flags)); - - // Itanium C++ ABI 2.9.5p7: - // __pointee is a pointer to the std::type_info derivation for the - // unqualified type being pointed to. - llvm::Constant *PointeeTypeInfo = - RTTIBuilder(CGM).BuildTypeInfo(UnqualifiedPointeeTy); - Fields.push_back(PointeeTypeInfo); -} - -/// BuildPointerToMemberTypeInfo - Build an abi::__pointer_to_member_type_info -/// struct, used for member pointer types. -void RTTIBuilder::BuildPointerToMemberTypeInfo(const MemberPointerType *Ty) { - QualType PointeeTy = Ty->getPointeeType(); - - Qualifiers Quals; - QualType UnqualifiedPointeeTy = - CGM.getContext().getUnqualifiedArrayType(PointeeTy, Quals); - - // Itanium C++ ABI 2.9.5p7: - // __flags is a flag word describing the cv-qualification and other - // attributes of the type pointed to. - unsigned Flags = ComputeQualifierFlags(Quals); - - const RecordType *ClassType = cast<RecordType>(Ty->getClass()); - - // Itanium C++ ABI 2.9.5p7: - // When the abi::__pbase_type_info is for a direct or indirect pointer to an - // incomplete class type, the incomplete target type flag is set. - if (ContainsIncompleteClassType(UnqualifiedPointeeTy)) - Flags |= PTI_Incomplete; - - if (IsIncompleteClassType(ClassType)) - Flags |= PTI_ContainingClassIncomplete; - - llvm::Type *UnsignedIntLTy = - CGM.getTypes().ConvertType(CGM.getContext().UnsignedIntTy); - Fields.push_back(llvm::ConstantInt::get(UnsignedIntLTy, Flags)); - - // Itanium C++ ABI 2.9.5p7: - // __pointee is a pointer to the std::type_info derivation for the - // unqualified type being pointed to. - llvm::Constant *PointeeTypeInfo = - RTTIBuilder(CGM).BuildTypeInfo(UnqualifiedPointeeTy); - Fields.push_back(PointeeTypeInfo); - - // Itanium C++ ABI 2.9.5p9: - // __context is a pointer to an abi::__class_type_info corresponding to the - // class type containing the member pointed to - // (e.g., the "A" in "int A::*"). - Fields.push_back(RTTIBuilder(CGM).BuildTypeInfo(QualType(ClassType, 0))); -} - -llvm::Constant *CodeGenModule::GetAddrOfRTTIDescriptor(QualType Ty, - bool ForEH) { - // Return a bogus pointer if RTTI is disabled, unless it's for EH. - // FIXME: should we even be calling this method if RTTI is disabled - // and it's not for EH? - if (!ForEH && !getLangOpts().RTTI) - return llvm::Constant::getNullValue(Int8PtrTy); - - if (ForEH && Ty->isObjCObjectPointerType() && - LangOpts.ObjCRuntime.isGNUFamily()) - return ObjCRuntime->GetEHType(Ty); - - return RTTIBuilder(*this).BuildTypeInfo(Ty); -} - -void CodeGenModule::EmitFundamentalRTTIDescriptor(QualType Type) { - QualType PointerType = Context.getPointerType(Type); - QualType PointerTypeConst = Context.getPointerType(Type.withConst()); - RTTIBuilder(*this).BuildTypeInfo(Type, true); - RTTIBuilder(*this).BuildTypeInfo(PointerType, true); - RTTIBuilder(*this).BuildTypeInfo(PointerTypeConst, true); -} - -void CodeGenModule::EmitFundamentalRTTIDescriptors() { - QualType FundamentalTypes[] = { Context.VoidTy, Context.NullPtrTy, - Context.BoolTy, Context.WCharTy, - Context.CharTy, Context.UnsignedCharTy, - Context.SignedCharTy, Context.ShortTy, - Context.UnsignedShortTy, Context.IntTy, - Context.UnsignedIntTy, Context.LongTy, - Context.UnsignedLongTy, Context.LongLongTy, - Context.UnsignedLongLongTy, Context.FloatTy, - Context.DoubleTy, Context.LongDoubleTy, - Context.Char16Ty, Context.Char32Ty }; - for (unsigned i = 0; i < sizeof(FundamentalTypes)/sizeof(QualType); ++i) - EmitFundamentalRTTIDescriptor(FundamentalTypes[i]); -} +//===--- CGCXXRTTI.cpp - Emit LLVM Code for C++ RTTI descriptors ----------===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+//
+// This contains code dealing with C++ code generation of RTTI descriptors.
+//
+//===----------------------------------------------------------------------===//
+
+#include "CodeGenModule.h"
+#include "CGCXXABI.h"
+#include "CGObjCRuntime.h"
+#include "clang/AST/RecordLayout.h"
+#include "clang/AST/Type.h"
+#include "clang/Frontend/CodeGenOptions.h"
+
+using namespace clang;
+using namespace CodeGen;
+
+namespace {
+class RTTIBuilder {
+ CodeGenModule &CGM; // Per-module state.
+ llvm::LLVMContext &VMContext;
+
+ /// Fields - The fields of the RTTI descriptor currently being built.
+ SmallVector<llvm::Constant *, 16> Fields;
+
+ /// GetAddrOfTypeName - Returns the mangled type name of the given type.
+ llvm::GlobalVariable *
+ GetAddrOfTypeName(QualType Ty, llvm::GlobalVariable::LinkageTypes Linkage);
+
+ /// GetAddrOfExternalRTTIDescriptor - Returns the constant for the RTTI
+ /// descriptor of the given type.
+ llvm::Constant *GetAddrOfExternalRTTIDescriptor(QualType Ty);
+
+ /// BuildVTablePointer - Build the vtable pointer for the given type.
+ void BuildVTablePointer(const Type *Ty);
+
+ /// BuildSIClassTypeInfo - Build an abi::__si_class_type_info, used for single
+ /// inheritance, according to the Itanium C++ ABI, 2.9.5p6b.
+ void BuildSIClassTypeInfo(const CXXRecordDecl *RD);
+
+ /// BuildVMIClassTypeInfo - Build an abi::__vmi_class_type_info, used for
+ /// classes with bases that do not satisfy the abi::__si_class_type_info
+ /// constraints, according ti the Itanium C++ ABI, 2.9.5p5c.
+ void BuildVMIClassTypeInfo(const CXXRecordDecl *RD);
+
+ /// BuildPointerTypeInfo - Build an abi::__pointer_type_info struct, used
+ /// for pointer types.
+ void BuildPointerTypeInfo(QualType PointeeTy);
+
+ /// BuildObjCObjectTypeInfo - Build the appropriate kind of
+ /// type_info for an object type.
+ void BuildObjCObjectTypeInfo(const ObjCObjectType *Ty);
+
+ /// BuildPointerToMemberTypeInfo - Build an abi::__pointer_to_member_type_info
+ /// struct, used for member pointer types.
+ void BuildPointerToMemberTypeInfo(const MemberPointerType *Ty);
+
+public:
+ RTTIBuilder(CodeGenModule &CGM) : CGM(CGM),
+ VMContext(CGM.getModule().getContext()) { }
+
+ // Pointer type info flags.
+ enum {
+ /// PTI_Const - Type has const qualifier.
+ PTI_Const = 0x1,
+
+ /// PTI_Volatile - Type has volatile qualifier.
+ PTI_Volatile = 0x2,
+
+ /// PTI_Restrict - Type has restrict qualifier.
+ PTI_Restrict = 0x4,
+
+ /// PTI_Incomplete - Type is incomplete.
+ PTI_Incomplete = 0x8,
+
+ /// PTI_ContainingClassIncomplete - Containing class is incomplete.
+ /// (in pointer to member).
+ PTI_ContainingClassIncomplete = 0x10
+ };
+
+ // VMI type info flags.
+ enum {
+ /// VMI_NonDiamondRepeat - Class has non-diamond repeated inheritance.
+ VMI_NonDiamondRepeat = 0x1,
+
+ /// VMI_DiamondShaped - Class is diamond shaped.
+ VMI_DiamondShaped = 0x2
+ };
+
+ // Base class type info flags.
+ enum {
+ /// BCTI_Virtual - Base class is virtual.
+ BCTI_Virtual = 0x1,
+
+ /// BCTI_Public - Base class is public.
+ BCTI_Public = 0x2
+ };
+
+ /// BuildTypeInfo - Build the RTTI type info struct for the given type.
+ ///
+ /// \param Force - true to force the creation of this RTTI value
+ llvm::Constant *BuildTypeInfo(QualType Ty, bool Force = false);
+};
+}
+
+llvm::GlobalVariable *
+RTTIBuilder::GetAddrOfTypeName(QualType Ty,
+ llvm::GlobalVariable::LinkageTypes Linkage) {
+ SmallString<256> OutName;
+ llvm::raw_svector_ostream Out(OutName);
+ CGM.getCXXABI().getMangleContext().mangleCXXRTTIName(Ty, Out);
+ Out.flush();
+ StringRef Name = OutName.str();
+
+ // We know that the mangled name of the type starts at index 4 of the
+ // mangled name of the typename, so we can just index into it in order to
+ // get the mangled name of the type.
+ llvm::Constant *Init = llvm::ConstantDataArray::getString(VMContext,
+ Name.substr(4));
+
+ llvm::GlobalVariable *GV =
+ CGM.CreateOrReplaceCXXRuntimeVariable(Name, Init->getType(), Linkage);
+
+ GV->setInitializer(Init);
+
+ return GV;
+}
+
+llvm::Constant *RTTIBuilder::GetAddrOfExternalRTTIDescriptor(QualType Ty) {
+ // Mangle the RTTI name.
+ SmallString<256> OutName;
+ llvm::raw_svector_ostream Out(OutName);
+ CGM.getCXXABI().getMangleContext().mangleCXXRTTI(Ty, Out);
+ Out.flush();
+ StringRef Name = OutName.str();
+
+ // Look for an existing global.
+ llvm::GlobalVariable *GV = CGM.getModule().getNamedGlobal(Name);
+
+ if (!GV) {
+ // Create a new global variable.
+ GV = new llvm::GlobalVariable(CGM.getModule(), CGM.Int8PtrTy,
+ /*Constant=*/true,
+ llvm::GlobalValue::ExternalLinkage, 0, Name);
+ }
+
+ return llvm::ConstantExpr::getBitCast(GV, CGM.Int8PtrTy);
+}
+
+/// TypeInfoIsInStandardLibrary - Given a builtin type, returns whether the type
+/// info for that type is defined in the standard library.
+static bool TypeInfoIsInStandardLibrary(const BuiltinType *Ty) {
+ // Itanium C++ ABI 2.9.2:
+ // Basic type information (e.g. for "int", "bool", etc.) will be kept in
+ // the run-time support library. Specifically, the run-time support
+ // library should contain type_info objects for the types X, X* and
+ // X const*, for every X in: void, std::nullptr_t, bool, wchar_t, char,
+ // unsigned char, signed char, short, unsigned short, int, unsigned int,
+ // long, unsigned long, long long, unsigned long long, float, double,
+ // long double, char16_t, char32_t, and the IEEE 754r decimal and
+ // half-precision floating point types.
+ switch (Ty->getKind()) {
+ case BuiltinType::Void:
+ case BuiltinType::NullPtr:
+ case BuiltinType::Bool:
+ case BuiltinType::WChar_S:
+ case BuiltinType::WChar_U:
+ case BuiltinType::Char_U:
+ case BuiltinType::Char_S:
+ case BuiltinType::UChar:
+ case BuiltinType::SChar:
+ case BuiltinType::Short:
+ case BuiltinType::UShort:
+ case BuiltinType::Int:
+ case BuiltinType::UInt:
+ case BuiltinType::Long:
+ case BuiltinType::ULong:
+ case BuiltinType::LongLong:
+ case BuiltinType::ULongLong:
+ case BuiltinType::Half:
+ case BuiltinType::Float:
+ case BuiltinType::Double:
+ case BuiltinType::LongDouble:
+ case BuiltinType::Char16:
+ case BuiltinType::Char32:
+ case BuiltinType::Int128:
+ case BuiltinType::UInt128:
+ case BuiltinType::OCLImage1d:
+ case BuiltinType::OCLImage1dArray:
+ case BuiltinType::OCLImage1dBuffer:
+ case BuiltinType::OCLImage2d:
+ case BuiltinType::OCLImage2dArray:
+ case BuiltinType::OCLImage3d:
+ return true;
+
+ case BuiltinType::Dependent:
+#define BUILTIN_TYPE(Id, SingletonId)
+#define PLACEHOLDER_TYPE(Id, SingletonId) \
+ case BuiltinType::Id:
+#include "clang/AST/BuiltinTypes.def"
+ llvm_unreachable("asking for RRTI for a placeholder type!");
+
+ case BuiltinType::ObjCId:
+ case BuiltinType::ObjCClass:
+ case BuiltinType::ObjCSel:
+ llvm_unreachable("FIXME: Objective-C types are unsupported!");
+ }
+
+ llvm_unreachable("Invalid BuiltinType Kind!");
+}
+
+static bool TypeInfoIsInStandardLibrary(const PointerType *PointerTy) {
+ QualType PointeeTy = PointerTy->getPointeeType();
+ const BuiltinType *BuiltinTy = dyn_cast<BuiltinType>(PointeeTy);
+ if (!BuiltinTy)
+ return false;
+
+ // Check the qualifiers.
+ Qualifiers Quals = PointeeTy.getQualifiers();
+ Quals.removeConst();
+
+ if (!Quals.empty())
+ return false;
+
+ return TypeInfoIsInStandardLibrary(BuiltinTy);
+}
+
+/// IsStandardLibraryRTTIDescriptor - Returns whether the type
+/// information for the given type exists in the standard library.
+static bool IsStandardLibraryRTTIDescriptor(QualType Ty) {
+ // Type info for builtin types is defined in the standard library.
+ if (const BuiltinType *BuiltinTy = dyn_cast<BuiltinType>(Ty))
+ return TypeInfoIsInStandardLibrary(BuiltinTy);
+
+ // Type info for some pointer types to builtin types is defined in the
+ // standard library.
+ if (const PointerType *PointerTy = dyn_cast<PointerType>(Ty))
+ return TypeInfoIsInStandardLibrary(PointerTy);
+
+ return false;
+}
+
+/// ShouldUseExternalRTTIDescriptor - Returns whether the type information for
+/// the given type exists somewhere else, and that we should not emit the type
+/// information in this translation unit. Assumes that it is not a
+/// standard-library type.
+static bool ShouldUseExternalRTTIDescriptor(CodeGenModule &CGM, QualType Ty) {
+ ASTContext &Context = CGM.getContext();
+
+ // If RTTI is disabled, don't consider key functions.
+ if (!Context.getLangOpts().RTTI) return false;
+
+ if (const RecordType *RecordTy = dyn_cast<RecordType>(Ty)) {
+ const CXXRecordDecl *RD = cast<CXXRecordDecl>(RecordTy->getDecl());
+ if (!RD->hasDefinition())
+ return false;
+
+ if (!RD->isDynamicClass())
+ return false;
+
+ return !CGM.getVTables().ShouldEmitVTableInThisTU(RD);
+ }
+
+ return false;
+}
+
+/// IsIncompleteClassType - Returns whether the given record type is incomplete.
+static bool IsIncompleteClassType(const RecordType *RecordTy) {
+ return !RecordTy->getDecl()->isCompleteDefinition();
+}
+
+/// ContainsIncompleteClassType - Returns whether the given type contains an
+/// incomplete class type. This is true if
+///
+/// * The given type is an incomplete class type.
+/// * The given type is a pointer type whose pointee type contains an
+/// incomplete class type.
+/// * The given type is a member pointer type whose class is an incomplete
+/// class type.
+/// * The given type is a member pointer type whoise pointee type contains an
+/// incomplete class type.
+/// is an indirect or direct pointer to an incomplete class type.
+static bool ContainsIncompleteClassType(QualType Ty) {
+ if (const RecordType *RecordTy = dyn_cast<RecordType>(Ty)) {
+ if (IsIncompleteClassType(RecordTy))
+ return true;
+ }
+
+ if (const PointerType *PointerTy = dyn_cast<PointerType>(Ty))
+ return ContainsIncompleteClassType(PointerTy->getPointeeType());
+
+ if (const MemberPointerType *MemberPointerTy =
+ dyn_cast<MemberPointerType>(Ty)) {
+ // Check if the class type is incomplete.
+ const RecordType *ClassType = cast<RecordType>(MemberPointerTy->getClass());
+ if (IsIncompleteClassType(ClassType))
+ return true;
+
+ return ContainsIncompleteClassType(MemberPointerTy->getPointeeType());
+ }
+
+ return false;
+}
+
+/// getTypeInfoLinkage - Return the linkage that the type info and type info
+/// name constants should have for the given type.
+static llvm::GlobalVariable::LinkageTypes
+getTypeInfoLinkage(CodeGenModule &CGM, QualType Ty) {
+ // Itanium C++ ABI 2.9.5p7:
+ // In addition, it and all of the intermediate abi::__pointer_type_info
+ // structs in the chain down to the abi::__class_type_info for the
+ // incomplete class type must be prevented from resolving to the
+ // corresponding type_info structs for the complete class type, possibly
+ // by making them local static objects. Finally, a dummy class RTTI is
+ // generated for the incomplete type that will not resolve to the final
+ // complete class RTTI (because the latter need not exist), possibly by
+ // making it a local static object.
+ if (ContainsIncompleteClassType(Ty))
+ return llvm::GlobalValue::InternalLinkage;
+
+ switch (Ty->getLinkage()) {
+ case NoLinkage:
+ case InternalLinkage:
+ case UniqueExternalLinkage:
+ return llvm::GlobalValue::InternalLinkage;
+
+ case ExternalLinkage:
+ if (!CGM.getLangOpts().RTTI) {
+ // RTTI is not enabled, which means that this type info struct is going
+ // to be used for exception handling. Give it linkonce_odr linkage.
+ return llvm::GlobalValue::LinkOnceODRLinkage;
+ }
+
+ if (const RecordType *Record = dyn_cast<RecordType>(Ty)) {
+ const CXXRecordDecl *RD = cast<CXXRecordDecl>(Record->getDecl());
+ if (RD->hasAttr<WeakAttr>())
+ return llvm::GlobalValue::WeakODRLinkage;
+ if (RD->isDynamicClass())
+ return CGM.getVTableLinkage(RD);
+ }
+
+ return llvm::GlobalValue::LinkOnceODRLinkage;
+ }
+
+ llvm_unreachable("Invalid linkage!");
+}
+
+// CanUseSingleInheritance - Return whether the given record decl has a "single,
+// public, non-virtual base at offset zero (i.e. the derived class is dynamic
+// iff the base is)", according to Itanium C++ ABI, 2.95p6b.
+static bool CanUseSingleInheritance(const CXXRecordDecl *RD) {
+ // Check the number of bases.
+ if (RD->getNumBases() != 1)
+ return false;
+
+ // Get the base.
+ CXXRecordDecl::base_class_const_iterator Base = RD->bases_begin();
+
+ // Check that the base is not virtual.
+ if (Base->isVirtual())
+ return false;
+
+ // Check that the base is public.
+ if (Base->getAccessSpecifier() != AS_public)
+ return false;
+
+ // Check that the class is dynamic iff the base is.
+ const CXXRecordDecl *BaseDecl =
+ cast<CXXRecordDecl>(Base->getType()->getAs<RecordType>()->getDecl());
+ if (!BaseDecl->isEmpty() &&
+ BaseDecl->isDynamicClass() != RD->isDynamicClass())
+ return false;
+
+ return true;
+}
+
+void RTTIBuilder::BuildVTablePointer(const Type *Ty) {
+ // abi::__class_type_info.
+ static const char * const ClassTypeInfo =
+ "_ZTVN10__cxxabiv117__class_type_infoE";
+ // abi::__si_class_type_info.
+ static const char * const SIClassTypeInfo =
+ "_ZTVN10__cxxabiv120__si_class_type_infoE";
+ // abi::__vmi_class_type_info.
+ static const char * const VMIClassTypeInfo =
+ "_ZTVN10__cxxabiv121__vmi_class_type_infoE";
+
+ const char *VTableName = 0;
+
+ switch (Ty->getTypeClass()) {
+#define TYPE(Class, Base)
+#define ABSTRACT_TYPE(Class, Base)
+#define NON_CANONICAL_UNLESS_DEPENDENT_TYPE(Class, Base) case Type::Class:
+#define NON_CANONICAL_TYPE(Class, Base) case Type::Class:
+#define DEPENDENT_TYPE(Class, Base) case Type::Class:
+#include "clang/AST/TypeNodes.def"
+ llvm_unreachable("Non-canonical and dependent types shouldn't get here");
+
+ case Type::LValueReference:
+ case Type::RValueReference:
+ llvm_unreachable("References shouldn't get here");
+
+ case Type::Builtin:
+ // GCC treats vector and complex types as fundamental types.
+ case Type::Vector:
+ case Type::ExtVector:
+ case Type::Complex:
+ case Type::Atomic:
+ // FIXME: GCC treats block pointers as fundamental types?!
+ case Type::BlockPointer:
+ // abi::__fundamental_type_info.
+ VTableName = "_ZTVN10__cxxabiv123__fundamental_type_infoE";
+ break;
+
+ case Type::ConstantArray:
+ case Type::IncompleteArray:
+ case Type::VariableArray:
+ // abi::__array_type_info.
+ VTableName = "_ZTVN10__cxxabiv117__array_type_infoE";
+ break;
+
+ case Type::FunctionNoProto:
+ case Type::FunctionProto:
+ // abi::__function_type_info.
+ VTableName = "_ZTVN10__cxxabiv120__function_type_infoE";
+ break;
+
+ case Type::Enum:
+ // abi::__enum_type_info.
+ VTableName = "_ZTVN10__cxxabiv116__enum_type_infoE";
+ break;
+
+ case Type::Record: {
+ const CXXRecordDecl *RD =
+ cast<CXXRecordDecl>(cast<RecordType>(Ty)->getDecl());
+
+ if (!RD->hasDefinition() || !RD->getNumBases()) {
+ VTableName = ClassTypeInfo;
+ } else if (CanUseSingleInheritance(RD)) {
+ VTableName = SIClassTypeInfo;
+ } else {
+ VTableName = VMIClassTypeInfo;
+ }
+
+ break;
+ }
+
+ case Type::ObjCObject:
+ // Ignore protocol qualifiers.
+ Ty = cast<ObjCObjectType>(Ty)->getBaseType().getTypePtr();
+
+ // Handle id and Class.
+ if (isa<BuiltinType>(Ty)) {
+ VTableName = ClassTypeInfo;
+ break;
+ }
+
+ assert(isa<ObjCInterfaceType>(Ty));
+ // Fall through.
+
+ case Type::ObjCInterface:
+ if (cast<ObjCInterfaceType>(Ty)->getDecl()->getSuperClass()) {
+ VTableName = SIClassTypeInfo;
+ } else {
+ VTableName = ClassTypeInfo;
+ }
+ break;
+
+ case Type::ObjCObjectPointer:
+ case Type::Pointer:
+ // abi::__pointer_type_info.
+ VTableName = "_ZTVN10__cxxabiv119__pointer_type_infoE";
+ break;
+
+ case Type::MemberPointer:
+ // abi::__pointer_to_member_type_info.
+ VTableName = "_ZTVN10__cxxabiv129__pointer_to_member_type_infoE";
+ break;
+ }
+
+ llvm::Constant *VTable =
+ CGM.getModule().getOrInsertGlobal(VTableName, CGM.Int8PtrTy);
+
+ llvm::Type *PtrDiffTy =
+ CGM.getTypes().ConvertType(CGM.getContext().getPointerDiffType());
+
+ // The vtable address point is 2.
+ llvm::Constant *Two = llvm::ConstantInt::get(PtrDiffTy, 2);
+ VTable = llvm::ConstantExpr::getInBoundsGetElementPtr(VTable, Two);
+ VTable = llvm::ConstantExpr::getBitCast(VTable, CGM.Int8PtrTy);
+
+ Fields.push_back(VTable);
+}
+
+// maybeUpdateRTTILinkage - Will update the linkage of the RTTI data structures
+// from available_externally to the correct linkage if necessary. An example of
+// this is:
+//
+// struct A {
+// virtual void f();
+// };
+//
+// const std::type_info &g() {
+// return typeid(A);
+// }
+//
+// void A::f() { }
+//
+// When we're generating the typeid(A) expression, we do not yet know that
+// A's key function is defined in this translation unit, so we will give the
+// typeinfo and typename structures available_externally linkage. When A::f
+// forces the vtable to be generated, we need to change the linkage of the
+// typeinfo and typename structs, otherwise we'll end up with undefined
+// externals when linking.
+static void
+maybeUpdateRTTILinkage(CodeGenModule &CGM, llvm::GlobalVariable *GV,
+ QualType Ty) {
+ // We're only interested in globals with available_externally linkage.
+ if (!GV->hasAvailableExternallyLinkage())
+ return;
+
+ // Get the real linkage for the type.
+ llvm::GlobalVariable::LinkageTypes Linkage = getTypeInfoLinkage(CGM, Ty);
+
+ // If variable is supposed to have available_externally linkage, we don't
+ // need to do anything.
+ if (Linkage == llvm::GlobalVariable::AvailableExternallyLinkage)
+ return;
+
+ // Update the typeinfo linkage.
+ GV->setLinkage(Linkage);
+
+ // Get the typename global.
+ SmallString<256> OutName;
+ llvm::raw_svector_ostream Out(OutName);
+ CGM.getCXXABI().getMangleContext().mangleCXXRTTIName(Ty, Out);
+ Out.flush();
+ StringRef Name = OutName.str();
+
+ llvm::GlobalVariable *TypeNameGV = CGM.getModule().getNamedGlobal(Name);
+
+ assert(TypeNameGV->hasAvailableExternallyLinkage() &&
+ "Type name has different linkage from type info!");
+
+ // And update its linkage.
+ TypeNameGV->setLinkage(Linkage);
+}
+
+llvm::Constant *RTTIBuilder::BuildTypeInfo(QualType Ty, bool Force) {
+ // We want to operate on the canonical type.
+ Ty = CGM.getContext().getCanonicalType(Ty);
+
+ // Check if we've already emitted an RTTI descriptor for this type.
+ SmallString<256> OutName;
+ llvm::raw_svector_ostream Out(OutName);
+ CGM.getCXXABI().getMangleContext().mangleCXXRTTI(Ty, Out);
+ Out.flush();
+ StringRef Name = OutName.str();
+
+ llvm::GlobalVariable *OldGV = CGM.getModule().getNamedGlobal(Name);
+ if (OldGV && !OldGV->isDeclaration()) {
+ maybeUpdateRTTILinkage(CGM, OldGV, Ty);
+
+ return llvm::ConstantExpr::getBitCast(OldGV, CGM.Int8PtrTy);
+ }
+
+ // Check if there is already an external RTTI descriptor for this type.
+ bool IsStdLib = IsStandardLibraryRTTIDescriptor(Ty);
+ if (!Force && (IsStdLib || ShouldUseExternalRTTIDescriptor(CGM, Ty)))
+ return GetAddrOfExternalRTTIDescriptor(Ty);
+
+ // Emit the standard library with external linkage.
+ llvm::GlobalVariable::LinkageTypes Linkage;
+ if (IsStdLib)
+ Linkage = llvm::GlobalValue::ExternalLinkage;
+ else
+ Linkage = getTypeInfoLinkage(CGM, Ty);
+
+ // Add the vtable pointer.
+ BuildVTablePointer(cast<Type>(Ty));
+
+ // And the name.
+ llvm::GlobalVariable *TypeName = GetAddrOfTypeName(Ty, Linkage);
+
+ Fields.push_back(llvm::ConstantExpr::getBitCast(TypeName, CGM.Int8PtrTy));
+
+ switch (Ty->getTypeClass()) {
+#define TYPE(Class, Base)
+#define ABSTRACT_TYPE(Class, Base)
+#define NON_CANONICAL_UNLESS_DEPENDENT_TYPE(Class, Base) case Type::Class:
+#define NON_CANONICAL_TYPE(Class, Base) case Type::Class:
+#define DEPENDENT_TYPE(Class, Base) case Type::Class:
+#include "clang/AST/TypeNodes.def"
+ llvm_unreachable("Non-canonical and dependent types shouldn't get here");
+
+ // GCC treats vector types as fundamental types.
+ case Type::Builtin:
+ case Type::Vector:
+ case Type::ExtVector:
+ case Type::Complex:
+ case Type::BlockPointer:
+ // Itanium C++ ABI 2.9.5p4:
+ // abi::__fundamental_type_info adds no data members to std::type_info.
+ break;
+
+ case Type::LValueReference:
+ case Type::RValueReference:
+ llvm_unreachable("References shouldn't get here");
+
+ case Type::ConstantArray:
+ case Type::IncompleteArray:
+ case Type::VariableArray:
+ // Itanium C++ ABI 2.9.5p5:
+ // abi::__array_type_info adds no data members to std::type_info.
+ break;
+
+ case Type::FunctionNoProto:
+ case Type::FunctionProto:
+ // Itanium C++ ABI 2.9.5p5:
+ // abi::__function_type_info adds no data members to std::type_info.
+ break;
+
+ case Type::Enum:
+ // Itanium C++ ABI 2.9.5p5:
+ // abi::__enum_type_info adds no data members to std::type_info.
+ break;
+
+ case Type::Record: {
+ const CXXRecordDecl *RD =
+ cast<CXXRecordDecl>(cast<RecordType>(Ty)->getDecl());
+ if (!RD->hasDefinition() || !RD->getNumBases()) {
+ // We don't need to emit any fields.
+ break;
+ }
+
+ if (CanUseSingleInheritance(RD))
+ BuildSIClassTypeInfo(RD);
+ else
+ BuildVMIClassTypeInfo(RD);
+
+ break;
+ }
+
+ case Type::ObjCObject:
+ case Type::ObjCInterface:
+ BuildObjCObjectTypeInfo(cast<ObjCObjectType>(Ty));
+ break;
+
+ case Type::ObjCObjectPointer:
+ BuildPointerTypeInfo(cast<ObjCObjectPointerType>(Ty)->getPointeeType());
+ break;
+
+ case Type::Pointer:
+ BuildPointerTypeInfo(cast<PointerType>(Ty)->getPointeeType());
+ break;
+
+ case Type::MemberPointer:
+ BuildPointerToMemberTypeInfo(cast<MemberPointerType>(Ty));
+ break;
+
+ case Type::Atomic:
+ // No fields, at least for the moment.
+ break;
+ }
+
+ llvm::Constant *Init = llvm::ConstantStruct::getAnon(Fields);
+
+ llvm::GlobalVariable *GV =
+ new llvm::GlobalVariable(CGM.getModule(), Init->getType(),
+ /*Constant=*/true, Linkage, Init, Name);
+
+ // If there's already an old global variable, replace it with the new one.
+ if (OldGV) {
+ GV->takeName(OldGV);
+ llvm::Constant *NewPtr =
+ llvm::ConstantExpr::getBitCast(GV, OldGV->getType());
+ OldGV->replaceAllUsesWith(NewPtr);
+ OldGV->eraseFromParent();
+ }
+
+ // GCC only relies on the uniqueness of the type names, not the
+ // type_infos themselves, so we can emit these as hidden symbols.
+ // But don't do this if we're worried about strict visibility
+ // compatibility.
+ if (const RecordType *RT = dyn_cast<RecordType>(Ty)) {
+ const CXXRecordDecl *RD = cast<CXXRecordDecl>(RT->getDecl());
+
+ CGM.setTypeVisibility(GV, RD, CodeGenModule::TVK_ForRTTI);
+ CGM.setTypeVisibility(TypeName, RD, CodeGenModule::TVK_ForRTTIName);
+ } else {
+ Visibility TypeInfoVisibility = DefaultVisibility;
+ if (CGM.getCodeGenOpts().HiddenWeakVTables &&
+ Linkage == llvm::GlobalValue::LinkOnceODRLinkage)
+ TypeInfoVisibility = HiddenVisibility;
+
+ // The type name should have the same visibility as the type itself.
+ Visibility ExplicitVisibility = Ty->getVisibility();
+ TypeName->setVisibility(CodeGenModule::
+ GetLLVMVisibility(ExplicitVisibility));
+
+ TypeInfoVisibility = minVisibility(TypeInfoVisibility, Ty->getVisibility());
+ GV->setVisibility(CodeGenModule::GetLLVMVisibility(TypeInfoVisibility));
+ }
+
+ GV->setUnnamedAddr(true);
+
+ return llvm::ConstantExpr::getBitCast(GV, CGM.Int8PtrTy);
+}
+
+/// ComputeQualifierFlags - Compute the pointer type info flags from the
+/// given qualifier.
+static unsigned ComputeQualifierFlags(Qualifiers Quals) {
+ unsigned Flags = 0;
+
+ if (Quals.hasConst())
+ Flags |= RTTIBuilder::PTI_Const;
+ if (Quals.hasVolatile())
+ Flags |= RTTIBuilder::PTI_Volatile;
+ if (Quals.hasRestrict())
+ Flags |= RTTIBuilder::PTI_Restrict;
+
+ return Flags;
+}
+
+/// BuildObjCObjectTypeInfo - Build the appropriate kind of type_info
+/// for the given Objective-C object type.
+void RTTIBuilder::BuildObjCObjectTypeInfo(const ObjCObjectType *OT) {
+ // Drop qualifiers.
+ const Type *T = OT->getBaseType().getTypePtr();
+ assert(isa<BuiltinType>(T) || isa<ObjCInterfaceType>(T));
+
+ // The builtin types are abi::__class_type_infos and don't require
+ // extra fields.
+ if (isa<BuiltinType>(T)) return;
+
+ ObjCInterfaceDecl *Class = cast<ObjCInterfaceType>(T)->getDecl();
+ ObjCInterfaceDecl *Super = Class->getSuperClass();
+
+ // Root classes are also __class_type_info.
+ if (!Super) return;
+
+ QualType SuperTy = CGM.getContext().getObjCInterfaceType(Super);
+
+ // Everything else is single inheritance.
+ llvm::Constant *BaseTypeInfo = RTTIBuilder(CGM).BuildTypeInfo(SuperTy);
+ Fields.push_back(BaseTypeInfo);
+}
+
+/// BuildSIClassTypeInfo - Build an abi::__si_class_type_info, used for single
+/// inheritance, according to the Itanium C++ ABI, 2.95p6b.
+void RTTIBuilder::BuildSIClassTypeInfo(const CXXRecordDecl *RD) {
+ // Itanium C++ ABI 2.9.5p6b:
+ // It adds to abi::__class_type_info a single member pointing to the
+ // type_info structure for the base type,
+ llvm::Constant *BaseTypeInfo =
+ RTTIBuilder(CGM).BuildTypeInfo(RD->bases_begin()->getType());
+ Fields.push_back(BaseTypeInfo);
+}
+
+namespace {
+ /// SeenBases - Contains virtual and non-virtual bases seen when traversing
+ /// a class hierarchy.
+ struct SeenBases {
+ llvm::SmallPtrSet<const CXXRecordDecl *, 16> NonVirtualBases;
+ llvm::SmallPtrSet<const CXXRecordDecl *, 16> VirtualBases;
+ };
+}
+
+/// ComputeVMIClassTypeInfoFlags - Compute the value of the flags member in
+/// abi::__vmi_class_type_info.
+///
+static unsigned ComputeVMIClassTypeInfoFlags(const CXXBaseSpecifier *Base,
+ SeenBases &Bases) {
+
+ unsigned Flags = 0;
+
+ const CXXRecordDecl *BaseDecl =
+ cast<CXXRecordDecl>(Base->getType()->getAs<RecordType>()->getDecl());
+
+ if (Base->isVirtual()) {
+ // Mark the virtual base as seen.
+ if (!Bases.VirtualBases.insert(BaseDecl)) {
+ // If this virtual base has been seen before, then the class is diamond
+ // shaped.
+ Flags |= RTTIBuilder::VMI_DiamondShaped;
+ } else {
+ if (Bases.NonVirtualBases.count(BaseDecl))
+ Flags |= RTTIBuilder::VMI_NonDiamondRepeat;
+ }
+ } else {
+ // Mark the non-virtual base as seen.
+ if (!Bases.NonVirtualBases.insert(BaseDecl)) {
+ // If this non-virtual base has been seen before, then the class has non-
+ // diamond shaped repeated inheritance.
+ Flags |= RTTIBuilder::VMI_NonDiamondRepeat;
+ } else {
+ if (Bases.VirtualBases.count(BaseDecl))
+ Flags |= RTTIBuilder::VMI_NonDiamondRepeat;
+ }
+ }
+
+ // Walk all bases.
+ for (CXXRecordDecl::base_class_const_iterator I = BaseDecl->bases_begin(),
+ E = BaseDecl->bases_end(); I != E; ++I)
+ Flags |= ComputeVMIClassTypeInfoFlags(I, Bases);
+
+ return Flags;
+}
+
+static unsigned ComputeVMIClassTypeInfoFlags(const CXXRecordDecl *RD) {
+ unsigned Flags = 0;
+ SeenBases Bases;
+
+ // Walk all bases.
+ for (CXXRecordDecl::base_class_const_iterator I = RD->bases_begin(),
+ E = RD->bases_end(); I != E; ++I)
+ Flags |= ComputeVMIClassTypeInfoFlags(I, Bases);
+
+ return Flags;
+}
+
+/// BuildVMIClassTypeInfo - Build an abi::__vmi_class_type_info, used for
+/// classes with bases that do not satisfy the abi::__si_class_type_info
+/// constraints, according ti the Itanium C++ ABI, 2.9.5p5c.
+void RTTIBuilder::BuildVMIClassTypeInfo(const CXXRecordDecl *RD) {
+ llvm::Type *UnsignedIntLTy =
+ CGM.getTypes().ConvertType(CGM.getContext().UnsignedIntTy);
+
+ // Itanium C++ ABI 2.9.5p6c:
+ // __flags is a word with flags describing details about the class
+ // structure, which may be referenced by using the __flags_masks
+ // enumeration. These flags refer to both direct and indirect bases.
+ unsigned Flags = ComputeVMIClassTypeInfoFlags(RD);
+ Fields.push_back(llvm::ConstantInt::get(UnsignedIntLTy, Flags));
+
+ // Itanium C++ ABI 2.9.5p6c:
+ // __base_count is a word with the number of direct proper base class
+ // descriptions that follow.
+ Fields.push_back(llvm::ConstantInt::get(UnsignedIntLTy, RD->getNumBases()));
+
+ if (!RD->getNumBases())
+ return;
+
+ llvm::Type *LongLTy =
+ CGM.getTypes().ConvertType(CGM.getContext().LongTy);
+
+ // Now add the base class descriptions.
+
+ // Itanium C++ ABI 2.9.5p6c:
+ // __base_info[] is an array of base class descriptions -- one for every
+ // direct proper base. Each description is of the type:
+ //
+ // struct abi::__base_class_type_info {
+ // public:
+ // const __class_type_info *__base_type;
+ // long __offset_flags;
+ //
+ // enum __offset_flags_masks {
+ // __virtual_mask = 0x1,
+ // __public_mask = 0x2,
+ // __offset_shift = 8
+ // };
+ // };
+ for (CXXRecordDecl::base_class_const_iterator I = RD->bases_begin(),
+ E = RD->bases_end(); I != E; ++I) {
+ const CXXBaseSpecifier *Base = I;
+
+ // The __base_type member points to the RTTI for the base type.
+ Fields.push_back(RTTIBuilder(CGM).BuildTypeInfo(Base->getType()));
+
+ const CXXRecordDecl *BaseDecl =
+ cast<CXXRecordDecl>(Base->getType()->getAs<RecordType>()->getDecl());
+
+ int64_t OffsetFlags = 0;
+
+ // All but the lower 8 bits of __offset_flags are a signed offset.
+ // For a non-virtual base, this is the offset in the object of the base
+ // subobject. For a virtual base, this is the offset in the virtual table of
+ // the virtual base offset for the virtual base referenced (negative).
+ CharUnits Offset;
+ if (Base->isVirtual())
+ Offset =
+ CGM.getVTableContext().getVirtualBaseOffsetOffset(RD, BaseDecl);
+ else {
+ const ASTRecordLayout &Layout = CGM.getContext().getASTRecordLayout(RD);
+ Offset = Layout.getBaseClassOffset(BaseDecl);
+ };
+
+ OffsetFlags = uint64_t(Offset.getQuantity()) << 8;
+
+ // The low-order byte of __offset_flags contains flags, as given by the
+ // masks from the enumeration __offset_flags_masks.
+ if (Base->isVirtual())
+ OffsetFlags |= BCTI_Virtual;
+ if (Base->getAccessSpecifier() == AS_public)
+ OffsetFlags |= BCTI_Public;
+
+ Fields.push_back(llvm::ConstantInt::get(LongLTy, OffsetFlags));
+ }
+}
+
+/// BuildPointerTypeInfo - Build an abi::__pointer_type_info struct,
+/// used for pointer types.
+void RTTIBuilder::BuildPointerTypeInfo(QualType PointeeTy) {
+ Qualifiers Quals;
+ QualType UnqualifiedPointeeTy =
+ CGM.getContext().getUnqualifiedArrayType(PointeeTy, Quals);
+
+ // Itanium C++ ABI 2.9.5p7:
+ // __flags is a flag word describing the cv-qualification and other
+ // attributes of the type pointed to
+ unsigned Flags = ComputeQualifierFlags(Quals);
+
+ // Itanium C++ ABI 2.9.5p7:
+ // When the abi::__pbase_type_info is for a direct or indirect pointer to an
+ // incomplete class type, the incomplete target type flag is set.
+ if (ContainsIncompleteClassType(UnqualifiedPointeeTy))
+ Flags |= PTI_Incomplete;
+
+ llvm::Type *UnsignedIntLTy =
+ CGM.getTypes().ConvertType(CGM.getContext().UnsignedIntTy);
+ Fields.push_back(llvm::ConstantInt::get(UnsignedIntLTy, Flags));
+
+ // Itanium C++ ABI 2.9.5p7:
+ // __pointee is a pointer to the std::type_info derivation for the
+ // unqualified type being pointed to.
+ llvm::Constant *PointeeTypeInfo =
+ RTTIBuilder(CGM).BuildTypeInfo(UnqualifiedPointeeTy);
+ Fields.push_back(PointeeTypeInfo);
+}
+
+/// BuildPointerToMemberTypeInfo - Build an abi::__pointer_to_member_type_info
+/// struct, used for member pointer types.
+void RTTIBuilder::BuildPointerToMemberTypeInfo(const MemberPointerType *Ty) {
+ QualType PointeeTy = Ty->getPointeeType();
+
+ Qualifiers Quals;
+ QualType UnqualifiedPointeeTy =
+ CGM.getContext().getUnqualifiedArrayType(PointeeTy, Quals);
+
+ // Itanium C++ ABI 2.9.5p7:
+ // __flags is a flag word describing the cv-qualification and other
+ // attributes of the type pointed to.
+ unsigned Flags = ComputeQualifierFlags(Quals);
+
+ const RecordType *ClassType = cast<RecordType>(Ty->getClass());
+
+ // Itanium C++ ABI 2.9.5p7:
+ // When the abi::__pbase_type_info is for a direct or indirect pointer to an
+ // incomplete class type, the incomplete target type flag is set.
+ if (ContainsIncompleteClassType(UnqualifiedPointeeTy))
+ Flags |= PTI_Incomplete;
+
+ if (IsIncompleteClassType(ClassType))
+ Flags |= PTI_ContainingClassIncomplete;
+
+ llvm::Type *UnsignedIntLTy =
+ CGM.getTypes().ConvertType(CGM.getContext().UnsignedIntTy);
+ Fields.push_back(llvm::ConstantInt::get(UnsignedIntLTy, Flags));
+
+ // Itanium C++ ABI 2.9.5p7:
+ // __pointee is a pointer to the std::type_info derivation for the
+ // unqualified type being pointed to.
+ llvm::Constant *PointeeTypeInfo =
+ RTTIBuilder(CGM).BuildTypeInfo(UnqualifiedPointeeTy);
+ Fields.push_back(PointeeTypeInfo);
+
+ // Itanium C++ ABI 2.9.5p9:
+ // __context is a pointer to an abi::__class_type_info corresponding to the
+ // class type containing the member pointed to
+ // (e.g., the "A" in "int A::*").
+ Fields.push_back(RTTIBuilder(CGM).BuildTypeInfo(QualType(ClassType, 0)));
+}
+
+llvm::Constant *CodeGenModule::GetAddrOfRTTIDescriptor(QualType Ty,
+ bool ForEH) {
+ // Return a bogus pointer if RTTI is disabled, unless it's for EH.
+ // FIXME: should we even be calling this method if RTTI is disabled
+ // and it's not for EH?
+ if (!ForEH && !getLangOpts().RTTI)
+ return llvm::Constant::getNullValue(Int8PtrTy);
+
+ if (ForEH && Ty->isObjCObjectPointerType() &&
+ LangOpts.ObjCRuntime.isGNUFamily())
+ return ObjCRuntime->GetEHType(Ty);
+
+ return RTTIBuilder(*this).BuildTypeInfo(Ty);
+}
+
+void CodeGenModule::EmitFundamentalRTTIDescriptor(QualType Type) {
+ QualType PointerType = Context.getPointerType(Type);
+ QualType PointerTypeConst = Context.getPointerType(Type.withConst());
+ RTTIBuilder(*this).BuildTypeInfo(Type, true);
+ RTTIBuilder(*this).BuildTypeInfo(PointerType, true);
+ RTTIBuilder(*this).BuildTypeInfo(PointerTypeConst, true);
+}
+
+void CodeGenModule::EmitFundamentalRTTIDescriptors() {
+ QualType FundamentalTypes[] = { Context.VoidTy, Context.NullPtrTy,
+ Context.BoolTy, Context.WCharTy,
+ Context.CharTy, Context.UnsignedCharTy,
+ Context.SignedCharTy, Context.ShortTy,
+ Context.UnsignedShortTy, Context.IntTy,
+ Context.UnsignedIntTy, Context.LongTy,
+ Context.UnsignedLongTy, Context.LongLongTy,
+ Context.UnsignedLongLongTy, Context.FloatTy,
+ Context.DoubleTy, Context.LongDoubleTy,
+ Context.Char16Ty, Context.Char32Ty };
+ for (unsigned i = 0; i < sizeof(FundamentalTypes)/sizeof(QualType); ++i)
+ EmitFundamentalRTTIDescriptor(FundamentalTypes[i]);
+}
diff --git a/clang/lib/CodeGen/CodeGenTypes.cpp b/clang/lib/CodeGen/CodeGenTypes.cpp index a0effa8c1f6..8cb6dd001cb 100644 --- a/clang/lib/CodeGen/CodeGenTypes.cpp +++ b/clang/lib/CodeGen/CodeGenTypes.cpp @@ -14,6 +14,7 @@ #include "CodeGenTypes.h" #include "CGCXXABI.h" #include "CGCall.h" +#include "CGOpenCLRuntime.h" #include "CGRecordLayout.h" #include "TargetInfo.h" #include "clang/AST/ASTContext.h" @@ -366,6 +367,15 @@ llvm::Type *CodeGenTypes::ConvertType(QualType T) { case BuiltinType::Int128: ResultType = llvm::IntegerType::get(getLLVMContext(), 128); break; + + case BuiltinType::OCLImage1d: + case BuiltinType::OCLImage1dArray: + case BuiltinType::OCLImage1dBuffer: + case BuiltinType::OCLImage2d: + case BuiltinType::OCLImage2dArray: + case BuiltinType::OCLImage3d: + ResultType = CGM.getOpenCLRuntime().convertOpenCLSpecificType(Ty); + break; case BuiltinType::Dependent: #define BUILTIN_TYPE(Id, SingletonId) diff --git a/clang/lib/Parse/ParseDecl.cpp b/clang/lib/Parse/ParseDecl.cpp index 518c8a07871..390fd34536e 100644 --- a/clang/lib/Parse/ParseDecl.cpp +++ b/clang/lib/Parse/ParseDecl.cpp @@ -2753,6 +2753,30 @@ void Parser::ParseDeclarationSpecifiers(DeclSpec &DS, case tok::kw___pixel: isInvalid = DS.SetTypeAltiVecPixel(true, Loc, PrevSpec, DiagID); break; + case tok::kw_image1d_t: + isInvalid = DS.SetTypeSpecType(DeclSpec::TST_image1d_t, Loc, + PrevSpec, DiagID); + break; + case tok::kw_image1d_array_t: + isInvalid = DS.SetTypeSpecType(DeclSpec::TST_image1d_array_t, Loc, + PrevSpec, DiagID); + break; + case tok::kw_image1d_buffer_t: + isInvalid = DS.SetTypeSpecType(DeclSpec::TST_image1d_buffer_t, Loc, + PrevSpec, DiagID); + break; + case tok::kw_image2d_t: + isInvalid = DS.SetTypeSpecType(DeclSpec::TST_image2d_t, Loc, + PrevSpec, DiagID); + break; + case tok::kw_image2d_array_t: + isInvalid = DS.SetTypeSpecType(DeclSpec::TST_image2d_array_t, Loc, + PrevSpec, DiagID); + break; + case tok::kw_image3d_t: + isInvalid = DS.SetTypeSpecType(DeclSpec::TST_image3d_t, Loc, + PrevSpec, DiagID); + break; case tok::kw___unknown_anytype: isInvalid = DS.SetTypeSpecType(TST_unknown_anytype, Loc, PrevSpec, DiagID); @@ -3596,6 +3620,14 @@ bool Parser::isKnownToBeTypeSpecifier(const Token &Tok) const { case tok::kw__Decimal128: case tok::kw___vector: + // OpenCL specific types: + case tok::kw_image1d_t: + case tok::kw_image1d_array_t: + case tok::kw_image1d_buffer_t: + case tok::kw_image2d_t: + case tok::kw_image2d_array_t: + case tok::kw_image3d_t: + // struct-or-union-specifier (C99) or class-specifier (C++) case tok::kw_class: case tok::kw_struct: @@ -3668,6 +3700,14 @@ bool Parser::isTypeSpecifierQualifier() { case tok::kw__Decimal128: case tok::kw___vector: + // OpenCL specific types: + case tok::kw_image1d_t: + case tok::kw_image1d_array_t: + case tok::kw_image1d_buffer_t: + case tok::kw_image2d_t: + case tok::kw_image2d_array_t: + case tok::kw_image3d_t: + // struct-or-union-specifier (C99) or class-specifier (C++) case tok::kw_class: case tok::kw_struct: @@ -3812,6 +3852,14 @@ bool Parser::isDeclarationSpecifier(bool DisambiguatingWithExpression) { case tok::kw__Decimal128: case tok::kw___vector: + // OpenCL specific types: + case tok::kw_image1d_t: + case tok::kw_image1d_array_t: + case tok::kw_image1d_buffer_t: + case tok::kw_image2d_t: + case tok::kw_image2d_array_t: + case tok::kw_image3d_t: + // struct-or-union-specifier (C99) or class-specifier (C++) case tok::kw_class: case tok::kw_struct: diff --git a/clang/lib/Parse/ParseExpr.cpp b/clang/lib/Parse/ParseExpr.cpp index 14980ee994f..b7705f8c0d3 100644 --- a/clang/lib/Parse/ParseExpr.cpp +++ b/clang/lib/Parse/ParseExpr.cpp @@ -1078,7 +1078,13 @@ ExprResult Parser::ParseCastExpression(bool isUnaryExpression, case tok::kw_void: case tok::kw_typename: case tok::kw_typeof: - case tok::kw___vector: { + case tok::kw___vector: + case tok::kw_image1d_t: + case tok::kw_image1d_array_t: + case tok::kw_image1d_buffer_t: + case tok::kw_image2d_t: + case tok::kw_image2d_array_t: + case tok::kw_image3d_t: { if (!getLangOpts().CPlusPlus) { Diag(Tok, diag::err_expected_expression); return ExprError(); diff --git a/clang/lib/Parse/ParseTentative.cpp b/clang/lib/Parse/ParseTentative.cpp index b26181f08ea..e411899ef4e 100644 --- a/clang/lib/Parse/ParseTentative.cpp +++ b/clang/lib/Parse/ParseTentative.cpp @@ -1,1574 +1,1580 @@ -//===--- ParseTentative.cpp - Ambiguity Resolution Parsing ----------------===// -// -// The LLVM Compiler Infrastructure -// -// This file is distributed under the University of Illinois Open Source -// License. See LICENSE.TXT for details. -// -//===----------------------------------------------------------------------===// -// -// This file implements the tentative parsing portions of the Parser -// interfaces, for ambiguity resolution. -// -//===----------------------------------------------------------------------===// - -#include "clang/Parse/Parser.h" -#include "clang/Parse/ParseDiagnostic.h" -#include "clang/Sema/ParsedTemplate.h" -using namespace clang; - -/// isCXXDeclarationStatement - C++-specialized function that disambiguates -/// between a declaration or an expression statement, when parsing function -/// bodies. Returns true for declaration, false for expression. -/// -/// declaration-statement: -/// block-declaration -/// -/// block-declaration: -/// simple-declaration -/// asm-definition -/// namespace-alias-definition -/// using-declaration -/// using-directive -/// [C++0x] static_assert-declaration -/// -/// asm-definition: -/// 'asm' '(' string-literal ')' ';' -/// -/// namespace-alias-definition: -/// 'namespace' identifier = qualified-namespace-specifier ';' -/// -/// using-declaration: -/// 'using' typename[opt] '::'[opt] nested-name-specifier -/// unqualified-id ';' -/// 'using' '::' unqualified-id ; -/// -/// using-directive: -/// 'using' 'namespace' '::'[opt] nested-name-specifier[opt] -/// namespace-name ';' -/// -bool Parser::isCXXDeclarationStatement() { - switch (Tok.getKind()) { - // asm-definition - case tok::kw_asm: - // namespace-alias-definition - case tok::kw_namespace: - // using-declaration - // using-directive - case tok::kw_using: - // static_assert-declaration - case tok::kw_static_assert: - case tok::kw__Static_assert: - return true; - // simple-declaration - default: - return isCXXSimpleDeclaration(/*AllowForRangeDecl=*/false); - } -} - -/// isCXXSimpleDeclaration - C++-specialized function that disambiguates -/// between a simple-declaration or an expression-statement. -/// If during the disambiguation process a parsing error is encountered, -/// the function returns true to let the declaration parsing code handle it. -/// Returns false if the statement is disambiguated as expression. -/// -/// simple-declaration: -/// decl-specifier-seq init-declarator-list[opt] ';' -/// -/// (if AllowForRangeDecl specified) -/// for ( for-range-declaration : for-range-initializer ) statement -/// for-range-declaration: -/// attribute-specifier-seqopt type-specifier-seq declarator -bool Parser::isCXXSimpleDeclaration(bool AllowForRangeDecl) { - // C++ 6.8p1: - // There is an ambiguity in the grammar involving expression-statements and - // declarations: An expression-statement with a function-style explicit type - // conversion (5.2.3) as its leftmost subexpression can be indistinguishable - // from a declaration where the first declarator starts with a '('. In those - // cases the statement is a declaration. [Note: To disambiguate, the whole - // statement might have to be examined to determine if it is an - // expression-statement or a declaration]. - - // C++ 6.8p3: - // The disambiguation is purely syntactic; that is, the meaning of the names - // occurring in such a statement, beyond whether they are type-names or not, - // is not generally used in or changed by the disambiguation. Class - // templates are instantiated as necessary to determine if a qualified name - // is a type-name. Disambiguation precedes parsing, and a statement - // disambiguated as a declaration may be an ill-formed declaration. - - // We don't have to parse all of the decl-specifier-seq part. There's only - // an ambiguity if the first decl-specifier is - // simple-type-specifier/typename-specifier followed by a '(', which may - // indicate a function-style cast expression. - // isCXXDeclarationSpecifier will return TPResult::Ambiguous() only in such - // a case. - - bool InvalidAsDeclaration = false; - TPResult TPR = isCXXDeclarationSpecifier(TPResult::False(), - &InvalidAsDeclaration); - if (TPR != TPResult::Ambiguous()) - return TPR != TPResult::False(); // Returns true for TPResult::True() or - // TPResult::Error(). - - // FIXME: TryParseSimpleDeclaration doesn't look past the first initializer, - // and so gets some cases wrong. We can't carry on if we've already seen - // something which makes this statement invalid as a declaration in this case, - // since it can cause us to misparse valid code. Revisit this once - // TryParseInitDeclaratorList is fixed. - if (InvalidAsDeclaration) - return false; - - // FIXME: Add statistics about the number of ambiguous statements encountered - // and how they were resolved (number of declarations+number of expressions). - - // Ok, we have a simple-type-specifier/typename-specifier followed by a '(', - // or an identifier which doesn't resolve as anything. We need tentative - // parsing... - - TentativeParsingAction PA(*this); - TPR = TryParseSimpleDeclaration(AllowForRangeDecl); - PA.Revert(); - - // In case of an error, let the declaration parsing code handle it. - if (TPR == TPResult::Error()) - return true; - - // Declarations take precedence over expressions. - if (TPR == TPResult::Ambiguous()) - TPR = TPResult::True(); - - assert(TPR == TPResult::True() || TPR == TPResult::False()); - return TPR == TPResult::True(); -} - -/// simple-declaration: -/// decl-specifier-seq init-declarator-list[opt] ';' -/// -/// (if AllowForRangeDecl specified) -/// for ( for-range-declaration : for-range-initializer ) statement -/// for-range-declaration: -/// attribute-specifier-seqopt type-specifier-seq declarator -/// -Parser::TPResult Parser::TryParseSimpleDeclaration(bool AllowForRangeDecl) { - if (Tok.is(tok::kw_typeof)) - TryParseTypeofSpecifier(); - else { - if (Tok.is(tok::annot_cxxscope)) - ConsumeToken(); - ConsumeToken(); - - if (getLangOpts().ObjC1 && Tok.is(tok::less)) - TryParseProtocolQualifiers(); - } - - // Two decl-specifiers in a row conclusively disambiguate this as being a - // simple-declaration. Don't bother calling isCXXDeclarationSpecifier in the - // overwhelmingly common case that the next token is a '('. - if (Tok.isNot(tok::l_paren)) { - TPResult TPR = isCXXDeclarationSpecifier(); - if (TPR == TPResult::Ambiguous()) - return TPResult::True(); - if (TPR == TPResult::True() || TPR == TPResult::Error()) - return TPR; - assert(TPR == TPResult::False()); - } - - TPResult TPR = TryParseInitDeclaratorList(); - if (TPR != TPResult::Ambiguous()) - return TPR; - - if (Tok.isNot(tok::semi) && (!AllowForRangeDecl || Tok.isNot(tok::colon))) - return TPResult::False(); - - return TPResult::Ambiguous(); -} - -/// init-declarator-list: -/// init-declarator -/// init-declarator-list ',' init-declarator -/// -/// init-declarator: -/// declarator initializer[opt] -/// [GNU] declarator simple-asm-expr[opt] attributes[opt] initializer[opt] -/// -/// initializer: -/// '=' initializer-clause -/// '(' expression-list ')' -/// -/// initializer-clause: -/// assignment-expression -/// '{' initializer-list ','[opt] '}' -/// '{' '}' -/// -Parser::TPResult Parser::TryParseInitDeclaratorList() { - while (1) { - // declarator - TPResult TPR = TryParseDeclarator(false/*mayBeAbstract*/); - if (TPR != TPResult::Ambiguous()) - return TPR; - - // [GNU] simple-asm-expr[opt] attributes[opt] - if (Tok.is(tok::kw_asm) || Tok.is(tok::kw___attribute)) - return TPResult::True(); - - // initializer[opt] - if (Tok.is(tok::l_paren)) { - // Parse through the parens. - ConsumeParen(); - if (!SkipUntil(tok::r_paren)) - return TPResult::Error(); - } else if (Tok.is(tok::equal) || isTokIdentifier_in()) { - // MSVC and g++ won't examine the rest of declarators if '=' is - // encountered; they just conclude that we have a declaration. - // EDG parses the initializer completely, which is the proper behavior - // for this case. - // - // At present, Clang follows MSVC and g++, since the parser does not have - // the ability to parse an expression fully without recording the - // results of that parse. - // Also allow 'in' after on objective-c declaration as in: - // for (int (^b)(void) in array). Ideally this should be done in the - // context of parsing for-init-statement of a foreach statement only. But, - // in any other context 'in' is invalid after a declaration and parser - // issues the error regardless of outcome of this decision. - // FIXME. Change if above assumption does not hold. - return TPResult::True(); - } - - if (Tok.isNot(tok::comma)) - break; - ConsumeToken(); // the comma. - } - - return TPResult::Ambiguous(); -} - -/// isCXXConditionDeclaration - Disambiguates between a declaration or an -/// expression for a condition of a if/switch/while/for statement. -/// If during the disambiguation process a parsing error is encountered, -/// the function returns true to let the declaration parsing code handle it. -/// -/// condition: -/// expression -/// type-specifier-seq declarator '=' assignment-expression -/// [C++11] type-specifier-seq declarator '=' initializer-clause -/// [C++11] type-specifier-seq declarator braced-init-list -/// [GNU] type-specifier-seq declarator simple-asm-expr[opt] attributes[opt] -/// '=' assignment-expression -/// -bool Parser::isCXXConditionDeclaration() { - TPResult TPR = isCXXDeclarationSpecifier(); - if (TPR != TPResult::Ambiguous()) - return TPR != TPResult::False(); // Returns true for TPResult::True() or - // TPResult::Error(). - - // FIXME: Add statistics about the number of ambiguous statements encountered - // and how they were resolved (number of declarations+number of expressions). - - // Ok, we have a simple-type-specifier/typename-specifier followed by a '('. - // We need tentative parsing... - - TentativeParsingAction PA(*this); - - // type-specifier-seq - if (Tok.is(tok::kw_typeof)) - TryParseTypeofSpecifier(); - else { - ConsumeToken(); - - if (getLangOpts().ObjC1 && Tok.is(tok::less)) - TryParseProtocolQualifiers(); - } - assert(Tok.is(tok::l_paren) && "Expected '('"); - - // declarator - TPR = TryParseDeclarator(false/*mayBeAbstract*/); - - // In case of an error, let the declaration parsing code handle it. - if (TPR == TPResult::Error()) - TPR = TPResult::True(); - - if (TPR == TPResult::Ambiguous()) { - // '=' - // [GNU] simple-asm-expr[opt] attributes[opt] - if (Tok.is(tok::equal) || - Tok.is(tok::kw_asm) || Tok.is(tok::kw___attribute)) - TPR = TPResult::True(); - else if (getLangOpts().CPlusPlus0x && Tok.is(tok::l_brace)) - TPR = TPResult::True(); - else - TPR = TPResult::False(); - } - - PA.Revert(); - - assert(TPR == TPResult::True() || TPR == TPResult::False()); - return TPR == TPResult::True(); -} - - /// \brief Determine whether the next set of tokens contains a type-id. - /// - /// The context parameter states what context we're parsing right - /// now, which affects how this routine copes with the token - /// following the type-id. If the context is TypeIdInParens, we have - /// already parsed the '(' and we will cease lookahead when we hit - /// the corresponding ')'. If the context is - /// TypeIdAsTemplateArgument, we've already parsed the '<' or ',' - /// before this template argument, and will cease lookahead when we - /// hit a '>', '>>' (in C++0x), or ','. Returns true for a type-id - /// and false for an expression. If during the disambiguation - /// process a parsing error is encountered, the function returns - /// true to let the declaration parsing code handle it. - /// - /// type-id: - /// type-specifier-seq abstract-declarator[opt] - /// -bool Parser::isCXXTypeId(TentativeCXXTypeIdContext Context, bool &isAmbiguous) { - - isAmbiguous = false; - - // C++ 8.2p2: - // The ambiguity arising from the similarity between a function-style cast and - // a type-id can occur in different contexts. The ambiguity appears as a - // choice between a function-style cast expression and a declaration of a - // type. The resolution is that any construct that could possibly be a type-id - // in its syntactic context shall be considered a type-id. - - TPResult TPR = isCXXDeclarationSpecifier(); - if (TPR != TPResult::Ambiguous()) - return TPR != TPResult::False(); // Returns true for TPResult::True() or - // TPResult::Error(). - - // FIXME: Add statistics about the number of ambiguous statements encountered - // and how they were resolved (number of declarations+number of expressions). - - // Ok, we have a simple-type-specifier/typename-specifier followed by a '('. - // We need tentative parsing... - - TentativeParsingAction PA(*this); - - // type-specifier-seq - if (Tok.is(tok::kw_typeof)) - TryParseTypeofSpecifier(); - else { - ConsumeToken(); - - if (getLangOpts().ObjC1 && Tok.is(tok::less)) - TryParseProtocolQualifiers(); - } - - assert(Tok.is(tok::l_paren) && "Expected '('"); - - // declarator - TPR = TryParseDeclarator(true/*mayBeAbstract*/, false/*mayHaveIdentifier*/); - - // In case of an error, let the declaration parsing code handle it. - if (TPR == TPResult::Error()) - TPR = TPResult::True(); - - if (TPR == TPResult::Ambiguous()) { - // We are supposed to be inside parens, so if after the abstract declarator - // we encounter a ')' this is a type-id, otherwise it's an expression. - if (Context == TypeIdInParens && Tok.is(tok::r_paren)) { - TPR = TPResult::True(); - isAmbiguous = true; - - // We are supposed to be inside a template argument, so if after - // the abstract declarator we encounter a '>', '>>' (in C++0x), or - // ',', this is a type-id. Otherwise, it's an expression. - } else if (Context == TypeIdAsTemplateArgument && - (Tok.is(tok::greater) || Tok.is(tok::comma) || - (getLangOpts().CPlusPlus0x && Tok.is(tok::greatergreater)))) { - TPR = TPResult::True(); - isAmbiguous = true; - - } else - TPR = TPResult::False(); - } - - PA.Revert(); - - assert(TPR == TPResult::True() || TPR == TPResult::False()); - return TPR == TPResult::True(); -} - -/// \brief Returns true if this is a C++11 attribute-specifier. Per -/// C++11 [dcl.attr.grammar]p6, two consecutive left square bracket tokens -/// always introduce an attribute. In Objective-C++11, this rule does not -/// apply if either '[' begins a message-send. -/// -/// If Disambiguate is true, we try harder to determine whether a '[[' starts -/// an attribute-specifier, and return CAK_InvalidAttributeSpecifier if not. -/// -/// If OuterMightBeMessageSend is true, we assume the outer '[' is either an -/// Obj-C message send or the start of an attribute. Otherwise, we assume it -/// is not an Obj-C message send. -/// -/// C++11 [dcl.attr.grammar]: -/// -/// attribute-specifier: -/// '[' '[' attribute-list ']' ']' -/// alignment-specifier -/// -/// attribute-list: -/// attribute[opt] -/// attribute-list ',' attribute[opt] -/// attribute '...' -/// attribute-list ',' attribute '...' -/// -/// attribute: -/// attribute-token attribute-argument-clause[opt] -/// -/// attribute-token: -/// identifier -/// identifier '::' identifier -/// -/// attribute-argument-clause: -/// '(' balanced-token-seq ')' -Parser::CXX11AttributeKind -Parser::isCXX11AttributeSpecifier(bool Disambiguate, - bool OuterMightBeMessageSend) { - if (Tok.is(tok::kw_alignas)) - return CAK_AttributeSpecifier; - - if (Tok.isNot(tok::l_square) || NextToken().isNot(tok::l_square)) - return CAK_NotAttributeSpecifier; - - // No tentative parsing if we don't need to look for ']]' or a lambda. - if (!Disambiguate && !getLangOpts().ObjC1) - return CAK_AttributeSpecifier; - - TentativeParsingAction PA(*this); - - // Opening brackets were checked for above. - ConsumeBracket(); - - // Outside Obj-C++11, treat anything with a matching ']]' as an attribute. - if (!getLangOpts().ObjC1) { - ConsumeBracket(); - - bool IsAttribute = SkipUntil(tok::r_square, false); - IsAttribute &= Tok.is(tok::r_square); - - PA.Revert(); - - return IsAttribute ? CAK_AttributeSpecifier : CAK_InvalidAttributeSpecifier; - } - - // In Obj-C++11, we need to distinguish four situations: - // 1a) int x[[attr]]; C++11 attribute. - // 1b) [[attr]]; C++11 statement attribute. - // 2) int x[[obj](){ return 1; }()]; Lambda in array size/index. - // 3a) int x[[obj get]]; Message send in array size/index. - // 3b) [[Class alloc] init]; Message send in message send. - // 4) [[obj]{ return self; }() doStuff]; Lambda in message send. - // (1) is an attribute, (2) is ill-formed, and (3) and (4) are accepted. - - // If we have a lambda-introducer, then this is definitely not a message send. - // FIXME: If this disambiguation is too slow, fold the tentative lambda parse - // into the tentative attribute parse below. - LambdaIntroducer Intro; - if (!TryParseLambdaIntroducer(Intro)) { - // A lambda cannot end with ']]', and an attribute must. - bool IsAttribute = Tok.is(tok::r_square); - - PA.Revert(); - - if (IsAttribute) - // Case 1: C++11 attribute. - return CAK_AttributeSpecifier; - - if (OuterMightBeMessageSend) - // Case 4: Lambda in message send. - return CAK_NotAttributeSpecifier; - - // Case 2: Lambda in array size / index. - return CAK_InvalidAttributeSpecifier; - } - - ConsumeBracket(); - - // If we don't have a lambda-introducer, then we have an attribute or a - // message-send. - bool IsAttribute = true; - while (Tok.isNot(tok::r_square)) { - if (Tok.is(tok::comma)) { - // Case 1: Stray commas can only occur in attributes. - PA.Revert(); - return CAK_AttributeSpecifier; - } - - // Parse the attribute-token, if present. - // C++11 [dcl.attr.grammar]: - // If a keyword or an alternative token that satisfies the syntactic - // requirements of an identifier is contained in an attribute-token, - // it is considered an identifier. - SourceLocation Loc; - if (!TryParseCXX11AttributeIdentifier(Loc)) { - IsAttribute = false; - break; - } - if (Tok.is(tok::coloncolon)) { - ConsumeToken(); - if (!TryParseCXX11AttributeIdentifier(Loc)) { - IsAttribute = false; - break; - } - } - - // Parse the attribute-argument-clause, if present. - if (Tok.is(tok::l_paren)) { - ConsumeParen(); - if (!SkipUntil(tok::r_paren, false)) { - IsAttribute = false; - break; - } - } - - if (Tok.is(tok::ellipsis)) - ConsumeToken(); - - if (Tok.isNot(tok::comma)) - break; - - ConsumeToken(); - } - - // An attribute must end ']]'. - if (IsAttribute) { - if (Tok.is(tok::r_square)) { - ConsumeBracket(); - IsAttribute = Tok.is(tok::r_square); - } else { - IsAttribute = false; - } - } - - PA.Revert(); - - if (IsAttribute) - // Case 1: C++11 statement attribute. - return CAK_AttributeSpecifier; - - // Case 3: Message send. - return CAK_NotAttributeSpecifier; -} - -/// declarator: -/// direct-declarator -/// ptr-operator declarator -/// -/// direct-declarator: -/// declarator-id -/// direct-declarator '(' parameter-declaration-clause ')' -/// cv-qualifier-seq[opt] exception-specification[opt] -/// direct-declarator '[' constant-expression[opt] ']' -/// '(' declarator ')' -/// [GNU] '(' attributes declarator ')' -/// -/// abstract-declarator: -/// ptr-operator abstract-declarator[opt] -/// direct-abstract-declarator -/// ... -/// -/// direct-abstract-declarator: -/// direct-abstract-declarator[opt] -/// '(' parameter-declaration-clause ')' cv-qualifier-seq[opt] -/// exception-specification[opt] -/// direct-abstract-declarator[opt] '[' constant-expression[opt] ']' -/// '(' abstract-declarator ')' -/// -/// ptr-operator: -/// '*' cv-qualifier-seq[opt] -/// '&' -/// [C++0x] '&&' [TODO] -/// '::'[opt] nested-name-specifier '*' cv-qualifier-seq[opt] -/// -/// cv-qualifier-seq: -/// cv-qualifier cv-qualifier-seq[opt] -/// -/// cv-qualifier: -/// 'const' -/// 'volatile' -/// -/// declarator-id: -/// '...'[opt] id-expression -/// -/// id-expression: -/// unqualified-id -/// qualified-id [TODO] -/// -/// unqualified-id: -/// identifier -/// operator-function-id [TODO] -/// conversion-function-id [TODO] -/// '~' class-name [TODO] -/// template-id [TODO] -/// -Parser::TPResult Parser::TryParseDeclarator(bool mayBeAbstract, - bool mayHaveIdentifier) { - // declarator: - // direct-declarator - // ptr-operator declarator - - while (1) { - if (Tok.is(tok::coloncolon) || Tok.is(tok::identifier)) - if (TryAnnotateCXXScopeToken(true)) - return TPResult::Error(); - - if (Tok.is(tok::star) || Tok.is(tok::amp) || Tok.is(tok::caret) || - Tok.is(tok::ampamp) || - (Tok.is(tok::annot_cxxscope) && NextToken().is(tok::star))) { - // ptr-operator - ConsumeToken(); - while (Tok.is(tok::kw_const) || - Tok.is(tok::kw_volatile) || - Tok.is(tok::kw_restrict)) - ConsumeToken(); - } else { - break; - } - } - - // direct-declarator: - // direct-abstract-declarator: - if (Tok.is(tok::ellipsis)) - ConsumeToken(); - - if ((Tok.is(tok::identifier) || - (Tok.is(tok::annot_cxxscope) && NextToken().is(tok::identifier))) && - mayHaveIdentifier) { - // declarator-id - if (Tok.is(tok::annot_cxxscope)) - ConsumeToken(); - else - TentativelyDeclaredIdentifiers.push_back(Tok.getIdentifierInfo()); - ConsumeToken(); - } else if (Tok.is(tok::l_paren)) { - ConsumeParen(); - if (mayBeAbstract && - (Tok.is(tok::r_paren) || // 'int()' is a function. - // 'int(...)' is a function. - (Tok.is(tok::ellipsis) && NextToken().is(tok::r_paren)) || - isDeclarationSpecifier())) { // 'int(int)' is a function. - // '(' parameter-declaration-clause ')' cv-qualifier-seq[opt] - // exception-specification[opt] - TPResult TPR = TryParseFunctionDeclarator(); - if (TPR != TPResult::Ambiguous()) - return TPR; - } else { - // '(' declarator ')' - // '(' attributes declarator ')' - // '(' abstract-declarator ')' - if (Tok.is(tok::kw___attribute) || - Tok.is(tok::kw___declspec) || - Tok.is(tok::kw___cdecl) || - Tok.is(tok::kw___stdcall) || - Tok.is(tok::kw___fastcall) || - Tok.is(tok::kw___thiscall) || - Tok.is(tok::kw___unaligned)) - return TPResult::True(); // attributes indicate declaration - TPResult TPR = TryParseDeclarator(mayBeAbstract, mayHaveIdentifier); - if (TPR != TPResult::Ambiguous()) - return TPR; - if (Tok.isNot(tok::r_paren)) - return TPResult::False(); - ConsumeParen(); - } - } else if (!mayBeAbstract) { - return TPResult::False(); - } - - while (1) { - TPResult TPR(TPResult::Ambiguous()); - - // abstract-declarator: ... - if (Tok.is(tok::ellipsis)) - ConsumeToken(); - - if (Tok.is(tok::l_paren)) { - // Check whether we have a function declarator or a possible ctor-style - // initializer that follows the declarator. Note that ctor-style - // initializers are not possible in contexts where abstract declarators - // are allowed. - if (!mayBeAbstract && !isCXXFunctionDeclarator()) - break; - - // direct-declarator '(' parameter-declaration-clause ')' - // cv-qualifier-seq[opt] exception-specification[opt] - ConsumeParen(); - TPR = TryParseFunctionDeclarator(); - } else if (Tok.is(tok::l_square)) { - // direct-declarator '[' constant-expression[opt] ']' - // direct-abstract-declarator[opt] '[' constant-expression[opt] ']' - TPR = TryParseBracketDeclarator(); - } else { - break; - } - - if (TPR != TPResult::Ambiguous()) - return TPR; - } - - return TPResult::Ambiguous(); -} - -Parser::TPResult -Parser::isExpressionOrTypeSpecifierSimple(tok::TokenKind Kind) { - switch (Kind) { - // Obviously starts an expression. - case tok::numeric_constant: - case tok::char_constant: - case tok::wide_char_constant: - case tok::utf16_char_constant: - case tok::utf32_char_constant: - case tok::string_literal: - case tok::wide_string_literal: - case tok::utf8_string_literal: - case tok::utf16_string_literal: - case tok::utf32_string_literal: - case tok::l_square: - case tok::l_paren: - case tok::amp: - case tok::ampamp: - case tok::star: - case tok::plus: - case tok::plusplus: - case tok::minus: - case tok::minusminus: - case tok::tilde: - case tok::exclaim: - case tok::kw_sizeof: - case tok::kw___func__: - case tok::kw_const_cast: - case tok::kw_delete: - case tok::kw_dynamic_cast: - case tok::kw_false: - case tok::kw_new: - case tok::kw_operator: - case tok::kw_reinterpret_cast: - case tok::kw_static_cast: - case tok::kw_this: - case tok::kw_throw: - case tok::kw_true: - case tok::kw_typeid: - case tok::kw_alignof: - case tok::kw_noexcept: - case tok::kw_nullptr: - case tok::kw__Alignof: - case tok::kw___null: - case tok::kw___alignof: - case tok::kw___builtin_choose_expr: - case tok::kw___builtin_offsetof: - case tok::kw___builtin_types_compatible_p: - case tok::kw___builtin_va_arg: - case tok::kw___imag: - case tok::kw___real: - case tok::kw___FUNCTION__: - case tok::kw_L__FUNCTION__: - case tok::kw___PRETTY_FUNCTION__: - case tok::kw___has_nothrow_assign: - case tok::kw___has_nothrow_copy: - case tok::kw___has_nothrow_constructor: - case tok::kw___has_trivial_assign: - case tok::kw___has_trivial_copy: - case tok::kw___has_trivial_constructor: - case tok::kw___has_trivial_destructor: - case tok::kw___has_virtual_destructor: - case tok::kw___is_abstract: - case tok::kw___is_base_of: - case tok::kw___is_class: - case tok::kw___is_convertible_to: - case tok::kw___is_empty: - case tok::kw___is_enum: - case tok::kw___is_interface_class: - case tok::kw___is_final: - case tok::kw___is_literal: - case tok::kw___is_literal_type: - case tok::kw___is_pod: - case tok::kw___is_polymorphic: - case tok::kw___is_trivial: - case tok::kw___is_trivially_assignable: - case tok::kw___is_trivially_constructible: - case tok::kw___is_trivially_copyable: - case tok::kw___is_union: - case tok::kw___uuidof: - return TPResult::True(); - - // Obviously starts a type-specifier-seq: - case tok::kw_char: - case tok::kw_const: - case tok::kw_double: - case tok::kw_enum: - case tok::kw_half: - case tok::kw_float: - case tok::kw_int: - case tok::kw_long: - case tok::kw___int64: - case tok::kw___int128: - case tok::kw_restrict: - case tok::kw_short: - case tok::kw_signed: - case tok::kw_struct: - case tok::kw_union: - case tok::kw_unsigned: - case tok::kw_void: - case tok::kw_volatile: - case tok::kw__Bool: - case tok::kw__Complex: - case tok::kw_class: - case tok::kw_typename: - case tok::kw_wchar_t: - case tok::kw_char16_t: - case tok::kw_char32_t: - case tok::kw___underlying_type: - case tok::kw_thread_local: - case tok::kw__Decimal32: - case tok::kw__Decimal64: - case tok::kw__Decimal128: - case tok::kw___thread: - case tok::kw_typeof: - case tok::kw___cdecl: - case tok::kw___stdcall: - case tok::kw___fastcall: - case tok::kw___thiscall: - case tok::kw___unaligned: - case tok::kw___vector: - case tok::kw___pixel: - case tok::kw__Atomic: - case tok::kw___unknown_anytype: - return TPResult::False(); - - default: - break; - } - - return TPResult::Ambiguous(); -} - -bool Parser::isTentativelyDeclared(IdentifierInfo *II) { - return std::find(TentativelyDeclaredIdentifiers.begin(), - TentativelyDeclaredIdentifiers.end(), II) - != TentativelyDeclaredIdentifiers.end(); -} - -/// isCXXDeclarationSpecifier - Returns TPResult::True() if it is a declaration -/// specifier, TPResult::False() if it is not, TPResult::Ambiguous() if it could -/// be either a decl-specifier or a function-style cast, and TPResult::Error() -/// if a parsing error was found and reported. -/// -/// If HasMissingTypename is provided, a name with a dependent scope specifier -/// will be treated as ambiguous if the 'typename' keyword is missing. If this -/// happens, *HasMissingTypename will be set to 'true'. This will also be used -/// as an indicator that undeclared identifiers (which will trigger a later -/// parse error) should be treated as types. Returns TPResult::Ambiguous() in -/// such cases. -/// -/// decl-specifier: -/// storage-class-specifier -/// type-specifier -/// function-specifier -/// 'friend' -/// 'typedef' -/// [C++0x] 'constexpr' -/// [GNU] attributes declaration-specifiers[opt] -/// -/// storage-class-specifier: -/// 'register' -/// 'static' -/// 'extern' -/// 'mutable' -/// 'auto' -/// [GNU] '__thread' -/// -/// function-specifier: -/// 'inline' -/// 'virtual' -/// 'explicit' -/// -/// typedef-name: -/// identifier -/// -/// type-specifier: -/// simple-type-specifier -/// class-specifier -/// enum-specifier -/// elaborated-type-specifier -/// typename-specifier -/// cv-qualifier -/// -/// simple-type-specifier: -/// '::'[opt] nested-name-specifier[opt] type-name -/// '::'[opt] nested-name-specifier 'template' -/// simple-template-id [TODO] -/// 'char' -/// 'wchar_t' -/// 'bool' -/// 'short' -/// 'int' -/// 'long' -/// 'signed' -/// 'unsigned' -/// 'float' -/// 'double' -/// 'void' -/// [GNU] typeof-specifier -/// [GNU] '_Complex' -/// [C++0x] 'auto' [TODO] -/// [C++0x] 'decltype' ( expression ) -/// -/// type-name: -/// class-name -/// enum-name -/// typedef-name -/// -/// elaborated-type-specifier: -/// class-key '::'[opt] nested-name-specifier[opt] identifier -/// class-key '::'[opt] nested-name-specifier[opt] 'template'[opt] -/// simple-template-id -/// 'enum' '::'[opt] nested-name-specifier[opt] identifier -/// -/// enum-name: -/// identifier -/// -/// enum-specifier: -/// 'enum' identifier[opt] '{' enumerator-list[opt] '}' -/// 'enum' identifier[opt] '{' enumerator-list ',' '}' -/// -/// class-specifier: -/// class-head '{' member-specification[opt] '}' -/// -/// class-head: -/// class-key identifier[opt] base-clause[opt] -/// class-key nested-name-specifier identifier base-clause[opt] -/// class-key nested-name-specifier[opt] simple-template-id -/// base-clause[opt] -/// -/// class-key: -/// 'class' -/// 'struct' -/// 'union' -/// -/// cv-qualifier: -/// 'const' -/// 'volatile' -/// [GNU] restrict -/// -Parser::TPResult -Parser::isCXXDeclarationSpecifier(Parser::TPResult BracedCastResult, - bool *HasMissingTypename) { - switch (Tok.getKind()) { - case tok::identifier: { - // Check for need to substitute AltiVec __vector keyword - // for "vector" identifier. - if (TryAltiVecVectorToken()) - return TPResult::True(); - - const Token &Next = NextToken(); - // In 'foo bar', 'foo' is always a type name outside of Objective-C. - if (!getLangOpts().ObjC1 && Next.is(tok::identifier)) - return TPResult::True(); - - if (Next.isNot(tok::coloncolon) && Next.isNot(tok::less)) { - // Determine whether this is a valid expression. If not, we will hit - // a parse error one way or another. In that case, tell the caller that - // this is ambiguous. Typo-correct to type and expression keywords and - // to types and identifiers, in order to try to recover from errors. - CorrectionCandidateCallback TypoCorrection; - TypoCorrection.WantRemainingKeywords = false; - switch (TryAnnotateName(false /* no nested name specifier */, - &TypoCorrection)) { - case ANK_Error: - return TPResult::Error(); - case ANK_TentativeDecl: - return TPResult::False(); - case ANK_TemplateName: - // A bare type template-name which can't be a template template - // argument is an error, and was probably intended to be a type. - return GreaterThanIsOperator ? TPResult::True() : TPResult::False(); - case ANK_Unresolved: - return HasMissingTypename ? TPResult::Ambiguous() : TPResult::False(); - case ANK_Success: - break; - } - assert(Tok.isNot(tok::identifier) && - "TryAnnotateName succeeded without producing an annotation"); - } else { - // This might possibly be a type with a dependent scope specifier and - // a missing 'typename' keyword. Don't use TryAnnotateName in this case, - // since it will annotate as a primary expression, and we want to use the - // "missing 'typename'" logic. - if (TryAnnotateTypeOrScopeToken()) - return TPResult::Error(); - // If annotation failed, assume it's a non-type. - // FIXME: If this happens due to an undeclared identifier, treat it as - // ambiguous. - if (Tok.is(tok::identifier)) - return TPResult::False(); - } - - // We annotated this token as something. Recurse to handle whatever we got. - return isCXXDeclarationSpecifier(BracedCastResult, HasMissingTypename); - } - - case tok::kw_typename: // typename T::type - // Annotate typenames and C++ scope specifiers. If we get one, just - // recurse to handle whatever we get. - if (TryAnnotateTypeOrScopeToken()) - return TPResult::Error(); - return isCXXDeclarationSpecifier(BracedCastResult, HasMissingTypename); - - case tok::coloncolon: { // ::foo::bar - const Token &Next = NextToken(); - if (Next.is(tok::kw_new) || // ::new - Next.is(tok::kw_delete)) // ::delete - return TPResult::False(); - } - // Fall through. - case tok::kw_decltype: - // Annotate typenames and C++ scope specifiers. If we get one, just - // recurse to handle whatever we get. - if (TryAnnotateTypeOrScopeToken()) - return TPResult::Error(); - return isCXXDeclarationSpecifier(BracedCastResult, HasMissingTypename); - - // decl-specifier: - // storage-class-specifier - // type-specifier - // function-specifier - // 'friend' - // 'typedef' - // 'constexpr' - case tok::kw_friend: - case tok::kw_typedef: - case tok::kw_constexpr: - // storage-class-specifier - case tok::kw_register: - case tok::kw_static: - case tok::kw_extern: - case tok::kw_mutable: - case tok::kw_auto: - case tok::kw___thread: - // function-specifier - case tok::kw_inline: - case tok::kw_virtual: - case tok::kw_explicit: - - // Modules - case tok::kw___module_private__: - - // Debugger support - case tok::kw___unknown_anytype: - - // type-specifier: - // simple-type-specifier - // class-specifier - // enum-specifier - // elaborated-type-specifier - // typename-specifier - // cv-qualifier - - // class-specifier - // elaborated-type-specifier - case tok::kw_class: - case tok::kw_struct: - case tok::kw_union: - // enum-specifier - case tok::kw_enum: - // cv-qualifier - case tok::kw_const: - case tok::kw_volatile: - - // GNU - case tok::kw_restrict: - case tok::kw__Complex: - case tok::kw___attribute: - return TPResult::True(); - - // Microsoft - case tok::kw___declspec: - case tok::kw___cdecl: - case tok::kw___stdcall: - case tok::kw___fastcall: - case tok::kw___thiscall: - case tok::kw___w64: - case tok::kw___ptr64: - case tok::kw___ptr32: - case tok::kw___forceinline: - case tok::kw___unaligned: - return TPResult::True(); - - // Borland - case tok::kw___pascal: - return TPResult::True(); - - // AltiVec - case tok::kw___vector: - return TPResult::True(); - - case tok::annot_template_id: { - TemplateIdAnnotation *TemplateId = takeTemplateIdAnnotation(Tok); - if (TemplateId->Kind != TNK_Type_template) - return TPResult::False(); - CXXScopeSpec SS; - AnnotateTemplateIdTokenAsType(); - assert(Tok.is(tok::annot_typename)); - goto case_typename; - } - - case tok::annot_cxxscope: // foo::bar or ::foo::bar, but already parsed - // We've already annotated a scope; try to annotate a type. - if (TryAnnotateTypeOrScopeToken()) - return TPResult::Error(); - if (!Tok.is(tok::annot_typename)) { - // If the next token is an identifier or a type qualifier, then this - // can't possibly be a valid expression either. - if (Tok.is(tok::annot_cxxscope) && NextToken().is(tok::identifier)) { - CXXScopeSpec SS; - Actions.RestoreNestedNameSpecifierAnnotation(Tok.getAnnotationValue(), - Tok.getAnnotationRange(), - SS); - if (SS.getScopeRep() && SS.getScopeRep()->isDependent()) { - TentativeParsingAction PA(*this); - ConsumeToken(); - ConsumeToken(); - bool isIdentifier = Tok.is(tok::identifier); - TPResult TPR = TPResult::False(); - if (!isIdentifier) - TPR = isCXXDeclarationSpecifier(BracedCastResult, - HasMissingTypename); - PA.Revert(); - - if (isIdentifier || - TPR == TPResult::True() || TPR == TPResult::Error()) - return TPResult::Error(); - - if (HasMissingTypename) { - // We can't tell whether this is a missing 'typename' or a valid - // expression. - *HasMissingTypename = true; - return TPResult::Ambiguous(); - } - } else { - // Try to resolve the name. If it doesn't exist, assume it was - // intended to name a type and keep disambiguating. - switch (TryAnnotateName(false /* SS is not dependent */)) { - case ANK_Error: - return TPResult::Error(); - case ANK_TentativeDecl: - return TPResult::False(); - case ANK_TemplateName: - // A bare type template-name which can't be a template template - // argument is an error, and was probably intended to be a type. - return GreaterThanIsOperator ? TPResult::True() : TPResult::False(); - case ANK_Unresolved: - return HasMissingTypename ? TPResult::Ambiguous() - : TPResult::False(); - case ANK_Success: - // Annotated it, check again. - assert(Tok.isNot(tok::annot_cxxscope) || - NextToken().isNot(tok::identifier)); - return isCXXDeclarationSpecifier(BracedCastResult, - HasMissingTypename); - } - } - } - return TPResult::False(); - } - // If that succeeded, fallthrough into the generic simple-type-id case. - - // The ambiguity resides in a simple-type-specifier/typename-specifier - // followed by a '('. The '(' could either be the start of: - // - // direct-declarator: - // '(' declarator ')' - // - // direct-abstract-declarator: - // '(' parameter-declaration-clause ')' cv-qualifier-seq[opt] - // exception-specification[opt] - // '(' abstract-declarator ')' - // - // or part of a function-style cast expression: - // - // simple-type-specifier '(' expression-list[opt] ')' - // - - // simple-type-specifier: - - case tok::annot_typename: - case_typename: - // In Objective-C, we might have a protocol-qualified type. - if (getLangOpts().ObjC1 && NextToken().is(tok::less)) { - // Tentatively parse the - TentativeParsingAction PA(*this); - ConsumeToken(); // The type token - - TPResult TPR = TryParseProtocolQualifiers(); - bool isFollowedByParen = Tok.is(tok::l_paren); - bool isFollowedByBrace = Tok.is(tok::l_brace); - - PA.Revert(); - - if (TPR == TPResult::Error()) - return TPResult::Error(); - - if (isFollowedByParen) - return TPResult::Ambiguous(); - - if (getLangOpts().CPlusPlus0x && isFollowedByBrace) - return BracedCastResult; - - return TPResult::True(); - } - - case tok::kw_char: - case tok::kw_wchar_t: - case tok::kw_char16_t: - case tok::kw_char32_t: - case tok::kw_bool: - case tok::kw_short: - case tok::kw_int: - case tok::kw_long: - case tok::kw___int64: - case tok::kw___int128: - case tok::kw_signed: - case tok::kw_unsigned: - case tok::kw_half: - case tok::kw_float: - case tok::kw_double: - case tok::kw_void: - case tok::annot_decltype: - if (NextToken().is(tok::l_paren)) - return TPResult::Ambiguous(); - - // This is a function-style cast in all cases we disambiguate other than - // one: - // struct S { - // enum E : int { a = 4 }; // enum - // enum E : int { 4 }; // bit-field - // }; - if (getLangOpts().CPlusPlus0x && NextToken().is(tok::l_brace)) - return BracedCastResult; - - if (isStartOfObjCClassMessageMissingOpenBracket()) - return TPResult::False(); - - return TPResult::True(); - - // GNU typeof support. - case tok::kw_typeof: { - if (NextToken().isNot(tok::l_paren)) - return TPResult::True(); - - TentativeParsingAction PA(*this); - - TPResult TPR = TryParseTypeofSpecifier(); - bool isFollowedByParen = Tok.is(tok::l_paren); - bool isFollowedByBrace = Tok.is(tok::l_brace); - - PA.Revert(); - - if (TPR == TPResult::Error()) - return TPResult::Error(); - - if (isFollowedByParen) - return TPResult::Ambiguous(); - - if (getLangOpts().CPlusPlus0x && isFollowedByBrace) - return BracedCastResult; - - return TPResult::True(); - } - - // C++0x type traits support - case tok::kw___underlying_type: - return TPResult::True(); - - // C11 _Atomic - case tok::kw__Atomic: - return TPResult::True(); - - default: - return TPResult::False(); - } -} - -/// [GNU] typeof-specifier: -/// 'typeof' '(' expressions ')' -/// 'typeof' '(' type-name ')' -/// -Parser::TPResult Parser::TryParseTypeofSpecifier() { - assert(Tok.is(tok::kw_typeof) && "Expected 'typeof'!"); - ConsumeToken(); - - assert(Tok.is(tok::l_paren) && "Expected '('"); - // Parse through the parens after 'typeof'. - ConsumeParen(); - if (!SkipUntil(tok::r_paren)) - return TPResult::Error(); - - return TPResult::Ambiguous(); -} - -/// [ObjC] protocol-qualifiers: -//// '<' identifier-list '>' -Parser::TPResult Parser::TryParseProtocolQualifiers() { - assert(Tok.is(tok::less) && "Expected '<' for qualifier list"); - ConsumeToken(); - do { - if (Tok.isNot(tok::identifier)) - return TPResult::Error(); - ConsumeToken(); - - if (Tok.is(tok::comma)) { - ConsumeToken(); - continue; - } - - if (Tok.is(tok::greater)) { - ConsumeToken(); - return TPResult::Ambiguous(); - } - } while (false); - - return TPResult::Error(); -} - -Parser::TPResult -Parser::TryParseDeclarationSpecifier(bool *HasMissingTypename) { - TPResult TPR = isCXXDeclarationSpecifier(TPResult::False(), - HasMissingTypename); - if (TPR != TPResult::Ambiguous()) - return TPR; - - if (Tok.is(tok::kw_typeof)) - TryParseTypeofSpecifier(); - else { - if (Tok.is(tok::annot_cxxscope)) - ConsumeToken(); - ConsumeToken(); - - if (getLangOpts().ObjC1 && Tok.is(tok::less)) - TryParseProtocolQualifiers(); - } - - return TPResult::Ambiguous(); -} - -/// isCXXFunctionDeclarator - Disambiguates between a function declarator or -/// a constructor-style initializer, when parsing declaration statements. -/// Returns true for function declarator and false for constructor-style -/// initializer. -/// If during the disambiguation process a parsing error is encountered, -/// the function returns true to let the declaration parsing code handle it. -/// -/// '(' parameter-declaration-clause ')' cv-qualifier-seq[opt] -/// exception-specification[opt] -/// -bool Parser::isCXXFunctionDeclarator(bool *IsAmbiguous) { - - // C++ 8.2p1: - // The ambiguity arising from the similarity between a function-style cast and - // a declaration mentioned in 6.8 can also occur in the context of a - // declaration. In that context, the choice is between a function declaration - // with a redundant set of parentheses around a parameter name and an object - // declaration with a function-style cast as the initializer. Just as for the - // ambiguities mentioned in 6.8, the resolution is to consider any construct - // that could possibly be a declaration a declaration. - - TentativeParsingAction PA(*this); - - ConsumeParen(); - bool InvalidAsDeclaration = false; - TPResult TPR = TryParseParameterDeclarationClause(&InvalidAsDeclaration); - if (TPR == TPResult::Ambiguous()) { - if (Tok.isNot(tok::r_paren)) - TPR = TPResult::False(); - else { - const Token &Next = NextToken(); - if (Next.is(tok::amp) || Next.is(tok::ampamp) || - Next.is(tok::kw_const) || Next.is(tok::kw_volatile) || - Next.is(tok::kw_throw) || Next.is(tok::kw_noexcept) || - Next.is(tok::l_square) || isCXX0XVirtSpecifier(Next) || - Next.is(tok::l_brace) || Next.is(tok::kw_try) || - Next.is(tok::equal) || Next.is(tok::arrow)) - // The next token cannot appear after a constructor-style initializer, - // and can appear next in a function definition. This must be a function - // declarator. - TPR = TPResult::True(); - else if (InvalidAsDeclaration) - // Use the absence of 'typename' as a tie-breaker. - TPR = TPResult::False(); - } - } - - PA.Revert(); - - if (IsAmbiguous && TPR == TPResult::Ambiguous()) - *IsAmbiguous = true; - - // In case of an error, let the declaration parsing code handle it. - return TPR != TPResult::False(); -} - -/// parameter-declaration-clause: -/// parameter-declaration-list[opt] '...'[opt] -/// parameter-declaration-list ',' '...' -/// -/// parameter-declaration-list: -/// parameter-declaration -/// parameter-declaration-list ',' parameter-declaration -/// -/// parameter-declaration: -/// attribute-specifier-seq[opt] decl-specifier-seq declarator attributes[opt] -/// attribute-specifier-seq[opt] decl-specifier-seq declarator attributes[opt] -/// '=' assignment-expression -/// attribute-specifier-seq[opt] decl-specifier-seq abstract-declarator[opt] -/// attributes[opt] -/// attribute-specifier-seq[opt] decl-specifier-seq abstract-declarator[opt] -/// attributes[opt] '=' assignment-expression -/// -Parser::TPResult -Parser::TryParseParameterDeclarationClause(bool *InvalidAsDeclaration) { - - if (Tok.is(tok::r_paren)) - return TPResult::Ambiguous(); - - // parameter-declaration-list[opt] '...'[opt] - // parameter-declaration-list ',' '...' - // - // parameter-declaration-list: - // parameter-declaration - // parameter-declaration-list ',' parameter-declaration - // - while (1) { - // '...'[opt] - if (Tok.is(tok::ellipsis)) { - ConsumeToken(); - if (Tok.is(tok::r_paren)) - return TPResult::True(); // '...)' is a sign of a function declarator. - else - return TPResult::False(); - } - - // An attribute-specifier-seq here is a sign of a function declarator. - if (isCXX11AttributeSpecifier(/*Disambiguate*/false, - /*OuterMightBeMessageSend*/true)) - return TPResult::True(); - - ParsedAttributes attrs(AttrFactory); - MaybeParseMicrosoftAttributes(attrs); - - // decl-specifier-seq - // A parameter-declaration's initializer must be preceded by an '=', so - // decl-specifier-seq '{' is not a parameter in C++11. - TPResult TPR = TryParseDeclarationSpecifier(InvalidAsDeclaration); - if (TPR != TPResult::Ambiguous()) - return TPR; - - // declarator - // abstract-declarator[opt] - TPR = TryParseDeclarator(true/*mayBeAbstract*/); - if (TPR != TPResult::Ambiguous()) - return TPR; - - // [GNU] attributes[opt] - if (Tok.is(tok::kw___attribute)) - return TPResult::True(); - - if (Tok.is(tok::equal)) { - // '=' assignment-expression - // Parse through assignment-expression. - if (!SkipUntil(tok::comma, tok::r_paren, true/*StopAtSemi*/, - true/*DontConsume*/)) - return TPResult::Error(); - } - - if (Tok.is(tok::ellipsis)) { - ConsumeToken(); - if (Tok.is(tok::r_paren)) - return TPResult::True(); // '...)' is a sign of a function declarator. - else - return TPResult::False(); - } - - if (Tok.isNot(tok::comma)) - break; - ConsumeToken(); // the comma. - } - - return TPResult::Ambiguous(); -} - -/// TryParseFunctionDeclarator - We parsed a '(' and we want to try to continue -/// parsing as a function declarator. -/// If TryParseFunctionDeclarator fully parsed the function declarator, it will -/// return TPResult::Ambiguous(), otherwise it will return either False() or -/// Error(). -/// -/// '(' parameter-declaration-clause ')' cv-qualifier-seq[opt] -/// exception-specification[opt] -/// -/// exception-specification: -/// 'throw' '(' type-id-list[opt] ')' -/// -Parser::TPResult Parser::TryParseFunctionDeclarator() { - - // The '(' is already parsed. - - TPResult TPR = TryParseParameterDeclarationClause(); - if (TPR == TPResult::Ambiguous() && Tok.isNot(tok::r_paren)) - TPR = TPResult::False(); - - if (TPR == TPResult::False() || TPR == TPResult::Error()) - return TPR; - - // Parse through the parens. - if (!SkipUntil(tok::r_paren)) - return TPResult::Error(); - - // cv-qualifier-seq - while (Tok.is(tok::kw_const) || - Tok.is(tok::kw_volatile) || - Tok.is(tok::kw_restrict) ) - ConsumeToken(); - - // ref-qualifier[opt] - if (Tok.is(tok::amp) || Tok.is(tok::ampamp)) - ConsumeToken(); - - // exception-specification - if (Tok.is(tok::kw_throw)) { - ConsumeToken(); - if (Tok.isNot(tok::l_paren)) - return TPResult::Error(); - - // Parse through the parens after 'throw'. - ConsumeParen(); - if (!SkipUntil(tok::r_paren)) - return TPResult::Error(); - } - if (Tok.is(tok::kw_noexcept)) { - ConsumeToken(); - // Possibly an expression as well. - if (Tok.is(tok::l_paren)) { - // Find the matching rparen. - ConsumeParen(); - if (!SkipUntil(tok::r_paren)) - return TPResult::Error(); - } - } - - return TPResult::Ambiguous(); -} - -/// '[' constant-expression[opt] ']' -/// -Parser::TPResult Parser::TryParseBracketDeclarator() { - ConsumeBracket(); - if (!SkipUntil(tok::r_square)) - return TPResult::Error(); - - return TPResult::Ambiguous(); -} +//===--- ParseTentative.cpp - Ambiguity Resolution Parsing ----------------===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+//
+// This file implements the tentative parsing portions of the Parser
+// interfaces, for ambiguity resolution.
+//
+//===----------------------------------------------------------------------===//
+
+#include "clang/Parse/Parser.h"
+#include "clang/Parse/ParseDiagnostic.h"
+#include "clang/Sema/ParsedTemplate.h"
+using namespace clang;
+
+/// isCXXDeclarationStatement - C++-specialized function that disambiguates
+/// between a declaration or an expression statement, when parsing function
+/// bodies. Returns true for declaration, false for expression.
+///
+/// declaration-statement:
+/// block-declaration
+///
+/// block-declaration:
+/// simple-declaration
+/// asm-definition
+/// namespace-alias-definition
+/// using-declaration
+/// using-directive
+/// [C++0x] static_assert-declaration
+///
+/// asm-definition:
+/// 'asm' '(' string-literal ')' ';'
+///
+/// namespace-alias-definition:
+/// 'namespace' identifier = qualified-namespace-specifier ';'
+///
+/// using-declaration:
+/// 'using' typename[opt] '::'[opt] nested-name-specifier
+/// unqualified-id ';'
+/// 'using' '::' unqualified-id ;
+///
+/// using-directive:
+/// 'using' 'namespace' '::'[opt] nested-name-specifier[opt]
+/// namespace-name ';'
+///
+bool Parser::isCXXDeclarationStatement() {
+ switch (Tok.getKind()) {
+ // asm-definition
+ case tok::kw_asm:
+ // namespace-alias-definition
+ case tok::kw_namespace:
+ // using-declaration
+ // using-directive
+ case tok::kw_using:
+ // static_assert-declaration
+ case tok::kw_static_assert:
+ case tok::kw__Static_assert:
+ return true;
+ // simple-declaration
+ default:
+ return isCXXSimpleDeclaration(/*AllowForRangeDecl=*/false);
+ }
+}
+
+/// isCXXSimpleDeclaration - C++-specialized function that disambiguates
+/// between a simple-declaration or an expression-statement.
+/// If during the disambiguation process a parsing error is encountered,
+/// the function returns true to let the declaration parsing code handle it.
+/// Returns false if the statement is disambiguated as expression.
+///
+/// simple-declaration:
+/// decl-specifier-seq init-declarator-list[opt] ';'
+///
+/// (if AllowForRangeDecl specified)
+/// for ( for-range-declaration : for-range-initializer ) statement
+/// for-range-declaration:
+/// attribute-specifier-seqopt type-specifier-seq declarator
+bool Parser::isCXXSimpleDeclaration(bool AllowForRangeDecl) {
+ // C++ 6.8p1:
+ // There is an ambiguity in the grammar involving expression-statements and
+ // declarations: An expression-statement with a function-style explicit type
+ // conversion (5.2.3) as its leftmost subexpression can be indistinguishable
+ // from a declaration where the first declarator starts with a '('. In those
+ // cases the statement is a declaration. [Note: To disambiguate, the whole
+ // statement might have to be examined to determine if it is an
+ // expression-statement or a declaration].
+
+ // C++ 6.8p3:
+ // The disambiguation is purely syntactic; that is, the meaning of the names
+ // occurring in such a statement, beyond whether they are type-names or not,
+ // is not generally used in or changed by the disambiguation. Class
+ // templates are instantiated as necessary to determine if a qualified name
+ // is a type-name. Disambiguation precedes parsing, and a statement
+ // disambiguated as a declaration may be an ill-formed declaration.
+
+ // We don't have to parse all of the decl-specifier-seq part. There's only
+ // an ambiguity if the first decl-specifier is
+ // simple-type-specifier/typename-specifier followed by a '(', which may
+ // indicate a function-style cast expression.
+ // isCXXDeclarationSpecifier will return TPResult::Ambiguous() only in such
+ // a case.
+
+ bool InvalidAsDeclaration = false;
+ TPResult TPR = isCXXDeclarationSpecifier(TPResult::False(),
+ &InvalidAsDeclaration);
+ if (TPR != TPResult::Ambiguous())
+ return TPR != TPResult::False(); // Returns true for TPResult::True() or
+ // TPResult::Error().
+
+ // FIXME: TryParseSimpleDeclaration doesn't look past the first initializer,
+ // and so gets some cases wrong. We can't carry on if we've already seen
+ // something which makes this statement invalid as a declaration in this case,
+ // since it can cause us to misparse valid code. Revisit this once
+ // TryParseInitDeclaratorList is fixed.
+ if (InvalidAsDeclaration)
+ return false;
+
+ // FIXME: Add statistics about the number of ambiguous statements encountered
+ // and how they were resolved (number of declarations+number of expressions).
+
+ // Ok, we have a simple-type-specifier/typename-specifier followed by a '(',
+ // or an identifier which doesn't resolve as anything. We need tentative
+ // parsing...
+
+ TentativeParsingAction PA(*this);
+ TPR = TryParseSimpleDeclaration(AllowForRangeDecl);
+ PA.Revert();
+
+ // In case of an error, let the declaration parsing code handle it.
+ if (TPR == TPResult::Error())
+ return true;
+
+ // Declarations take precedence over expressions.
+ if (TPR == TPResult::Ambiguous())
+ TPR = TPResult::True();
+
+ assert(TPR == TPResult::True() || TPR == TPResult::False());
+ return TPR == TPResult::True();
+}
+
+/// simple-declaration:
+/// decl-specifier-seq init-declarator-list[opt] ';'
+///
+/// (if AllowForRangeDecl specified)
+/// for ( for-range-declaration : for-range-initializer ) statement
+/// for-range-declaration:
+/// attribute-specifier-seqopt type-specifier-seq declarator
+///
+Parser::TPResult Parser::TryParseSimpleDeclaration(bool AllowForRangeDecl) {
+ if (Tok.is(tok::kw_typeof))
+ TryParseTypeofSpecifier();
+ else {
+ if (Tok.is(tok::annot_cxxscope))
+ ConsumeToken();
+ ConsumeToken();
+
+ if (getLangOpts().ObjC1 && Tok.is(tok::less))
+ TryParseProtocolQualifiers();
+ }
+
+ // Two decl-specifiers in a row conclusively disambiguate this as being a
+ // simple-declaration. Don't bother calling isCXXDeclarationSpecifier in the
+ // overwhelmingly common case that the next token is a '('.
+ if (Tok.isNot(tok::l_paren)) {
+ TPResult TPR = isCXXDeclarationSpecifier();
+ if (TPR == TPResult::Ambiguous())
+ return TPResult::True();
+ if (TPR == TPResult::True() || TPR == TPResult::Error())
+ return TPR;
+ assert(TPR == TPResult::False());
+ }
+
+ TPResult TPR = TryParseInitDeclaratorList();
+ if (TPR != TPResult::Ambiguous())
+ return TPR;
+
+ if (Tok.isNot(tok::semi) && (!AllowForRangeDecl || Tok.isNot(tok::colon)))
+ return TPResult::False();
+
+ return TPResult::Ambiguous();
+}
+
+/// init-declarator-list:
+/// init-declarator
+/// init-declarator-list ',' init-declarator
+///
+/// init-declarator:
+/// declarator initializer[opt]
+/// [GNU] declarator simple-asm-expr[opt] attributes[opt] initializer[opt]
+///
+/// initializer:
+/// '=' initializer-clause
+/// '(' expression-list ')'
+///
+/// initializer-clause:
+/// assignment-expression
+/// '{' initializer-list ','[opt] '}'
+/// '{' '}'
+///
+Parser::TPResult Parser::TryParseInitDeclaratorList() {
+ while (1) {
+ // declarator
+ TPResult TPR = TryParseDeclarator(false/*mayBeAbstract*/);
+ if (TPR != TPResult::Ambiguous())
+ return TPR;
+
+ // [GNU] simple-asm-expr[opt] attributes[opt]
+ if (Tok.is(tok::kw_asm) || Tok.is(tok::kw___attribute))
+ return TPResult::True();
+
+ // initializer[opt]
+ if (Tok.is(tok::l_paren)) {
+ // Parse through the parens.
+ ConsumeParen();
+ if (!SkipUntil(tok::r_paren))
+ return TPResult::Error();
+ } else if (Tok.is(tok::equal) || isTokIdentifier_in()) {
+ // MSVC and g++ won't examine the rest of declarators if '=' is
+ // encountered; they just conclude that we have a declaration.
+ // EDG parses the initializer completely, which is the proper behavior
+ // for this case.
+ //
+ // At present, Clang follows MSVC and g++, since the parser does not have
+ // the ability to parse an expression fully without recording the
+ // results of that parse.
+ // Also allow 'in' after on objective-c declaration as in:
+ // for (int (^b)(void) in array). Ideally this should be done in the
+ // context of parsing for-init-statement of a foreach statement only. But,
+ // in any other context 'in' is invalid after a declaration and parser
+ // issues the error regardless of outcome of this decision.
+ // FIXME. Change if above assumption does not hold.
+ return TPResult::True();
+ }
+
+ if (Tok.isNot(tok::comma))
+ break;
+ ConsumeToken(); // the comma.
+ }
+
+ return TPResult::Ambiguous();
+}
+
+/// isCXXConditionDeclaration - Disambiguates between a declaration or an
+/// expression for a condition of a if/switch/while/for statement.
+/// If during the disambiguation process a parsing error is encountered,
+/// the function returns true to let the declaration parsing code handle it.
+///
+/// condition:
+/// expression
+/// type-specifier-seq declarator '=' assignment-expression
+/// [C++11] type-specifier-seq declarator '=' initializer-clause
+/// [C++11] type-specifier-seq declarator braced-init-list
+/// [GNU] type-specifier-seq declarator simple-asm-expr[opt] attributes[opt]
+/// '=' assignment-expression
+///
+bool Parser::isCXXConditionDeclaration() {
+ TPResult TPR = isCXXDeclarationSpecifier();
+ if (TPR != TPResult::Ambiguous())
+ return TPR != TPResult::False(); // Returns true for TPResult::True() or
+ // TPResult::Error().
+
+ // FIXME: Add statistics about the number of ambiguous statements encountered
+ // and how they were resolved (number of declarations+number of expressions).
+
+ // Ok, we have a simple-type-specifier/typename-specifier followed by a '('.
+ // We need tentative parsing...
+
+ TentativeParsingAction PA(*this);
+
+ // type-specifier-seq
+ if (Tok.is(tok::kw_typeof))
+ TryParseTypeofSpecifier();
+ else {
+ ConsumeToken();
+
+ if (getLangOpts().ObjC1 && Tok.is(tok::less))
+ TryParseProtocolQualifiers();
+ }
+ assert(Tok.is(tok::l_paren) && "Expected '('");
+
+ // declarator
+ TPR = TryParseDeclarator(false/*mayBeAbstract*/);
+
+ // In case of an error, let the declaration parsing code handle it.
+ if (TPR == TPResult::Error())
+ TPR = TPResult::True();
+
+ if (TPR == TPResult::Ambiguous()) {
+ // '='
+ // [GNU] simple-asm-expr[opt] attributes[opt]
+ if (Tok.is(tok::equal) ||
+ Tok.is(tok::kw_asm) || Tok.is(tok::kw___attribute))
+ TPR = TPResult::True();
+ else if (getLangOpts().CPlusPlus0x && Tok.is(tok::l_brace))
+ TPR = TPResult::True();
+ else
+ TPR = TPResult::False();
+ }
+
+ PA.Revert();
+
+ assert(TPR == TPResult::True() || TPR == TPResult::False());
+ return TPR == TPResult::True();
+}
+
+ /// \brief Determine whether the next set of tokens contains a type-id.
+ ///
+ /// The context parameter states what context we're parsing right
+ /// now, which affects how this routine copes with the token
+ /// following the type-id. If the context is TypeIdInParens, we have
+ /// already parsed the '(' and we will cease lookahead when we hit
+ /// the corresponding ')'. If the context is
+ /// TypeIdAsTemplateArgument, we've already parsed the '<' or ','
+ /// before this template argument, and will cease lookahead when we
+ /// hit a '>', '>>' (in C++0x), or ','. Returns true for a type-id
+ /// and false for an expression. If during the disambiguation
+ /// process a parsing error is encountered, the function returns
+ /// true to let the declaration parsing code handle it.
+ ///
+ /// type-id:
+ /// type-specifier-seq abstract-declarator[opt]
+ ///
+bool Parser::isCXXTypeId(TentativeCXXTypeIdContext Context, bool &isAmbiguous) {
+
+ isAmbiguous = false;
+
+ // C++ 8.2p2:
+ // The ambiguity arising from the similarity between a function-style cast and
+ // a type-id can occur in different contexts. The ambiguity appears as a
+ // choice between a function-style cast expression and a declaration of a
+ // type. The resolution is that any construct that could possibly be a type-id
+ // in its syntactic context shall be considered a type-id.
+
+ TPResult TPR = isCXXDeclarationSpecifier();
+ if (TPR != TPResult::Ambiguous())
+ return TPR != TPResult::False(); // Returns true for TPResult::True() or
+ // TPResult::Error().
+
+ // FIXME: Add statistics about the number of ambiguous statements encountered
+ // and how they were resolved (number of declarations+number of expressions).
+
+ // Ok, we have a simple-type-specifier/typename-specifier followed by a '('.
+ // We need tentative parsing...
+
+ TentativeParsingAction PA(*this);
+
+ // type-specifier-seq
+ if (Tok.is(tok::kw_typeof))
+ TryParseTypeofSpecifier();
+ else {
+ ConsumeToken();
+
+ if (getLangOpts().ObjC1 && Tok.is(tok::less))
+ TryParseProtocolQualifiers();
+ }
+
+ assert(Tok.is(tok::l_paren) && "Expected '('");
+
+ // declarator
+ TPR = TryParseDeclarator(true/*mayBeAbstract*/, false/*mayHaveIdentifier*/);
+
+ // In case of an error, let the declaration parsing code handle it.
+ if (TPR == TPResult::Error())
+ TPR = TPResult::True();
+
+ if (TPR == TPResult::Ambiguous()) {
+ // We are supposed to be inside parens, so if after the abstract declarator
+ // we encounter a ')' this is a type-id, otherwise it's an expression.
+ if (Context == TypeIdInParens && Tok.is(tok::r_paren)) {
+ TPR = TPResult::True();
+ isAmbiguous = true;
+
+ // We are supposed to be inside a template argument, so if after
+ // the abstract declarator we encounter a '>', '>>' (in C++0x), or
+ // ',', this is a type-id. Otherwise, it's an expression.
+ } else if (Context == TypeIdAsTemplateArgument &&
+ (Tok.is(tok::greater) || Tok.is(tok::comma) ||
+ (getLangOpts().CPlusPlus0x && Tok.is(tok::greatergreater)))) {
+ TPR = TPResult::True();
+ isAmbiguous = true;
+
+ } else
+ TPR = TPResult::False();
+ }
+
+ PA.Revert();
+
+ assert(TPR == TPResult::True() || TPR == TPResult::False());
+ return TPR == TPResult::True();
+}
+
+/// \brief Returns true if this is a C++11 attribute-specifier. Per
+/// C++11 [dcl.attr.grammar]p6, two consecutive left square bracket tokens
+/// always introduce an attribute. In Objective-C++11, this rule does not
+/// apply if either '[' begins a message-send.
+///
+/// If Disambiguate is true, we try harder to determine whether a '[[' starts
+/// an attribute-specifier, and return CAK_InvalidAttributeSpecifier if not.
+///
+/// If OuterMightBeMessageSend is true, we assume the outer '[' is either an
+/// Obj-C message send or the start of an attribute. Otherwise, we assume it
+/// is not an Obj-C message send.
+///
+/// C++11 [dcl.attr.grammar]:
+///
+/// attribute-specifier:
+/// '[' '[' attribute-list ']' ']'
+/// alignment-specifier
+///
+/// attribute-list:
+/// attribute[opt]
+/// attribute-list ',' attribute[opt]
+/// attribute '...'
+/// attribute-list ',' attribute '...'
+///
+/// attribute:
+/// attribute-token attribute-argument-clause[opt]
+///
+/// attribute-token:
+/// identifier
+/// identifier '::' identifier
+///
+/// attribute-argument-clause:
+/// '(' balanced-token-seq ')'
+Parser::CXX11AttributeKind
+Parser::isCXX11AttributeSpecifier(bool Disambiguate,
+ bool OuterMightBeMessageSend) {
+ if (Tok.is(tok::kw_alignas))
+ return CAK_AttributeSpecifier;
+
+ if (Tok.isNot(tok::l_square) || NextToken().isNot(tok::l_square))
+ return CAK_NotAttributeSpecifier;
+
+ // No tentative parsing if we don't need to look for ']]' or a lambda.
+ if (!Disambiguate && !getLangOpts().ObjC1)
+ return CAK_AttributeSpecifier;
+
+ TentativeParsingAction PA(*this);
+
+ // Opening brackets were checked for above.
+ ConsumeBracket();
+
+ // Outside Obj-C++11, treat anything with a matching ']]' as an attribute.
+ if (!getLangOpts().ObjC1) {
+ ConsumeBracket();
+
+ bool IsAttribute = SkipUntil(tok::r_square, false);
+ IsAttribute &= Tok.is(tok::r_square);
+
+ PA.Revert();
+
+ return IsAttribute ? CAK_AttributeSpecifier : CAK_InvalidAttributeSpecifier;
+ }
+
+ // In Obj-C++11, we need to distinguish four situations:
+ // 1a) int x[[attr]]; C++11 attribute.
+ // 1b) [[attr]]; C++11 statement attribute.
+ // 2) int x[[obj](){ return 1; }()]; Lambda in array size/index.
+ // 3a) int x[[obj get]]; Message send in array size/index.
+ // 3b) [[Class alloc] init]; Message send in message send.
+ // 4) [[obj]{ return self; }() doStuff]; Lambda in message send.
+ // (1) is an attribute, (2) is ill-formed, and (3) and (4) are accepted.
+
+ // If we have a lambda-introducer, then this is definitely not a message send.
+ // FIXME: If this disambiguation is too slow, fold the tentative lambda parse
+ // into the tentative attribute parse below.
+ LambdaIntroducer Intro;
+ if (!TryParseLambdaIntroducer(Intro)) {
+ // A lambda cannot end with ']]', and an attribute must.
+ bool IsAttribute = Tok.is(tok::r_square);
+
+ PA.Revert();
+
+ if (IsAttribute)
+ // Case 1: C++11 attribute.
+ return CAK_AttributeSpecifier;
+
+ if (OuterMightBeMessageSend)
+ // Case 4: Lambda in message send.
+ return CAK_NotAttributeSpecifier;
+
+ // Case 2: Lambda in array size / index.
+ return CAK_InvalidAttributeSpecifier;
+ }
+
+ ConsumeBracket();
+
+ // If we don't have a lambda-introducer, then we have an attribute or a
+ // message-send.
+ bool IsAttribute = true;
+ while (Tok.isNot(tok::r_square)) {
+ if (Tok.is(tok::comma)) {
+ // Case 1: Stray commas can only occur in attributes.
+ PA.Revert();
+ return CAK_AttributeSpecifier;
+ }
+
+ // Parse the attribute-token, if present.
+ // C++11 [dcl.attr.grammar]:
+ // If a keyword or an alternative token that satisfies the syntactic
+ // requirements of an identifier is contained in an attribute-token,
+ // it is considered an identifier.
+ SourceLocation Loc;
+ if (!TryParseCXX11AttributeIdentifier(Loc)) {
+ IsAttribute = false;
+ break;
+ }
+ if (Tok.is(tok::coloncolon)) {
+ ConsumeToken();
+ if (!TryParseCXX11AttributeIdentifier(Loc)) {
+ IsAttribute = false;
+ break;
+ }
+ }
+
+ // Parse the attribute-argument-clause, if present.
+ if (Tok.is(tok::l_paren)) {
+ ConsumeParen();
+ if (!SkipUntil(tok::r_paren, false)) {
+ IsAttribute = false;
+ break;
+ }
+ }
+
+ if (Tok.is(tok::ellipsis))
+ ConsumeToken();
+
+ if (Tok.isNot(tok::comma))
+ break;
+
+ ConsumeToken();
+ }
+
+ // An attribute must end ']]'.
+ if (IsAttribute) {
+ if (Tok.is(tok::r_square)) {
+ ConsumeBracket();
+ IsAttribute = Tok.is(tok::r_square);
+ } else {
+ IsAttribute = false;
+ }
+ }
+
+ PA.Revert();
+
+ if (IsAttribute)
+ // Case 1: C++11 statement attribute.
+ return CAK_AttributeSpecifier;
+
+ // Case 3: Message send.
+ return CAK_NotAttributeSpecifier;
+}
+
+/// declarator:
+/// direct-declarator
+/// ptr-operator declarator
+///
+/// direct-declarator:
+/// declarator-id
+/// direct-declarator '(' parameter-declaration-clause ')'
+/// cv-qualifier-seq[opt] exception-specification[opt]
+/// direct-declarator '[' constant-expression[opt] ']'
+/// '(' declarator ')'
+/// [GNU] '(' attributes declarator ')'
+///
+/// abstract-declarator:
+/// ptr-operator abstract-declarator[opt]
+/// direct-abstract-declarator
+/// ...
+///
+/// direct-abstract-declarator:
+/// direct-abstract-declarator[opt]
+/// '(' parameter-declaration-clause ')' cv-qualifier-seq[opt]
+/// exception-specification[opt]
+/// direct-abstract-declarator[opt] '[' constant-expression[opt] ']'
+/// '(' abstract-declarator ')'
+///
+/// ptr-operator:
+/// '*' cv-qualifier-seq[opt]
+/// '&'
+/// [C++0x] '&&' [TODO]
+/// '::'[opt] nested-name-specifier '*' cv-qualifier-seq[opt]
+///
+/// cv-qualifier-seq:
+/// cv-qualifier cv-qualifier-seq[opt]
+///
+/// cv-qualifier:
+/// 'const'
+/// 'volatile'
+///
+/// declarator-id:
+/// '...'[opt] id-expression
+///
+/// id-expression:
+/// unqualified-id
+/// qualified-id [TODO]
+///
+/// unqualified-id:
+/// identifier
+/// operator-function-id [TODO]
+/// conversion-function-id [TODO]
+/// '~' class-name [TODO]
+/// template-id [TODO]
+///
+Parser::TPResult Parser::TryParseDeclarator(bool mayBeAbstract,
+ bool mayHaveIdentifier) {
+ // declarator:
+ // direct-declarator
+ // ptr-operator declarator
+
+ while (1) {
+ if (Tok.is(tok::coloncolon) || Tok.is(tok::identifier))
+ if (TryAnnotateCXXScopeToken(true))
+ return TPResult::Error();
+
+ if (Tok.is(tok::star) || Tok.is(tok::amp) || Tok.is(tok::caret) ||
+ Tok.is(tok::ampamp) ||
+ (Tok.is(tok::annot_cxxscope) && NextToken().is(tok::star))) {
+ // ptr-operator
+ ConsumeToken();
+ while (Tok.is(tok::kw_const) ||
+ Tok.is(tok::kw_volatile) ||
+ Tok.is(tok::kw_restrict))
+ ConsumeToken();
+ } else {
+ break;
+ }
+ }
+
+ // direct-declarator:
+ // direct-abstract-declarator:
+ if (Tok.is(tok::ellipsis))
+ ConsumeToken();
+
+ if ((Tok.is(tok::identifier) ||
+ (Tok.is(tok::annot_cxxscope) && NextToken().is(tok::identifier))) &&
+ mayHaveIdentifier) {
+ // declarator-id
+ if (Tok.is(tok::annot_cxxscope))
+ ConsumeToken();
+ else
+ TentativelyDeclaredIdentifiers.push_back(Tok.getIdentifierInfo());
+ ConsumeToken();
+ } else if (Tok.is(tok::l_paren)) {
+ ConsumeParen();
+ if (mayBeAbstract &&
+ (Tok.is(tok::r_paren) || // 'int()' is a function.
+ // 'int(...)' is a function.
+ (Tok.is(tok::ellipsis) && NextToken().is(tok::r_paren)) ||
+ isDeclarationSpecifier())) { // 'int(int)' is a function.
+ // '(' parameter-declaration-clause ')' cv-qualifier-seq[opt]
+ // exception-specification[opt]
+ TPResult TPR = TryParseFunctionDeclarator();
+ if (TPR != TPResult::Ambiguous())
+ return TPR;
+ } else {
+ // '(' declarator ')'
+ // '(' attributes declarator ')'
+ // '(' abstract-declarator ')'
+ if (Tok.is(tok::kw___attribute) ||
+ Tok.is(tok::kw___declspec) ||
+ Tok.is(tok::kw___cdecl) ||
+ Tok.is(tok::kw___stdcall) ||
+ Tok.is(tok::kw___fastcall) ||
+ Tok.is(tok::kw___thiscall) ||
+ Tok.is(tok::kw___unaligned))
+ return TPResult::True(); // attributes indicate declaration
+ TPResult TPR = TryParseDeclarator(mayBeAbstract, mayHaveIdentifier);
+ if (TPR != TPResult::Ambiguous())
+ return TPR;
+ if (Tok.isNot(tok::r_paren))
+ return TPResult::False();
+ ConsumeParen();
+ }
+ } else if (!mayBeAbstract) {
+ return TPResult::False();
+ }
+
+ while (1) {
+ TPResult TPR(TPResult::Ambiguous());
+
+ // abstract-declarator: ...
+ if (Tok.is(tok::ellipsis))
+ ConsumeToken();
+
+ if (Tok.is(tok::l_paren)) {
+ // Check whether we have a function declarator or a possible ctor-style
+ // initializer that follows the declarator. Note that ctor-style
+ // initializers are not possible in contexts where abstract declarators
+ // are allowed.
+ if (!mayBeAbstract && !isCXXFunctionDeclarator())
+ break;
+
+ // direct-declarator '(' parameter-declaration-clause ')'
+ // cv-qualifier-seq[opt] exception-specification[opt]
+ ConsumeParen();
+ TPR = TryParseFunctionDeclarator();
+ } else if (Tok.is(tok::l_square)) {
+ // direct-declarator '[' constant-expression[opt] ']'
+ // direct-abstract-declarator[opt] '[' constant-expression[opt] ']'
+ TPR = TryParseBracketDeclarator();
+ } else {
+ break;
+ }
+
+ if (TPR != TPResult::Ambiguous())
+ return TPR;
+ }
+
+ return TPResult::Ambiguous();
+}
+
+Parser::TPResult
+Parser::isExpressionOrTypeSpecifierSimple(tok::TokenKind Kind) {
+ switch (Kind) {
+ // Obviously starts an expression.
+ case tok::numeric_constant:
+ case tok::char_constant:
+ case tok::wide_char_constant:
+ case tok::utf16_char_constant:
+ case tok::utf32_char_constant:
+ case tok::string_literal:
+ case tok::wide_string_literal:
+ case tok::utf8_string_literal:
+ case tok::utf16_string_literal:
+ case tok::utf32_string_literal:
+ case tok::l_square:
+ case tok::l_paren:
+ case tok::amp:
+ case tok::ampamp:
+ case tok::star:
+ case tok::plus:
+ case tok::plusplus:
+ case tok::minus:
+ case tok::minusminus:
+ case tok::tilde:
+ case tok::exclaim:
+ case tok::kw_sizeof:
+ case tok::kw___func__:
+ case tok::kw_const_cast:
+ case tok::kw_delete:
+ case tok::kw_dynamic_cast:
+ case tok::kw_false:
+ case tok::kw_new:
+ case tok::kw_operator:
+ case tok::kw_reinterpret_cast:
+ case tok::kw_static_cast:
+ case tok::kw_this:
+ case tok::kw_throw:
+ case tok::kw_true:
+ case tok::kw_typeid:
+ case tok::kw_alignof:
+ case tok::kw_noexcept:
+ case tok::kw_nullptr:
+ case tok::kw__Alignof:
+ case tok::kw___null:
+ case tok::kw___alignof:
+ case tok::kw___builtin_choose_expr:
+ case tok::kw___builtin_offsetof:
+ case tok::kw___builtin_types_compatible_p:
+ case tok::kw___builtin_va_arg:
+ case tok::kw___imag:
+ case tok::kw___real:
+ case tok::kw___FUNCTION__:
+ case tok::kw_L__FUNCTION__:
+ case tok::kw___PRETTY_FUNCTION__:
+ case tok::kw___has_nothrow_assign:
+ case tok::kw___has_nothrow_copy:
+ case tok::kw___has_nothrow_constructor:
+ case tok::kw___has_trivial_assign:
+ case tok::kw___has_trivial_copy:
+ case tok::kw___has_trivial_constructor:
+ case tok::kw___has_trivial_destructor:
+ case tok::kw___has_virtual_destructor:
+ case tok::kw___is_abstract:
+ case tok::kw___is_base_of:
+ case tok::kw___is_class:
+ case tok::kw___is_convertible_to:
+ case tok::kw___is_empty:
+ case tok::kw___is_enum:
+ case tok::kw___is_interface_class:
+ case tok::kw___is_final:
+ case tok::kw___is_literal:
+ case tok::kw___is_literal_type:
+ case tok::kw___is_pod:
+ case tok::kw___is_polymorphic:
+ case tok::kw___is_trivial:
+ case tok::kw___is_trivially_assignable:
+ case tok::kw___is_trivially_constructible:
+ case tok::kw___is_trivially_copyable:
+ case tok::kw___is_union:
+ case tok::kw___uuidof:
+ return TPResult::True();
+
+ // Obviously starts a type-specifier-seq:
+ case tok::kw_char:
+ case tok::kw_const:
+ case tok::kw_double:
+ case tok::kw_enum:
+ case tok::kw_half:
+ case tok::kw_float:
+ case tok::kw_int:
+ case tok::kw_long:
+ case tok::kw___int64:
+ case tok::kw___int128:
+ case tok::kw_restrict:
+ case tok::kw_short:
+ case tok::kw_signed:
+ case tok::kw_struct:
+ case tok::kw_union:
+ case tok::kw_unsigned:
+ case tok::kw_void:
+ case tok::kw_volatile:
+ case tok::kw__Bool:
+ case tok::kw__Complex:
+ case tok::kw_class:
+ case tok::kw_typename:
+ case tok::kw_wchar_t:
+ case tok::kw_char16_t:
+ case tok::kw_char32_t:
+ case tok::kw___underlying_type:
+ case tok::kw_thread_local:
+ case tok::kw__Decimal32:
+ case tok::kw__Decimal64:
+ case tok::kw__Decimal128:
+ case tok::kw___thread:
+ case tok::kw_typeof:
+ case tok::kw___cdecl:
+ case tok::kw___stdcall:
+ case tok::kw___fastcall:
+ case tok::kw___thiscall:
+ case tok::kw___unaligned:
+ case tok::kw___vector:
+ case tok::kw___pixel:
+ case tok::kw__Atomic:
+ case tok::kw_image1d_t:
+ case tok::kw_image1d_array_t:
+ case tok::kw_image1d_buffer_t:
+ case tok::kw_image2d_t:
+ case tok::kw_image2d_array_t:
+ case tok::kw_image3d_t:
+ case tok::kw___unknown_anytype:
+ return TPResult::False();
+
+ default:
+ break;
+ }
+
+ return TPResult::Ambiguous();
+}
+
+bool Parser::isTentativelyDeclared(IdentifierInfo *II) {
+ return std::find(TentativelyDeclaredIdentifiers.begin(),
+ TentativelyDeclaredIdentifiers.end(), II)
+ != TentativelyDeclaredIdentifiers.end();
+}
+
+/// isCXXDeclarationSpecifier - Returns TPResult::True() if it is a declaration
+/// specifier, TPResult::False() if it is not, TPResult::Ambiguous() if it could
+/// be either a decl-specifier or a function-style cast, and TPResult::Error()
+/// if a parsing error was found and reported.
+///
+/// If HasMissingTypename is provided, a name with a dependent scope specifier
+/// will be treated as ambiguous if the 'typename' keyword is missing. If this
+/// happens, *HasMissingTypename will be set to 'true'. This will also be used
+/// as an indicator that undeclared identifiers (which will trigger a later
+/// parse error) should be treated as types. Returns TPResult::Ambiguous() in
+/// such cases.
+///
+/// decl-specifier:
+/// storage-class-specifier
+/// type-specifier
+/// function-specifier
+/// 'friend'
+/// 'typedef'
+/// [C++0x] 'constexpr'
+/// [GNU] attributes declaration-specifiers[opt]
+///
+/// storage-class-specifier:
+/// 'register'
+/// 'static'
+/// 'extern'
+/// 'mutable'
+/// 'auto'
+/// [GNU] '__thread'
+///
+/// function-specifier:
+/// 'inline'
+/// 'virtual'
+/// 'explicit'
+///
+/// typedef-name:
+/// identifier
+///
+/// type-specifier:
+/// simple-type-specifier
+/// class-specifier
+/// enum-specifier
+/// elaborated-type-specifier
+/// typename-specifier
+/// cv-qualifier
+///
+/// simple-type-specifier:
+/// '::'[opt] nested-name-specifier[opt] type-name
+/// '::'[opt] nested-name-specifier 'template'
+/// simple-template-id [TODO]
+/// 'char'
+/// 'wchar_t'
+/// 'bool'
+/// 'short'
+/// 'int'
+/// 'long'
+/// 'signed'
+/// 'unsigned'
+/// 'float'
+/// 'double'
+/// 'void'
+/// [GNU] typeof-specifier
+/// [GNU] '_Complex'
+/// [C++0x] 'auto' [TODO]
+/// [C++0x] 'decltype' ( expression )
+///
+/// type-name:
+/// class-name
+/// enum-name
+/// typedef-name
+///
+/// elaborated-type-specifier:
+/// class-key '::'[opt] nested-name-specifier[opt] identifier
+/// class-key '::'[opt] nested-name-specifier[opt] 'template'[opt]
+/// simple-template-id
+/// 'enum' '::'[opt] nested-name-specifier[opt] identifier
+///
+/// enum-name:
+/// identifier
+///
+/// enum-specifier:
+/// 'enum' identifier[opt] '{' enumerator-list[opt] '}'
+/// 'enum' identifier[opt] '{' enumerator-list ',' '}'
+///
+/// class-specifier:
+/// class-head '{' member-specification[opt] '}'
+///
+/// class-head:
+/// class-key identifier[opt] base-clause[opt]
+/// class-key nested-name-specifier identifier base-clause[opt]
+/// class-key nested-name-specifier[opt] simple-template-id
+/// base-clause[opt]
+///
+/// class-key:
+/// 'class'
+/// 'struct'
+/// 'union'
+///
+/// cv-qualifier:
+/// 'const'
+/// 'volatile'
+/// [GNU] restrict
+///
+Parser::TPResult
+Parser::isCXXDeclarationSpecifier(Parser::TPResult BracedCastResult,
+ bool *HasMissingTypename) {
+ switch (Tok.getKind()) {
+ case tok::identifier: {
+ // Check for need to substitute AltiVec __vector keyword
+ // for "vector" identifier.
+ if (TryAltiVecVectorToken())
+ return TPResult::True();
+
+ const Token &Next = NextToken();
+ // In 'foo bar', 'foo' is always a type name outside of Objective-C.
+ if (!getLangOpts().ObjC1 && Next.is(tok::identifier))
+ return TPResult::True();
+
+ if (Next.isNot(tok::coloncolon) && Next.isNot(tok::less)) {
+ // Determine whether this is a valid expression. If not, we will hit
+ // a parse error one way or another. In that case, tell the caller that
+ // this is ambiguous. Typo-correct to type and expression keywords and
+ // to types and identifiers, in order to try to recover from errors.
+ CorrectionCandidateCallback TypoCorrection;
+ TypoCorrection.WantRemainingKeywords = false;
+ switch (TryAnnotateName(false /* no nested name specifier */,
+ &TypoCorrection)) {
+ case ANK_Error:
+ return TPResult::Error();
+ case ANK_TentativeDecl:
+ return TPResult::False();
+ case ANK_TemplateName:
+ // A bare type template-name which can't be a template template
+ // argument is an error, and was probably intended to be a type.
+ return GreaterThanIsOperator ? TPResult::True() : TPResult::False();
+ case ANK_Unresolved:
+ return HasMissingTypename ? TPResult::Ambiguous() : TPResult::False();
+ case ANK_Success:
+ break;
+ }
+ assert(Tok.isNot(tok::identifier) &&
+ "TryAnnotateName succeeded without producing an annotation");
+ } else {
+ // This might possibly be a type with a dependent scope specifier and
+ // a missing 'typename' keyword. Don't use TryAnnotateName in this case,
+ // since it will annotate as a primary expression, and we want to use the
+ // "missing 'typename'" logic.
+ if (TryAnnotateTypeOrScopeToken())
+ return TPResult::Error();
+ // If annotation failed, assume it's a non-type.
+ // FIXME: If this happens due to an undeclared identifier, treat it as
+ // ambiguous.
+ if (Tok.is(tok::identifier))
+ return TPResult::False();
+ }
+
+ // We annotated this token as something. Recurse to handle whatever we got.
+ return isCXXDeclarationSpecifier(BracedCastResult, HasMissingTypename);
+ }
+
+ case tok::kw_typename: // typename T::type
+ // Annotate typenames and C++ scope specifiers. If we get one, just
+ // recurse to handle whatever we get.
+ if (TryAnnotateTypeOrScopeToken())
+ return TPResult::Error();
+ return isCXXDeclarationSpecifier(BracedCastResult, HasMissingTypename);
+
+ case tok::coloncolon: { // ::foo::bar
+ const Token &Next = NextToken();
+ if (Next.is(tok::kw_new) || // ::new
+ Next.is(tok::kw_delete)) // ::delete
+ return TPResult::False();
+ }
+ // Fall through.
+ case tok::kw_decltype:
+ // Annotate typenames and C++ scope specifiers. If we get one, just
+ // recurse to handle whatever we get.
+ if (TryAnnotateTypeOrScopeToken())
+ return TPResult::Error();
+ return isCXXDeclarationSpecifier(BracedCastResult, HasMissingTypename);
+
+ // decl-specifier:
+ // storage-class-specifier
+ // type-specifier
+ // function-specifier
+ // 'friend'
+ // 'typedef'
+ // 'constexpr'
+ case tok::kw_friend:
+ case tok::kw_typedef:
+ case tok::kw_constexpr:
+ // storage-class-specifier
+ case tok::kw_register:
+ case tok::kw_static:
+ case tok::kw_extern:
+ case tok::kw_mutable:
+ case tok::kw_auto:
+ case tok::kw___thread:
+ // function-specifier
+ case tok::kw_inline:
+ case tok::kw_virtual:
+ case tok::kw_explicit:
+
+ // Modules
+ case tok::kw___module_private__:
+
+ // Debugger support
+ case tok::kw___unknown_anytype:
+
+ // type-specifier:
+ // simple-type-specifier
+ // class-specifier
+ // enum-specifier
+ // elaborated-type-specifier
+ // typename-specifier
+ // cv-qualifier
+
+ // class-specifier
+ // elaborated-type-specifier
+ case tok::kw_class:
+ case tok::kw_struct:
+ case tok::kw_union:
+ // enum-specifier
+ case tok::kw_enum:
+ // cv-qualifier
+ case tok::kw_const:
+ case tok::kw_volatile:
+
+ // GNU
+ case tok::kw_restrict:
+ case tok::kw__Complex:
+ case tok::kw___attribute:
+ return TPResult::True();
+
+ // Microsoft
+ case tok::kw___declspec:
+ case tok::kw___cdecl:
+ case tok::kw___stdcall:
+ case tok::kw___fastcall:
+ case tok::kw___thiscall:
+ case tok::kw___w64:
+ case tok::kw___ptr64:
+ case tok::kw___ptr32:
+ case tok::kw___forceinline:
+ case tok::kw___unaligned:
+ return TPResult::True();
+
+ // Borland
+ case tok::kw___pascal:
+ return TPResult::True();
+
+ // AltiVec
+ case tok::kw___vector:
+ return TPResult::True();
+
+ case tok::annot_template_id: {
+ TemplateIdAnnotation *TemplateId = takeTemplateIdAnnotation(Tok);
+ if (TemplateId->Kind != TNK_Type_template)
+ return TPResult::False();
+ CXXScopeSpec SS;
+ AnnotateTemplateIdTokenAsType();
+ assert(Tok.is(tok::annot_typename));
+ goto case_typename;
+ }
+
+ case tok::annot_cxxscope: // foo::bar or ::foo::bar, but already parsed
+ // We've already annotated a scope; try to annotate a type.
+ if (TryAnnotateTypeOrScopeToken())
+ return TPResult::Error();
+ if (!Tok.is(tok::annot_typename)) {
+ // If the next token is an identifier or a type qualifier, then this
+ // can't possibly be a valid expression either.
+ if (Tok.is(tok::annot_cxxscope) && NextToken().is(tok::identifier)) {
+ CXXScopeSpec SS;
+ Actions.RestoreNestedNameSpecifierAnnotation(Tok.getAnnotationValue(),
+ Tok.getAnnotationRange(),
+ SS);
+ if (SS.getScopeRep() && SS.getScopeRep()->isDependent()) {
+ TentativeParsingAction PA(*this);
+ ConsumeToken();
+ ConsumeToken();
+ bool isIdentifier = Tok.is(tok::identifier);
+ TPResult TPR = TPResult::False();
+ if (!isIdentifier)
+ TPR = isCXXDeclarationSpecifier(BracedCastResult,
+ HasMissingTypename);
+ PA.Revert();
+
+ if (isIdentifier ||
+ TPR == TPResult::True() || TPR == TPResult::Error())
+ return TPResult::Error();
+
+ if (HasMissingTypename) {
+ // We can't tell whether this is a missing 'typename' or a valid
+ // expression.
+ *HasMissingTypename = true;
+ return TPResult::Ambiguous();
+ }
+ } else {
+ // Try to resolve the name. If it doesn't exist, assume it was
+ // intended to name a type and keep disambiguating.
+ switch (TryAnnotateName(false /* SS is not dependent */)) {
+ case ANK_Error:
+ return TPResult::Error();
+ case ANK_TentativeDecl:
+ return TPResult::False();
+ case ANK_TemplateName:
+ // A bare type template-name which can't be a template template
+ // argument is an error, and was probably intended to be a type.
+ return GreaterThanIsOperator ? TPResult::True() : TPResult::False();
+ case ANK_Unresolved:
+ return HasMissingTypename ? TPResult::Ambiguous()
+ : TPResult::False();
+ case ANK_Success:
+ // Annotated it, check again.
+ assert(Tok.isNot(tok::annot_cxxscope) ||
+ NextToken().isNot(tok::identifier));
+ return isCXXDeclarationSpecifier(BracedCastResult,
+ HasMissingTypename);
+ }
+ }
+ }
+ return TPResult::False();
+ }
+ // If that succeeded, fallthrough into the generic simple-type-id case.
+
+ // The ambiguity resides in a simple-type-specifier/typename-specifier
+ // followed by a '('. The '(' could either be the start of:
+ //
+ // direct-declarator:
+ // '(' declarator ')'
+ //
+ // direct-abstract-declarator:
+ // '(' parameter-declaration-clause ')' cv-qualifier-seq[opt]
+ // exception-specification[opt]
+ // '(' abstract-declarator ')'
+ //
+ // or part of a function-style cast expression:
+ //
+ // simple-type-specifier '(' expression-list[opt] ')'
+ //
+
+ // simple-type-specifier:
+
+ case tok::annot_typename:
+ case_typename:
+ // In Objective-C, we might have a protocol-qualified type.
+ if (getLangOpts().ObjC1 && NextToken().is(tok::less)) {
+ // Tentatively parse the
+ TentativeParsingAction PA(*this);
+ ConsumeToken(); // The type token
+
+ TPResult TPR = TryParseProtocolQualifiers();
+ bool isFollowedByParen = Tok.is(tok::l_paren);
+ bool isFollowedByBrace = Tok.is(tok::l_brace);
+
+ PA.Revert();
+
+ if (TPR == TPResult::Error())
+ return TPResult::Error();
+
+ if (isFollowedByParen)
+ return TPResult::Ambiguous();
+
+ if (getLangOpts().CPlusPlus0x && isFollowedByBrace)
+ return BracedCastResult;
+
+ return TPResult::True();
+ }
+
+ case tok::kw_char:
+ case tok::kw_wchar_t:
+ case tok::kw_char16_t:
+ case tok::kw_char32_t:
+ case tok::kw_bool:
+ case tok::kw_short:
+ case tok::kw_int:
+ case tok::kw_long:
+ case tok::kw___int64:
+ case tok::kw___int128:
+ case tok::kw_signed:
+ case tok::kw_unsigned:
+ case tok::kw_half:
+ case tok::kw_float:
+ case tok::kw_double:
+ case tok::kw_void:
+ case tok::annot_decltype:
+ if (NextToken().is(tok::l_paren))
+ return TPResult::Ambiguous();
+
+ // This is a function-style cast in all cases we disambiguate other than
+ // one:
+ // struct S {
+ // enum E : int { a = 4 }; // enum
+ // enum E : int { 4 }; // bit-field
+ // };
+ if (getLangOpts().CPlusPlus0x && NextToken().is(tok::l_brace))
+ return BracedCastResult;
+
+ if (isStartOfObjCClassMessageMissingOpenBracket())
+ return TPResult::False();
+
+ return TPResult::True();
+
+ // GNU typeof support.
+ case tok::kw_typeof: {
+ if (NextToken().isNot(tok::l_paren))
+ return TPResult::True();
+
+ TentativeParsingAction PA(*this);
+
+ TPResult TPR = TryParseTypeofSpecifier();
+ bool isFollowedByParen = Tok.is(tok::l_paren);
+ bool isFollowedByBrace = Tok.is(tok::l_brace);
+
+ PA.Revert();
+
+ if (TPR == TPResult::Error())
+ return TPResult::Error();
+
+ if (isFollowedByParen)
+ return TPResult::Ambiguous();
+
+ if (getLangOpts().CPlusPlus0x && isFollowedByBrace)
+ return BracedCastResult;
+
+ return TPResult::True();
+ }
+
+ // C++0x type traits support
+ case tok::kw___underlying_type:
+ return TPResult::True();
+
+ // C11 _Atomic
+ case tok::kw__Atomic:
+ return TPResult::True();
+
+ default:
+ return TPResult::False();
+ }
+}
+
+/// [GNU] typeof-specifier:
+/// 'typeof' '(' expressions ')'
+/// 'typeof' '(' type-name ')'
+///
+Parser::TPResult Parser::TryParseTypeofSpecifier() {
+ assert(Tok.is(tok::kw_typeof) && "Expected 'typeof'!");
+ ConsumeToken();
+
+ assert(Tok.is(tok::l_paren) && "Expected '('");
+ // Parse through the parens after 'typeof'.
+ ConsumeParen();
+ if (!SkipUntil(tok::r_paren))
+ return TPResult::Error();
+
+ return TPResult::Ambiguous();
+}
+
+/// [ObjC] protocol-qualifiers:
+//// '<' identifier-list '>'
+Parser::TPResult Parser::TryParseProtocolQualifiers() {
+ assert(Tok.is(tok::less) && "Expected '<' for qualifier list");
+ ConsumeToken();
+ do {
+ if (Tok.isNot(tok::identifier))
+ return TPResult::Error();
+ ConsumeToken();
+
+ if (Tok.is(tok::comma)) {
+ ConsumeToken();
+ continue;
+ }
+
+ if (Tok.is(tok::greater)) {
+ ConsumeToken();
+ return TPResult::Ambiguous();
+ }
+ } while (false);
+
+ return TPResult::Error();
+}
+
+Parser::TPResult
+Parser::TryParseDeclarationSpecifier(bool *HasMissingTypename) {
+ TPResult TPR = isCXXDeclarationSpecifier(TPResult::False(),
+ HasMissingTypename);
+ if (TPR != TPResult::Ambiguous())
+ return TPR;
+
+ if (Tok.is(tok::kw_typeof))
+ TryParseTypeofSpecifier();
+ else {
+ if (Tok.is(tok::annot_cxxscope))
+ ConsumeToken();
+ ConsumeToken();
+
+ if (getLangOpts().ObjC1 && Tok.is(tok::less))
+ TryParseProtocolQualifiers();
+ }
+
+ return TPResult::Ambiguous();
+}
+
+/// isCXXFunctionDeclarator - Disambiguates between a function declarator or
+/// a constructor-style initializer, when parsing declaration statements.
+/// Returns true for function declarator and false for constructor-style
+/// initializer.
+/// If during the disambiguation process a parsing error is encountered,
+/// the function returns true to let the declaration parsing code handle it.
+///
+/// '(' parameter-declaration-clause ')' cv-qualifier-seq[opt]
+/// exception-specification[opt]
+///
+bool Parser::isCXXFunctionDeclarator(bool *IsAmbiguous) {
+
+ // C++ 8.2p1:
+ // The ambiguity arising from the similarity between a function-style cast and
+ // a declaration mentioned in 6.8 can also occur in the context of a
+ // declaration. In that context, the choice is between a function declaration
+ // with a redundant set of parentheses around a parameter name and an object
+ // declaration with a function-style cast as the initializer. Just as for the
+ // ambiguities mentioned in 6.8, the resolution is to consider any construct
+ // that could possibly be a declaration a declaration.
+
+ TentativeParsingAction PA(*this);
+
+ ConsumeParen();
+ bool InvalidAsDeclaration = false;
+ TPResult TPR = TryParseParameterDeclarationClause(&InvalidAsDeclaration);
+ if (TPR == TPResult::Ambiguous()) {
+ if (Tok.isNot(tok::r_paren))
+ TPR = TPResult::False();
+ else {
+ const Token &Next = NextToken();
+ if (Next.is(tok::amp) || Next.is(tok::ampamp) ||
+ Next.is(tok::kw_const) || Next.is(tok::kw_volatile) ||
+ Next.is(tok::kw_throw) || Next.is(tok::kw_noexcept) ||
+ Next.is(tok::l_square) || isCXX0XVirtSpecifier(Next) ||
+ Next.is(tok::l_brace) || Next.is(tok::kw_try) ||
+ Next.is(tok::equal) || Next.is(tok::arrow))
+ // The next token cannot appear after a constructor-style initializer,
+ // and can appear next in a function definition. This must be a function
+ // declarator.
+ TPR = TPResult::True();
+ else if (InvalidAsDeclaration)
+ // Use the absence of 'typename' as a tie-breaker.
+ TPR = TPResult::False();
+ }
+ }
+
+ PA.Revert();
+
+ if (IsAmbiguous && TPR == TPResult::Ambiguous())
+ *IsAmbiguous = true;
+
+ // In case of an error, let the declaration parsing code handle it.
+ return TPR != TPResult::False();
+}
+
+/// parameter-declaration-clause:
+/// parameter-declaration-list[opt] '...'[opt]
+/// parameter-declaration-list ',' '...'
+///
+/// parameter-declaration-list:
+/// parameter-declaration
+/// parameter-declaration-list ',' parameter-declaration
+///
+/// parameter-declaration:
+/// attribute-specifier-seq[opt] decl-specifier-seq declarator attributes[opt]
+/// attribute-specifier-seq[opt] decl-specifier-seq declarator attributes[opt]
+/// '=' assignment-expression
+/// attribute-specifier-seq[opt] decl-specifier-seq abstract-declarator[opt]
+/// attributes[opt]
+/// attribute-specifier-seq[opt] decl-specifier-seq abstract-declarator[opt]
+/// attributes[opt] '=' assignment-expression
+///
+Parser::TPResult
+Parser::TryParseParameterDeclarationClause(bool *InvalidAsDeclaration) {
+
+ if (Tok.is(tok::r_paren))
+ return TPResult::Ambiguous();
+
+ // parameter-declaration-list[opt] '...'[opt]
+ // parameter-declaration-list ',' '...'
+ //
+ // parameter-declaration-list:
+ // parameter-declaration
+ // parameter-declaration-list ',' parameter-declaration
+ //
+ while (1) {
+ // '...'[opt]
+ if (Tok.is(tok::ellipsis)) {
+ ConsumeToken();
+ if (Tok.is(tok::r_paren))
+ return TPResult::True(); // '...)' is a sign of a function declarator.
+ else
+ return TPResult::False();
+ }
+
+ // An attribute-specifier-seq here is a sign of a function declarator.
+ if (isCXX11AttributeSpecifier(/*Disambiguate*/false,
+ /*OuterMightBeMessageSend*/true))
+ return TPResult::True();
+
+ ParsedAttributes attrs(AttrFactory);
+ MaybeParseMicrosoftAttributes(attrs);
+
+ // decl-specifier-seq
+ // A parameter-declaration's initializer must be preceded by an '=', so
+ // decl-specifier-seq '{' is not a parameter in C++11.
+ TPResult TPR = TryParseDeclarationSpecifier(InvalidAsDeclaration);
+ if (TPR != TPResult::Ambiguous())
+ return TPR;
+
+ // declarator
+ // abstract-declarator[opt]
+ TPR = TryParseDeclarator(true/*mayBeAbstract*/);
+ if (TPR != TPResult::Ambiguous())
+ return TPR;
+
+ // [GNU] attributes[opt]
+ if (Tok.is(tok::kw___attribute))
+ return TPResult::True();
+
+ if (Tok.is(tok::equal)) {
+ // '=' assignment-expression
+ // Parse through assignment-expression.
+ if (!SkipUntil(tok::comma, tok::r_paren, true/*StopAtSemi*/,
+ true/*DontConsume*/))
+ return TPResult::Error();
+ }
+
+ if (Tok.is(tok::ellipsis)) {
+ ConsumeToken();
+ if (Tok.is(tok::r_paren))
+ return TPResult::True(); // '...)' is a sign of a function declarator.
+ else
+ return TPResult::False();
+ }
+
+ if (Tok.isNot(tok::comma))
+ break;
+ ConsumeToken(); // the comma.
+ }
+
+ return TPResult::Ambiguous();
+}
+
+/// TryParseFunctionDeclarator - We parsed a '(' and we want to try to continue
+/// parsing as a function declarator.
+/// If TryParseFunctionDeclarator fully parsed the function declarator, it will
+/// return TPResult::Ambiguous(), otherwise it will return either False() or
+/// Error().
+///
+/// '(' parameter-declaration-clause ')' cv-qualifier-seq[opt]
+/// exception-specification[opt]
+///
+/// exception-specification:
+/// 'throw' '(' type-id-list[opt] ')'
+///
+Parser::TPResult Parser::TryParseFunctionDeclarator() {
+
+ // The '(' is already parsed.
+
+ TPResult TPR = TryParseParameterDeclarationClause();
+ if (TPR == TPResult::Ambiguous() && Tok.isNot(tok::r_paren))
+ TPR = TPResult::False();
+
+ if (TPR == TPResult::False() || TPR == TPResult::Error())
+ return TPR;
+
+ // Parse through the parens.
+ if (!SkipUntil(tok::r_paren))
+ return TPResult::Error();
+
+ // cv-qualifier-seq
+ while (Tok.is(tok::kw_const) ||
+ Tok.is(tok::kw_volatile) ||
+ Tok.is(tok::kw_restrict) )
+ ConsumeToken();
+
+ // ref-qualifier[opt]
+ if (Tok.is(tok::amp) || Tok.is(tok::ampamp))
+ ConsumeToken();
+
+ // exception-specification
+ if (Tok.is(tok::kw_throw)) {
+ ConsumeToken();
+ if (Tok.isNot(tok::l_paren))
+ return TPResult::Error();
+
+ // Parse through the parens after 'throw'.
+ ConsumeParen();
+ if (!SkipUntil(tok::r_paren))
+ return TPResult::Error();
+ }
+ if (Tok.is(tok::kw_noexcept)) {
+ ConsumeToken();
+ // Possibly an expression as well.
+ if (Tok.is(tok::l_paren)) {
+ // Find the matching rparen.
+ ConsumeParen();
+ if (!SkipUntil(tok::r_paren))
+ return TPResult::Error();
+ }
+ }
+
+ return TPResult::Ambiguous();
+}
+
+/// '[' constant-expression[opt] ']'
+///
+Parser::TPResult Parser::TryParseBracketDeclarator() {
+ ConsumeBracket();
+ if (!SkipUntil(tok::r_square))
+ return TPResult::Error();
+
+ return TPResult::Ambiguous();
+}
diff --git a/clang/lib/Sema/DeclSpec.cpp b/clang/lib/Sema/DeclSpec.cpp index 040e638b2e4..b34b953a036 100644 --- a/clang/lib/Sema/DeclSpec.cpp +++ b/clang/lib/Sema/DeclSpec.cpp @@ -280,6 +280,12 @@ bool Declarator::isDeclarationOfFunction() const { case TST_unspecified: case TST_void: case TST_wchar: + case TST_image1d_t: + case TST_image1d_array_t: + case TST_image1d_buffer_t: + case TST_image2d_t: + case TST_image2d_array_t: + case TST_image3d_t: return false; case TST_decltype: @@ -414,6 +420,12 @@ const char *DeclSpec::getSpecifierName(DeclSpec::TST T) { case DeclSpec::TST_underlyingType: return "__underlying_type"; case DeclSpec::TST_unknown_anytype: return "__unknown_anytype"; case DeclSpec::TST_atomic: return "_Atomic"; + case DeclSpec::TST_image1d_t: return "image1d_t"; + case DeclSpec::TST_image1d_array_t: return "image1d_array_t"; + case DeclSpec::TST_image1d_buffer_t: return "image1d_buffer_t"; + case DeclSpec::TST_image2d_t: return "image2d_t"; + case DeclSpec::TST_image2d_array_t: return "image2d_array_t"; + case DeclSpec::TST_image3d_t: return "image3d_t"; case DeclSpec::TST_error: return "(error)"; } llvm_unreachable("Unknown typespec!"); diff --git a/clang/lib/Sema/SemaTemplateVariadic.cpp b/clang/lib/Sema/SemaTemplateVariadic.cpp index f7978253af6..6c7032089a0 100644 --- a/clang/lib/Sema/SemaTemplateVariadic.cpp +++ b/clang/lib/Sema/SemaTemplateVariadic.cpp @@ -731,6 +731,12 @@ bool Sema::containsUnexpandedParameterPacks(Declarator &D) { case TST_class: case TST_auto: case TST_unknown_anytype: + case TST_image1d_t: + case TST_image1d_array_t: + case TST_image1d_buffer_t: + case TST_image2d_t: + case TST_image2d_array_t: + case TST_image3d_t: case TST_error: break; } diff --git a/clang/lib/Sema/SemaType.cpp b/clang/lib/Sema/SemaType.cpp index 2c7b7c18ece..1afc8c7f25b 100644 --- a/clang/lib/Sema/SemaType.cpp +++ b/clang/lib/Sema/SemaType.cpp @@ -903,6 +903,30 @@ static QualType ConvertDeclSpecToType(TypeProcessingState &state) { } break; + case DeclSpec::TST_image1d_t: + Result = Context.OCLImage1dTy; + break; + + case DeclSpec::TST_image1d_array_t: + Result = Context.OCLImage1dArrayTy; + break; + + case DeclSpec::TST_image1d_buffer_t: + Result = Context.OCLImage1dBufferTy; + break; + + case DeclSpec::TST_image2d_t: + Result = Context.OCLImage2dTy; + break; + + case DeclSpec::TST_image2d_array_t: + Result = Context.OCLImage2dArrayTy; + break; + + case DeclSpec::TST_image3d_t: + Result = Context.OCLImage3dTy; + break; + case DeclSpec::TST_error: Result = Context.IntTy; declarator.setInvalidType(true); diff --git a/clang/lib/Serialization/ASTCommon.cpp b/clang/lib/Serialization/ASTCommon.cpp index aec8a815654..91eec732978 100644 --- a/clang/lib/Serialization/ASTCommon.cpp +++ b/clang/lib/Serialization/ASTCommon.cpp @@ -1,80 +1,86 @@ -//===--- ASTCommon.cpp - Common stuff for ASTReader/ASTWriter----*- C++ -*-===// -// -// The LLVM Compiler Infrastructure -// -// This file is distributed under the University of Illinois Open Source -// License. See LICENSE.TXT for details. -// -//===----------------------------------------------------------------------===// -// -// This file defines common functions that both ASTReader and ASTWriter use. -// -//===----------------------------------------------------------------------===// - -#include "ASTCommon.h" -#include "clang/Basic/IdentifierTable.h" -#include "clang/Serialization/ASTDeserializationListener.h" -#include "llvm/ADT/StringExtras.h" - -using namespace clang; - -// Give ASTDeserializationListener's VTable a home. -ASTDeserializationListener::~ASTDeserializationListener() { } - -serialization::TypeIdx -serialization::TypeIdxFromBuiltin(const BuiltinType *BT) { - unsigned ID = 0; - switch (BT->getKind()) { - case BuiltinType::Void: ID = PREDEF_TYPE_VOID_ID; break; - case BuiltinType::Bool: ID = PREDEF_TYPE_BOOL_ID; break; - case BuiltinType::Char_U: ID = PREDEF_TYPE_CHAR_U_ID; break; - case BuiltinType::UChar: ID = PREDEF_TYPE_UCHAR_ID; break; - case BuiltinType::UShort: ID = PREDEF_TYPE_USHORT_ID; break; - case BuiltinType::UInt: ID = PREDEF_TYPE_UINT_ID; break; - case BuiltinType::ULong: ID = PREDEF_TYPE_ULONG_ID; break; - case BuiltinType::ULongLong: ID = PREDEF_TYPE_ULONGLONG_ID; break; - case BuiltinType::UInt128: ID = PREDEF_TYPE_UINT128_ID; break; - case BuiltinType::Char_S: ID = PREDEF_TYPE_CHAR_S_ID; break; - case BuiltinType::SChar: ID = PREDEF_TYPE_SCHAR_ID; break; - case BuiltinType::WChar_S: - case BuiltinType::WChar_U: ID = PREDEF_TYPE_WCHAR_ID; break; - case BuiltinType::Short: ID = PREDEF_TYPE_SHORT_ID; break; - case BuiltinType::Int: ID = PREDEF_TYPE_INT_ID; break; - case BuiltinType::Long: ID = PREDEF_TYPE_LONG_ID; break; - case BuiltinType::LongLong: ID = PREDEF_TYPE_LONGLONG_ID; break; - case BuiltinType::Int128: ID = PREDEF_TYPE_INT128_ID; break; - case BuiltinType::Half: ID = PREDEF_TYPE_HALF_ID; break; - case BuiltinType::Float: ID = PREDEF_TYPE_FLOAT_ID; break; - case BuiltinType::Double: ID = PREDEF_TYPE_DOUBLE_ID; break; - case BuiltinType::LongDouble: ID = PREDEF_TYPE_LONGDOUBLE_ID; break; - case BuiltinType::NullPtr: ID = PREDEF_TYPE_NULLPTR_ID; break; - case BuiltinType::Char16: ID = PREDEF_TYPE_CHAR16_ID; break; - case BuiltinType::Char32: ID = PREDEF_TYPE_CHAR32_ID; break; - case BuiltinType::Overload: ID = PREDEF_TYPE_OVERLOAD_ID; break; - case BuiltinType::BoundMember:ID = PREDEF_TYPE_BOUND_MEMBER; break; - case BuiltinType::PseudoObject:ID = PREDEF_TYPE_PSEUDO_OBJECT;break; - case BuiltinType::Dependent: ID = PREDEF_TYPE_DEPENDENT_ID; break; - case BuiltinType::UnknownAny: ID = PREDEF_TYPE_UNKNOWN_ANY; break; - case BuiltinType::ARCUnbridgedCast: - ID = PREDEF_TYPE_ARC_UNBRIDGED_CAST; break; - case BuiltinType::ObjCId: ID = PREDEF_TYPE_OBJC_ID; break; - case BuiltinType::ObjCClass: ID = PREDEF_TYPE_OBJC_CLASS; break; - case BuiltinType::ObjCSel: ID = PREDEF_TYPE_OBJC_SEL; break; - case BuiltinType::BuiltinFn: - ID = PREDEF_TYPE_BUILTIN_FN; break; - - } - - return TypeIdx(ID); -} - -unsigned serialization::ComputeHash(Selector Sel) { - unsigned N = Sel.getNumArgs(); - if (N == 0) - ++N; - unsigned R = 5381; - for (unsigned I = 0; I != N; ++I) - if (IdentifierInfo *II = Sel.getIdentifierInfoForSlot(I)) - R = llvm::HashString(II->getName(), R); - return R; -} +//===--- ASTCommon.cpp - Common stuff for ASTReader/ASTWriter----*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+//
+// This file defines common functions that both ASTReader and ASTWriter use.
+//
+//===----------------------------------------------------------------------===//
+
+#include "ASTCommon.h"
+#include "clang/Basic/IdentifierTable.h"
+#include "clang/Serialization/ASTDeserializationListener.h"
+#include "llvm/ADT/StringExtras.h"
+
+using namespace clang;
+
+// Give ASTDeserializationListener's VTable a home.
+ASTDeserializationListener::~ASTDeserializationListener() { }
+
+serialization::TypeIdx
+serialization::TypeIdxFromBuiltin(const BuiltinType *BT) {
+ unsigned ID = 0;
+ switch (BT->getKind()) {
+ case BuiltinType::Void: ID = PREDEF_TYPE_VOID_ID; break;
+ case BuiltinType::Bool: ID = PREDEF_TYPE_BOOL_ID; break;
+ case BuiltinType::Char_U: ID = PREDEF_TYPE_CHAR_U_ID; break;
+ case BuiltinType::UChar: ID = PREDEF_TYPE_UCHAR_ID; break;
+ case BuiltinType::UShort: ID = PREDEF_TYPE_USHORT_ID; break;
+ case BuiltinType::UInt: ID = PREDEF_TYPE_UINT_ID; break;
+ case BuiltinType::ULong: ID = PREDEF_TYPE_ULONG_ID; break;
+ case BuiltinType::ULongLong: ID = PREDEF_TYPE_ULONGLONG_ID; break;
+ case BuiltinType::UInt128: ID = PREDEF_TYPE_UINT128_ID; break;
+ case BuiltinType::Char_S: ID = PREDEF_TYPE_CHAR_S_ID; break;
+ case BuiltinType::SChar: ID = PREDEF_TYPE_SCHAR_ID; break;
+ case BuiltinType::WChar_S:
+ case BuiltinType::WChar_U: ID = PREDEF_TYPE_WCHAR_ID; break;
+ case BuiltinType::Short: ID = PREDEF_TYPE_SHORT_ID; break;
+ case BuiltinType::Int: ID = PREDEF_TYPE_INT_ID; break;
+ case BuiltinType::Long: ID = PREDEF_TYPE_LONG_ID; break;
+ case BuiltinType::LongLong: ID = PREDEF_TYPE_LONGLONG_ID; break;
+ case BuiltinType::Int128: ID = PREDEF_TYPE_INT128_ID; break;
+ case BuiltinType::Half: ID = PREDEF_TYPE_HALF_ID; break;
+ case BuiltinType::Float: ID = PREDEF_TYPE_FLOAT_ID; break;
+ case BuiltinType::Double: ID = PREDEF_TYPE_DOUBLE_ID; break;
+ case BuiltinType::LongDouble: ID = PREDEF_TYPE_LONGDOUBLE_ID; break;
+ case BuiltinType::NullPtr: ID = PREDEF_TYPE_NULLPTR_ID; break;
+ case BuiltinType::Char16: ID = PREDEF_TYPE_CHAR16_ID; break;
+ case BuiltinType::Char32: ID = PREDEF_TYPE_CHAR32_ID; break;
+ case BuiltinType::Overload: ID = PREDEF_TYPE_OVERLOAD_ID; break;
+ case BuiltinType::BoundMember:ID = PREDEF_TYPE_BOUND_MEMBER; break;
+ case BuiltinType::PseudoObject:ID = PREDEF_TYPE_PSEUDO_OBJECT;break;
+ case BuiltinType::Dependent: ID = PREDEF_TYPE_DEPENDENT_ID; break;
+ case BuiltinType::UnknownAny: ID = PREDEF_TYPE_UNKNOWN_ANY; break;
+ case BuiltinType::ARCUnbridgedCast:
+ ID = PREDEF_TYPE_ARC_UNBRIDGED_CAST; break;
+ case BuiltinType::ObjCId: ID = PREDEF_TYPE_OBJC_ID; break;
+ case BuiltinType::ObjCClass: ID = PREDEF_TYPE_OBJC_CLASS; break;
+ case BuiltinType::ObjCSel: ID = PREDEF_TYPE_OBJC_SEL; break;
+ case BuiltinType::OCLImage1d: ID = PREDEF_TYPE_IMAGE1D_ID; break;
+ case BuiltinType::OCLImage1dArray: ID = PREDEF_TYPE_IMAGE1D_ARR_ID; break;
+ case BuiltinType::OCLImage1dBuffer: ID = PREDEF_TYPE_IMAGE1D_BUFF_ID; break;
+ case BuiltinType::OCLImage2d: ID = PREDEF_TYPE_IMAGE2D_ID; break;
+ case BuiltinType::OCLImage2dArray: ID = PREDEF_TYPE_IMAGE2D_ARR_ID; break;
+ case BuiltinType::OCLImage3d: ID = PREDEF_TYPE_IMAGE3D_ID; break;
+ case BuiltinType::BuiltinFn:
+ ID = PREDEF_TYPE_BUILTIN_FN; break;
+
+ }
+
+ return TypeIdx(ID);
+}
+
+unsigned serialization::ComputeHash(Selector Sel) {
+ unsigned N = Sel.getNumArgs();
+ if (N == 0)
+ ++N;
+ unsigned R = 5381;
+ for (unsigned I = 0; I != N; ++I)
+ if (IdentifierInfo *II = Sel.getIdentifierInfoForSlot(I))
+ R = llvm::HashString(II->getName(), R);
+ return R;
+}
diff --git a/clang/lib/Serialization/ASTReader.cpp b/clang/lib/Serialization/ASTReader.cpp index c0976ee1e65..88b56141242 100644 --- a/clang/lib/Serialization/ASTReader.cpp +++ b/clang/lib/Serialization/ASTReader.cpp @@ -1,6992 +1,6998 @@ -//===--- ASTReader.cpp - AST File Reader ------------------------*- C++ -*-===// -// -// The LLVM Compiler Infrastructure -// -// This file is distributed under the University of Illinois Open Source -// License. See LICENSE.TXT for details. -// -//===----------------------------------------------------------------------===// -// -// This file defines the ASTReader class, which reads AST files. -// -//===----------------------------------------------------------------------===// - -#include "clang/Serialization/ASTReader.h" -#include "ASTCommon.h" -#include "ASTReaderInternals.h" -#include "clang/AST/ASTConsumer.h" -#include "clang/AST/ASTContext.h" -#include "clang/AST/DeclTemplate.h" -#include "clang/AST/Expr.h" -#include "clang/AST/ExprCXX.h" -#include "clang/AST/NestedNameSpecifier.h" -#include "clang/AST/Type.h" -#include "clang/AST/TypeLocVisitor.h" -#include "clang/Basic/FileManager.h" -#include "clang/Basic/FileSystemStatCache.h" -#include "clang/Basic/OnDiskHashTable.h" -#include "clang/Basic/SourceManager.h" -#include "clang/Basic/SourceManagerInternals.h" -#include "clang/Basic/TargetInfo.h" -#include "clang/Basic/TargetOptions.h" -#include "clang/Basic/Version.h" -#include "clang/Basic/VersionTuple.h" -#include "clang/Lex/HeaderSearch.h" -#include "clang/Lex/HeaderSearchOptions.h" -#include "clang/Lex/MacroInfo.h" -#include "clang/Lex/PreprocessingRecord.h" -#include "clang/Lex/Preprocessor.h" -#include "clang/Lex/PreprocessorOptions.h" -#include "clang/Sema/Scope.h" -#include "clang/Sema/Sema.h" -#include "clang/Serialization/ASTDeserializationListener.h" -#include "clang/Serialization/ModuleManager.h" -#include "clang/Serialization/SerializationDiagnostic.h" -#include "llvm/ADT/StringExtras.h" -#include "llvm/Bitcode/BitstreamReader.h" -#include "llvm/Support/ErrorHandling.h" -#include "llvm/Support/FileSystem.h" -#include "llvm/Support/MemoryBuffer.h" -#include "llvm/Support/Path.h" -#include "llvm/Support/SaveAndRestore.h" -#include "llvm/Support/system_error.h" -#include <algorithm> -#include <cstdio> -#include <iterator> - -using namespace clang; -using namespace clang::serialization; -using namespace clang::serialization::reader; - -//===----------------------------------------------------------------------===// -// PCH validator implementation -//===----------------------------------------------------------------------===// - -ASTReaderListener::~ASTReaderListener() {} - -/// \brief Compare the given set of language options against an existing set of -/// language options. -/// -/// \param Diags If non-NULL, diagnostics will be emitted via this engine. -/// -/// \returns true if the languagae options mis-match, false otherwise. -static bool checkLanguageOptions(const LangOptions &LangOpts, - const LangOptions &ExistingLangOpts, - DiagnosticsEngine *Diags) { -#define LANGOPT(Name, Bits, Default, Description) \ - if (ExistingLangOpts.Name != LangOpts.Name) { \ - if (Diags) \ - Diags->Report(diag::err_pch_langopt_mismatch) \ - << Description << LangOpts.Name << ExistingLangOpts.Name; \ - return true; \ - } - -#define VALUE_LANGOPT(Name, Bits, Default, Description) \ - if (ExistingLangOpts.Name != LangOpts.Name) { \ - if (Diags) \ - Diags->Report(diag::err_pch_langopt_value_mismatch) \ - << Description; \ - return true; \ - } - -#define ENUM_LANGOPT(Name, Type, Bits, Default, Description) \ - if (ExistingLangOpts.get##Name() != LangOpts.get##Name()) { \ - if (Diags) \ - Diags->Report(diag::err_pch_langopt_value_mismatch) \ - << Description; \ - return true; \ - } - -#define BENIGN_LANGOPT(Name, Bits, Default, Description) -#define BENIGN_ENUM_LANGOPT(Name, Type, Bits, Default, Description) -#include "clang/Basic/LangOptions.def" - - if (ExistingLangOpts.ObjCRuntime != LangOpts.ObjCRuntime) { - if (Diags) - Diags->Report(diag::err_pch_langopt_value_mismatch) - << "target Objective-C runtime"; - return true; - } - - return false; -} - -/// \brief Compare the given set of target options against an existing set of -/// target options. -/// -/// \param Diags If non-NULL, diagnostics will be emitted via this engine. -/// -/// \returns true if the target options mis-match, false otherwise. -static bool checkTargetOptions(const TargetOptions &TargetOpts, - const TargetOptions &ExistingTargetOpts, - DiagnosticsEngine *Diags) { -#define CHECK_TARGET_OPT(Field, Name) \ - if (TargetOpts.Field != ExistingTargetOpts.Field) { \ - if (Diags) \ - Diags->Report(diag::err_pch_targetopt_mismatch) \ - << Name << TargetOpts.Field << ExistingTargetOpts.Field; \ - return true; \ - } - - CHECK_TARGET_OPT(Triple, "target"); - CHECK_TARGET_OPT(CPU, "target CPU"); - CHECK_TARGET_OPT(ABI, "target ABI"); - CHECK_TARGET_OPT(CXXABI, "target C++ ABI"); - CHECK_TARGET_OPT(LinkerVersion, "target linker version"); -#undef CHECK_TARGET_OPT - - // Compare feature sets. - SmallVector<StringRef, 4> ExistingFeatures( - ExistingTargetOpts.FeaturesAsWritten.begin(), - ExistingTargetOpts.FeaturesAsWritten.end()); - SmallVector<StringRef, 4> ReadFeatures(TargetOpts.FeaturesAsWritten.begin(), - TargetOpts.FeaturesAsWritten.end()); - std::sort(ExistingFeatures.begin(), ExistingFeatures.end()); - std::sort(ReadFeatures.begin(), ReadFeatures.end()); - - unsigned ExistingIdx = 0, ExistingN = ExistingFeatures.size(); - unsigned ReadIdx = 0, ReadN = ReadFeatures.size(); - while (ExistingIdx < ExistingN && ReadIdx < ReadN) { - if (ExistingFeatures[ExistingIdx] == ReadFeatures[ReadIdx]) { - ++ExistingIdx; - ++ReadIdx; - continue; - } - - if (ReadFeatures[ReadIdx] < ExistingFeatures[ExistingIdx]) { - if (Diags) - Diags->Report(diag::err_pch_targetopt_feature_mismatch) - << false << ReadFeatures[ReadIdx]; - return true; - } - - if (Diags) - Diags->Report(diag::err_pch_targetopt_feature_mismatch) - << true << ExistingFeatures[ExistingIdx]; - return true; - } - - if (ExistingIdx < ExistingN) { - if (Diags) - Diags->Report(diag::err_pch_targetopt_feature_mismatch) - << true << ExistingFeatures[ExistingIdx]; - return true; - } - - if (ReadIdx < ReadN) { - if (Diags) - Diags->Report(diag::err_pch_targetopt_feature_mismatch) - << false << ReadFeatures[ReadIdx]; - return true; - } - - return false; -} - -bool -PCHValidator::ReadLanguageOptions(const LangOptions &LangOpts, - bool Complain) { - const LangOptions &ExistingLangOpts = PP.getLangOpts(); - return checkLanguageOptions(LangOpts, ExistingLangOpts, - Complain? &Reader.Diags : 0); -} - -bool PCHValidator::ReadTargetOptions(const TargetOptions &TargetOpts, - bool Complain) { - const TargetOptions &ExistingTargetOpts = PP.getTargetInfo().getTargetOpts(); - return checkTargetOptions(TargetOpts, ExistingTargetOpts, - Complain? &Reader.Diags : 0); -} - -namespace { - typedef llvm::StringMap<std::pair<StringRef, bool /*IsUndef*/> > - MacroDefinitionsMap; -} - -/// \brief Collect the macro definitions provided by the given preprocessor -/// options. -static void collectMacroDefinitions(const PreprocessorOptions &PPOpts, - MacroDefinitionsMap &Macros, - SmallVectorImpl<StringRef> *MacroNames = 0){ - for (unsigned I = 0, N = PPOpts.Macros.size(); I != N; ++I) { - StringRef Macro = PPOpts.Macros[I].first; - bool IsUndef = PPOpts.Macros[I].second; - - std::pair<StringRef, StringRef> MacroPair = Macro.split('='); - StringRef MacroName = MacroPair.first; - StringRef MacroBody = MacroPair.second; - - // For an #undef'd macro, we only care about the name. - if (IsUndef) { - if (MacroNames && !Macros.count(MacroName)) - MacroNames->push_back(MacroName); - - Macros[MacroName] = std::make_pair("", true); - continue; - } - - // For a #define'd macro, figure out the actual definition. - if (MacroName.size() == Macro.size()) - MacroBody = "1"; - else { - // Note: GCC drops anything following an end-of-line character. - StringRef::size_type End = MacroBody.find_first_of("\n\r"); - MacroBody = MacroBody.substr(0, End); - } - - if (MacroNames && !Macros.count(MacroName)) - MacroNames->push_back(MacroName); - Macros[MacroName] = std::make_pair(MacroBody, false); - } -} - -/// \brief Check the preprocessor options deserialized from the control block -/// against the preprocessor options in an existing preprocessor. -/// -/// \param Diags If non-null, produce diagnostics for any mismatches incurred. -static bool checkPreprocessorOptions(const PreprocessorOptions &PPOpts, - const PreprocessorOptions &ExistingPPOpts, - DiagnosticsEngine *Diags, - FileManager &FileMgr, - std::string &SuggestedPredefines) { - // Check macro definitions. - MacroDefinitionsMap ASTFileMacros; - collectMacroDefinitions(PPOpts, ASTFileMacros); - MacroDefinitionsMap ExistingMacros; - SmallVector<StringRef, 4> ExistingMacroNames; - collectMacroDefinitions(ExistingPPOpts, ExistingMacros, &ExistingMacroNames); - - for (unsigned I = 0, N = ExistingMacroNames.size(); I != N; ++I) { - // Dig out the macro definition in the existing preprocessor options. - StringRef MacroName = ExistingMacroNames[I]; - std::pair<StringRef, bool> Existing = ExistingMacros[MacroName]; - - // Check whether we know anything about this macro name or not. - llvm::StringMap<std::pair<StringRef, bool /*IsUndef*/> >::iterator Known - = ASTFileMacros.find(MacroName); - if (Known == ASTFileMacros.end()) { - // FIXME: Check whether this identifier was referenced anywhere in the - // AST file. If so, we should reject the AST file. Unfortunately, this - // information isn't in the control block. What shall we do about it? - - if (Existing.second) { - SuggestedPredefines += "#undef "; - SuggestedPredefines += MacroName.str(); - SuggestedPredefines += '\n'; - } else { - SuggestedPredefines += "#define "; - SuggestedPredefines += MacroName.str(); - SuggestedPredefines += ' '; - SuggestedPredefines += Existing.first.str(); - SuggestedPredefines += '\n'; - } - continue; - } - - // If the macro was defined in one but undef'd in the other, we have a - // conflict. - if (Existing.second != Known->second.second) { - if (Diags) { - Diags->Report(diag::err_pch_macro_def_undef) - << MacroName << Known->second.second; - } - return true; - } - - // If the macro was #undef'd in both, or if the macro bodies are identical, - // it's fine. - if (Existing.second || Existing.first == Known->second.first) - continue; - - // The macro bodies differ; complain. - if (Diags) { - Diags->Report(diag::err_pch_macro_def_conflict) - << MacroName << Known->second.first << Existing.first; - } - return true; - } - - // Check whether we're using predefines. - if (PPOpts.UsePredefines != ExistingPPOpts.UsePredefines) { - if (Diags) { - Diags->Report(diag::err_pch_undef) << ExistingPPOpts.UsePredefines; - } - return true; - } - - // Compute the #include and #include_macros lines we need. - for (unsigned I = 0, N = ExistingPPOpts.Includes.size(); I != N; ++I) { - StringRef File = ExistingPPOpts.Includes[I]; - if (File == ExistingPPOpts.ImplicitPCHInclude) - continue; - - if (std::find(PPOpts.Includes.begin(), PPOpts.Includes.end(), File) - != PPOpts.Includes.end()) - continue; - - SuggestedPredefines += "#include \""; - SuggestedPredefines += - HeaderSearch::NormalizeDashIncludePath(File, FileMgr); - SuggestedPredefines += "\"\n"; - } - - for (unsigned I = 0, N = ExistingPPOpts.MacroIncludes.size(); I != N; ++I) { - StringRef File = ExistingPPOpts.MacroIncludes[I]; - if (std::find(PPOpts.MacroIncludes.begin(), PPOpts.MacroIncludes.end(), - File) - != PPOpts.MacroIncludes.end()) - continue; - - SuggestedPredefines += "#__include_macros \""; - SuggestedPredefines += - HeaderSearch::NormalizeDashIncludePath(File, FileMgr); - SuggestedPredefines += "\"\n##\n"; - } - - return false; -} - -bool PCHValidator::ReadPreprocessorOptions(const PreprocessorOptions &PPOpts, - bool Complain, - std::string &SuggestedPredefines) { - const PreprocessorOptions &ExistingPPOpts = PP.getPreprocessorOpts(); - - return checkPreprocessorOptions(PPOpts, ExistingPPOpts, - Complain? &Reader.Diags : 0, - PP.getFileManager(), - SuggestedPredefines); -} - -void PCHValidator::ReadHeaderFileInfo(const HeaderFileInfo &HFI, - unsigned ID) { - PP.getHeaderSearchInfo().setHeaderFileInfoForUID(HFI, ID); - ++NumHeaderInfos; -} - -void PCHValidator::ReadCounter(const ModuleFile &M, unsigned Value) { - PP.setCounterValue(Value); -} - -//===----------------------------------------------------------------------===// -// AST reader implementation -//===----------------------------------------------------------------------===// - -void -ASTReader::setDeserializationListener(ASTDeserializationListener *Listener) { - DeserializationListener = Listener; -} - - - -unsigned ASTSelectorLookupTrait::ComputeHash(Selector Sel) { - return serialization::ComputeHash(Sel); -} - - -std::pair<unsigned, unsigned> -ASTSelectorLookupTrait::ReadKeyDataLength(const unsigned char*& d) { - using namespace clang::io; - unsigned KeyLen = ReadUnalignedLE16(d); - unsigned DataLen = ReadUnalignedLE16(d); - return std::make_pair(KeyLen, DataLen); -} - -ASTSelectorLookupTrait::internal_key_type -ASTSelectorLookupTrait::ReadKey(const unsigned char* d, unsigned) { - using namespace clang::io; - SelectorTable &SelTable = Reader.getContext().Selectors; - unsigned N = ReadUnalignedLE16(d); - IdentifierInfo *FirstII - = Reader.getLocalIdentifier(F, ReadUnalignedLE32(d)); - if (N == 0) - return SelTable.getNullarySelector(FirstII); - else if (N == 1) - return SelTable.getUnarySelector(FirstII); - - SmallVector<IdentifierInfo *, 16> Args; - Args.push_back(FirstII); - for (unsigned I = 1; I != N; ++I) - Args.push_back(Reader.getLocalIdentifier(F, ReadUnalignedLE32(d))); - - return SelTable.getSelector(N, Args.data()); -} - -ASTSelectorLookupTrait::data_type -ASTSelectorLookupTrait::ReadData(Selector, const unsigned char* d, - unsigned DataLen) { - using namespace clang::io; - - data_type Result; - - Result.ID = Reader.getGlobalSelectorID(F, ReadUnalignedLE32(d)); - unsigned NumInstanceMethods = ReadUnalignedLE16(d); - unsigned NumFactoryMethods = ReadUnalignedLE16(d); - - // Load instance methods - for (unsigned I = 0; I != NumInstanceMethods; ++I) { - if (ObjCMethodDecl *Method - = Reader.GetLocalDeclAs<ObjCMethodDecl>(F, ReadUnalignedLE32(d))) - Result.Instance.push_back(Method); - } - - // Load factory methods - for (unsigned I = 0; I != NumFactoryMethods; ++I) { - if (ObjCMethodDecl *Method - = Reader.GetLocalDeclAs<ObjCMethodDecl>(F, ReadUnalignedLE32(d))) - Result.Factory.push_back(Method); - } - - return Result; -} - -unsigned ASTIdentifierLookupTrait::ComputeHash(const internal_key_type& a) { - return llvm::HashString(StringRef(a.first, a.second)); -} - -std::pair<unsigned, unsigned> -ASTIdentifierLookupTrait::ReadKeyDataLength(const unsigned char*& d) { - using namespace clang::io; - unsigned DataLen = ReadUnalignedLE16(d); - unsigned KeyLen = ReadUnalignedLE16(d); - return std::make_pair(KeyLen, DataLen); -} - -std::pair<const char*, unsigned> -ASTIdentifierLookupTrait::ReadKey(const unsigned char* d, unsigned n) { - assert(n >= 2 && d[n-1] == '\0'); - return std::make_pair((const char*) d, n-1); -} - -IdentifierInfo *ASTIdentifierLookupTrait::ReadData(const internal_key_type& k, - const unsigned char* d, - unsigned DataLen) { - using namespace clang::io; - unsigned RawID = ReadUnalignedLE32(d); - bool IsInteresting = RawID & 0x01; - - // Wipe out the "is interesting" bit. - RawID = RawID >> 1; - - IdentID ID = Reader.getGlobalIdentifierID(F, RawID); - if (!IsInteresting) { - // For uninteresting identifiers, just build the IdentifierInfo - // and associate it with the persistent ID. - IdentifierInfo *II = KnownII; - if (!II) { - II = &Reader.getIdentifierTable().getOwn(StringRef(k.first, k.second)); - KnownII = II; - } - Reader.SetIdentifierInfo(ID, II); - II->setIsFromAST(); - Reader.markIdentifierUpToDate(II); - return II; - } - - unsigned ObjCOrBuiltinID = ReadUnalignedLE16(d); - unsigned Bits = ReadUnalignedLE16(d); - bool CPlusPlusOperatorKeyword = Bits & 0x01; - Bits >>= 1; - bool HasRevertedTokenIDToIdentifier = Bits & 0x01; - Bits >>= 1; - bool Poisoned = Bits & 0x01; - Bits >>= 1; - bool ExtensionToken = Bits & 0x01; - Bits >>= 1; - bool hadMacroDefinition = Bits & 0x01; - Bits >>= 1; - - assert(Bits == 0 && "Extra bits in the identifier?"); - DataLen -= 8; - - // Build the IdentifierInfo itself and link the identifier ID with - // the new IdentifierInfo. - IdentifierInfo *II = KnownII; - if (!II) { - II = &Reader.getIdentifierTable().getOwn(StringRef(k.first, k.second)); - KnownII = II; - } - Reader.markIdentifierUpToDate(II); - II->setIsFromAST(); - - // Set or check the various bits in the IdentifierInfo structure. - // Token IDs are read-only. - if (HasRevertedTokenIDToIdentifier) - II->RevertTokenIDToIdentifier(); - II->setObjCOrBuiltinID(ObjCOrBuiltinID); - assert(II->isExtensionToken() == ExtensionToken && - "Incorrect extension token flag"); - (void)ExtensionToken; - if (Poisoned) - II->setIsPoisoned(true); - assert(II->isCPlusPlusOperatorKeyword() == CPlusPlusOperatorKeyword && - "Incorrect C++ operator keyword flag"); - (void)CPlusPlusOperatorKeyword; - - // If this identifier is a macro, deserialize the macro - // definition. - if (hadMacroDefinition) { - SmallVector<MacroID, 4> MacroIDs; - while (uint32_t LocalID = ReadUnalignedLE32(d)) { - MacroIDs.push_back(Reader.getGlobalMacroID(F, LocalID)); - DataLen -= 4; - } - DataLen -= 4; - Reader.setIdentifierIsMacro(II, MacroIDs); - } - - Reader.SetIdentifierInfo(ID, II); - - // Read all of the declarations visible at global scope with this - // name. - if (DataLen > 0) { - SmallVector<uint32_t, 4> DeclIDs; - for (; DataLen > 0; DataLen -= 4) - DeclIDs.push_back(Reader.getGlobalDeclID(F, ReadUnalignedLE32(d))); - Reader.SetGloballyVisibleDecls(II, DeclIDs); - } - - return II; -} - -unsigned -ASTDeclContextNameLookupTrait::ComputeHash(const DeclNameKey &Key) const { - llvm::FoldingSetNodeID ID; - ID.AddInteger(Key.Kind); - - switch (Key.Kind) { - case DeclarationName::Identifier: - case DeclarationName::CXXLiteralOperatorName: - ID.AddString(((IdentifierInfo*)Key.Data)->getName()); - break; - case DeclarationName::ObjCZeroArgSelector: - case DeclarationName::ObjCOneArgSelector: - case DeclarationName::ObjCMultiArgSelector: - ID.AddInteger(serialization::ComputeHash(Selector(Key.Data))); - break; - case DeclarationName::CXXOperatorName: - ID.AddInteger((OverloadedOperatorKind)Key.Data); - break; - case DeclarationName::CXXConstructorName: - case DeclarationName::CXXDestructorName: - case DeclarationName::CXXConversionFunctionName: - case DeclarationName::CXXUsingDirective: - break; - } - - return ID.ComputeHash(); -} - -ASTDeclContextNameLookupTrait::internal_key_type -ASTDeclContextNameLookupTrait::GetInternalKey( - const external_key_type& Name) const { - DeclNameKey Key; - Key.Kind = Name.getNameKind(); - switch (Name.getNameKind()) { - case DeclarationName::Identifier: - Key.Data = (uint64_t)Name.getAsIdentifierInfo(); - break; - case DeclarationName::ObjCZeroArgSelector: - case DeclarationName::ObjCOneArgSelector: - case DeclarationName::ObjCMultiArgSelector: - Key.Data = (uint64_t)Name.getObjCSelector().getAsOpaquePtr(); - break; - case DeclarationName::CXXOperatorName: - Key.Data = Name.getCXXOverloadedOperator(); - break; - case DeclarationName::CXXLiteralOperatorName: - Key.Data = (uint64_t)Name.getCXXLiteralIdentifier(); - break; - case DeclarationName::CXXConstructorName: - case DeclarationName::CXXDestructorName: - case DeclarationName::CXXConversionFunctionName: - case DeclarationName::CXXUsingDirective: - Key.Data = 0; - break; - } - - return Key; -} - -std::pair<unsigned, unsigned> -ASTDeclContextNameLookupTrait::ReadKeyDataLength(const unsigned char*& d) { - using namespace clang::io; - unsigned KeyLen = ReadUnalignedLE16(d); - unsigned DataLen = ReadUnalignedLE16(d); - return std::make_pair(KeyLen, DataLen); -} - -ASTDeclContextNameLookupTrait::internal_key_type -ASTDeclContextNameLookupTrait::ReadKey(const unsigned char* d, unsigned) { - using namespace clang::io; - - DeclNameKey Key; - Key.Kind = (DeclarationName::NameKind)*d++; - switch (Key.Kind) { - case DeclarationName::Identifier: - Key.Data = (uint64_t)Reader.getLocalIdentifier(F, ReadUnalignedLE32(d)); - break; - case DeclarationName::ObjCZeroArgSelector: - case DeclarationName::ObjCOneArgSelector: - case DeclarationName::ObjCMultiArgSelector: - Key.Data = - (uint64_t)Reader.getLocalSelector(F, ReadUnalignedLE32(d)) - .getAsOpaquePtr(); - break; - case DeclarationName::CXXOperatorName: - Key.Data = *d++; // OverloadedOperatorKind - break; - case DeclarationName::CXXLiteralOperatorName: - Key.Data = (uint64_t)Reader.getLocalIdentifier(F, ReadUnalignedLE32(d)); - break; - case DeclarationName::CXXConstructorName: - case DeclarationName::CXXDestructorName: - case DeclarationName::CXXConversionFunctionName: - case DeclarationName::CXXUsingDirective: - Key.Data = 0; - break; - } - - return Key; -} - -ASTDeclContextNameLookupTrait::data_type -ASTDeclContextNameLookupTrait::ReadData(internal_key_type, - const unsigned char* d, - unsigned DataLen) { - using namespace clang::io; - unsigned NumDecls = ReadUnalignedLE16(d); - LE32DeclID *Start = (LE32DeclID *)d; - return std::make_pair(Start, Start + NumDecls); -} - -bool ASTReader::ReadDeclContextStorage(ModuleFile &M, - llvm::BitstreamCursor &Cursor, - const std::pair<uint64_t, uint64_t> &Offsets, - DeclContextInfo &Info) { - SavedStreamPosition SavedPosition(Cursor); - // First the lexical decls. - if (Offsets.first != 0) { - Cursor.JumpToBit(Offsets.first); - - RecordData Record; - const char *Blob; - unsigned BlobLen; - unsigned Code = Cursor.ReadCode(); - unsigned RecCode = Cursor.ReadRecord(Code, Record, &Blob, &BlobLen); - if (RecCode != DECL_CONTEXT_LEXICAL) { - Error("Expected lexical block"); - return true; - } - - Info.LexicalDecls = reinterpret_cast<const KindDeclIDPair*>(Blob); - Info.NumLexicalDecls = BlobLen / sizeof(KindDeclIDPair); - } - - // Now the lookup table. - if (Offsets.second != 0) { - Cursor.JumpToBit(Offsets.second); - - RecordData Record; - const char *Blob; - unsigned BlobLen; - unsigned Code = Cursor.ReadCode(); - unsigned RecCode = Cursor.ReadRecord(Code, Record, &Blob, &BlobLen); - if (RecCode != DECL_CONTEXT_VISIBLE) { - Error("Expected visible lookup table block"); - return true; - } - Info.NameLookupTableData - = ASTDeclContextNameLookupTable::Create( - (const unsigned char *)Blob + Record[0], - (const unsigned char *)Blob, - ASTDeclContextNameLookupTrait(*this, M)); - } - - return false; -} - -void ASTReader::Error(StringRef Msg) { - Error(diag::err_fe_pch_malformed, Msg); -} - -void ASTReader::Error(unsigned DiagID, - StringRef Arg1, StringRef Arg2) { - if (Diags.isDiagnosticInFlight()) - Diags.SetDelayedDiagnostic(DiagID, Arg1, Arg2); - else - Diag(DiagID) << Arg1 << Arg2; -} - -//===----------------------------------------------------------------------===// -// Source Manager Deserialization -//===----------------------------------------------------------------------===// - -/// \brief Read the line table in the source manager block. -/// \returns true if there was an error. -bool ASTReader::ParseLineTable(ModuleFile &F, - SmallVectorImpl<uint64_t> &Record) { - unsigned Idx = 0; - LineTableInfo &LineTable = SourceMgr.getLineTable(); - - // Parse the file names - std::map<int, int> FileIDs; - for (int I = 0, N = Record[Idx++]; I != N; ++I) { - // Extract the file name - unsigned FilenameLen = Record[Idx++]; - std::string Filename(&Record[Idx], &Record[Idx] + FilenameLen); - Idx += FilenameLen; - MaybeAddSystemRootToFilename(F, Filename); - FileIDs[I] = LineTable.getLineTableFilenameID(Filename); - } - - // Parse the line entries - std::vector<LineEntry> Entries; - while (Idx < Record.size()) { - int FID = Record[Idx++]; - assert(FID >= 0 && "Serialized line entries for non-local file."); - // Remap FileID from 1-based old view. - FID += F.SLocEntryBaseID - 1; - - // Extract the line entries - unsigned NumEntries = Record[Idx++]; - assert(NumEntries && "Numentries is 00000"); - Entries.clear(); - Entries.reserve(NumEntries); - for (unsigned I = 0; I != NumEntries; ++I) { - unsigned FileOffset = Record[Idx++]; - unsigned LineNo = Record[Idx++]; - int FilenameID = FileIDs[Record[Idx++]]; - SrcMgr::CharacteristicKind FileKind - = (SrcMgr::CharacteristicKind)Record[Idx++]; - unsigned IncludeOffset = Record[Idx++]; - Entries.push_back(LineEntry::get(FileOffset, LineNo, FilenameID, - FileKind, IncludeOffset)); - } - LineTable.AddEntry(FileID::get(FID), Entries); - } - - return false; -} - -/// \brief Read a source manager block -bool ASTReader::ReadSourceManagerBlock(ModuleFile &F) { - using namespace SrcMgr; - - llvm::BitstreamCursor &SLocEntryCursor = F.SLocEntryCursor; - - // Set the source-location entry cursor to the current position in - // the stream. This cursor will be used to read the contents of the - // source manager block initially, and then lazily read - // source-location entries as needed. - SLocEntryCursor = F.Stream; - - // The stream itself is going to skip over the source manager block. - if (F.Stream.SkipBlock()) { - Error("malformed block record in AST file"); - return true; - } - - // Enter the source manager block. - if (SLocEntryCursor.EnterSubBlock(SOURCE_MANAGER_BLOCK_ID)) { - Error("malformed source manager block record in AST file"); - return true; - } - - RecordData Record; - while (true) { - unsigned Code = SLocEntryCursor.ReadCode(); - if (Code == llvm::bitc::END_BLOCK) { - if (SLocEntryCursor.ReadBlockEnd()) { - Error("error at end of Source Manager block in AST file"); - return true; - } - return false; - } - - if (Code == llvm::bitc::ENTER_SUBBLOCK) { - // No known subblocks, always skip them. - SLocEntryCursor.ReadSubBlockID(); - if (SLocEntryCursor.SkipBlock()) { - Error("malformed block record in AST file"); - return true; - } - continue; - } - - if (Code == llvm::bitc::DEFINE_ABBREV) { - SLocEntryCursor.ReadAbbrevRecord(); - continue; - } - - // Read a record. - const char *BlobStart; - unsigned BlobLen; - Record.clear(); - switch (SLocEntryCursor.ReadRecord(Code, Record, &BlobStart, &BlobLen)) { - default: // Default behavior: ignore. - break; - - case SM_SLOC_FILE_ENTRY: - case SM_SLOC_BUFFER_ENTRY: - case SM_SLOC_EXPANSION_ENTRY: - // Once we hit one of the source location entries, we're done. - return false; - } - } -} - -/// \brief If a header file is not found at the path that we expect it to be -/// and the PCH file was moved from its original location, try to resolve the -/// file by assuming that header+PCH were moved together and the header is in -/// the same place relative to the PCH. -static std::string -resolveFileRelativeToOriginalDir(const std::string &Filename, - const std::string &OriginalDir, - const std::string &CurrDir) { - assert(OriginalDir != CurrDir && - "No point trying to resolve the file if the PCH dir didn't change"); - using namespace llvm::sys; - SmallString<128> filePath(Filename); - fs::make_absolute(filePath); - assert(path::is_absolute(OriginalDir)); - SmallString<128> currPCHPath(CurrDir); - - path::const_iterator fileDirI = path::begin(path::parent_path(filePath)), - fileDirE = path::end(path::parent_path(filePath)); - path::const_iterator origDirI = path::begin(OriginalDir), - origDirE = path::end(OriginalDir); - // Skip the common path components from filePath and OriginalDir. - while (fileDirI != fileDirE && origDirI != origDirE && - *fileDirI == *origDirI) { - ++fileDirI; - ++origDirI; - } - for (; origDirI != origDirE; ++origDirI) - path::append(currPCHPath, ".."); - path::append(currPCHPath, fileDirI, fileDirE); - path::append(currPCHPath, path::filename(Filename)); - return currPCHPath.str(); -} - -bool ASTReader::ReadSLocEntry(int ID) { - if (ID == 0) - return false; - - if (unsigned(-ID) - 2 >= getTotalNumSLocs() || ID > 0) { - Error("source location entry ID out-of-range for AST file"); - return true; - } - - ModuleFile *F = GlobalSLocEntryMap.find(-ID)->second; - F->SLocEntryCursor.JumpToBit(F->SLocEntryOffsets[ID - F->SLocEntryBaseID]); - llvm::BitstreamCursor &SLocEntryCursor = F->SLocEntryCursor; - unsigned BaseOffset = F->SLocEntryBaseOffset; - - ++NumSLocEntriesRead; - unsigned Code = SLocEntryCursor.ReadCode(); - if (Code == llvm::bitc::END_BLOCK || - Code == llvm::bitc::ENTER_SUBBLOCK || - Code == llvm::bitc::DEFINE_ABBREV) { - Error("incorrectly-formatted source location entry in AST file"); - return true; - } - - RecordData Record; - const char *BlobStart; - unsigned BlobLen; - switch (SLocEntryCursor.ReadRecord(Code, Record, &BlobStart, &BlobLen)) { - default: - Error("incorrectly-formatted source location entry in AST file"); - return true; - - case SM_SLOC_FILE_ENTRY: { - // We will detect whether a file changed and return 'Failure' for it, but - // we will also try to fail gracefully by setting up the SLocEntry. - unsigned InputID = Record[4]; - InputFile IF = getInputFile(*F, InputID); - const FileEntry *File = IF.getPointer(); - bool OverriddenBuffer = IF.getInt(); - - if (!IF.getPointer()) - return true; - - SourceLocation IncludeLoc = ReadSourceLocation(*F, Record[1]); - if (IncludeLoc.isInvalid() && F->Kind != MK_MainFile) { - // This is the module's main file. - IncludeLoc = getImportLocation(F); - } - SrcMgr::CharacteristicKind - FileCharacter = (SrcMgr::CharacteristicKind)Record[2]; - FileID FID = SourceMgr.createFileID(File, IncludeLoc, FileCharacter, - ID, BaseOffset + Record[0]); - SrcMgr::FileInfo &FileInfo = - const_cast<SrcMgr::FileInfo&>(SourceMgr.getSLocEntry(FID).getFile()); - FileInfo.NumCreatedFIDs = Record[5]; - if (Record[3]) - FileInfo.setHasLineDirectives(); - - const DeclID *FirstDecl = F->FileSortedDecls + Record[6]; - unsigned NumFileDecls = Record[7]; - if (NumFileDecls) { - assert(F->FileSortedDecls && "FILE_SORTED_DECLS not encountered yet ?"); - FileDeclIDs[FID] = FileDeclsInfo(F, llvm::makeArrayRef(FirstDecl, - NumFileDecls)); - } - - const SrcMgr::ContentCache *ContentCache - = SourceMgr.getOrCreateContentCache(File, - /*isSystemFile=*/FileCharacter != SrcMgr::C_User); - if (OverriddenBuffer && !ContentCache->BufferOverridden && - ContentCache->ContentsEntry == ContentCache->OrigEntry) { - unsigned Code = SLocEntryCursor.ReadCode(); - Record.clear(); - unsigned RecCode - = SLocEntryCursor.ReadRecord(Code, Record, &BlobStart, &BlobLen); - - if (RecCode != SM_SLOC_BUFFER_BLOB) { - Error("AST record has invalid code"); - return true; - } - - llvm::MemoryBuffer *Buffer - = llvm::MemoryBuffer::getMemBuffer(StringRef(BlobStart, BlobLen - 1), - File->getName()); - SourceMgr.overrideFileContents(File, Buffer); - } - - break; - } - - case SM_SLOC_BUFFER_ENTRY: { - const char *Name = BlobStart; - unsigned Offset = Record[0]; - SrcMgr::CharacteristicKind - FileCharacter = (SrcMgr::CharacteristicKind)Record[2]; - SourceLocation IncludeLoc = ReadSourceLocation(*F, Record[1]); - if (IncludeLoc.isInvalid() && F->Kind == MK_Module) { - IncludeLoc = getImportLocation(F); - } - unsigned Code = SLocEntryCursor.ReadCode(); - Record.clear(); - unsigned RecCode - = SLocEntryCursor.ReadRecord(Code, Record, &BlobStart, &BlobLen); - - if (RecCode != SM_SLOC_BUFFER_BLOB) { - Error("AST record has invalid code"); - return true; - } - - llvm::MemoryBuffer *Buffer - = llvm::MemoryBuffer::getMemBuffer(StringRef(BlobStart, BlobLen - 1), - Name); - SourceMgr.createFileIDForMemBuffer(Buffer, FileCharacter, ID, - BaseOffset + Offset, IncludeLoc); - break; - } - - case SM_SLOC_EXPANSION_ENTRY: { - SourceLocation SpellingLoc = ReadSourceLocation(*F, Record[1]); - SourceMgr.createExpansionLoc(SpellingLoc, - ReadSourceLocation(*F, Record[2]), - ReadSourceLocation(*F, Record[3]), - Record[4], - ID, - BaseOffset + Record[0]); - break; - } - } - - return false; -} - -std::pair<SourceLocation, StringRef> ASTReader::getModuleImportLoc(int ID) { - if (ID == 0) - return std::make_pair(SourceLocation(), ""); - - if (unsigned(-ID) - 2 >= getTotalNumSLocs() || ID > 0) { - Error("source location entry ID out-of-range for AST file"); - return std::make_pair(SourceLocation(), ""); - } - - // Find which module file this entry lands in. - ModuleFile *M = GlobalSLocEntryMap.find(-ID)->second; - if (M->Kind != MK_Module) - return std::make_pair(SourceLocation(), ""); - - // FIXME: Can we map this down to a particular submodule? That would be - // ideal. - return std::make_pair(M->ImportLoc, llvm::sys::path::stem(M->FileName)); -} - -/// \brief Find the location where the module F is imported. -SourceLocation ASTReader::getImportLocation(ModuleFile *F) { - if (F->ImportLoc.isValid()) - return F->ImportLoc; - - // Otherwise we have a PCH. It's considered to be "imported" at the first - // location of its includer. - if (F->ImportedBy.empty() || !F->ImportedBy[0]) { - // Main file is the importer. We assume that it is the first entry in the - // entry table. We can't ask the manager, because at the time of PCH loading - // the main file entry doesn't exist yet. - // The very first entry is the invalid instantiation loc, which takes up - // offsets 0 and 1. - return SourceLocation::getFromRawEncoding(2U); - } - //return F->Loaders[0]->FirstLoc; - return F->ImportedBy[0]->FirstLoc; -} - -/// ReadBlockAbbrevs - Enter a subblock of the specified BlockID with the -/// specified cursor. Read the abbreviations that are at the top of the block -/// and then leave the cursor pointing into the block. -bool ASTReader::ReadBlockAbbrevs(llvm::BitstreamCursor &Cursor, - unsigned BlockID) { - if (Cursor.EnterSubBlock(BlockID)) { - Error("malformed block record in AST file"); - return Failure; - } - - while (true) { - uint64_t Offset = Cursor.GetCurrentBitNo(); - unsigned Code = Cursor.ReadCode(); - - // We expect all abbrevs to be at the start of the block. - if (Code != llvm::bitc::DEFINE_ABBREV) { - Cursor.JumpToBit(Offset); - return false; - } - Cursor.ReadAbbrevRecord(); - } -} - -void ASTReader::ReadMacroRecord(ModuleFile &F, uint64_t Offset, - MacroInfo *Hint) { - llvm::BitstreamCursor &Stream = F.MacroCursor; - - // Keep track of where we are in the stream, then jump back there - // after reading this macro. - SavedStreamPosition SavedPosition(Stream); - - Stream.JumpToBit(Offset); - RecordData Record; - SmallVector<IdentifierInfo*, 16> MacroArgs; - MacroInfo *Macro = 0; - - // RAII object to add the loaded macro information once we're done - // adding tokens. - struct AddLoadedMacroInfoRAII { - Preprocessor &PP; - MacroInfo *Hint; - MacroInfo *MI; - IdentifierInfo *II; - - AddLoadedMacroInfoRAII(Preprocessor &PP, MacroInfo *Hint) - : PP(PP), Hint(Hint), MI(), II() { } - ~AddLoadedMacroInfoRAII( ) { - if (MI) { - // Finally, install the macro. - PP.addLoadedMacroInfo(II, MI, Hint); - } - } - } AddLoadedMacroInfo(PP, Hint); - - while (true) { - unsigned Code = Stream.ReadCode(); - switch (Code) { - case llvm::bitc::END_BLOCK: - return; - - case llvm::bitc::ENTER_SUBBLOCK: - // No known subblocks, always skip them. - Stream.ReadSubBlockID(); - if (Stream.SkipBlock()) { - Error("malformed block record in AST file"); - return; - } - continue; - - case llvm::bitc::DEFINE_ABBREV: - Stream.ReadAbbrevRecord(); - continue; - default: break; - } - - // Read a record. - const char *BlobStart = 0; - unsigned BlobLen = 0; - Record.clear(); - PreprocessorRecordTypes RecType = - (PreprocessorRecordTypes)Stream.ReadRecord(Code, Record, BlobStart, - BlobLen); - switch (RecType) { - case PP_MACRO_OBJECT_LIKE: - case PP_MACRO_FUNCTION_LIKE: { - // If we already have a macro, that means that we've hit the end - // of the definition of the macro we were looking for. We're - // done. - if (Macro) - return; - - IdentifierInfo *II = getLocalIdentifier(F, Record[0]); - if (II == 0) { - Error("macro must have a name in AST file"); - return; - } - - unsigned GlobalID = getGlobalMacroID(F, Record[1]); - - // If this macro has already been loaded, don't do so again. - if (MacrosLoaded[GlobalID - NUM_PREDEF_MACRO_IDS]) - return; - - SubmoduleID GlobalSubmoduleID = getGlobalSubmoduleID(F, Record[2]); - unsigned NextIndex = 3; - SourceLocation Loc = ReadSourceLocation(F, Record, NextIndex); - MacroInfo *MI = PP.AllocateMacroInfo(Loc); - - // Record this macro. - MacrosLoaded[GlobalID - NUM_PREDEF_MACRO_IDS] = MI; - - SourceLocation UndefLoc = ReadSourceLocation(F, Record, NextIndex); - if (UndefLoc.isValid()) - MI->setUndefLoc(UndefLoc); - - MI->setIsUsed(Record[NextIndex++]); - MI->setIsFromAST(); - - bool IsPublic = Record[NextIndex++]; - MI->setVisibility(IsPublic, ReadSourceLocation(F, Record, NextIndex)); - - if (RecType == PP_MACRO_FUNCTION_LIKE) { - // Decode function-like macro info. - bool isC99VarArgs = Record[NextIndex++]; - bool isGNUVarArgs = Record[NextIndex++]; - bool hasCommaPasting = Record[NextIndex++]; - MacroArgs.clear(); - unsigned NumArgs = Record[NextIndex++]; - for (unsigned i = 0; i != NumArgs; ++i) - MacroArgs.push_back(getLocalIdentifier(F, Record[NextIndex++])); - - // Install function-like macro info. - MI->setIsFunctionLike(); - if (isC99VarArgs) MI->setIsC99Varargs(); - if (isGNUVarArgs) MI->setIsGNUVarargs(); - if (hasCommaPasting) MI->setHasCommaPasting(); - MI->setArgumentList(MacroArgs.data(), MacroArgs.size(), - PP.getPreprocessorAllocator()); - } - - if (DeserializationListener) - DeserializationListener->MacroRead(GlobalID, MI); - - // If an update record marked this as undefined, do so now. - // FIXME: Only if the submodule this update came from is visible? - MacroUpdatesMap::iterator Update = MacroUpdates.find(GlobalID); - if (Update != MacroUpdates.end()) { - if (MI->getUndefLoc().isInvalid()) { - for (unsigned I = 0, N = Update->second.size(); I != N; ++I) { - bool Hidden = false; - if (unsigned SubmoduleID = Update->second[I].first) { - if (Module *Owner = getSubmodule(SubmoduleID)) { - if (Owner->NameVisibility == Module::Hidden) { - // Note that this #undef is hidden. - Hidden = true; - - // Record this hiding for later. - HiddenNamesMap[Owner].push_back( - HiddenName(II, MI, Update->second[I].second.UndefLoc)); - } - } - } - - if (!Hidden) { - MI->setUndefLoc(Update->second[I].second.UndefLoc); - if (PPMutationListener *Listener = PP.getPPMutationListener()) - Listener->UndefinedMacro(MI); - break; - } - } - } - MacroUpdates.erase(Update); - } - - // Determine whether this macro definition is visible. - bool Hidden = !MI->isPublic(); - if (!Hidden && GlobalSubmoduleID) { - if (Module *Owner = getSubmodule(GlobalSubmoduleID)) { - if (Owner->NameVisibility == Module::Hidden) { - // The owning module is not visible, and this macro definition - // should not be, either. - Hidden = true; - - // Note that this macro definition was hidden because its owning - // module is not yet visible. - HiddenNamesMap[Owner].push_back(HiddenName(II, MI)); - } - } - } - MI->setHidden(Hidden); - - // Make sure we install the macro once we're done. - AddLoadedMacroInfo.MI = MI; - AddLoadedMacroInfo.II = II; - - // Remember that we saw this macro last so that we add the tokens that - // form its body to it. - Macro = MI; - - if (NextIndex + 1 == Record.size() && PP.getPreprocessingRecord() && - Record[NextIndex]) { - // We have a macro definition. Register the association - PreprocessedEntityID - GlobalID = getGlobalPreprocessedEntityID(F, Record[NextIndex]); - PreprocessingRecord &PPRec = *PP.getPreprocessingRecord(); - PPRec.RegisterMacroDefinition(Macro, - PPRec.getPPEntityID(GlobalID-1, /*isLoaded=*/true)); - } - - ++NumMacrosRead; - break; - } - - case PP_TOKEN: { - // If we see a TOKEN before a PP_MACRO_*, then the file is - // erroneous, just pretend we didn't see this. - if (Macro == 0) break; - - Token Tok; - Tok.startToken(); - Tok.setLocation(ReadSourceLocation(F, Record[0])); - Tok.setLength(Record[1]); - if (IdentifierInfo *II = getLocalIdentifier(F, Record[2])) - Tok.setIdentifierInfo(II); - Tok.setKind((tok::TokenKind)Record[3]); - Tok.setFlag((Token::TokenFlags)Record[4]); - Macro->AddTokenToBody(Tok); - break; - } - } - } -} - -PreprocessedEntityID -ASTReader::getGlobalPreprocessedEntityID(ModuleFile &M, unsigned LocalID) const { - ContinuousRangeMap<uint32_t, int, 2>::const_iterator - I = M.PreprocessedEntityRemap.find(LocalID - NUM_PREDEF_PP_ENTITY_IDS); - assert(I != M.PreprocessedEntityRemap.end() - && "Invalid index into preprocessed entity index remap"); - - return LocalID + I->second; -} - -unsigned HeaderFileInfoTrait::ComputeHash(const char *path) { - return llvm::HashString(llvm::sys::path::filename(path)); -} - -HeaderFileInfoTrait::internal_key_type -HeaderFileInfoTrait::GetInternalKey(const char *path) { return path; } - -bool HeaderFileInfoTrait::EqualKey(internal_key_type a, internal_key_type b) { - if (strcmp(a, b) == 0) - return true; - - if (llvm::sys::path::filename(a) != llvm::sys::path::filename(b)) - return false; - - // Determine whether the actual files are equivalent. - bool Result = false; - if (llvm::sys::fs::equivalent(a, b, Result)) - return false; - - return Result; -} - -std::pair<unsigned, unsigned> -HeaderFileInfoTrait::ReadKeyDataLength(const unsigned char*& d) { - unsigned KeyLen = (unsigned) clang::io::ReadUnalignedLE16(d); - unsigned DataLen = (unsigned) *d++; - return std::make_pair(KeyLen + 1, DataLen); -} - -HeaderFileInfoTrait::data_type -HeaderFileInfoTrait::ReadData(const internal_key_type, const unsigned char *d, - unsigned DataLen) { - const unsigned char *End = d + DataLen; - using namespace clang::io; - HeaderFileInfo HFI; - unsigned Flags = *d++; - HFI.isImport = (Flags >> 5) & 0x01; - HFI.isPragmaOnce = (Flags >> 4) & 0x01; - HFI.DirInfo = (Flags >> 2) & 0x03; - HFI.Resolved = (Flags >> 1) & 0x01; - HFI.IndexHeaderMapHeader = Flags & 0x01; - HFI.NumIncludes = ReadUnalignedLE16(d); - HFI.ControllingMacroID = Reader.getGlobalIdentifierID(M, - ReadUnalignedLE32(d)); - if (unsigned FrameworkOffset = ReadUnalignedLE32(d)) { - // The framework offset is 1 greater than the actual offset, - // since 0 is used as an indicator for "no framework name". - StringRef FrameworkName(FrameworkStrings + FrameworkOffset - 1); - HFI.Framework = HS->getUniqueFrameworkName(FrameworkName); - } - - assert(End == d && "Wrong data length in HeaderFileInfo deserialization"); - (void)End; - - // This HeaderFileInfo was externally loaded. - HFI.External = true; - return HFI; -} - -void ASTReader::setIdentifierIsMacro(IdentifierInfo *II, ArrayRef<MacroID> IDs){ - II->setHadMacroDefinition(true); - assert(NumCurrentElementsDeserializing > 0 &&"Missing deserialization guard"); - PendingMacroIDs[II].append(IDs.begin(), IDs.end()); -} - -void ASTReader::ReadDefinedMacros() { - // Note that we are loading defined macros. - Deserializing Macros(this); - - for (ModuleReverseIterator I = ModuleMgr.rbegin(), - E = ModuleMgr.rend(); I != E; ++I) { - llvm::BitstreamCursor &MacroCursor = (*I)->MacroCursor; - - // If there was no preprocessor block, skip this file. - if (!MacroCursor.getBitStreamReader()) - continue; - - llvm::BitstreamCursor Cursor = MacroCursor; - Cursor.JumpToBit((*I)->MacroStartOffset); - - RecordData Record; - while (true) { - unsigned Code = Cursor.ReadCode(); - if (Code == llvm::bitc::END_BLOCK) - break; - - if (Code == llvm::bitc::ENTER_SUBBLOCK) { - // No known subblocks, always skip them. - Cursor.ReadSubBlockID(); - if (Cursor.SkipBlock()) { - Error("malformed block record in AST file"); - return; - } - continue; - } - - if (Code == llvm::bitc::DEFINE_ABBREV) { - Cursor.ReadAbbrevRecord(); - continue; - } - - // Read a record. - const char *BlobStart; - unsigned BlobLen; - Record.clear(); - switch (Cursor.ReadRecord(Code, Record, &BlobStart, &BlobLen)) { - default: // Default behavior: ignore. - break; - - case PP_MACRO_OBJECT_LIKE: - case PP_MACRO_FUNCTION_LIKE: - getLocalIdentifier(**I, Record[0]); - break; - - case PP_TOKEN: - // Ignore tokens. - break; - } - } - } -} - -namespace { - /// \brief Visitor class used to look up identifirs in an AST file. - class IdentifierLookupVisitor { - StringRef Name; - unsigned PriorGeneration; - IdentifierInfo *Found; - public: - IdentifierLookupVisitor(StringRef Name, unsigned PriorGeneration) - : Name(Name), PriorGeneration(PriorGeneration), Found() { } - - static bool visit(ModuleFile &M, void *UserData) { - IdentifierLookupVisitor *This - = static_cast<IdentifierLookupVisitor *>(UserData); - - // If we've already searched this module file, skip it now. - if (M.Generation <= This->PriorGeneration) - return true; - - ASTIdentifierLookupTable *IdTable - = (ASTIdentifierLookupTable *)M.IdentifierLookupTable; - if (!IdTable) - return false; - - ASTIdentifierLookupTrait Trait(IdTable->getInfoObj().getReader(), - M, This->Found); - - std::pair<const char*, unsigned> Key(This->Name.begin(), - This->Name.size()); - ASTIdentifierLookupTable::iterator Pos = IdTable->find(Key, &Trait); - if (Pos == IdTable->end()) - return false; - - // Dereferencing the iterator has the effect of building the - // IdentifierInfo node and populating it with the various - // declarations it needs. - This->Found = *Pos; - return true; - } - - // \brief Retrieve the identifier info found within the module - // files. - IdentifierInfo *getIdentifierInfo() const { return Found; } - }; -} - -void ASTReader::updateOutOfDateIdentifier(IdentifierInfo &II) { - // Note that we are loading an identifier. - Deserializing AnIdentifier(this); - - unsigned PriorGeneration = 0; - if (getContext().getLangOpts().Modules) - PriorGeneration = IdentifierGeneration[&II]; - - IdentifierLookupVisitor Visitor(II.getName(), PriorGeneration); - ModuleMgr.visit(IdentifierLookupVisitor::visit, &Visitor); - markIdentifierUpToDate(&II); -} - -void ASTReader::markIdentifierUpToDate(IdentifierInfo *II) { - if (!II) - return; - - II->setOutOfDate(false); - - // Update the generation for this identifier. - if (getContext().getLangOpts().Modules) - IdentifierGeneration[II] = CurrentGeneration; -} - -llvm::PointerIntPair<const FileEntry *, 1, bool> -ASTReader::getInputFile(ModuleFile &F, unsigned ID, bool Complain) { - // If this ID is bogus, just return an empty input file. - if (ID == 0 || ID > F.InputFilesLoaded.size()) - return InputFile(); - - // If we've already loaded this input file, return it. - if (F.InputFilesLoaded[ID-1].getPointer()) - return F.InputFilesLoaded[ID-1]; - - // Go find this input file. - llvm::BitstreamCursor &Cursor = F.InputFilesCursor; - SavedStreamPosition SavedPosition(Cursor); - Cursor.JumpToBit(F.InputFileOffsets[ID-1]); - - unsigned Code = Cursor.ReadCode(); - RecordData Record; - const char *BlobStart = 0; - unsigned BlobLen = 0; - switch ((InputFileRecordTypes)Cursor.ReadRecord(Code, Record, - &BlobStart, &BlobLen)) { - case INPUT_FILE: { - unsigned StoredID = Record[0]; - assert(ID == StoredID && "Bogus stored ID or offset"); - (void)StoredID; - off_t StoredSize = (off_t)Record[1]; - time_t StoredTime = (time_t)Record[2]; - bool Overridden = (bool)Record[3]; - - // Get the file entry for this input file. - StringRef OrigFilename(BlobStart, BlobLen); - std::string Filename = OrigFilename; - MaybeAddSystemRootToFilename(F, Filename); - const FileEntry *File - = Overridden? FileMgr.getVirtualFile(Filename, StoredSize, StoredTime) - : FileMgr.getFile(Filename, /*OpenFile=*/false); - - // If we didn't find the file, resolve it relative to the - // original directory from which this AST file was created. - if (File == 0 && !F.OriginalDir.empty() && !CurrentDir.empty() && - F.OriginalDir != CurrentDir) { - std::string Resolved = resolveFileRelativeToOriginalDir(Filename, - F.OriginalDir, - CurrentDir); - if (!Resolved.empty()) - File = FileMgr.getFile(Resolved); - } - - // For an overridden file, create a virtual file with the stored - // size/timestamp. - if (Overridden && File == 0) { - File = FileMgr.getVirtualFile(Filename, StoredSize, StoredTime); - } - - if (File == 0) { - if (Complain) { - std::string ErrorStr = "could not find file '"; - ErrorStr += Filename; - ErrorStr += "' referenced by AST file"; - Error(ErrorStr.c_str()); - } - return InputFile(); - } - - // Note that we've loaded this input file. - F.InputFilesLoaded[ID-1] = InputFile(File, Overridden); - - // Check if there was a request to override the contents of the file - // that was part of the precompiled header. Overridding such a file - // can lead to problems when lexing using the source locations from the - // PCH. - SourceManager &SM = getSourceManager(); - if (!Overridden && SM.isFileOverridden(File)) { - Error(diag::err_fe_pch_file_overridden, Filename); - // After emitting the diagnostic, recover by disabling the override so - // that the original file will be used. - SM.disableFileContentsOverride(File); - // The FileEntry is a virtual file entry with the size of the contents - // that would override the original contents. Set it to the original's - // size/time. - FileMgr.modifyFileEntry(const_cast<FileEntry*>(File), - StoredSize, StoredTime); - } - - // For an overridden file, there is nothing to validate. - if (Overridden) - return InputFile(File, Overridden); - - if ((StoredSize != File->getSize() -#if !defined(LLVM_ON_WIN32) - // In our regression testing, the Windows file system seems to - // have inconsistent modification times that sometimes - // erroneously trigger this error-handling path. - || StoredTime != File->getModificationTime() -#endif - )) { - if (Complain) - Error(diag::err_fe_pch_file_modified, Filename); - - return InputFile(); - } - - return InputFile(File, Overridden); - } - } - - return InputFile(); -} - -const FileEntry *ASTReader::getFileEntry(StringRef filenameStrRef) { - ModuleFile &M = ModuleMgr.getPrimaryModule(); - std::string Filename = filenameStrRef; - MaybeAddSystemRootToFilename(M, Filename); - const FileEntry *File = FileMgr.getFile(Filename); - if (File == 0 && !M.OriginalDir.empty() && !CurrentDir.empty() && - M.OriginalDir != CurrentDir) { - std::string resolved = resolveFileRelativeToOriginalDir(Filename, - M.OriginalDir, - CurrentDir); - if (!resolved.empty()) - File = FileMgr.getFile(resolved); - } - - return File; -} - -/// \brief If we are loading a relocatable PCH file, and the filename is -/// not an absolute path, add the system root to the beginning of the file -/// name. -void ASTReader::MaybeAddSystemRootToFilename(ModuleFile &M, - std::string &Filename) { - // If this is not a relocatable PCH file, there's nothing to do. - if (!M.RelocatablePCH) - return; - - if (Filename.empty() || llvm::sys::path::is_absolute(Filename)) - return; - - if (isysroot.empty()) { - // If no system root was given, default to '/' - Filename.insert(Filename.begin(), '/'); - return; - } - - unsigned Length = isysroot.size(); - if (isysroot[Length - 1] != '/') - Filename.insert(Filename.begin(), '/'); - - Filename.insert(Filename.begin(), isysroot.begin(), isysroot.end()); -} - -ASTReader::ASTReadResult -ASTReader::ReadControlBlock(ModuleFile &F, - llvm::SmallVectorImpl<ImportedModule> &Loaded, - unsigned ClientLoadCapabilities) { - llvm::BitstreamCursor &Stream = F.Stream; - - if (Stream.EnterSubBlock(CONTROL_BLOCK_ID)) { - Error("malformed block record in AST file"); - return Failure; - } - - // Read all of the records and blocks in the control block. - RecordData Record; - while (!Stream.AtEndOfStream()) { - unsigned Code = Stream.ReadCode(); - if (Code == llvm::bitc::END_BLOCK) { - if (Stream.ReadBlockEnd()) { - Error("error at end of control block in AST file"); - return Failure; - } - - // Validate all of the input files. - if (!DisableValidation) { - bool Complain = (ClientLoadCapabilities & ARR_OutOfDate) == 0; - for (unsigned I = 0, N = Record[0]; I < N; ++I) - if (!getInputFile(F, I+1, Complain).getPointer()) - return OutOfDate; - } - - return Success; - } - - if (Code == llvm::bitc::ENTER_SUBBLOCK) { - switch (Stream.ReadSubBlockID()) { - case INPUT_FILES_BLOCK_ID: - F.InputFilesCursor = Stream; - if (Stream.SkipBlock() || // Skip with the main cursor - // Read the abbreviations - ReadBlockAbbrevs(F.InputFilesCursor, INPUT_FILES_BLOCK_ID)) { - Error("malformed block record in AST file"); - return Failure; - } - continue; - - default: - if (!Stream.SkipBlock()) - continue; - break; - } - - Error("malformed block record in AST file"); - return Failure; - } - - if (Code == llvm::bitc::DEFINE_ABBREV) { - Stream.ReadAbbrevRecord(); - continue; - } - - // Read and process a record. - Record.clear(); - const char *BlobStart = 0; - unsigned BlobLen = 0; - switch ((ControlRecordTypes)Stream.ReadRecord(Code, Record, - &BlobStart, &BlobLen)) { - case METADATA: { - if (Record[0] != VERSION_MAJOR && !DisableValidation) { - if ((ClientLoadCapabilities & ARR_VersionMismatch) == 0) - Diag(Record[0] < VERSION_MAJOR? diag::warn_pch_version_too_old - : diag::warn_pch_version_too_new); - return VersionMismatch; - } - - bool hasErrors = Record[5]; - if (hasErrors && !DisableValidation && !AllowASTWithCompilerErrors) { - Diag(diag::err_pch_with_compiler_errors); - return HadErrors; - } - - F.RelocatablePCH = Record[4]; - - const std::string &CurBranch = getClangFullRepositoryVersion(); - StringRef ASTBranch(BlobStart, BlobLen); - if (StringRef(CurBranch) != ASTBranch && !DisableValidation) { - if ((ClientLoadCapabilities & ARR_VersionMismatch) == 0) - Diag(diag::warn_pch_different_branch) << ASTBranch << CurBranch; - return VersionMismatch; - } - break; - } - - case IMPORTS: { - // Load each of the imported PCH files. - unsigned Idx = 0, N = Record.size(); - while (Idx < N) { - // Read information about the AST file. - ModuleKind ImportedKind = (ModuleKind)Record[Idx++]; - // The import location will be the local one for now; we will adjust - // all import locations of module imports after the global source - // location info are setup. - SourceLocation ImportLoc = - SourceLocation::getFromRawEncoding(Record[Idx++]); - unsigned Length = Record[Idx++]; - SmallString<128> ImportedFile(Record.begin() + Idx, - Record.begin() + Idx + Length); - Idx += Length; - - // Load the AST file. - switch(ReadASTCore(ImportedFile, ImportedKind, ImportLoc, &F, Loaded, - ClientLoadCapabilities)) { - case Failure: return Failure; - // If we have to ignore the dependency, we'll have to ignore this too. - case OutOfDate: return OutOfDate; - case VersionMismatch: return VersionMismatch; - case ConfigurationMismatch: return ConfigurationMismatch; - case HadErrors: return HadErrors; - case Success: break; - } - } - break; - } - - case LANGUAGE_OPTIONS: { - bool Complain = (ClientLoadCapabilities & ARR_ConfigurationMismatch) == 0; - if (Listener && &F == *ModuleMgr.begin() && - ParseLanguageOptions(Record, Complain, *Listener) && - !DisableValidation) - return ConfigurationMismatch; - break; - } - - case TARGET_OPTIONS: { - bool Complain = (ClientLoadCapabilities & ARR_ConfigurationMismatch)==0; - if (Listener && &F == *ModuleMgr.begin() && - ParseTargetOptions(Record, Complain, *Listener) && - !DisableValidation) - return ConfigurationMismatch; - break; - } - - case DIAGNOSTIC_OPTIONS: { - bool Complain = (ClientLoadCapabilities & ARR_ConfigurationMismatch)==0; - if (Listener && &F == *ModuleMgr.begin() && - ParseDiagnosticOptions(Record, Complain, *Listener) && - !DisableValidation) - return ConfigurationMismatch; - break; - } - - case FILE_SYSTEM_OPTIONS: { - bool Complain = (ClientLoadCapabilities & ARR_ConfigurationMismatch)==0; - if (Listener && &F == *ModuleMgr.begin() && - ParseFileSystemOptions(Record, Complain, *Listener) && - !DisableValidation) - return ConfigurationMismatch; - break; - } - - case HEADER_SEARCH_OPTIONS: { - bool Complain = (ClientLoadCapabilities & ARR_ConfigurationMismatch)==0; - if (Listener && &F == *ModuleMgr.begin() && - ParseHeaderSearchOptions(Record, Complain, *Listener) && - !DisableValidation) - return ConfigurationMismatch; - break; - } - - case PREPROCESSOR_OPTIONS: { - bool Complain = (ClientLoadCapabilities & ARR_ConfigurationMismatch)==0; - if (Listener && &F == *ModuleMgr.begin() && - ParsePreprocessorOptions(Record, Complain, *Listener, - SuggestedPredefines) && - !DisableValidation) - return ConfigurationMismatch; - break; - } - - case ORIGINAL_FILE: - F.OriginalSourceFileID = FileID::get(Record[0]); - F.ActualOriginalSourceFileName.assign(BlobStart, BlobLen); - F.OriginalSourceFileName = F.ActualOriginalSourceFileName; - MaybeAddSystemRootToFilename(F, F.OriginalSourceFileName); - break; - - case ORIGINAL_FILE_ID: - F.OriginalSourceFileID = FileID::get(Record[0]); - break; - - case ORIGINAL_PCH_DIR: - F.OriginalDir.assign(BlobStart, BlobLen); - break; - - case INPUT_FILE_OFFSETS: - F.InputFileOffsets = (const uint32_t *)BlobStart; - F.InputFilesLoaded.resize(Record[0]); - break; - } - } - - Error("premature end of bitstream in AST file"); - return Failure; -} - -bool ASTReader::ReadASTBlock(ModuleFile &F) { - llvm::BitstreamCursor &Stream = F.Stream; - - if (Stream.EnterSubBlock(AST_BLOCK_ID)) { - Error("malformed block record in AST file"); - return true; - } - - // Read all of the records and blocks for the AST file. - RecordData Record; - while (!Stream.AtEndOfStream()) { - unsigned Code = Stream.ReadCode(); - if (Code == llvm::bitc::END_BLOCK) { - if (Stream.ReadBlockEnd()) { - Error("error at end of module block in AST file"); - return true; - } - - DeclContext *DC = Context.getTranslationUnitDecl(); - if (!DC->hasExternalVisibleStorage() && DC->hasExternalLexicalStorage()) - DC->setMustBuildLookupTable(); - - return false; - } - - if (Code == llvm::bitc::ENTER_SUBBLOCK) { - switch (Stream.ReadSubBlockID()) { - case DECLTYPES_BLOCK_ID: - // We lazily load the decls block, but we want to set up the - // DeclsCursor cursor to point into it. Clone our current bitcode - // cursor to it, enter the block and read the abbrevs in that block. - // With the main cursor, we just skip over it. - F.DeclsCursor = Stream; - if (Stream.SkipBlock() || // Skip with the main cursor. - // Read the abbrevs. - ReadBlockAbbrevs(F.DeclsCursor, DECLTYPES_BLOCK_ID)) { - Error("malformed block record in AST file"); - return true; - } - break; - - case DECL_UPDATES_BLOCK_ID: - if (Stream.SkipBlock()) { - Error("malformed block record in AST file"); - return true; - } - break; - - case PREPROCESSOR_BLOCK_ID: - F.MacroCursor = Stream; - if (!PP.getExternalSource()) - PP.setExternalSource(this); - - if (Stream.SkipBlock() || - ReadBlockAbbrevs(F.MacroCursor, PREPROCESSOR_BLOCK_ID)) { - Error("malformed block record in AST file"); - return true; - } - F.MacroStartOffset = F.MacroCursor.GetCurrentBitNo(); - break; - - case PREPROCESSOR_DETAIL_BLOCK_ID: - F.PreprocessorDetailCursor = Stream; - if (Stream.SkipBlock() || - ReadBlockAbbrevs(F.PreprocessorDetailCursor, - PREPROCESSOR_DETAIL_BLOCK_ID)) { - Error("malformed preprocessor detail record in AST file"); - return true; - } - F.PreprocessorDetailStartOffset - = F.PreprocessorDetailCursor.GetCurrentBitNo(); - - if (!PP.getPreprocessingRecord()) - PP.createPreprocessingRecord(); - if (!PP.getPreprocessingRecord()->getExternalSource()) - PP.getPreprocessingRecord()->SetExternalSource(*this); - break; - - case SOURCE_MANAGER_BLOCK_ID: - if (ReadSourceManagerBlock(F)) - return true; - break; - - case SUBMODULE_BLOCK_ID: - if (ReadSubmoduleBlock(F)) - return true; - break; - - case COMMENTS_BLOCK_ID: { - llvm::BitstreamCursor C = Stream; - if (Stream.SkipBlock() || - ReadBlockAbbrevs(C, COMMENTS_BLOCK_ID)) { - Error("malformed comments block in AST file"); - return true; - } - CommentsCursors.push_back(std::make_pair(C, &F)); - break; - } - - default: - if (!Stream.SkipBlock()) - break; - Error("malformed block record in AST file"); - return true; - } - continue; - } - - if (Code == llvm::bitc::DEFINE_ABBREV) { - Stream.ReadAbbrevRecord(); - continue; - } - - // Read and process a record. - Record.clear(); - const char *BlobStart = 0; - unsigned BlobLen = 0; - switch ((ASTRecordTypes)Stream.ReadRecord(Code, Record, - &BlobStart, &BlobLen)) { - default: // Default behavior: ignore. - break; - - case TYPE_OFFSET: { - if (F.LocalNumTypes != 0) { - Error("duplicate TYPE_OFFSET record in AST file"); - return true; - } - F.TypeOffsets = (const uint32_t *)BlobStart; - F.LocalNumTypes = Record[0]; - unsigned LocalBaseTypeIndex = Record[1]; - F.BaseTypeIndex = getTotalNumTypes(); - - if (F.LocalNumTypes > 0) { - // Introduce the global -> local mapping for types within this module. - GlobalTypeMap.insert(std::make_pair(getTotalNumTypes(), &F)); - - // Introduce the local -> global mapping for types within this module. - F.TypeRemap.insertOrReplace( - std::make_pair(LocalBaseTypeIndex, - F.BaseTypeIndex - LocalBaseTypeIndex)); - - TypesLoaded.resize(TypesLoaded.size() + F.LocalNumTypes); - } - break; - } - - case DECL_OFFSET: { - if (F.LocalNumDecls != 0) { - Error("duplicate DECL_OFFSET record in AST file"); - return true; - } - F.DeclOffsets = (const DeclOffset *)BlobStart; - F.LocalNumDecls = Record[0]; - unsigned LocalBaseDeclID = Record[1]; - F.BaseDeclID = getTotalNumDecls(); - - if (F.LocalNumDecls > 0) { - // Introduce the global -> local mapping for declarations within this - // module. - GlobalDeclMap.insert( - std::make_pair(getTotalNumDecls() + NUM_PREDEF_DECL_IDS, &F)); - - // Introduce the local -> global mapping for declarations within this - // module. - F.DeclRemap.insertOrReplace( - std::make_pair(LocalBaseDeclID, F.BaseDeclID - LocalBaseDeclID)); - - // Introduce the global -> local mapping for declarations within this - // module. - F.GlobalToLocalDeclIDs[&F] = LocalBaseDeclID; - - DeclsLoaded.resize(DeclsLoaded.size() + F.LocalNumDecls); - } - break; - } - - case TU_UPDATE_LEXICAL: { - DeclContext *TU = Context.getTranslationUnitDecl(); - DeclContextInfo &Info = F.DeclContextInfos[TU]; - Info.LexicalDecls = reinterpret_cast<const KindDeclIDPair *>(BlobStart); - Info.NumLexicalDecls - = static_cast<unsigned int>(BlobLen / sizeof(KindDeclIDPair)); - TU->setHasExternalLexicalStorage(true); - break; - } - - case UPDATE_VISIBLE: { - unsigned Idx = 0; - serialization::DeclID ID = ReadDeclID(F, Record, Idx); - ASTDeclContextNameLookupTable *Table = - ASTDeclContextNameLookupTable::Create( - (const unsigned char *)BlobStart + Record[Idx++], - (const unsigned char *)BlobStart, - ASTDeclContextNameLookupTrait(*this, F)); - if (ID == PREDEF_DECL_TRANSLATION_UNIT_ID) { // Is it the TU? - DeclContext *TU = Context.getTranslationUnitDecl(); - F.DeclContextInfos[TU].NameLookupTableData = Table; - TU->setHasExternalVisibleStorage(true); - } else - PendingVisibleUpdates[ID].push_back(std::make_pair(Table, &F)); - break; - } - - case IDENTIFIER_TABLE: - F.IdentifierTableData = BlobStart; - if (Record[0]) { - F.IdentifierLookupTable - = ASTIdentifierLookupTable::Create( - (const unsigned char *)F.IdentifierTableData + Record[0], - (const unsigned char *)F.IdentifierTableData, - ASTIdentifierLookupTrait(*this, F)); - - PP.getIdentifierTable().setExternalIdentifierLookup(this); - } - break; - - case IDENTIFIER_OFFSET: { - if (F.LocalNumIdentifiers != 0) { - Error("duplicate IDENTIFIER_OFFSET record in AST file"); - return true; - } - F.IdentifierOffsets = (const uint32_t *)BlobStart; - F.LocalNumIdentifiers = Record[0]; - unsigned LocalBaseIdentifierID = Record[1]; - F.BaseIdentifierID = getTotalNumIdentifiers(); - - if (F.LocalNumIdentifiers > 0) { - // Introduce the global -> local mapping for identifiers within this - // module. - GlobalIdentifierMap.insert(std::make_pair(getTotalNumIdentifiers() + 1, - &F)); - - // Introduce the local -> global mapping for identifiers within this - // module. - F.IdentifierRemap.insertOrReplace( - std::make_pair(LocalBaseIdentifierID, - F.BaseIdentifierID - LocalBaseIdentifierID)); - - IdentifiersLoaded.resize(IdentifiersLoaded.size() - + F.LocalNumIdentifiers); - } - break; - } - - case EXTERNAL_DEFINITIONS: - for (unsigned I = 0, N = Record.size(); I != N; ++I) - ExternalDefinitions.push_back(getGlobalDeclID(F, Record[I])); - break; - - case SPECIAL_TYPES: - for (unsigned I = 0, N = Record.size(); I != N; ++I) - SpecialTypes.push_back(getGlobalTypeID(F, Record[I])); - break; - - case STATISTICS: - TotalNumStatements += Record[0]; - TotalNumMacros += Record[1]; - TotalLexicalDeclContexts += Record[2]; - TotalVisibleDeclContexts += Record[3]; - break; - - case UNUSED_FILESCOPED_DECLS: - for (unsigned I = 0, N = Record.size(); I != N; ++I) - UnusedFileScopedDecls.push_back(getGlobalDeclID(F, Record[I])); - break; - - case DELEGATING_CTORS: - for (unsigned I = 0, N = Record.size(); I != N; ++I) - DelegatingCtorDecls.push_back(getGlobalDeclID(F, Record[I])); - break; - - case WEAK_UNDECLARED_IDENTIFIERS: - if (Record.size() % 4 != 0) { - Error("invalid weak identifiers record"); - return true; - } - - // FIXME: Ignore weak undeclared identifiers from non-original PCH - // files. This isn't the way to do it :) - WeakUndeclaredIdentifiers.clear(); - - // Translate the weak, undeclared identifiers into global IDs. - for (unsigned I = 0, N = Record.size(); I < N; /* in loop */) { - WeakUndeclaredIdentifiers.push_back( - getGlobalIdentifierID(F, Record[I++])); - WeakUndeclaredIdentifiers.push_back( - getGlobalIdentifierID(F, Record[I++])); - WeakUndeclaredIdentifiers.push_back( - ReadSourceLocation(F, Record, I).getRawEncoding()); - WeakUndeclaredIdentifiers.push_back(Record[I++]); - } - break; - - case LOCALLY_SCOPED_EXTERNAL_DECLS: - for (unsigned I = 0, N = Record.size(); I != N; ++I) - LocallyScopedExternalDecls.push_back(getGlobalDeclID(F, Record[I])); - break; - - case SELECTOR_OFFSETS: { - F.SelectorOffsets = (const uint32_t *)BlobStart; - F.LocalNumSelectors = Record[0]; - unsigned LocalBaseSelectorID = Record[1]; - F.BaseSelectorID = getTotalNumSelectors(); - - if (F.LocalNumSelectors > 0) { - // Introduce the global -> local mapping for selectors within this - // module. - GlobalSelectorMap.insert(std::make_pair(getTotalNumSelectors()+1, &F)); - - // Introduce the local -> global mapping for selectors within this - // module. - F.SelectorRemap.insertOrReplace( - std::make_pair(LocalBaseSelectorID, - F.BaseSelectorID - LocalBaseSelectorID)); - - SelectorsLoaded.resize(SelectorsLoaded.size() + F.LocalNumSelectors); - } - break; - } - - case METHOD_POOL: - F.SelectorLookupTableData = (const unsigned char *)BlobStart; - if (Record[0]) - F.SelectorLookupTable - = ASTSelectorLookupTable::Create( - F.SelectorLookupTableData + Record[0], - F.SelectorLookupTableData, - ASTSelectorLookupTrait(*this, F)); - TotalNumMethodPoolEntries += Record[1]; - break; - - case REFERENCED_SELECTOR_POOL: - if (!Record.empty()) { - for (unsigned Idx = 0, N = Record.size() - 1; Idx < N; /* in loop */) { - ReferencedSelectorsData.push_back(getGlobalSelectorID(F, - Record[Idx++])); - ReferencedSelectorsData.push_back(ReadSourceLocation(F, Record, Idx). - getRawEncoding()); - } - } - break; - - case PP_COUNTER_VALUE: - if (!Record.empty() && Listener) - Listener->ReadCounter(F, Record[0]); - break; - - case FILE_SORTED_DECLS: - F.FileSortedDecls = (const DeclID *)BlobStart; - F.NumFileSortedDecls = Record[0]; - break; - - case SOURCE_LOCATION_OFFSETS: { - F.SLocEntryOffsets = (const uint32_t *)BlobStart; - F.LocalNumSLocEntries = Record[0]; - unsigned SLocSpaceSize = Record[1]; - llvm::tie(F.SLocEntryBaseID, F.SLocEntryBaseOffset) = - SourceMgr.AllocateLoadedSLocEntries(F.LocalNumSLocEntries, - SLocSpaceSize); - // Make our entry in the range map. BaseID is negative and growing, so - // we invert it. Because we invert it, though, we need the other end of - // the range. - unsigned RangeStart = - unsigned(-F.SLocEntryBaseID) - F.LocalNumSLocEntries + 1; - GlobalSLocEntryMap.insert(std::make_pair(RangeStart, &F)); - F.FirstLoc = SourceLocation::getFromRawEncoding(F.SLocEntryBaseOffset); - - // SLocEntryBaseOffset is lower than MaxLoadedOffset and decreasing. - assert((F.SLocEntryBaseOffset & (1U << 31U)) == 0); - GlobalSLocOffsetMap.insert( - std::make_pair(SourceManager::MaxLoadedOffset - F.SLocEntryBaseOffset - - SLocSpaceSize,&F)); - - // Initialize the remapping table. - // Invalid stays invalid. - F.SLocRemap.insert(std::make_pair(0U, 0)); - // This module. Base was 2 when being compiled. - F.SLocRemap.insert(std::make_pair(2U, - static_cast<int>(F.SLocEntryBaseOffset - 2))); - - TotalNumSLocEntries += F.LocalNumSLocEntries; - break; - } - - case MODULE_OFFSET_MAP: { - // Additional remapping information. - const unsigned char *Data = (const unsigned char*)BlobStart; - const unsigned char *DataEnd = Data + BlobLen; - - // Continuous range maps we may be updating in our module. - ContinuousRangeMap<uint32_t, int, 2>::Builder SLocRemap(F.SLocRemap); - ContinuousRangeMap<uint32_t, int, 2>::Builder - IdentifierRemap(F.IdentifierRemap); - ContinuousRangeMap<uint32_t, int, 2>::Builder - MacroRemap(F.MacroRemap); - ContinuousRangeMap<uint32_t, int, 2>::Builder - PreprocessedEntityRemap(F.PreprocessedEntityRemap); - ContinuousRangeMap<uint32_t, int, 2>::Builder - SubmoduleRemap(F.SubmoduleRemap); - ContinuousRangeMap<uint32_t, int, 2>::Builder - SelectorRemap(F.SelectorRemap); - ContinuousRangeMap<uint32_t, int, 2>::Builder DeclRemap(F.DeclRemap); - ContinuousRangeMap<uint32_t, int, 2>::Builder TypeRemap(F.TypeRemap); - - while(Data < DataEnd) { - uint16_t Len = io::ReadUnalignedLE16(Data); - StringRef Name = StringRef((const char*)Data, Len); - Data += Len; - ModuleFile *OM = ModuleMgr.lookup(Name); - if (!OM) { - Error("SourceLocation remap refers to unknown module"); - return true; - } - - uint32_t SLocOffset = io::ReadUnalignedLE32(Data); - uint32_t IdentifierIDOffset = io::ReadUnalignedLE32(Data); - uint32_t MacroIDOffset = io::ReadUnalignedLE32(Data); - uint32_t PreprocessedEntityIDOffset = io::ReadUnalignedLE32(Data); - uint32_t SubmoduleIDOffset = io::ReadUnalignedLE32(Data); - uint32_t SelectorIDOffset = io::ReadUnalignedLE32(Data); - uint32_t DeclIDOffset = io::ReadUnalignedLE32(Data); - uint32_t TypeIndexOffset = io::ReadUnalignedLE32(Data); - - // Source location offset is mapped to OM->SLocEntryBaseOffset. - SLocRemap.insert(std::make_pair(SLocOffset, - static_cast<int>(OM->SLocEntryBaseOffset - SLocOffset))); - IdentifierRemap.insert( - std::make_pair(IdentifierIDOffset, - OM->BaseIdentifierID - IdentifierIDOffset)); - MacroRemap.insert(std::make_pair(MacroIDOffset, - OM->BaseMacroID - MacroIDOffset)); - PreprocessedEntityRemap.insert( - std::make_pair(PreprocessedEntityIDOffset, - OM->BasePreprocessedEntityID - PreprocessedEntityIDOffset)); - SubmoduleRemap.insert(std::make_pair(SubmoduleIDOffset, - OM->BaseSubmoduleID - SubmoduleIDOffset)); - SelectorRemap.insert(std::make_pair(SelectorIDOffset, - OM->BaseSelectorID - SelectorIDOffset)); - DeclRemap.insert(std::make_pair(DeclIDOffset, - OM->BaseDeclID - DeclIDOffset)); - - TypeRemap.insert(std::make_pair(TypeIndexOffset, - OM->BaseTypeIndex - TypeIndexOffset)); - - // Global -> local mappings. - F.GlobalToLocalDeclIDs[OM] = DeclIDOffset; - } - break; - } - - case SOURCE_MANAGER_LINE_TABLE: - if (ParseLineTable(F, Record)) - return true; - break; - - case SOURCE_LOCATION_PRELOADS: { - // Need to transform from the local view (1-based IDs) to the global view, - // which is based off F.SLocEntryBaseID. - if (!F.PreloadSLocEntries.empty()) { - Error("Multiple SOURCE_LOCATION_PRELOADS records in AST file"); - return true; - } - - F.PreloadSLocEntries.swap(Record); - break; - } - - case EXT_VECTOR_DECLS: - for (unsigned I = 0, N = Record.size(); I != N; ++I) - ExtVectorDecls.push_back(getGlobalDeclID(F, Record[I])); - break; - - case VTABLE_USES: - if (Record.size() % 3 != 0) { - Error("Invalid VTABLE_USES record"); - return true; - } - - // Later tables overwrite earlier ones. - // FIXME: Modules will have some trouble with this. This is clearly not - // the right way to do this. - VTableUses.clear(); - - for (unsigned Idx = 0, N = Record.size(); Idx != N; /* In loop */) { - VTableUses.push_back(getGlobalDeclID(F, Record[Idx++])); - VTableUses.push_back( - ReadSourceLocation(F, Record, Idx).getRawEncoding()); - VTableUses.push_back(Record[Idx++]); - } - break; - - case DYNAMIC_CLASSES: - for (unsigned I = 0, N = Record.size(); I != N; ++I) - DynamicClasses.push_back(getGlobalDeclID(F, Record[I])); - break; - - case PENDING_IMPLICIT_INSTANTIATIONS: - if (PendingInstantiations.size() % 2 != 0) { - Error("Invalid existing PendingInstantiations"); - return true; - } - - if (Record.size() % 2 != 0) { - Error("Invalid PENDING_IMPLICIT_INSTANTIATIONS block"); - return true; - } - - for (unsigned I = 0, N = Record.size(); I != N; /* in loop */) { - PendingInstantiations.push_back(getGlobalDeclID(F, Record[I++])); - PendingInstantiations.push_back( - ReadSourceLocation(F, Record, I).getRawEncoding()); - } - break; - - case SEMA_DECL_REFS: - // Later tables overwrite earlier ones. - // FIXME: Modules will have some trouble with this. - SemaDeclRefs.clear(); - for (unsigned I = 0, N = Record.size(); I != N; ++I) - SemaDeclRefs.push_back(getGlobalDeclID(F, Record[I])); - break; - - case PPD_ENTITIES_OFFSETS: { - F.PreprocessedEntityOffsets = (const PPEntityOffset *)BlobStart; - assert(BlobLen % sizeof(PPEntityOffset) == 0); - F.NumPreprocessedEntities = BlobLen / sizeof(PPEntityOffset); - - unsigned LocalBasePreprocessedEntityID = Record[0]; - - unsigned StartingID; - if (!PP.getPreprocessingRecord()) - PP.createPreprocessingRecord(); - if (!PP.getPreprocessingRecord()->getExternalSource()) - PP.getPreprocessingRecord()->SetExternalSource(*this); - StartingID - = PP.getPreprocessingRecord() - ->allocateLoadedEntities(F.NumPreprocessedEntities); - F.BasePreprocessedEntityID = StartingID; - - if (F.NumPreprocessedEntities > 0) { - // Introduce the global -> local mapping for preprocessed entities in - // this module. - GlobalPreprocessedEntityMap.insert(std::make_pair(StartingID, &F)); - - // Introduce the local -> global mapping for preprocessed entities in - // this module. - F.PreprocessedEntityRemap.insertOrReplace( - std::make_pair(LocalBasePreprocessedEntityID, - F.BasePreprocessedEntityID - LocalBasePreprocessedEntityID)); - } - - break; - } - - case DECL_UPDATE_OFFSETS: { - if (Record.size() % 2 != 0) { - Error("invalid DECL_UPDATE_OFFSETS block in AST file"); - return true; - } - for (unsigned I = 0, N = Record.size(); I != N; I += 2) - DeclUpdateOffsets[getGlobalDeclID(F, Record[I])] - .push_back(std::make_pair(&F, Record[I+1])); - break; - } - - case DECL_REPLACEMENTS: { - if (Record.size() % 3 != 0) { - Error("invalid DECL_REPLACEMENTS block in AST file"); - return true; - } - for (unsigned I = 0, N = Record.size(); I != N; I += 3) - ReplacedDecls[getGlobalDeclID(F, Record[I])] - = ReplacedDeclInfo(&F, Record[I+1], Record[I+2]); - break; - } - - case OBJC_CATEGORIES_MAP: { - if (F.LocalNumObjCCategoriesInMap != 0) { - Error("duplicate OBJC_CATEGORIES_MAP record in AST file"); - return true; - } - - F.LocalNumObjCCategoriesInMap = Record[0]; - F.ObjCCategoriesMap = (const ObjCCategoriesInfo *)BlobStart; - break; - } - - case OBJC_CATEGORIES: - F.ObjCCategories.swap(Record); - break; - - case CXX_BASE_SPECIFIER_OFFSETS: { - if (F.LocalNumCXXBaseSpecifiers != 0) { - Error("duplicate CXX_BASE_SPECIFIER_OFFSETS record in AST file"); - return true; - } - - F.LocalNumCXXBaseSpecifiers = Record[0]; - F.CXXBaseSpecifiersOffsets = (const uint32_t *)BlobStart; - NumCXXBaseSpecifiersLoaded += F.LocalNumCXXBaseSpecifiers; - break; - } - - case DIAG_PRAGMA_MAPPINGS: - if (F.PragmaDiagMappings.empty()) - F.PragmaDiagMappings.swap(Record); - else - F.PragmaDiagMappings.insert(F.PragmaDiagMappings.end(), - Record.begin(), Record.end()); - break; - - case CUDA_SPECIAL_DECL_REFS: - // Later tables overwrite earlier ones. - // FIXME: Modules will have trouble with this. - CUDASpecialDeclRefs.clear(); - for (unsigned I = 0, N = Record.size(); I != N; ++I) - CUDASpecialDeclRefs.push_back(getGlobalDeclID(F, Record[I])); - break; - - case HEADER_SEARCH_TABLE: { - F.HeaderFileInfoTableData = BlobStart; - F.LocalNumHeaderFileInfos = Record[1]; - F.HeaderFileFrameworkStrings = BlobStart + Record[2]; - if (Record[0]) { - F.HeaderFileInfoTable - = HeaderFileInfoLookupTable::Create( - (const unsigned char *)F.HeaderFileInfoTableData + Record[0], - (const unsigned char *)F.HeaderFileInfoTableData, - HeaderFileInfoTrait(*this, F, - &PP.getHeaderSearchInfo(), - BlobStart + Record[2])); - - PP.getHeaderSearchInfo().SetExternalSource(this); - if (!PP.getHeaderSearchInfo().getExternalLookup()) - PP.getHeaderSearchInfo().SetExternalLookup(this); - } - break; - } - - case FP_PRAGMA_OPTIONS: - // Later tables overwrite earlier ones. - FPPragmaOptions.swap(Record); - break; - - case OPENCL_EXTENSIONS: - // Later tables overwrite earlier ones. - OpenCLExtensions.swap(Record); - break; - - case TENTATIVE_DEFINITIONS: - for (unsigned I = 0, N = Record.size(); I != N; ++I) - TentativeDefinitions.push_back(getGlobalDeclID(F, Record[I])); - break; - - case KNOWN_NAMESPACES: - for (unsigned I = 0, N = Record.size(); I != N; ++I) - KnownNamespaces.push_back(getGlobalDeclID(F, Record[I])); - break; - - case IMPORTED_MODULES: { - if (F.Kind != MK_Module) { - // If we aren't loading a module (which has its own exports), make - // all of the imported modules visible. - // FIXME: Deal with macros-only imports. - for (unsigned I = 0, N = Record.size(); I != N; ++I) { - if (unsigned GlobalID = getGlobalSubmoduleID(F, Record[I])) - ImportedModules.push_back(GlobalID); - } - } - break; - } - - case LOCAL_REDECLARATIONS: { - F.RedeclarationChains.swap(Record); - break; - } - - case LOCAL_REDECLARATIONS_MAP: { - if (F.LocalNumRedeclarationsInMap != 0) { - Error("duplicate LOCAL_REDECLARATIONS_MAP record in AST file"); - return true; - } - - F.LocalNumRedeclarationsInMap = Record[0]; - F.RedeclarationsMap = (const LocalRedeclarationsInfo *)BlobStart; - break; - } - - case MERGED_DECLARATIONS: { - for (unsigned Idx = 0; Idx < Record.size(); /* increment in loop */) { - GlobalDeclID CanonID = getGlobalDeclID(F, Record[Idx++]); - SmallVectorImpl<GlobalDeclID> &Decls = StoredMergedDecls[CanonID]; - for (unsigned N = Record[Idx++]; N > 0; --N) - Decls.push_back(getGlobalDeclID(F, Record[Idx++])); - } - break; - } - - case MACRO_OFFSET: { - if (F.LocalNumMacros != 0) { - Error("duplicate MACRO_OFFSET record in AST file"); - return true; - } - F.MacroOffsets = (const uint32_t *)BlobStart; - F.LocalNumMacros = Record[0]; - unsigned LocalBaseMacroID = Record[1]; - F.BaseMacroID = getTotalNumMacros(); - - if (F.LocalNumMacros > 0) { - // Introduce the global -> local mapping for macros within this module. - GlobalMacroMap.insert(std::make_pair(getTotalNumMacros() + 1, &F)); - - // Introduce the local -> global mapping for macros within this module. - F.MacroRemap.insertOrReplace( - std::make_pair(LocalBaseMacroID, - F.BaseMacroID - LocalBaseMacroID)); - - MacrosLoaded.resize(MacrosLoaded.size() + F.LocalNumMacros); - } - break; - } - - case MACRO_UPDATES: { - for (unsigned I = 0, N = Record.size(); I != N; /* in loop */) { - MacroID ID = getGlobalMacroID(F, Record[I++]); - if (I == N) - break; - - SourceLocation UndefLoc = ReadSourceLocation(F, Record, I); - SubmoduleID SubmoduleID = getGlobalSubmoduleID(F, Record[I++]);; - MacroUpdate Update; - Update.UndefLoc = UndefLoc; - MacroUpdates[ID].push_back(std::make_pair(SubmoduleID, Update)); - } - break; - } - } - } - Error("premature end of bitstream in AST file"); - return true; -} - -void ASTReader::makeNamesVisible(const HiddenNames &Names) { - for (unsigned I = 0, N = Names.size(); I != N; ++I) { - switch (Names[I].getKind()) { - case HiddenName::Declaration: - Names[I].getDecl()->Hidden = false; - break; - - case HiddenName::MacroVisibility: { - std::pair<IdentifierInfo *, MacroInfo *> Macro = Names[I].getMacro(); - Macro.second->setHidden(!Macro.second->isPublic()); - if (Macro.second->isDefined()) { - PP.makeLoadedMacroInfoVisible(Macro.first, Macro.second); - } - break; - } - - case HiddenName::MacroUndef: { - std::pair<IdentifierInfo *, MacroInfo *> Macro = Names[I].getMacro(); - if (Macro.second->isDefined()) { - Macro.second->setUndefLoc(Names[I].getMacroUndefLoc()); - if (PPMutationListener *Listener = PP.getPPMutationListener()) - Listener->UndefinedMacro(Macro.second); - PP.makeLoadedMacroInfoVisible(Macro.first, Macro.second); - } - break; - } - } - } -} - -void ASTReader::makeModuleVisible(Module *Mod, - Module::NameVisibilityKind NameVisibility) { - llvm::SmallPtrSet<Module *, 4> Visited; - llvm::SmallVector<Module *, 4> Stack; - Stack.push_back(Mod); - while (!Stack.empty()) { - Mod = Stack.back(); - Stack.pop_back(); - - if (NameVisibility <= Mod->NameVisibility) { - // This module already has this level of visibility (or greater), so - // there is nothing more to do. - continue; - } - - if (!Mod->isAvailable()) { - // Modules that aren't available cannot be made visible. - continue; - } - - // Update the module's name visibility. - Mod->NameVisibility = NameVisibility; - - // If we've already deserialized any names from this module, - // mark them as visible. - HiddenNamesMapType::iterator Hidden = HiddenNamesMap.find(Mod); - if (Hidden != HiddenNamesMap.end()) { - makeNamesVisible(Hidden->second); - HiddenNamesMap.erase(Hidden); - } - - // Push any non-explicit submodules onto the stack to be marked as - // visible. - for (Module::submodule_iterator Sub = Mod->submodule_begin(), - SubEnd = Mod->submodule_end(); - Sub != SubEnd; ++Sub) { - if (!(*Sub)->IsExplicit && Visited.insert(*Sub)) - Stack.push_back(*Sub); - } - - // Push any exported modules onto the stack to be marked as visible. - bool AnyWildcard = false; - bool UnrestrictedWildcard = false; - llvm::SmallVector<Module *, 4> WildcardRestrictions; - for (unsigned I = 0, N = Mod->Exports.size(); I != N; ++I) { - Module *Exported = Mod->Exports[I].getPointer(); - if (!Mod->Exports[I].getInt()) { - // Export a named module directly; no wildcards involved. - if (Visited.insert(Exported)) - Stack.push_back(Exported); - - continue; - } - - // Wildcard export: export all of the imported modules that match - // the given pattern. - AnyWildcard = true; - if (UnrestrictedWildcard) - continue; - - if (Module *Restriction = Mod->Exports[I].getPointer()) - WildcardRestrictions.push_back(Restriction); - else { - WildcardRestrictions.clear(); - UnrestrictedWildcard = true; - } - } - - // If there were any wildcards, push any imported modules that were - // re-exported by the wildcard restriction. - if (!AnyWildcard) - continue; - - for (unsigned I = 0, N = Mod->Imports.size(); I != N; ++I) { - Module *Imported = Mod->Imports[I]; - if (!Visited.insert(Imported)) - continue; - - bool Acceptable = UnrestrictedWildcard; - if (!Acceptable) { - // Check whether this module meets one of the restrictions. - for (unsigned R = 0, NR = WildcardRestrictions.size(); R != NR; ++R) { - Module *Restriction = WildcardRestrictions[R]; - if (Imported == Restriction || Imported->isSubModuleOf(Restriction)) { - Acceptable = true; - break; - } - } - } - - if (!Acceptable) - continue; - - Stack.push_back(Imported); - } - } -} - -ASTReader::ASTReadResult ASTReader::ReadAST(const std::string &FileName, - ModuleKind Type, - SourceLocation ImportLoc, - unsigned ClientLoadCapabilities) { - // Bump the generation number. - unsigned PreviousGeneration = CurrentGeneration++; - - unsigned NumModules = ModuleMgr.size(); - llvm::SmallVector<ImportedModule, 4> Loaded; - switch(ASTReadResult ReadResult = ReadASTCore(FileName, Type, ImportLoc, - /*ImportedBy=*/0, Loaded, - ClientLoadCapabilities)) { - case Failure: - case OutOfDate: - case VersionMismatch: - case ConfigurationMismatch: - case HadErrors: - ModuleMgr.removeModules(ModuleMgr.begin() + NumModules, ModuleMgr.end()); - return ReadResult; - - case Success: - break; - } - - // Here comes stuff that we only do once the entire chain is loaded. - - // Load the AST blocks of all of the modules that we loaded. - for (llvm::SmallVectorImpl<ImportedModule>::iterator M = Loaded.begin(), - MEnd = Loaded.end(); - M != MEnd; ++M) { - ModuleFile &F = *M->Mod; - - // Read the AST block. - if (ReadASTBlock(F)) - return Failure; - - // Once read, set the ModuleFile bit base offset and update the size in - // bits of all files we've seen. - F.GlobalBitOffset = TotalModulesSizeInBits; - TotalModulesSizeInBits += F.SizeInBits; - GlobalBitOffsetsMap.insert(std::make_pair(F.GlobalBitOffset, &F)); - - // Preload SLocEntries. - for (unsigned I = 0, N = F.PreloadSLocEntries.size(); I != N; ++I) { - int Index = int(F.PreloadSLocEntries[I] - 1) + F.SLocEntryBaseID; - // Load it through the SourceManager and don't call ReadSLocEntry() - // directly because the entry may have already been loaded in which case - // calling ReadSLocEntry() directly would trigger an assertion in - // SourceManager. - SourceMgr.getLoadedSLocEntryByID(Index); - } - } - - // Setup the import locations. - for (llvm::SmallVectorImpl<ImportedModule>::iterator M = Loaded.begin(), - MEnd = Loaded.end(); - M != MEnd; ++M) { - ModuleFile &F = *M->Mod; - if (!M->ImportedBy) - F.ImportLoc = M->ImportLoc; - else - F.ImportLoc = ReadSourceLocation(*M->ImportedBy, - M->ImportLoc.getRawEncoding()); - } - - // Mark all of the identifiers in the identifier table as being out of date, - // so that various accessors know to check the loaded modules when the - // identifier is used. - for (IdentifierTable::iterator Id = PP.getIdentifierTable().begin(), - IdEnd = PP.getIdentifierTable().end(); - Id != IdEnd; ++Id) - Id->second->setOutOfDate(true); - - // Resolve any unresolved module exports. - for (unsigned I = 0, N = UnresolvedModuleImportExports.size(); I != N; ++I) { - UnresolvedModuleImportExport &Unresolved = UnresolvedModuleImportExports[I]; - SubmoduleID GlobalID = getGlobalSubmoduleID(*Unresolved.File,Unresolved.ID); - Module *ResolvedMod = getSubmodule(GlobalID); - - if (Unresolved.IsImport) { - if (ResolvedMod) - Unresolved.Mod->Imports.push_back(ResolvedMod); - continue; - } - - if (ResolvedMod || Unresolved.IsWildcard) - Unresolved.Mod->Exports.push_back( - Module::ExportDecl(ResolvedMod, Unresolved.IsWildcard)); - } - UnresolvedModuleImportExports.clear(); - - InitializeContext(); - - if (DeserializationListener) - DeserializationListener->ReaderInitialized(this); - - ModuleFile &PrimaryModule = ModuleMgr.getPrimaryModule(); - if (!PrimaryModule.OriginalSourceFileID.isInvalid()) { - PrimaryModule.OriginalSourceFileID - = FileID::get(PrimaryModule.SLocEntryBaseID - + PrimaryModule.OriginalSourceFileID.getOpaqueValue() - 1); - - // If this AST file is a precompiled preamble, then set the - // preamble file ID of the source manager to the file source file - // from which the preamble was built. - if (Type == MK_Preamble) { - SourceMgr.setPreambleFileID(PrimaryModule.OriginalSourceFileID); - } else if (Type == MK_MainFile) { - SourceMgr.setMainFileID(PrimaryModule.OriginalSourceFileID); - } - } - - // For any Objective-C class definitions we have already loaded, make sure - // that we load any additional categories. - for (unsigned I = 0, N = ObjCClassesLoaded.size(); I != N; ++I) { - loadObjCCategories(ObjCClassesLoaded[I]->getGlobalID(), - ObjCClassesLoaded[I], - PreviousGeneration); - } - - return Success; -} - -ASTReader::ASTReadResult -ASTReader::ReadASTCore(StringRef FileName, - ModuleKind Type, - SourceLocation ImportLoc, - ModuleFile *ImportedBy, - llvm::SmallVectorImpl<ImportedModule> &Loaded, - unsigned ClientLoadCapabilities) { - ModuleFile *M; - bool NewModule; - std::string ErrorStr; - llvm::tie(M, NewModule) = ModuleMgr.addModule(FileName, Type, ImportLoc, - ImportedBy, CurrentGeneration, - ErrorStr); - - if (!M) { - // We couldn't load the module. - std::string Msg = "Unable to load module \"" + FileName.str() + "\": " - + ErrorStr; - Error(Msg); - return Failure; - } - - if (!NewModule) { - // We've already loaded this module. - return Success; - } - - // FIXME: This seems rather a hack. Should CurrentDir be part of the - // module? - if (FileName != "-") { - CurrentDir = llvm::sys::path::parent_path(FileName); - if (CurrentDir.empty()) CurrentDir = "."; - } - - ModuleFile &F = *M; - llvm::BitstreamCursor &Stream = F.Stream; - Stream.init(F.StreamFile); - F.SizeInBits = F.Buffer->getBufferSize() * 8; - - // Sniff for the signature. - if (Stream.Read(8) != 'C' || - Stream.Read(8) != 'P' || - Stream.Read(8) != 'C' || - Stream.Read(8) != 'H') { - Diag(diag::err_not_a_pch_file) << FileName; - return Failure; - } - - // This is used for compatibility with older PCH formats. - bool HaveReadControlBlock = false; - - while (!Stream.AtEndOfStream()) { - unsigned Code = Stream.ReadCode(); - - if (Code != llvm::bitc::ENTER_SUBBLOCK) { - Error("invalid record at top-level of AST file"); - return Failure; - } - - unsigned BlockID = Stream.ReadSubBlockID(); - - // We only know the control subblock ID. - switch (BlockID) { - case llvm::bitc::BLOCKINFO_BLOCK_ID: - if (Stream.ReadBlockInfoBlock()) { - Error("malformed BlockInfoBlock in AST file"); - return Failure; - } - break; - case CONTROL_BLOCK_ID: - HaveReadControlBlock = true; - switch (ReadControlBlock(F, Loaded, ClientLoadCapabilities)) { - case Success: - break; - - case Failure: return Failure; - case OutOfDate: return OutOfDate; - case VersionMismatch: return VersionMismatch; - case ConfigurationMismatch: return ConfigurationMismatch; - case HadErrors: return HadErrors; - } - break; - case AST_BLOCK_ID: - if (!HaveReadControlBlock) { - if ((ClientLoadCapabilities & ARR_VersionMismatch) == 0) - Diag(diag::warn_pch_version_too_old); - return VersionMismatch; - } - - // Record that we've loaded this module. - Loaded.push_back(ImportedModule(M, ImportedBy, ImportLoc)); - return Success; - - default: - if (Stream.SkipBlock()) { - Error("malformed block record in AST file"); - return Failure; - } - break; - } - } - - return Success; -} - -void ASTReader::InitializeContext() { - // If there's a listener, notify them that we "read" the translation unit. - if (DeserializationListener) - DeserializationListener->DeclRead(PREDEF_DECL_TRANSLATION_UNIT_ID, - Context.getTranslationUnitDecl()); - - // Make sure we load the declaration update records for the translation unit, - // if there are any. - loadDeclUpdateRecords(PREDEF_DECL_TRANSLATION_UNIT_ID, - Context.getTranslationUnitDecl()); - - // FIXME: Find a better way to deal with collisions between these - // built-in types. Right now, we just ignore the problem. - - // Load the special types. - if (SpecialTypes.size() >= NumSpecialTypeIDs) { - if (unsigned String = SpecialTypes[SPECIAL_TYPE_CF_CONSTANT_STRING]) { - if (!Context.CFConstantStringTypeDecl) - Context.setCFConstantStringType(GetType(String)); - } - - if (unsigned File = SpecialTypes[SPECIAL_TYPE_FILE]) { - QualType FileType = GetType(File); - if (FileType.isNull()) { - Error("FILE type is NULL"); - return; - } - - if (!Context.FILEDecl) { - if (const TypedefType *Typedef = FileType->getAs<TypedefType>()) - Context.setFILEDecl(Typedef->getDecl()); - else { - const TagType *Tag = FileType->getAs<TagType>(); - if (!Tag) { - Error("Invalid FILE type in AST file"); - return; - } - Context.setFILEDecl(Tag->getDecl()); - } - } - } - - if (unsigned Jmp_buf = SpecialTypes[SPECIAL_TYPE_JMP_BUF]) { - QualType Jmp_bufType = GetType(Jmp_buf); - if (Jmp_bufType.isNull()) { - Error("jmp_buf type is NULL"); - return; - } - - if (!Context.jmp_bufDecl) { - if (const TypedefType *Typedef = Jmp_bufType->getAs<TypedefType>()) - Context.setjmp_bufDecl(Typedef->getDecl()); - else { - const TagType *Tag = Jmp_bufType->getAs<TagType>(); - if (!Tag) { - Error("Invalid jmp_buf type in AST file"); - return; - } - Context.setjmp_bufDecl(Tag->getDecl()); - } - } - } - - if (unsigned Sigjmp_buf = SpecialTypes[SPECIAL_TYPE_SIGJMP_BUF]) { - QualType Sigjmp_bufType = GetType(Sigjmp_buf); - if (Sigjmp_bufType.isNull()) { - Error("sigjmp_buf type is NULL"); - return; - } - - if (!Context.sigjmp_bufDecl) { - if (const TypedefType *Typedef = Sigjmp_bufType->getAs<TypedefType>()) - Context.setsigjmp_bufDecl(Typedef->getDecl()); - else { - const TagType *Tag = Sigjmp_bufType->getAs<TagType>(); - assert(Tag && "Invalid sigjmp_buf type in AST file"); - Context.setsigjmp_bufDecl(Tag->getDecl()); - } - } - } - - if (unsigned ObjCIdRedef - = SpecialTypes[SPECIAL_TYPE_OBJC_ID_REDEFINITION]) { - if (Context.ObjCIdRedefinitionType.isNull()) - Context.ObjCIdRedefinitionType = GetType(ObjCIdRedef); - } - - if (unsigned ObjCClassRedef - = SpecialTypes[SPECIAL_TYPE_OBJC_CLASS_REDEFINITION]) { - if (Context.ObjCClassRedefinitionType.isNull()) - Context.ObjCClassRedefinitionType = GetType(ObjCClassRedef); - } - - if (unsigned ObjCSelRedef - = SpecialTypes[SPECIAL_TYPE_OBJC_SEL_REDEFINITION]) { - if (Context.ObjCSelRedefinitionType.isNull()) - Context.ObjCSelRedefinitionType = GetType(ObjCSelRedef); - } - - if (unsigned Ucontext_t = SpecialTypes[SPECIAL_TYPE_UCONTEXT_T]) { - QualType Ucontext_tType = GetType(Ucontext_t); - if (Ucontext_tType.isNull()) { - Error("ucontext_t type is NULL"); - return; - } - - if (!Context.ucontext_tDecl) { - if (const TypedefType *Typedef = Ucontext_tType->getAs<TypedefType>()) - Context.setucontext_tDecl(Typedef->getDecl()); - else { - const TagType *Tag = Ucontext_tType->getAs<TagType>(); - assert(Tag && "Invalid ucontext_t type in AST file"); - Context.setucontext_tDecl(Tag->getDecl()); - } - } - } - } - - ReadPragmaDiagnosticMappings(Context.getDiagnostics()); - - // If there were any CUDA special declarations, deserialize them. - if (!CUDASpecialDeclRefs.empty()) { - assert(CUDASpecialDeclRefs.size() == 1 && "More decl refs than expected!"); - Context.setcudaConfigureCallDecl( - cast<FunctionDecl>(GetDecl(CUDASpecialDeclRefs[0]))); - } - - // Re-export any modules that were imported by a non-module AST file. - for (unsigned I = 0, N = ImportedModules.size(); I != N; ++I) { - if (Module *Imported = getSubmodule(ImportedModules[I])) - makeModuleVisible(Imported, Module::AllVisible); - } - ImportedModules.clear(); -} - -void ASTReader::finalizeForWriting() { - for (HiddenNamesMapType::iterator Hidden = HiddenNamesMap.begin(), - HiddenEnd = HiddenNamesMap.end(); - Hidden != HiddenEnd; ++Hidden) { - makeNamesVisible(Hidden->second); - } - HiddenNamesMap.clear(); -} - -/// \brief Retrieve the name of the original source file name -/// directly from the AST file, without actually loading the AST -/// file. -std::string ASTReader::getOriginalSourceFile(const std::string &ASTFileName, - FileManager &FileMgr, - DiagnosticsEngine &Diags) { - // Open the AST file. - std::string ErrStr; - OwningPtr<llvm::MemoryBuffer> Buffer; - Buffer.reset(FileMgr.getBufferForFile(ASTFileName, &ErrStr)); - if (!Buffer) { - Diags.Report(diag::err_fe_unable_to_read_pch_file) << ASTFileName << ErrStr; - return std::string(); - } - - // Initialize the stream - llvm::BitstreamReader StreamFile; - llvm::BitstreamCursor Stream; - StreamFile.init((const unsigned char *)Buffer->getBufferStart(), - (const unsigned char *)Buffer->getBufferEnd()); - Stream.init(StreamFile); - - // Sniff for the signature. - if (Stream.Read(8) != 'C' || - Stream.Read(8) != 'P' || - Stream.Read(8) != 'C' || - Stream.Read(8) != 'H') { - Diags.Report(diag::err_fe_not_a_pch_file) << ASTFileName; - return std::string(); - } - - RecordData Record; - while (!Stream.AtEndOfStream()) { - unsigned Code = Stream.ReadCode(); - - if (Code == llvm::bitc::ENTER_SUBBLOCK) { - unsigned BlockID = Stream.ReadSubBlockID(); - - // We only know the AST subblock ID. - switch (BlockID) { - case CONTROL_BLOCK_ID: - if (Stream.EnterSubBlock(CONTROL_BLOCK_ID)) { - Diags.Report(diag::err_fe_pch_malformed_block) << ASTFileName; - return std::string(); - } - break; - - default: - if (Stream.SkipBlock()) { - Diags.Report(diag::err_fe_pch_malformed_block) << ASTFileName; - return std::string(); - } - break; - } - continue; - } - - if (Code == llvm::bitc::END_BLOCK) { - if (Stream.ReadBlockEnd()) { - Diags.Report(diag::err_fe_pch_error_at_end_block) << ASTFileName; - return std::string(); - } - continue; - } - - if (Code == llvm::bitc::DEFINE_ABBREV) { - Stream.ReadAbbrevRecord(); - continue; - } - - Record.clear(); - const char *BlobStart = 0; - unsigned BlobLen = 0; - if (Stream.ReadRecord(Code, Record, &BlobStart, &BlobLen) == ORIGINAL_FILE) - return std::string(BlobStart, BlobLen); - } - - return std::string(); -} - -namespace { - class SimplePCHValidator : public ASTReaderListener { - const LangOptions &ExistingLangOpts; - const TargetOptions &ExistingTargetOpts; - const PreprocessorOptions &ExistingPPOpts; - FileManager &FileMgr; - - public: - SimplePCHValidator(const LangOptions &ExistingLangOpts, - const TargetOptions &ExistingTargetOpts, - const PreprocessorOptions &ExistingPPOpts, - FileManager &FileMgr) - : ExistingLangOpts(ExistingLangOpts), - ExistingTargetOpts(ExistingTargetOpts), - ExistingPPOpts(ExistingPPOpts), - FileMgr(FileMgr) - { - } - - virtual bool ReadLanguageOptions(const LangOptions &LangOpts, - bool Complain) { - return checkLanguageOptions(ExistingLangOpts, LangOpts, 0); - } - virtual bool ReadTargetOptions(const TargetOptions &TargetOpts, - bool Complain) { - return checkTargetOptions(ExistingTargetOpts, TargetOpts, 0); - } - virtual bool ReadPreprocessorOptions(const PreprocessorOptions &PPOpts, - bool Complain, - std::string &SuggestedPredefines) { - return checkPreprocessorOptions(ExistingPPOpts, PPOpts, 0, FileMgr, - SuggestedPredefines); - } - }; -} - -bool ASTReader::readASTFileControlBlock(StringRef Filename, - FileManager &FileMgr, - ASTReaderListener &Listener) { - // Open the AST file. - std::string ErrStr; - OwningPtr<llvm::MemoryBuffer> Buffer; - Buffer.reset(FileMgr.getBufferForFile(Filename, &ErrStr)); - if (!Buffer) { - return true; - } - - // Initialize the stream - llvm::BitstreamReader StreamFile; - llvm::BitstreamCursor Stream; - StreamFile.init((const unsigned char *)Buffer->getBufferStart(), - (const unsigned char *)Buffer->getBufferEnd()); - Stream.init(StreamFile); - - // Sniff for the signature. - if (Stream.Read(8) != 'C' || - Stream.Read(8) != 'P' || - Stream.Read(8) != 'C' || - Stream.Read(8) != 'H') { - return true; - } - - RecordData Record; - bool InControlBlock = false; - while (!Stream.AtEndOfStream()) { - unsigned Code = Stream.ReadCode(); - - if (Code == llvm::bitc::ENTER_SUBBLOCK) { - unsigned BlockID = Stream.ReadSubBlockID(); - - // We only know the control subblock ID. - switch (BlockID) { - case CONTROL_BLOCK_ID: - if (Stream.EnterSubBlock(CONTROL_BLOCK_ID)) { - return true; - } else { - InControlBlock = true; - } - break; - - default: - if (Stream.SkipBlock()) - return true; - break; - } - continue; - } - - if (Code == llvm::bitc::END_BLOCK) { - if (Stream.ReadBlockEnd()) { - return true; - } - - InControlBlock = false; - continue; - } - - if (Code == llvm::bitc::DEFINE_ABBREV) { - Stream.ReadAbbrevRecord(); - continue; - } - - Record.clear(); - const char *BlobStart = 0; - unsigned BlobLen = 0; - unsigned RecCode = Stream.ReadRecord(Code, Record, &BlobStart, &BlobLen); - if (InControlBlock) { - switch ((ControlRecordTypes)RecCode) { - case METADATA: { - if (Record[0] != VERSION_MAJOR) { - return true; - } - - const std::string &CurBranch = getClangFullRepositoryVersion(); - StringRef ASTBranch(BlobStart, BlobLen); - if (StringRef(CurBranch) != ASTBranch) - return true; - - break; - } - case LANGUAGE_OPTIONS: - if (ParseLanguageOptions(Record, false, Listener)) - return true; - break; - - case TARGET_OPTIONS: - if (ParseTargetOptions(Record, false, Listener)) - return true; - break; - - case DIAGNOSTIC_OPTIONS: - if (ParseDiagnosticOptions(Record, false, Listener)) - return true; - break; - - case FILE_SYSTEM_OPTIONS: - if (ParseFileSystemOptions(Record, false, Listener)) - return true; - break; - - case HEADER_SEARCH_OPTIONS: - if (ParseHeaderSearchOptions(Record, false, Listener)) - return true; - break; - - case PREPROCESSOR_OPTIONS: { - std::string IgnoredSuggestedPredefines; - if (ParsePreprocessorOptions(Record, false, Listener, - IgnoredSuggestedPredefines)) - return true; - break; - } - - default: - // No other validation to perform. - break; - } - } - } - - return false; -} - - -bool ASTReader::isAcceptableASTFile(StringRef Filename, - FileManager &FileMgr, - const LangOptions &LangOpts, - const TargetOptions &TargetOpts, - const PreprocessorOptions &PPOpts) { - SimplePCHValidator validator(LangOpts, TargetOpts, PPOpts, FileMgr); - return !readASTFileControlBlock(Filename, FileMgr, validator); -} - -bool ASTReader::ReadSubmoduleBlock(ModuleFile &F) { - // Enter the submodule block. - if (F.Stream.EnterSubBlock(SUBMODULE_BLOCK_ID)) { - Error("malformed submodule block record in AST file"); - return true; - } - - ModuleMap &ModMap = PP.getHeaderSearchInfo().getModuleMap(); - bool First = true; - Module *CurrentModule = 0; - RecordData Record; - while (true) { - unsigned Code = F.Stream.ReadCode(); - if (Code == llvm::bitc::END_BLOCK) { - if (F.Stream.ReadBlockEnd()) { - Error("error at end of submodule block in AST file"); - return true; - } - return false; - } - - if (Code == llvm::bitc::ENTER_SUBBLOCK) { - // No known subblocks, always skip them. - F.Stream.ReadSubBlockID(); - if (F.Stream.SkipBlock()) { - Error("malformed block record in AST file"); - return true; - } - continue; - } - - if (Code == llvm::bitc::DEFINE_ABBREV) { - F.Stream.ReadAbbrevRecord(); - continue; - } - - // Read a record. - const char *BlobStart; - unsigned BlobLen; - Record.clear(); - switch (F.Stream.ReadRecord(Code, Record, &BlobStart, &BlobLen)) { - default: // Default behavior: ignore. - break; - - case SUBMODULE_DEFINITION: { - if (First) { - Error("missing submodule metadata record at beginning of block"); - return true; - } - - if (Record.size() < 7) { - Error("malformed module definition"); - return true; - } - - StringRef Name(BlobStart, BlobLen); - SubmoduleID GlobalID = getGlobalSubmoduleID(F, Record[0]); - SubmoduleID Parent = getGlobalSubmoduleID(F, Record[1]); - bool IsFramework = Record[2]; - bool IsExplicit = Record[3]; - bool IsSystem = Record[4]; - bool InferSubmodules = Record[5]; - bool InferExplicitSubmodules = Record[6]; - bool InferExportWildcard = Record[7]; - - Module *ParentModule = 0; - if (Parent) - ParentModule = getSubmodule(Parent); - - // Retrieve this (sub)module from the module map, creating it if - // necessary. - CurrentModule = ModMap.findOrCreateModule(Name, ParentModule, - IsFramework, - IsExplicit).first; - SubmoduleID GlobalIndex = GlobalID - NUM_PREDEF_SUBMODULE_IDS; - if (GlobalIndex >= SubmodulesLoaded.size() || - SubmodulesLoaded[GlobalIndex]) { - Error("too many submodules"); - return true; - } - - CurrentModule->setASTFile(F.File); - CurrentModule->IsFromModuleFile = true; - CurrentModule->IsSystem = IsSystem || CurrentModule->IsSystem; - CurrentModule->InferSubmodules = InferSubmodules; - CurrentModule->InferExplicitSubmodules = InferExplicitSubmodules; - CurrentModule->InferExportWildcard = InferExportWildcard; - if (DeserializationListener) - DeserializationListener->ModuleRead(GlobalID, CurrentModule); - - SubmodulesLoaded[GlobalIndex] = CurrentModule; - break; - } - - case SUBMODULE_UMBRELLA_HEADER: { - if (First) { - Error("missing submodule metadata record at beginning of block"); - return true; - } - - if (!CurrentModule) - break; - - StringRef FileName(BlobStart, BlobLen); - if (const FileEntry *Umbrella = PP.getFileManager().getFile(FileName)) { - if (!CurrentModule->getUmbrellaHeader()) - ModMap.setUmbrellaHeader(CurrentModule, Umbrella); - else if (CurrentModule->getUmbrellaHeader() != Umbrella) { - Error("mismatched umbrella headers in submodule"); - return true; - } - } - break; - } - - case SUBMODULE_HEADER: { - if (First) { - Error("missing submodule metadata record at beginning of block"); - return true; - } - - if (!CurrentModule) - break; - - // FIXME: Be more lazy about this! - StringRef FileName(BlobStart, BlobLen); - if (const FileEntry *File = PP.getFileManager().getFile(FileName)) { - if (std::find(CurrentModule->Headers.begin(), - CurrentModule->Headers.end(), - File) == CurrentModule->Headers.end()) - ModMap.addHeader(CurrentModule, File, false); - } - break; - } - - case SUBMODULE_EXCLUDED_HEADER: { - if (First) { - Error("missing submodule metadata record at beginning of block"); - return true; - } - - if (!CurrentModule) - break; - - // FIXME: Be more lazy about this! - StringRef FileName(BlobStart, BlobLen); - if (const FileEntry *File = PP.getFileManager().getFile(FileName)) { - if (std::find(CurrentModule->Headers.begin(), - CurrentModule->Headers.end(), - File) == CurrentModule->Headers.end()) - ModMap.addHeader(CurrentModule, File, true); - } - break; - } - - case SUBMODULE_TOPHEADER: { - if (First) { - Error("missing submodule metadata record at beginning of block"); - return true; - } - - if (!CurrentModule) - break; - - // FIXME: Be more lazy about this! - StringRef FileName(BlobStart, BlobLen); - if (const FileEntry *File = PP.getFileManager().getFile(FileName)) - CurrentModule->TopHeaders.insert(File); - break; - } - - case SUBMODULE_UMBRELLA_DIR: { - if (First) { - Error("missing submodule metadata record at beginning of block"); - return true; - } - - if (!CurrentModule) - break; - - StringRef DirName(BlobStart, BlobLen); - if (const DirectoryEntry *Umbrella - = PP.getFileManager().getDirectory(DirName)) { - if (!CurrentModule->getUmbrellaDir()) - ModMap.setUmbrellaDir(CurrentModule, Umbrella); - else if (CurrentModule->getUmbrellaDir() != Umbrella) { - Error("mismatched umbrella directories in submodule"); - return true; - } - } - break; - } - - case SUBMODULE_METADATA: { - if (!First) { - Error("submodule metadata record not at beginning of block"); - return true; - } - First = false; - - F.BaseSubmoduleID = getTotalNumSubmodules(); - F.LocalNumSubmodules = Record[0]; - unsigned LocalBaseSubmoduleID = Record[1]; - if (F.LocalNumSubmodules > 0) { - // Introduce the global -> local mapping for submodules within this - // module. - GlobalSubmoduleMap.insert(std::make_pair(getTotalNumSubmodules()+1,&F)); - - // Introduce the local -> global mapping for submodules within this - // module. - F.SubmoduleRemap.insertOrReplace( - std::make_pair(LocalBaseSubmoduleID, - F.BaseSubmoduleID - LocalBaseSubmoduleID)); - - SubmodulesLoaded.resize(SubmodulesLoaded.size() + F.LocalNumSubmodules); - } - break; - } - - case SUBMODULE_IMPORTS: { - if (First) { - Error("missing submodule metadata record at beginning of block"); - return true; - } - - if (!CurrentModule) - break; - - for (unsigned Idx = 0; Idx != Record.size(); ++Idx) { - UnresolvedModuleImportExport Unresolved; - Unresolved.File = &F; - Unresolved.Mod = CurrentModule; - Unresolved.ID = Record[Idx]; - Unresolved.IsImport = true; - Unresolved.IsWildcard = false; - UnresolvedModuleImportExports.push_back(Unresolved); - } - break; - } - - case SUBMODULE_EXPORTS: { - if (First) { - Error("missing submodule metadata record at beginning of block"); - return true; - } - - if (!CurrentModule) - break; - - for (unsigned Idx = 0; Idx + 1 < Record.size(); Idx += 2) { - UnresolvedModuleImportExport Unresolved; - Unresolved.File = &F; - Unresolved.Mod = CurrentModule; - Unresolved.ID = Record[Idx]; - Unresolved.IsImport = false; - Unresolved.IsWildcard = Record[Idx + 1]; - UnresolvedModuleImportExports.push_back(Unresolved); - } - - // Once we've loaded the set of exports, there's no reason to keep - // the parsed, unresolved exports around. - CurrentModule->UnresolvedExports.clear(); - break; - } - case SUBMODULE_REQUIRES: { - if (First) { - Error("missing submodule metadata record at beginning of block"); - return true; - } - - if (!CurrentModule) - break; - - CurrentModule->addRequirement(StringRef(BlobStart, BlobLen), - Context.getLangOpts(), - Context.getTargetInfo()); - break; - } - } - } -} - -/// \brief Parse the record that corresponds to a LangOptions data -/// structure. -/// -/// This routine parses the language options from the AST file and then gives -/// them to the AST listener if one is set. -/// -/// \returns true if the listener deems the file unacceptable, false otherwise. -bool ASTReader::ParseLanguageOptions(const RecordData &Record, - bool Complain, - ASTReaderListener &Listener) { - LangOptions LangOpts; - unsigned Idx = 0; -#define LANGOPT(Name, Bits, Default, Description) \ - LangOpts.Name = Record[Idx++]; -#define ENUM_LANGOPT(Name, Type, Bits, Default, Description) \ - LangOpts.set##Name(static_cast<LangOptions::Type>(Record[Idx++])); -#include "clang/Basic/LangOptions.def" - - ObjCRuntime::Kind runtimeKind = (ObjCRuntime::Kind) Record[Idx++]; - VersionTuple runtimeVersion = ReadVersionTuple(Record, Idx); - LangOpts.ObjCRuntime = ObjCRuntime(runtimeKind, runtimeVersion); - - unsigned Length = Record[Idx++]; - LangOpts.CurrentModule.assign(Record.begin() + Idx, - Record.begin() + Idx + Length); - return Listener.ReadLanguageOptions(LangOpts, Complain); -} - -bool ASTReader::ParseTargetOptions(const RecordData &Record, - bool Complain, - ASTReaderListener &Listener) { - unsigned Idx = 0; - TargetOptions TargetOpts; - TargetOpts.Triple = ReadString(Record, Idx); - TargetOpts.CPU = ReadString(Record, Idx); - TargetOpts.ABI = ReadString(Record, Idx); - TargetOpts.CXXABI = ReadString(Record, Idx); - TargetOpts.LinkerVersion = ReadString(Record, Idx); - for (unsigned N = Record[Idx++]; N; --N) { - TargetOpts.FeaturesAsWritten.push_back(ReadString(Record, Idx)); - } - for (unsigned N = Record[Idx++]; N; --N) { - TargetOpts.Features.push_back(ReadString(Record, Idx)); - } - - return Listener.ReadTargetOptions(TargetOpts, Complain); -} - -bool ASTReader::ParseDiagnosticOptions(const RecordData &Record, bool Complain, - ASTReaderListener &Listener) { - DiagnosticOptions DiagOpts; - unsigned Idx = 0; -#define DIAGOPT(Name, Bits, Default) DiagOpts.Name = Record[Idx++]; -#define ENUM_DIAGOPT(Name, Type, Bits, Default) \ - DiagOpts.set##Name(static_cast<Type>(Record[Idx++])); -#include "clang/Basic/DiagnosticOptions.def" - - for (unsigned N = Record[Idx++]; N; --N) { - DiagOpts.Warnings.push_back(ReadString(Record, Idx)); - } - - return Listener.ReadDiagnosticOptions(DiagOpts, Complain); -} - -bool ASTReader::ParseFileSystemOptions(const RecordData &Record, bool Complain, - ASTReaderListener &Listener) { - FileSystemOptions FSOpts; - unsigned Idx = 0; - FSOpts.WorkingDir = ReadString(Record, Idx); - return Listener.ReadFileSystemOptions(FSOpts, Complain); -} - -bool ASTReader::ParseHeaderSearchOptions(const RecordData &Record, - bool Complain, - ASTReaderListener &Listener) { - HeaderSearchOptions HSOpts; - unsigned Idx = 0; - HSOpts.Sysroot = ReadString(Record, Idx); - - // Include entries. - for (unsigned N = Record[Idx++]; N; --N) { - std::string Path = ReadString(Record, Idx); - frontend::IncludeDirGroup Group - = static_cast<frontend::IncludeDirGroup>(Record[Idx++]); - bool IsUserSupplied = Record[Idx++]; - bool IsFramework = Record[Idx++]; - bool IgnoreSysRoot = Record[Idx++]; - bool IsInternal = Record[Idx++]; - bool ImplicitExternC = Record[Idx++]; - HSOpts.UserEntries.push_back( - HeaderSearchOptions::Entry(Path, Group, IsUserSupplied, IsFramework, - IgnoreSysRoot, IsInternal, ImplicitExternC)); - } - - // System header prefixes. - for (unsigned N = Record[Idx++]; N; --N) { - std::string Prefix = ReadString(Record, Idx); - bool IsSystemHeader = Record[Idx++]; - HSOpts.SystemHeaderPrefixes.push_back( - HeaderSearchOptions::SystemHeaderPrefix(Prefix, IsSystemHeader)); - } - - HSOpts.ResourceDir = ReadString(Record, Idx); - HSOpts.ModuleCachePath = ReadString(Record, Idx); - HSOpts.DisableModuleHash = Record[Idx++]; - HSOpts.UseBuiltinIncludes = Record[Idx++]; - HSOpts.UseStandardSystemIncludes = Record[Idx++]; - HSOpts.UseStandardCXXIncludes = Record[Idx++]; - HSOpts.UseLibcxx = Record[Idx++]; - - return Listener.ReadHeaderSearchOptions(HSOpts, Complain); -} - -bool ASTReader::ParsePreprocessorOptions(const RecordData &Record, - bool Complain, - ASTReaderListener &Listener, - std::string &SuggestedPredefines) { - PreprocessorOptions PPOpts; - unsigned Idx = 0; - - // Macro definitions/undefs - for (unsigned N = Record[Idx++]; N; --N) { - std::string Macro = ReadString(Record, Idx); - bool IsUndef = Record[Idx++]; - PPOpts.Macros.push_back(std::make_pair(Macro, IsUndef)); - } - - // Includes - for (unsigned N = Record[Idx++]; N; --N) { - PPOpts.Includes.push_back(ReadString(Record, Idx)); - } - - // Macro Includes - for (unsigned N = Record[Idx++]; N; --N) { - PPOpts.MacroIncludes.push_back(ReadString(Record, Idx)); - } - - PPOpts.UsePredefines = Record[Idx++]; - PPOpts.ImplicitPCHInclude = ReadString(Record, Idx); - PPOpts.ImplicitPTHInclude = ReadString(Record, Idx); - PPOpts.ObjCXXARCStandardLibrary = - static_cast<ObjCXXARCStandardLibraryKind>(Record[Idx++]); - SuggestedPredefines.clear(); - return Listener.ReadPreprocessorOptions(PPOpts, Complain, - SuggestedPredefines); -} - -std::pair<ModuleFile *, unsigned> -ASTReader::getModulePreprocessedEntity(unsigned GlobalIndex) { - GlobalPreprocessedEntityMapType::iterator - I = GlobalPreprocessedEntityMap.find(GlobalIndex); - assert(I != GlobalPreprocessedEntityMap.end() && - "Corrupted global preprocessed entity map"); - ModuleFile *M = I->second; - unsigned LocalIndex = GlobalIndex - M->BasePreprocessedEntityID; - return std::make_pair(M, LocalIndex); -} - -std::pair<PreprocessingRecord::iterator, PreprocessingRecord::iterator> -ASTReader::getModulePreprocessedEntities(ModuleFile &Mod) const { - if (PreprocessingRecord *PPRec = PP.getPreprocessingRecord()) - return PPRec->getIteratorsForLoadedRange(Mod.BasePreprocessedEntityID, - Mod.NumPreprocessedEntities); - - return std::make_pair(PreprocessingRecord::iterator(), - PreprocessingRecord::iterator()); -} - -std::pair<ASTReader::ModuleDeclIterator, ASTReader::ModuleDeclIterator> -ASTReader::getModuleFileLevelDecls(ModuleFile &Mod) { - return std::make_pair(ModuleDeclIterator(this, &Mod, Mod.FileSortedDecls), - ModuleDeclIterator(this, &Mod, - Mod.FileSortedDecls + Mod.NumFileSortedDecls)); -} - -PreprocessedEntity *ASTReader::ReadPreprocessedEntity(unsigned Index) { - PreprocessedEntityID PPID = Index+1; - std::pair<ModuleFile *, unsigned> PPInfo = getModulePreprocessedEntity(Index); - ModuleFile &M = *PPInfo.first; - unsigned LocalIndex = PPInfo.second; - const PPEntityOffset &PPOffs = M.PreprocessedEntityOffsets[LocalIndex]; - - SavedStreamPosition SavedPosition(M.PreprocessorDetailCursor); - M.PreprocessorDetailCursor.JumpToBit(PPOffs.BitOffset); - - unsigned Code = M.PreprocessorDetailCursor.ReadCode(); - switch (Code) { - case llvm::bitc::END_BLOCK: - return 0; - - case llvm::bitc::ENTER_SUBBLOCK: - Error("unexpected subblock record in preprocessor detail block"); - return 0; - - case llvm::bitc::DEFINE_ABBREV: - Error("unexpected abbrevation record in preprocessor detail block"); - return 0; - - default: - break; - } - - if (!PP.getPreprocessingRecord()) { - Error("no preprocessing record"); - return 0; - } - - // Read the record. - SourceRange Range(ReadSourceLocation(M, PPOffs.Begin), - ReadSourceLocation(M, PPOffs.End)); - PreprocessingRecord &PPRec = *PP.getPreprocessingRecord(); - const char *BlobStart = 0; - unsigned BlobLen = 0; - RecordData Record; - PreprocessorDetailRecordTypes RecType = - (PreprocessorDetailRecordTypes)M.PreprocessorDetailCursor.ReadRecord( - Code, Record, BlobStart, BlobLen); - switch (RecType) { - case PPD_MACRO_EXPANSION: { - bool isBuiltin = Record[0]; - IdentifierInfo *Name = 0; - MacroDefinition *Def = 0; - if (isBuiltin) - Name = getLocalIdentifier(M, Record[1]); - else { - PreprocessedEntityID - GlobalID = getGlobalPreprocessedEntityID(M, Record[1]); - Def =cast<MacroDefinition>(PPRec.getLoadedPreprocessedEntity(GlobalID-1)); - } - - MacroExpansion *ME; - if (isBuiltin) - ME = new (PPRec) MacroExpansion(Name, Range); - else - ME = new (PPRec) MacroExpansion(Def, Range); - - return ME; - } - - case PPD_MACRO_DEFINITION: { - // Decode the identifier info and then check again; if the macro is - // still defined and associated with the identifier, - IdentifierInfo *II = getLocalIdentifier(M, Record[0]); - MacroDefinition *MD - = new (PPRec) MacroDefinition(II, Range); - - if (DeserializationListener) - DeserializationListener->MacroDefinitionRead(PPID, MD); - - return MD; - } - - case PPD_INCLUSION_DIRECTIVE: { - const char *FullFileNameStart = BlobStart + Record[0]; - StringRef FullFileName(FullFileNameStart, BlobLen - Record[0]); - const FileEntry *File = 0; - if (!FullFileName.empty()) - File = PP.getFileManager().getFile(FullFileName); - - // FIXME: Stable encoding - InclusionDirective::InclusionKind Kind - = static_cast<InclusionDirective::InclusionKind>(Record[2]); - InclusionDirective *ID - = new (PPRec) InclusionDirective(PPRec, Kind, - StringRef(BlobStart, Record[0]), - Record[1], Record[3], - File, - Range); - return ID; - } - } - - llvm_unreachable("Invalid PreprocessorDetailRecordTypes"); -} - -/// \brief \arg SLocMapI points at a chunk of a module that contains no -/// preprocessed entities or the entities it contains are not the ones we are -/// looking for. Find the next module that contains entities and return the ID -/// of the first entry. -PreprocessedEntityID ASTReader::findNextPreprocessedEntity( - GlobalSLocOffsetMapType::const_iterator SLocMapI) const { - ++SLocMapI; - for (GlobalSLocOffsetMapType::const_iterator - EndI = GlobalSLocOffsetMap.end(); SLocMapI != EndI; ++SLocMapI) { - ModuleFile &M = *SLocMapI->second; - if (M.NumPreprocessedEntities) - return M.BasePreprocessedEntityID; - } - - return getTotalNumPreprocessedEntities(); -} - -namespace { - -template <unsigned PPEntityOffset::*PPLoc> -struct PPEntityComp { - const ASTReader &Reader; - ModuleFile &M; - - PPEntityComp(const ASTReader &Reader, ModuleFile &M) : Reader(Reader), M(M) { } - - bool operator()(const PPEntityOffset &L, const PPEntityOffset &R) const { - SourceLocation LHS = getLoc(L); - SourceLocation RHS = getLoc(R); - return Reader.getSourceManager().isBeforeInTranslationUnit(LHS, RHS); - } - - bool operator()(const PPEntityOffset &L, SourceLocation RHS) const { - SourceLocation LHS = getLoc(L); - return Reader.getSourceManager().isBeforeInTranslationUnit(LHS, RHS); - } - - bool operator()(SourceLocation LHS, const PPEntityOffset &R) const { - SourceLocation RHS = getLoc(R); - return Reader.getSourceManager().isBeforeInTranslationUnit(LHS, RHS); - } - - SourceLocation getLoc(const PPEntityOffset &PPE) const { - return Reader.ReadSourceLocation(M, PPE.*PPLoc); - } -}; - -} - -/// \brief Returns the first preprocessed entity ID that ends after \arg BLoc. -PreprocessedEntityID -ASTReader::findBeginPreprocessedEntity(SourceLocation BLoc) const { - if (SourceMgr.isLocalSourceLocation(BLoc)) - return getTotalNumPreprocessedEntities(); - - GlobalSLocOffsetMapType::const_iterator - SLocMapI = GlobalSLocOffsetMap.find(SourceManager::MaxLoadedOffset - - BLoc.getOffset()); - assert(SLocMapI != GlobalSLocOffsetMap.end() && - "Corrupted global sloc offset map"); - - if (SLocMapI->second->NumPreprocessedEntities == 0) - return findNextPreprocessedEntity(SLocMapI); - - ModuleFile &M = *SLocMapI->second; - typedef const PPEntityOffset *pp_iterator; - pp_iterator pp_begin = M.PreprocessedEntityOffsets; - pp_iterator pp_end = pp_begin + M.NumPreprocessedEntities; - - size_t Count = M.NumPreprocessedEntities; - size_t Half; - pp_iterator First = pp_begin; - pp_iterator PPI; - - // Do a binary search manually instead of using std::lower_bound because - // The end locations of entities may be unordered (when a macro expansion - // is inside another macro argument), but for this case it is not important - // whether we get the first macro expansion or its containing macro. - while (Count > 0) { - Half = Count/2; - PPI = First; - std::advance(PPI, Half); - if (SourceMgr.isBeforeInTranslationUnit(ReadSourceLocation(M, PPI->End), - BLoc)){ - First = PPI; - ++First; - Count = Count - Half - 1; - } else - Count = Half; - } - - if (PPI == pp_end) - return findNextPreprocessedEntity(SLocMapI); - - return M.BasePreprocessedEntityID + (PPI - pp_begin); -} - -/// \brief Returns the first preprocessed entity ID that begins after \arg ELoc. -PreprocessedEntityID -ASTReader::findEndPreprocessedEntity(SourceLocation ELoc) const { - if (SourceMgr.isLocalSourceLocation(ELoc)) - return getTotalNumPreprocessedEntities(); - - GlobalSLocOffsetMapType::const_iterator - SLocMapI = GlobalSLocOffsetMap.find(SourceManager::MaxLoadedOffset - - ELoc.getOffset()); - assert(SLocMapI != GlobalSLocOffsetMap.end() && - "Corrupted global sloc offset map"); - - if (SLocMapI->second->NumPreprocessedEntities == 0) - return findNextPreprocessedEntity(SLocMapI); - - ModuleFile &M = *SLocMapI->second; - typedef const PPEntityOffset *pp_iterator; - pp_iterator pp_begin = M.PreprocessedEntityOffsets; - pp_iterator pp_end = pp_begin + M.NumPreprocessedEntities; - pp_iterator PPI = - std::upper_bound(pp_begin, pp_end, ELoc, - PPEntityComp<&PPEntityOffset::Begin>(*this, M)); - - if (PPI == pp_end) - return findNextPreprocessedEntity(SLocMapI); - - return M.BasePreprocessedEntityID + (PPI - pp_begin); -} - -/// \brief Returns a pair of [Begin, End) indices of preallocated -/// preprocessed entities that \arg Range encompasses. -std::pair<unsigned, unsigned> - ASTReader::findPreprocessedEntitiesInRange(SourceRange Range) { - if (Range.isInvalid()) - return std::make_pair(0,0); - assert(!SourceMgr.isBeforeInTranslationUnit(Range.getEnd(),Range.getBegin())); - - PreprocessedEntityID BeginID = findBeginPreprocessedEntity(Range.getBegin()); - PreprocessedEntityID EndID = findEndPreprocessedEntity(Range.getEnd()); - return std::make_pair(BeginID, EndID); -} - -/// \brief Optionally returns true or false if the preallocated preprocessed -/// entity with index \arg Index came from file \arg FID. -llvm::Optional<bool> ASTReader::isPreprocessedEntityInFileID(unsigned Index, - FileID FID) { - if (FID.isInvalid()) - return false; - - std::pair<ModuleFile *, unsigned> PPInfo = getModulePreprocessedEntity(Index); - ModuleFile &M = *PPInfo.first; - unsigned LocalIndex = PPInfo.second; - const PPEntityOffset &PPOffs = M.PreprocessedEntityOffsets[LocalIndex]; - - SourceLocation Loc = ReadSourceLocation(M, PPOffs.Begin); - if (Loc.isInvalid()) - return false; - - if (SourceMgr.isInFileID(SourceMgr.getFileLoc(Loc), FID)) - return true; - else - return false; -} - -namespace { - /// \brief Visitor used to search for information about a header file. - class HeaderFileInfoVisitor { - ASTReader &Reader; - const FileEntry *FE; - - llvm::Optional<HeaderFileInfo> HFI; - - public: - HeaderFileInfoVisitor(ASTReader &Reader, const FileEntry *FE) - : Reader(Reader), FE(FE) { } - - static bool visit(ModuleFile &M, void *UserData) { - HeaderFileInfoVisitor *This - = static_cast<HeaderFileInfoVisitor *>(UserData); - - HeaderFileInfoTrait Trait(This->Reader, M, - &This->Reader.getPreprocessor().getHeaderSearchInfo(), - M.HeaderFileFrameworkStrings, - This->FE->getName()); - - HeaderFileInfoLookupTable *Table - = static_cast<HeaderFileInfoLookupTable *>(M.HeaderFileInfoTable); - if (!Table) - return false; - - // Look in the on-disk hash table for an entry for this file name. - HeaderFileInfoLookupTable::iterator Pos = Table->find(This->FE->getName(), - &Trait); - if (Pos == Table->end()) - return false; - - This->HFI = *Pos; - return true; - } - - llvm::Optional<HeaderFileInfo> getHeaderFileInfo() const { return HFI; } - }; -} - -HeaderFileInfo ASTReader::GetHeaderFileInfo(const FileEntry *FE) { - HeaderFileInfoVisitor Visitor(*this, FE); - ModuleMgr.visit(&HeaderFileInfoVisitor::visit, &Visitor); - if (llvm::Optional<HeaderFileInfo> HFI = Visitor.getHeaderFileInfo()) { - if (Listener) - Listener->ReadHeaderFileInfo(*HFI, FE->getUID()); - return *HFI; - } - - return HeaderFileInfo(); -} - -void ASTReader::ReadPragmaDiagnosticMappings(DiagnosticsEngine &Diag) { - // FIXME: Make it work properly with modules. - llvm::SmallVector<DiagnosticsEngine::DiagState *, 32> DiagStates; - for (ModuleIterator I = ModuleMgr.begin(), E = ModuleMgr.end(); I != E; ++I) { - ModuleFile &F = *(*I); - unsigned Idx = 0; - DiagStates.clear(); - assert(!Diag.DiagStates.empty()); - DiagStates.push_back(&Diag.DiagStates.front()); // the command-line one. - while (Idx < F.PragmaDiagMappings.size()) { - SourceLocation Loc = ReadSourceLocation(F, F.PragmaDiagMappings[Idx++]); - unsigned DiagStateID = F.PragmaDiagMappings[Idx++]; - if (DiagStateID != 0) { - Diag.DiagStatePoints.push_back( - DiagnosticsEngine::DiagStatePoint(DiagStates[DiagStateID-1], - FullSourceLoc(Loc, SourceMgr))); - continue; - } - - assert(DiagStateID == 0); - // A new DiagState was created here. - Diag.DiagStates.push_back(*Diag.GetCurDiagState()); - DiagnosticsEngine::DiagState *NewState = &Diag.DiagStates.back(); - DiagStates.push_back(NewState); - Diag.DiagStatePoints.push_back( - DiagnosticsEngine::DiagStatePoint(NewState, - FullSourceLoc(Loc, SourceMgr))); - while (1) { - assert(Idx < F.PragmaDiagMappings.size() && - "Invalid data, didn't find '-1' marking end of diag/map pairs"); - if (Idx >= F.PragmaDiagMappings.size()) { - break; // Something is messed up but at least avoid infinite loop in - // release build. - } - unsigned DiagID = F.PragmaDiagMappings[Idx++]; - if (DiagID == (unsigned)-1) { - break; // no more diag/map pairs for this location. - } - diag::Mapping Map = (diag::Mapping)F.PragmaDiagMappings[Idx++]; - DiagnosticMappingInfo MappingInfo = Diag.makeMappingInfo(Map, Loc); - Diag.GetCurDiagState()->setMappingInfo(DiagID, MappingInfo); - } - } - } -} - -/// \brief Get the correct cursor and offset for loading a type. -ASTReader::RecordLocation ASTReader::TypeCursorForIndex(unsigned Index) { - GlobalTypeMapType::iterator I = GlobalTypeMap.find(Index); - assert(I != GlobalTypeMap.end() && "Corrupted global type map"); - ModuleFile *M = I->second; - return RecordLocation(M, M->TypeOffsets[Index - M->BaseTypeIndex]); -} - -/// \brief Read and return the type with the given index.. -/// -/// The index is the type ID, shifted and minus the number of predefs. This -/// routine actually reads the record corresponding to the type at the given -/// location. It is a helper routine for GetType, which deals with reading type -/// IDs. -QualType ASTReader::readTypeRecord(unsigned Index) { - RecordLocation Loc = TypeCursorForIndex(Index); - llvm::BitstreamCursor &DeclsCursor = Loc.F->DeclsCursor; - - // Keep track of where we are in the stream, then jump back there - // after reading this type. - SavedStreamPosition SavedPosition(DeclsCursor); - - ReadingKindTracker ReadingKind(Read_Type, *this); - - // Note that we are loading a type record. - Deserializing AType(this); - - unsigned Idx = 0; - DeclsCursor.JumpToBit(Loc.Offset); - RecordData Record; - unsigned Code = DeclsCursor.ReadCode(); - switch ((TypeCode)DeclsCursor.ReadRecord(Code, Record)) { - case TYPE_EXT_QUAL: { - if (Record.size() != 2) { - Error("Incorrect encoding of extended qualifier type"); - return QualType(); - } - QualType Base = readType(*Loc.F, Record, Idx); - Qualifiers Quals = Qualifiers::fromOpaqueValue(Record[Idx++]); - return Context.getQualifiedType(Base, Quals); - } - - case TYPE_COMPLEX: { - if (Record.size() != 1) { - Error("Incorrect encoding of complex type"); - return QualType(); - } - QualType ElemType = readType(*Loc.F, Record, Idx); - return Context.getComplexType(ElemType); - } - - case TYPE_POINTER: { - if (Record.size() != 1) { - Error("Incorrect encoding of pointer type"); - return QualType(); - } - QualType PointeeType = readType(*Loc.F, Record, Idx); - return Context.getPointerType(PointeeType); - } - - case TYPE_BLOCK_POINTER: { - if (Record.size() != 1) { - Error("Incorrect encoding of block pointer type"); - return QualType(); - } - QualType PointeeType = readType(*Loc.F, Record, Idx); - return Context.getBlockPointerType(PointeeType); - } - - case TYPE_LVALUE_REFERENCE: { - if (Record.size() != 2) { - Error("Incorrect encoding of lvalue reference type"); - return QualType(); - } - QualType PointeeType = readType(*Loc.F, Record, Idx); - return Context.getLValueReferenceType(PointeeType, Record[1]); - } - - case TYPE_RVALUE_REFERENCE: { - if (Record.size() != 1) { - Error("Incorrect encoding of rvalue reference type"); - return QualType(); - } - QualType PointeeType = readType(*Loc.F, Record, Idx); - return Context.getRValueReferenceType(PointeeType); - } - - case TYPE_MEMBER_POINTER: { - if (Record.size() != 2) { - Error("Incorrect encoding of member pointer type"); - return QualType(); - } - QualType PointeeType = readType(*Loc.F, Record, Idx); - QualType ClassType = readType(*Loc.F, Record, Idx); - if (PointeeType.isNull() || ClassType.isNull()) - return QualType(); - - return Context.getMemberPointerType(PointeeType, ClassType.getTypePtr()); - } - - case TYPE_CONSTANT_ARRAY: { - QualType ElementType = readType(*Loc.F, Record, Idx); - ArrayType::ArraySizeModifier ASM = (ArrayType::ArraySizeModifier)Record[1]; - unsigned IndexTypeQuals = Record[2]; - unsigned Idx = 3; - llvm::APInt Size = ReadAPInt(Record, Idx); - return Context.getConstantArrayType(ElementType, Size, - ASM, IndexTypeQuals); - } - - case TYPE_INCOMPLETE_ARRAY: { - QualType ElementType = readType(*Loc.F, Record, Idx); - ArrayType::ArraySizeModifier ASM = (ArrayType::ArraySizeModifier)Record[1]; - unsigned IndexTypeQuals = Record[2]; - return Context.getIncompleteArrayType(ElementType, ASM, IndexTypeQuals); - } - - case TYPE_VARIABLE_ARRAY: { - QualType ElementType = readType(*Loc.F, Record, Idx); - ArrayType::ArraySizeModifier ASM = (ArrayType::ArraySizeModifier)Record[1]; - unsigned IndexTypeQuals = Record[2]; - SourceLocation LBLoc = ReadSourceLocation(*Loc.F, Record[3]); - SourceLocation RBLoc = ReadSourceLocation(*Loc.F, Record[4]); - return Context.getVariableArrayType(ElementType, ReadExpr(*Loc.F), - ASM, IndexTypeQuals, - SourceRange(LBLoc, RBLoc)); - } - - case TYPE_VECTOR: { - if (Record.size() != 3) { - Error("incorrect encoding of vector type in AST file"); - return QualType(); - } - - QualType ElementType = readType(*Loc.F, Record, Idx); - unsigned NumElements = Record[1]; - unsigned VecKind = Record[2]; - return Context.getVectorType(ElementType, NumElements, - (VectorType::VectorKind)VecKind); - } - - case TYPE_EXT_VECTOR: { - if (Record.size() != 3) { - Error("incorrect encoding of extended vector type in AST file"); - return QualType(); - } - - QualType ElementType = readType(*Loc.F, Record, Idx); - unsigned NumElements = Record[1]; - return Context.getExtVectorType(ElementType, NumElements); - } - - case TYPE_FUNCTION_NO_PROTO: { - if (Record.size() != 6) { - Error("incorrect encoding of no-proto function type"); - return QualType(); - } - QualType ResultType = readType(*Loc.F, Record, Idx); - FunctionType::ExtInfo Info(Record[1], Record[2], Record[3], - (CallingConv)Record[4], Record[5]); - return Context.getFunctionNoProtoType(ResultType, Info); - } - - case TYPE_FUNCTION_PROTO: { - QualType ResultType = readType(*Loc.F, Record, Idx); - - FunctionProtoType::ExtProtoInfo EPI; - EPI.ExtInfo = FunctionType::ExtInfo(/*noreturn*/ Record[1], - /*hasregparm*/ Record[2], - /*regparm*/ Record[3], - static_cast<CallingConv>(Record[4]), - /*produces*/ Record[5]); - - unsigned Idx = 6; - unsigned NumParams = Record[Idx++]; - SmallVector<QualType, 16> ParamTypes; - for (unsigned I = 0; I != NumParams; ++I) - ParamTypes.push_back(readType(*Loc.F, Record, Idx)); - - EPI.Variadic = Record[Idx++]; - EPI.HasTrailingReturn = Record[Idx++]; - EPI.TypeQuals = Record[Idx++]; - EPI.RefQualifier = static_cast<RefQualifierKind>(Record[Idx++]); - ExceptionSpecificationType EST = - static_cast<ExceptionSpecificationType>(Record[Idx++]); - EPI.ExceptionSpecType = EST; - SmallVector<QualType, 2> Exceptions; - if (EST == EST_Dynamic) { - EPI.NumExceptions = Record[Idx++]; - for (unsigned I = 0; I != EPI.NumExceptions; ++I) - Exceptions.push_back(readType(*Loc.F, Record, Idx)); - EPI.Exceptions = Exceptions.data(); - } else if (EST == EST_ComputedNoexcept) { - EPI.NoexceptExpr = ReadExpr(*Loc.F); - } else if (EST == EST_Uninstantiated) { - EPI.ExceptionSpecDecl = ReadDeclAs<FunctionDecl>(*Loc.F, Record, Idx); - EPI.ExceptionSpecTemplate = ReadDeclAs<FunctionDecl>(*Loc.F, Record, Idx); - } else if (EST == EST_Unevaluated) { - EPI.ExceptionSpecDecl = ReadDeclAs<FunctionDecl>(*Loc.F, Record, Idx); - } - return Context.getFunctionType(ResultType, ParamTypes.data(), NumParams, - EPI); - } - - case TYPE_UNRESOLVED_USING: { - unsigned Idx = 0; - return Context.getTypeDeclType( - ReadDeclAs<UnresolvedUsingTypenameDecl>(*Loc.F, Record, Idx)); - } - - case TYPE_TYPEDEF: { - if (Record.size() != 2) { - Error("incorrect encoding of typedef type"); - return QualType(); - } - unsigned Idx = 0; - TypedefNameDecl *Decl = ReadDeclAs<TypedefNameDecl>(*Loc.F, Record, Idx); - QualType Canonical = readType(*Loc.F, Record, Idx); - if (!Canonical.isNull()) - Canonical = Context.getCanonicalType(Canonical); - return Context.getTypedefType(Decl, Canonical); - } - - case TYPE_TYPEOF_EXPR: - return Context.getTypeOfExprType(ReadExpr(*Loc.F)); - - case TYPE_TYPEOF: { - if (Record.size() != 1) { - Error("incorrect encoding of typeof(type) in AST file"); - return QualType(); - } - QualType UnderlyingType = readType(*Loc.F, Record, Idx); - return Context.getTypeOfType(UnderlyingType); - } - - case TYPE_DECLTYPE: { - QualType UnderlyingType = readType(*Loc.F, Record, Idx); - return Context.getDecltypeType(ReadExpr(*Loc.F), UnderlyingType); - } - - case TYPE_UNARY_TRANSFORM: { - QualType BaseType = readType(*Loc.F, Record, Idx); - QualType UnderlyingType = readType(*Loc.F, Record, Idx); - UnaryTransformType::UTTKind UKind = (UnaryTransformType::UTTKind)Record[2]; - return Context.getUnaryTransformType(BaseType, UnderlyingType, UKind); - } - - case TYPE_AUTO: - return Context.getAutoType(readType(*Loc.F, Record, Idx)); - - case TYPE_RECORD: { - if (Record.size() != 2) { - Error("incorrect encoding of record type"); - return QualType(); - } - unsigned Idx = 0; - bool IsDependent = Record[Idx++]; - RecordDecl *RD = ReadDeclAs<RecordDecl>(*Loc.F, Record, Idx); - RD = cast_or_null<RecordDecl>(RD->getCanonicalDecl()); - QualType T = Context.getRecordType(RD); - const_cast<Type*>(T.getTypePtr())->setDependent(IsDependent); - return T; - } - - case TYPE_ENUM: { - if (Record.size() != 2) { - Error("incorrect encoding of enum type"); - return QualType(); - } - unsigned Idx = 0; - bool IsDependent = Record[Idx++]; - QualType T - = Context.getEnumType(ReadDeclAs<EnumDecl>(*Loc.F, Record, Idx)); - const_cast<Type*>(T.getTypePtr())->setDependent(IsDependent); - return T; - } - - case TYPE_ATTRIBUTED: { - if (Record.size() != 3) { - Error("incorrect encoding of attributed type"); - return QualType(); - } - QualType modifiedType = readType(*Loc.F, Record, Idx); - QualType equivalentType = readType(*Loc.F, Record, Idx); - AttributedType::Kind kind = static_cast<AttributedType::Kind>(Record[2]); - return Context.getAttributedType(kind, modifiedType, equivalentType); - } - - case TYPE_PAREN: { - if (Record.size() != 1) { - Error("incorrect encoding of paren type"); - return QualType(); - } - QualType InnerType = readType(*Loc.F, Record, Idx); - return Context.getParenType(InnerType); - } - - case TYPE_PACK_EXPANSION: { - if (Record.size() != 2) { - Error("incorrect encoding of pack expansion type"); - return QualType(); - } - QualType Pattern = readType(*Loc.F, Record, Idx); - if (Pattern.isNull()) - return QualType(); - llvm::Optional<unsigned> NumExpansions; - if (Record[1]) - NumExpansions = Record[1] - 1; - return Context.getPackExpansionType(Pattern, NumExpansions); - } - - case TYPE_ELABORATED: { - unsigned Idx = 0; - ElaboratedTypeKeyword Keyword = (ElaboratedTypeKeyword)Record[Idx++]; - NestedNameSpecifier *NNS = ReadNestedNameSpecifier(*Loc.F, Record, Idx); - QualType NamedType = readType(*Loc.F, Record, Idx); - return Context.getElaboratedType(Keyword, NNS, NamedType); - } - - case TYPE_OBJC_INTERFACE: { - unsigned Idx = 0; - ObjCInterfaceDecl *ItfD - = ReadDeclAs<ObjCInterfaceDecl>(*Loc.F, Record, Idx); - return Context.getObjCInterfaceType(ItfD->getCanonicalDecl()); - } - - case TYPE_OBJC_OBJECT: { - unsigned Idx = 0; - QualType Base = readType(*Loc.F, Record, Idx); - unsigned NumProtos = Record[Idx++]; - SmallVector<ObjCProtocolDecl*, 4> Protos; - for (unsigned I = 0; I != NumProtos; ++I) - Protos.push_back(ReadDeclAs<ObjCProtocolDecl>(*Loc.F, Record, Idx)); - return Context.getObjCObjectType(Base, Protos.data(), NumProtos); - } - - case TYPE_OBJC_OBJECT_POINTER: { - unsigned Idx = 0; - QualType Pointee = readType(*Loc.F, Record, Idx); - return Context.getObjCObjectPointerType(Pointee); - } - - case TYPE_SUBST_TEMPLATE_TYPE_PARM: { - unsigned Idx = 0; - QualType Parm = readType(*Loc.F, Record, Idx); - QualType Replacement = readType(*Loc.F, Record, Idx); - return - Context.getSubstTemplateTypeParmType(cast<TemplateTypeParmType>(Parm), - Replacement); - } - - case TYPE_SUBST_TEMPLATE_TYPE_PARM_PACK: { - unsigned Idx = 0; - QualType Parm = readType(*Loc.F, Record, Idx); - TemplateArgument ArgPack = ReadTemplateArgument(*Loc.F, Record, Idx); - return Context.getSubstTemplateTypeParmPackType( - cast<TemplateTypeParmType>(Parm), - ArgPack); - } - - case TYPE_INJECTED_CLASS_NAME: { - CXXRecordDecl *D = ReadDeclAs<CXXRecordDecl>(*Loc.F, Record, Idx); - QualType TST = readType(*Loc.F, Record, Idx); // probably derivable - // FIXME: ASTContext::getInjectedClassNameType is not currently suitable - // for AST reading, too much interdependencies. - return - QualType(new (Context, TypeAlignment) InjectedClassNameType(D, TST), 0); - } - - case TYPE_TEMPLATE_TYPE_PARM: { - unsigned Idx = 0; - unsigned Depth = Record[Idx++]; - unsigned Index = Record[Idx++]; - bool Pack = Record[Idx++]; - TemplateTypeParmDecl *D - = ReadDeclAs<TemplateTypeParmDecl>(*Loc.F, Record, Idx); - return Context.getTemplateTypeParmType(Depth, Index, Pack, D); - } - - case TYPE_DEPENDENT_NAME: { - unsigned Idx = 0; - ElaboratedTypeKeyword Keyword = (ElaboratedTypeKeyword)Record[Idx++]; - NestedNameSpecifier *NNS = ReadNestedNameSpecifier(*Loc.F, Record, Idx); - const IdentifierInfo *Name = this->GetIdentifierInfo(*Loc.F, Record, Idx); - QualType Canon = readType(*Loc.F, Record, Idx); - if (!Canon.isNull()) - Canon = Context.getCanonicalType(Canon); - return Context.getDependentNameType(Keyword, NNS, Name, Canon); - } - - case TYPE_DEPENDENT_TEMPLATE_SPECIALIZATION: { - unsigned Idx = 0; - ElaboratedTypeKeyword Keyword = (ElaboratedTypeKeyword)Record[Idx++]; - NestedNameSpecifier *NNS = ReadNestedNameSpecifier(*Loc.F, Record, Idx); - const IdentifierInfo *Name = this->GetIdentifierInfo(*Loc.F, Record, Idx); - unsigned NumArgs = Record[Idx++]; - SmallVector<TemplateArgument, 8> Args; - Args.reserve(NumArgs); - while (NumArgs--) - Args.push_back(ReadTemplateArgument(*Loc.F, Record, Idx)); - return Context.getDependentTemplateSpecializationType(Keyword, NNS, Name, - Args.size(), Args.data()); - } - - case TYPE_DEPENDENT_SIZED_ARRAY: { - unsigned Idx = 0; - - // ArrayType - QualType ElementType = readType(*Loc.F, Record, Idx); - ArrayType::ArraySizeModifier ASM - = (ArrayType::ArraySizeModifier)Record[Idx++]; - unsigned IndexTypeQuals = Record[Idx++]; - - // DependentSizedArrayType - Expr *NumElts = ReadExpr(*Loc.F); - SourceRange Brackets = ReadSourceRange(*Loc.F, Record, Idx); - - return Context.getDependentSizedArrayType(ElementType, NumElts, ASM, - IndexTypeQuals, Brackets); - } - - case TYPE_TEMPLATE_SPECIALIZATION: { - unsigned Idx = 0; - bool IsDependent = Record[Idx++]; - TemplateName Name = ReadTemplateName(*Loc.F, Record, Idx); - SmallVector<TemplateArgument, 8> Args; - ReadTemplateArgumentList(Args, *Loc.F, Record, Idx); - QualType Underlying = readType(*Loc.F, Record, Idx); - QualType T; - if (Underlying.isNull()) - T = Context.getCanonicalTemplateSpecializationType(Name, Args.data(), - Args.size()); - else - T = Context.getTemplateSpecializationType(Name, Args.data(), - Args.size(), Underlying); - const_cast<Type*>(T.getTypePtr())->setDependent(IsDependent); - return T; - } - - case TYPE_ATOMIC: { - if (Record.size() != 1) { - Error("Incorrect encoding of atomic type"); - return QualType(); - } - QualType ValueType = readType(*Loc.F, Record, Idx); - return Context.getAtomicType(ValueType); - } - } - llvm_unreachable("Invalid TypeCode!"); -} - -class clang::TypeLocReader : public TypeLocVisitor<TypeLocReader> { - ASTReader &Reader; - ModuleFile &F; - const ASTReader::RecordData &Record; - unsigned &Idx; - - SourceLocation ReadSourceLocation(const ASTReader::RecordData &R, - unsigned &I) { - return Reader.ReadSourceLocation(F, R, I); - } - - template<typename T> - T *ReadDeclAs(const ASTReader::RecordData &Record, unsigned &Idx) { - return Reader.ReadDeclAs<T>(F, Record, Idx); - } - -public: - TypeLocReader(ASTReader &Reader, ModuleFile &F, - const ASTReader::RecordData &Record, unsigned &Idx) - : Reader(Reader), F(F), Record(Record), Idx(Idx) - { } - - // We want compile-time assurance that we've enumerated all of - // these, so unfortunately we have to declare them first, then - // define them out-of-line. -#define ABSTRACT_TYPELOC(CLASS, PARENT) -#define TYPELOC(CLASS, PARENT) \ - void Visit##CLASS##TypeLoc(CLASS##TypeLoc TyLoc); -#include "clang/AST/TypeLocNodes.def" - - void VisitFunctionTypeLoc(FunctionTypeLoc); - void VisitArrayTypeLoc(ArrayTypeLoc); -}; - -void TypeLocReader::VisitQualifiedTypeLoc(QualifiedTypeLoc TL) { - // nothing to do -} -void TypeLocReader::VisitBuiltinTypeLoc(BuiltinTypeLoc TL) { - TL.setBuiltinLoc(ReadSourceLocation(Record, Idx)); - if (TL.needsExtraLocalData()) { - TL.setWrittenTypeSpec(static_cast<DeclSpec::TST>(Record[Idx++])); - TL.setWrittenSignSpec(static_cast<DeclSpec::TSS>(Record[Idx++])); - TL.setWrittenWidthSpec(static_cast<DeclSpec::TSW>(Record[Idx++])); - TL.setModeAttr(Record[Idx++]); - } -} -void TypeLocReader::VisitComplexTypeLoc(ComplexTypeLoc TL) { - TL.setNameLoc(ReadSourceLocation(Record, Idx)); -} -void TypeLocReader::VisitPointerTypeLoc(PointerTypeLoc TL) { - TL.setStarLoc(ReadSourceLocation(Record, Idx)); -} -void TypeLocReader::VisitBlockPointerTypeLoc(BlockPointerTypeLoc TL) { - TL.setCaretLoc(ReadSourceLocation(Record, Idx)); -} -void TypeLocReader::VisitLValueReferenceTypeLoc(LValueReferenceTypeLoc TL) { - TL.setAmpLoc(ReadSourceLocation(Record, Idx)); -} -void TypeLocReader::VisitRValueReferenceTypeLoc(RValueReferenceTypeLoc TL) { - TL.setAmpAmpLoc(ReadSourceLocation(Record, Idx)); -} -void TypeLocReader::VisitMemberPointerTypeLoc(MemberPointerTypeLoc TL) { - TL.setStarLoc(ReadSourceLocation(Record, Idx)); - TL.setClassTInfo(Reader.GetTypeSourceInfo(F, Record, Idx)); -} -void TypeLocReader::VisitArrayTypeLoc(ArrayTypeLoc TL) { - TL.setLBracketLoc(ReadSourceLocation(Record, Idx)); - TL.setRBracketLoc(ReadSourceLocation(Record, Idx)); - if (Record[Idx++]) - TL.setSizeExpr(Reader.ReadExpr(F)); - else - TL.setSizeExpr(0); -} -void TypeLocReader::VisitConstantArrayTypeLoc(ConstantArrayTypeLoc TL) { - VisitArrayTypeLoc(TL); -} -void TypeLocReader::VisitIncompleteArrayTypeLoc(IncompleteArrayTypeLoc TL) { - VisitArrayTypeLoc(TL); -} -void TypeLocReader::VisitVariableArrayTypeLoc(VariableArrayTypeLoc TL) { - VisitArrayTypeLoc(TL); -} -void TypeLocReader::VisitDependentSizedArrayTypeLoc( - DependentSizedArrayTypeLoc TL) { - VisitArrayTypeLoc(TL); -} -void TypeLocReader::VisitDependentSizedExtVectorTypeLoc( - DependentSizedExtVectorTypeLoc TL) { - TL.setNameLoc(ReadSourceLocation(Record, Idx)); -} -void TypeLocReader::VisitVectorTypeLoc(VectorTypeLoc TL) { - TL.setNameLoc(ReadSourceLocation(Record, Idx)); -} -void TypeLocReader::VisitExtVectorTypeLoc(ExtVectorTypeLoc TL) { - TL.setNameLoc(ReadSourceLocation(Record, Idx)); -} -void TypeLocReader::VisitFunctionTypeLoc(FunctionTypeLoc TL) { - TL.setLocalRangeBegin(ReadSourceLocation(Record, Idx)); - TL.setLParenLoc(ReadSourceLocation(Record, Idx)); - TL.setRParenLoc(ReadSourceLocation(Record, Idx)); - TL.setLocalRangeEnd(ReadSourceLocation(Record, Idx)); - for (unsigned i = 0, e = TL.getNumArgs(); i != e; ++i) { - TL.setArg(i, ReadDeclAs<ParmVarDecl>(Record, Idx)); - } -} -void TypeLocReader::VisitFunctionProtoTypeLoc(FunctionProtoTypeLoc TL) { - VisitFunctionTypeLoc(TL); -} -void TypeLocReader::VisitFunctionNoProtoTypeLoc(FunctionNoProtoTypeLoc TL) { - VisitFunctionTypeLoc(TL); -} -void TypeLocReader::VisitUnresolvedUsingTypeLoc(UnresolvedUsingTypeLoc TL) { - TL.setNameLoc(ReadSourceLocation(Record, Idx)); -} -void TypeLocReader::VisitTypedefTypeLoc(TypedefTypeLoc TL) { - TL.setNameLoc(ReadSourceLocation(Record, Idx)); -} -void TypeLocReader::VisitTypeOfExprTypeLoc(TypeOfExprTypeLoc TL) { - TL.setTypeofLoc(ReadSourceLocation(Record, Idx)); - TL.setLParenLoc(ReadSourceLocation(Record, Idx)); - TL.setRParenLoc(ReadSourceLocation(Record, Idx)); -} -void TypeLocReader::VisitTypeOfTypeLoc(TypeOfTypeLoc TL) { - TL.setTypeofLoc(ReadSourceLocation(Record, Idx)); - TL.setLParenLoc(ReadSourceLocation(Record, Idx)); - TL.setRParenLoc(ReadSourceLocation(Record, Idx)); - TL.setUnderlyingTInfo(Reader.GetTypeSourceInfo(F, Record, Idx)); -} -void TypeLocReader::VisitDecltypeTypeLoc(DecltypeTypeLoc TL) { - TL.setNameLoc(ReadSourceLocation(Record, Idx)); -} -void TypeLocReader::VisitUnaryTransformTypeLoc(UnaryTransformTypeLoc TL) { - TL.setKWLoc(ReadSourceLocation(Record, Idx)); - TL.setLParenLoc(ReadSourceLocation(Record, Idx)); - TL.setRParenLoc(ReadSourceLocation(Record, Idx)); - TL.setUnderlyingTInfo(Reader.GetTypeSourceInfo(F, Record, Idx)); -} -void TypeLocReader::VisitAutoTypeLoc(AutoTypeLoc TL) { - TL.setNameLoc(ReadSourceLocation(Record, Idx)); -} -void TypeLocReader::VisitRecordTypeLoc(RecordTypeLoc TL) { - TL.setNameLoc(ReadSourceLocation(Record, Idx)); -} -void TypeLocReader::VisitEnumTypeLoc(EnumTypeLoc TL) { - TL.setNameLoc(ReadSourceLocation(Record, Idx)); -} -void TypeLocReader::VisitAttributedTypeLoc(AttributedTypeLoc TL) { - TL.setAttrNameLoc(ReadSourceLocation(Record, Idx)); - if (TL.hasAttrOperand()) { - SourceRange range; - range.setBegin(ReadSourceLocation(Record, Idx)); - range.setEnd(ReadSourceLocation(Record, Idx)); - TL.setAttrOperandParensRange(range); - } - if (TL.hasAttrExprOperand()) { - if (Record[Idx++]) - TL.setAttrExprOperand(Reader.ReadExpr(F)); - else - TL.setAttrExprOperand(0); - } else if (TL.hasAttrEnumOperand()) - TL.setAttrEnumOperandLoc(ReadSourceLocation(Record, Idx)); -} -void TypeLocReader::VisitTemplateTypeParmTypeLoc(TemplateTypeParmTypeLoc TL) { - TL.setNameLoc(ReadSourceLocation(Record, Idx)); -} -void TypeLocReader::VisitSubstTemplateTypeParmTypeLoc( - SubstTemplateTypeParmTypeLoc TL) { - TL.setNameLoc(ReadSourceLocation(Record, Idx)); -} -void TypeLocReader::VisitSubstTemplateTypeParmPackTypeLoc( - SubstTemplateTypeParmPackTypeLoc TL) { - TL.setNameLoc(ReadSourceLocation(Record, Idx)); -} -void TypeLocReader::VisitTemplateSpecializationTypeLoc( - TemplateSpecializationTypeLoc TL) { - TL.setTemplateKeywordLoc(ReadSourceLocation(Record, Idx)); - TL.setTemplateNameLoc(ReadSourceLocation(Record, Idx)); - TL.setLAngleLoc(ReadSourceLocation(Record, Idx)); - TL.setRAngleLoc(ReadSourceLocation(Record, Idx)); - for (unsigned i = 0, e = TL.getNumArgs(); i != e; ++i) - TL.setArgLocInfo(i, - Reader.GetTemplateArgumentLocInfo(F, - TL.getTypePtr()->getArg(i).getKind(), - Record, Idx)); -} -void TypeLocReader::VisitParenTypeLoc(ParenTypeLoc TL) { - TL.setLParenLoc(ReadSourceLocation(Record, Idx)); - TL.setRParenLoc(ReadSourceLocation(Record, Idx)); -} -void TypeLocReader::VisitElaboratedTypeLoc(ElaboratedTypeLoc TL) { - TL.setElaboratedKeywordLoc(ReadSourceLocation(Record, Idx)); - TL.setQualifierLoc(Reader.ReadNestedNameSpecifierLoc(F, Record, Idx)); -} -void TypeLocReader::VisitInjectedClassNameTypeLoc(InjectedClassNameTypeLoc TL) { - TL.setNameLoc(ReadSourceLocation(Record, Idx)); -} -void TypeLocReader::VisitDependentNameTypeLoc(DependentNameTypeLoc TL) { - TL.setElaboratedKeywordLoc(ReadSourceLocation(Record, Idx)); - TL.setQualifierLoc(Reader.ReadNestedNameSpecifierLoc(F, Record, Idx)); - TL.setNameLoc(ReadSourceLocation(Record, Idx)); -} -void TypeLocReader::VisitDependentTemplateSpecializationTypeLoc( - DependentTemplateSpecializationTypeLoc TL) { - TL.setElaboratedKeywordLoc(ReadSourceLocation(Record, Idx)); - TL.setQualifierLoc(Reader.ReadNestedNameSpecifierLoc(F, Record, Idx)); - TL.setTemplateKeywordLoc(ReadSourceLocation(Record, Idx)); - TL.setTemplateNameLoc(ReadSourceLocation(Record, Idx)); - TL.setLAngleLoc(ReadSourceLocation(Record, Idx)); - TL.setRAngleLoc(ReadSourceLocation(Record, Idx)); - for (unsigned I = 0, E = TL.getNumArgs(); I != E; ++I) - TL.setArgLocInfo(I, - Reader.GetTemplateArgumentLocInfo(F, - TL.getTypePtr()->getArg(I).getKind(), - Record, Idx)); -} -void TypeLocReader::VisitPackExpansionTypeLoc(PackExpansionTypeLoc TL) { - TL.setEllipsisLoc(ReadSourceLocation(Record, Idx)); -} -void TypeLocReader::VisitObjCInterfaceTypeLoc(ObjCInterfaceTypeLoc TL) { - TL.setNameLoc(ReadSourceLocation(Record, Idx)); -} -void TypeLocReader::VisitObjCObjectTypeLoc(ObjCObjectTypeLoc TL) { - TL.setHasBaseTypeAsWritten(Record[Idx++]); - TL.setLAngleLoc(ReadSourceLocation(Record, Idx)); - TL.setRAngleLoc(ReadSourceLocation(Record, Idx)); - for (unsigned i = 0, e = TL.getNumProtocols(); i != e; ++i) - TL.setProtocolLoc(i, ReadSourceLocation(Record, Idx)); -} -void TypeLocReader::VisitObjCObjectPointerTypeLoc(ObjCObjectPointerTypeLoc TL) { - TL.setStarLoc(ReadSourceLocation(Record, Idx)); -} -void TypeLocReader::VisitAtomicTypeLoc(AtomicTypeLoc TL) { - TL.setKWLoc(ReadSourceLocation(Record, Idx)); - TL.setLParenLoc(ReadSourceLocation(Record, Idx)); - TL.setRParenLoc(ReadSourceLocation(Record, Idx)); -} - -TypeSourceInfo *ASTReader::GetTypeSourceInfo(ModuleFile &F, - const RecordData &Record, - unsigned &Idx) { - QualType InfoTy = readType(F, Record, Idx); - if (InfoTy.isNull()) - return 0; - - TypeSourceInfo *TInfo = getContext().CreateTypeSourceInfo(InfoTy); - TypeLocReader TLR(*this, F, Record, Idx); - for (TypeLoc TL = TInfo->getTypeLoc(); !TL.isNull(); TL = TL.getNextTypeLoc()) - TLR.Visit(TL); - return TInfo; -} - -QualType ASTReader::GetType(TypeID ID) { - unsigned FastQuals = ID & Qualifiers::FastMask; - unsigned Index = ID >> Qualifiers::FastWidth; - - if (Index < NUM_PREDEF_TYPE_IDS) { - QualType T; - switch ((PredefinedTypeIDs)Index) { - case PREDEF_TYPE_NULL_ID: return QualType(); - case PREDEF_TYPE_VOID_ID: T = Context.VoidTy; break; - case PREDEF_TYPE_BOOL_ID: T = Context.BoolTy; break; - - case PREDEF_TYPE_CHAR_U_ID: - case PREDEF_TYPE_CHAR_S_ID: - // FIXME: Check that the signedness of CharTy is correct! - T = Context.CharTy; - break; - - case PREDEF_TYPE_UCHAR_ID: T = Context.UnsignedCharTy; break; - case PREDEF_TYPE_USHORT_ID: T = Context.UnsignedShortTy; break; - case PREDEF_TYPE_UINT_ID: T = Context.UnsignedIntTy; break; - case PREDEF_TYPE_ULONG_ID: T = Context.UnsignedLongTy; break; - case PREDEF_TYPE_ULONGLONG_ID: T = Context.UnsignedLongLongTy; break; - case PREDEF_TYPE_UINT128_ID: T = Context.UnsignedInt128Ty; break; - case PREDEF_TYPE_SCHAR_ID: T = Context.SignedCharTy; break; - case PREDEF_TYPE_WCHAR_ID: T = Context.WCharTy; break; - case PREDEF_TYPE_SHORT_ID: T = Context.ShortTy; break; - case PREDEF_TYPE_INT_ID: T = Context.IntTy; break; - case PREDEF_TYPE_LONG_ID: T = Context.LongTy; break; - case PREDEF_TYPE_LONGLONG_ID: T = Context.LongLongTy; break; - case PREDEF_TYPE_INT128_ID: T = Context.Int128Ty; break; - case PREDEF_TYPE_HALF_ID: T = Context.HalfTy; break; - case PREDEF_TYPE_FLOAT_ID: T = Context.FloatTy; break; - case PREDEF_TYPE_DOUBLE_ID: T = Context.DoubleTy; break; - case PREDEF_TYPE_LONGDOUBLE_ID: T = Context.LongDoubleTy; break; - case PREDEF_TYPE_OVERLOAD_ID: T = Context.OverloadTy; break; - case PREDEF_TYPE_BOUND_MEMBER: T = Context.BoundMemberTy; break; - case PREDEF_TYPE_PSEUDO_OBJECT: T = Context.PseudoObjectTy; break; - case PREDEF_TYPE_DEPENDENT_ID: T = Context.DependentTy; break; - case PREDEF_TYPE_UNKNOWN_ANY: T = Context.UnknownAnyTy; break; - case PREDEF_TYPE_NULLPTR_ID: T = Context.NullPtrTy; break; - case PREDEF_TYPE_CHAR16_ID: T = Context.Char16Ty; break; - case PREDEF_TYPE_CHAR32_ID: T = Context.Char32Ty; break; - case PREDEF_TYPE_OBJC_ID: T = Context.ObjCBuiltinIdTy; break; - case PREDEF_TYPE_OBJC_CLASS: T = Context.ObjCBuiltinClassTy; break; - case PREDEF_TYPE_OBJC_SEL: T = Context.ObjCBuiltinSelTy; break; - case PREDEF_TYPE_AUTO_DEDUCT: T = Context.getAutoDeductType(); break; - - case PREDEF_TYPE_AUTO_RREF_DEDUCT: - T = Context.getAutoRRefDeductType(); - break; - - case PREDEF_TYPE_ARC_UNBRIDGED_CAST: - T = Context.ARCUnbridgedCastTy; - break; - - case PREDEF_TYPE_VA_LIST_TAG: - T = Context.getVaListTagType(); - break; - - case PREDEF_TYPE_BUILTIN_FN: - T = Context.BuiltinFnTy; - break; - } - - assert(!T.isNull() && "Unknown predefined type"); - return T.withFastQualifiers(FastQuals); - } - - Index -= NUM_PREDEF_TYPE_IDS; - assert(Index < TypesLoaded.size() && "Type index out-of-range"); - if (TypesLoaded[Index].isNull()) { - TypesLoaded[Index] = readTypeRecord(Index); - if (TypesLoaded[Index].isNull()) - return QualType(); - - TypesLoaded[Index]->setFromAST(); - if (DeserializationListener) - DeserializationListener->TypeRead(TypeIdx::fromTypeID(ID), - TypesLoaded[Index]); - } - - return TypesLoaded[Index].withFastQualifiers(FastQuals); -} - -QualType ASTReader::getLocalType(ModuleFile &F, unsigned LocalID) { - return GetType(getGlobalTypeID(F, LocalID)); -} - -serialization::TypeID -ASTReader::getGlobalTypeID(ModuleFile &F, unsigned LocalID) const { - unsigned FastQuals = LocalID & Qualifiers::FastMask; - unsigned LocalIndex = LocalID >> Qualifiers::FastWidth; - - if (LocalIndex < NUM_PREDEF_TYPE_IDS) - return LocalID; - - ContinuousRangeMap<uint32_t, int, 2>::iterator I - = F.TypeRemap.find(LocalIndex - NUM_PREDEF_TYPE_IDS); - assert(I != F.TypeRemap.end() && "Invalid index into type index remap"); - - unsigned GlobalIndex = LocalIndex + I->second; - return (GlobalIndex << Qualifiers::FastWidth) | FastQuals; -} - -TemplateArgumentLocInfo -ASTReader::GetTemplateArgumentLocInfo(ModuleFile &F, - TemplateArgument::ArgKind Kind, - const RecordData &Record, - unsigned &Index) { - switch (Kind) { - case TemplateArgument::Expression: - return ReadExpr(F); - case TemplateArgument::Type: - return GetTypeSourceInfo(F, Record, Index); - case TemplateArgument::Template: { - NestedNameSpecifierLoc QualifierLoc = ReadNestedNameSpecifierLoc(F, Record, - Index); - SourceLocation TemplateNameLoc = ReadSourceLocation(F, Record, Index); - return TemplateArgumentLocInfo(QualifierLoc, TemplateNameLoc, - SourceLocation()); - } - case TemplateArgument::TemplateExpansion: { - NestedNameSpecifierLoc QualifierLoc = ReadNestedNameSpecifierLoc(F, Record, - Index); - SourceLocation TemplateNameLoc = ReadSourceLocation(F, Record, Index); - SourceLocation EllipsisLoc = ReadSourceLocation(F, Record, Index); - return TemplateArgumentLocInfo(QualifierLoc, TemplateNameLoc, - EllipsisLoc); - } - case TemplateArgument::Null: - case TemplateArgument::Integral: - case TemplateArgument::Declaration: - case TemplateArgument::NullPtr: - case TemplateArgument::Pack: - // FIXME: Is this right? - return TemplateArgumentLocInfo(); - } - llvm_unreachable("unexpected template argument loc"); -} - -TemplateArgumentLoc -ASTReader::ReadTemplateArgumentLoc(ModuleFile &F, - const RecordData &Record, unsigned &Index) { - TemplateArgument Arg = ReadTemplateArgument(F, Record, Index); - - if (Arg.getKind() == TemplateArgument::Expression) { - if (Record[Index++]) // bool InfoHasSameExpr. - return TemplateArgumentLoc(Arg, TemplateArgumentLocInfo(Arg.getAsExpr())); - } - return TemplateArgumentLoc(Arg, GetTemplateArgumentLocInfo(F, Arg.getKind(), - Record, Index)); -} - -Decl *ASTReader::GetExternalDecl(uint32_t ID) { - return GetDecl(ID); -} - -uint64_t ASTReader::readCXXBaseSpecifiers(ModuleFile &M, const RecordData &Record, - unsigned &Idx){ - if (Idx >= Record.size()) - return 0; - - unsigned LocalID = Record[Idx++]; - return getGlobalBitOffset(M, M.CXXBaseSpecifiersOffsets[LocalID - 1]); -} - -CXXBaseSpecifier *ASTReader::GetExternalCXXBaseSpecifiers(uint64_t Offset) { - RecordLocation Loc = getLocalBitOffset(Offset); - llvm::BitstreamCursor &Cursor = Loc.F->DeclsCursor; - SavedStreamPosition SavedPosition(Cursor); - Cursor.JumpToBit(Loc.Offset); - ReadingKindTracker ReadingKind(Read_Decl, *this); - RecordData Record; - unsigned Code = Cursor.ReadCode(); - unsigned RecCode = Cursor.ReadRecord(Code, Record); - if (RecCode != DECL_CXX_BASE_SPECIFIERS) { - Error("Malformed AST file: missing C++ base specifiers"); - return 0; - } - - unsigned Idx = 0; - unsigned NumBases = Record[Idx++]; - void *Mem = Context.Allocate(sizeof(CXXBaseSpecifier) * NumBases); - CXXBaseSpecifier *Bases = new (Mem) CXXBaseSpecifier [NumBases]; - for (unsigned I = 0; I != NumBases; ++I) - Bases[I] = ReadCXXBaseSpecifier(*Loc.F, Record, Idx); - return Bases; -} - -serialization::DeclID -ASTReader::getGlobalDeclID(ModuleFile &F, LocalDeclID LocalID) const { - if (LocalID < NUM_PREDEF_DECL_IDS) - return LocalID; - - ContinuousRangeMap<uint32_t, int, 2>::iterator I - = F.DeclRemap.find(LocalID - NUM_PREDEF_DECL_IDS); - assert(I != F.DeclRemap.end() && "Invalid index into decl index remap"); - - return LocalID + I->second; -} - -bool ASTReader::isDeclIDFromModule(serialization::GlobalDeclID ID, - ModuleFile &M) const { - GlobalDeclMapType::const_iterator I = GlobalDeclMap.find(ID); - assert(I != GlobalDeclMap.end() && "Corrupted global declaration map"); - return &M == I->second; -} - -ModuleFile *ASTReader::getOwningModuleFile(Decl *D) { - if (!D->isFromASTFile()) - return 0; - GlobalDeclMapType::const_iterator I = GlobalDeclMap.find(D->getGlobalID()); - assert(I != GlobalDeclMap.end() && "Corrupted global declaration map"); - return I->second; -} - -SourceLocation ASTReader::getSourceLocationForDeclID(GlobalDeclID ID) { - if (ID < NUM_PREDEF_DECL_IDS) - return SourceLocation(); - - unsigned Index = ID - NUM_PREDEF_DECL_IDS; - - if (Index > DeclsLoaded.size()) { - Error("declaration ID out-of-range for AST file"); - return SourceLocation(); - } - - if (Decl *D = DeclsLoaded[Index]) - return D->getLocation(); - - unsigned RawLocation = 0; - RecordLocation Rec = DeclCursorForID(ID, RawLocation); - return ReadSourceLocation(*Rec.F, RawLocation); -} - -Decl *ASTReader::GetDecl(DeclID ID) { - if (ID < NUM_PREDEF_DECL_IDS) { - switch ((PredefinedDeclIDs)ID) { - case PREDEF_DECL_NULL_ID: - return 0; - - case PREDEF_DECL_TRANSLATION_UNIT_ID: - return Context.getTranslationUnitDecl(); - - case PREDEF_DECL_OBJC_ID_ID: - return Context.getObjCIdDecl(); - - case PREDEF_DECL_OBJC_SEL_ID: - return Context.getObjCSelDecl(); - - case PREDEF_DECL_OBJC_CLASS_ID: - return Context.getObjCClassDecl(); - - case PREDEF_DECL_OBJC_PROTOCOL_ID: - return Context.getObjCProtocolDecl(); - - case PREDEF_DECL_INT_128_ID: - return Context.getInt128Decl(); - - case PREDEF_DECL_UNSIGNED_INT_128_ID: - return Context.getUInt128Decl(); - - case PREDEF_DECL_OBJC_INSTANCETYPE_ID: - return Context.getObjCInstanceTypeDecl(); - - case PREDEF_DECL_BUILTIN_VA_LIST_ID: - return Context.getBuiltinVaListDecl(); - } - } - - unsigned Index = ID - NUM_PREDEF_DECL_IDS; - - if (Index >= DeclsLoaded.size()) { - assert(0 && "declaration ID out-of-range for AST file"); - Error("declaration ID out-of-range for AST file"); - return 0; - } - - if (!DeclsLoaded[Index]) { - ReadDeclRecord(ID); - if (DeserializationListener) - DeserializationListener->DeclRead(ID, DeclsLoaded[Index]); - } - - return DeclsLoaded[Index]; -} - -DeclID ASTReader::mapGlobalIDToModuleFileGlobalID(ModuleFile &M, - DeclID GlobalID) { - if (GlobalID < NUM_PREDEF_DECL_IDS) - return GlobalID; - - GlobalDeclMapType::const_iterator I = GlobalDeclMap.find(GlobalID); - assert(I != GlobalDeclMap.end() && "Corrupted global declaration map"); - ModuleFile *Owner = I->second; - - llvm::DenseMap<ModuleFile *, serialization::DeclID>::iterator Pos - = M.GlobalToLocalDeclIDs.find(Owner); - if (Pos == M.GlobalToLocalDeclIDs.end()) - return 0; - - return GlobalID - Owner->BaseDeclID + Pos->second; -} - -serialization::DeclID ASTReader::ReadDeclID(ModuleFile &F, - const RecordData &Record, - unsigned &Idx) { - if (Idx >= Record.size()) { - Error("Corrupted AST file"); - return 0; - } - - return getGlobalDeclID(F, Record[Idx++]); -} - -/// \brief Resolve the offset of a statement into a statement. -/// -/// This operation will read a new statement from the external -/// source each time it is called, and is meant to be used via a -/// LazyOffsetPtr (which is used by Decls for the body of functions, etc). -Stmt *ASTReader::GetExternalDeclStmt(uint64_t Offset) { - // Switch case IDs are per Decl. - ClearSwitchCaseIDs(); - - // Offset here is a global offset across the entire chain. - RecordLocation Loc = getLocalBitOffset(Offset); - Loc.F->DeclsCursor.JumpToBit(Loc.Offset); - return ReadStmtFromStream(*Loc.F); -} - -namespace { - class FindExternalLexicalDeclsVisitor { - ASTReader &Reader; - const DeclContext *DC; - bool (*isKindWeWant)(Decl::Kind); - - SmallVectorImpl<Decl*> &Decls; - bool PredefsVisited[NUM_PREDEF_DECL_IDS]; - - public: - FindExternalLexicalDeclsVisitor(ASTReader &Reader, const DeclContext *DC, - bool (*isKindWeWant)(Decl::Kind), - SmallVectorImpl<Decl*> &Decls) - : Reader(Reader), DC(DC), isKindWeWant(isKindWeWant), Decls(Decls) - { - for (unsigned I = 0; I != NUM_PREDEF_DECL_IDS; ++I) - PredefsVisited[I] = false; - } - - static bool visit(ModuleFile &M, bool Preorder, void *UserData) { - if (Preorder) - return false; - - FindExternalLexicalDeclsVisitor *This - = static_cast<FindExternalLexicalDeclsVisitor *>(UserData); - - ModuleFile::DeclContextInfosMap::iterator Info - = M.DeclContextInfos.find(This->DC); - if (Info == M.DeclContextInfos.end() || !Info->second.LexicalDecls) - return false; - - // Load all of the declaration IDs - for (const KindDeclIDPair *ID = Info->second.LexicalDecls, - *IDE = ID + Info->second.NumLexicalDecls; - ID != IDE; ++ID) { - if (This->isKindWeWant && !This->isKindWeWant((Decl::Kind)ID->first)) - continue; - - // Don't add predefined declarations to the lexical context more - // than once. - if (ID->second < NUM_PREDEF_DECL_IDS) { - if (This->PredefsVisited[ID->second]) - continue; - - This->PredefsVisited[ID->second] = true; - } - - if (Decl *D = This->Reader.GetLocalDecl(M, ID->second)) { - if (!This->DC->isDeclInLexicalTraversal(D)) - This->Decls.push_back(D); - } - } - - return false; - } - }; -} - -ExternalLoadResult ASTReader::FindExternalLexicalDecls(const DeclContext *DC, - bool (*isKindWeWant)(Decl::Kind), - SmallVectorImpl<Decl*> &Decls) { - // There might be lexical decls in multiple modules, for the TU at - // least. Walk all of the modules in the order they were loaded. - FindExternalLexicalDeclsVisitor Visitor(*this, DC, isKindWeWant, Decls); - ModuleMgr.visitDepthFirst(&FindExternalLexicalDeclsVisitor::visit, &Visitor); - ++NumLexicalDeclContextsRead; - return ELR_Success; -} - -namespace { - -class DeclIDComp { - ASTReader &Reader; - ModuleFile &Mod; - -public: - DeclIDComp(ASTReader &Reader, ModuleFile &M) : Reader(Reader), Mod(M) {} - - bool operator()(LocalDeclID L, LocalDeclID R) const { - SourceLocation LHS = getLocation(L); - SourceLocation RHS = getLocation(R); - return Reader.getSourceManager().isBeforeInTranslationUnit(LHS, RHS); - } - - bool operator()(SourceLocation LHS, LocalDeclID R) const { - SourceLocation RHS = getLocation(R); - return Reader.getSourceManager().isBeforeInTranslationUnit(LHS, RHS); - } - - bool operator()(LocalDeclID L, SourceLocation RHS) const { - SourceLocation LHS = getLocation(L); - return Reader.getSourceManager().isBeforeInTranslationUnit(LHS, RHS); - } - - SourceLocation getLocation(LocalDeclID ID) const { - return Reader.getSourceManager().getFileLoc( - Reader.getSourceLocationForDeclID(Reader.getGlobalDeclID(Mod, ID))); - } -}; - -} - -void ASTReader::FindFileRegionDecls(FileID File, - unsigned Offset, unsigned Length, - SmallVectorImpl<Decl *> &Decls) { - SourceManager &SM = getSourceManager(); - - llvm::DenseMap<FileID, FileDeclsInfo>::iterator I = FileDeclIDs.find(File); - if (I == FileDeclIDs.end()) - return; - - FileDeclsInfo &DInfo = I->second; - if (DInfo.Decls.empty()) - return; - - SourceLocation - BeginLoc = SM.getLocForStartOfFile(File).getLocWithOffset(Offset); - SourceLocation EndLoc = BeginLoc.getLocWithOffset(Length); - - DeclIDComp DIDComp(*this, *DInfo.Mod); - ArrayRef<serialization::LocalDeclID>::iterator - BeginIt = std::lower_bound(DInfo.Decls.begin(), DInfo.Decls.end(), - BeginLoc, DIDComp); - if (BeginIt != DInfo.Decls.begin()) - --BeginIt; - - // If we are pointing at a top-level decl inside an objc container, we need - // to backtrack until we find it otherwise we will fail to report that the - // region overlaps with an objc container. - while (BeginIt != DInfo.Decls.begin() && - GetDecl(getGlobalDeclID(*DInfo.Mod, *BeginIt)) - ->isTopLevelDeclInObjCContainer()) - --BeginIt; - - ArrayRef<serialization::LocalDeclID>::iterator - EndIt = std::upper_bound(DInfo.Decls.begin(), DInfo.Decls.end(), - EndLoc, DIDComp); - if (EndIt != DInfo.Decls.end()) - ++EndIt; - - for (ArrayRef<serialization::LocalDeclID>::iterator - DIt = BeginIt; DIt != EndIt; ++DIt) - Decls.push_back(GetDecl(getGlobalDeclID(*DInfo.Mod, *DIt))); -} - -namespace { - /// \brief ModuleFile visitor used to perform name lookup into a - /// declaration context. - class DeclContextNameLookupVisitor { - ASTReader &Reader; - llvm::SmallVectorImpl<const DeclContext *> &Contexts; - DeclarationName Name; - SmallVectorImpl<NamedDecl *> &Decls; - - public: - DeclContextNameLookupVisitor(ASTReader &Reader, - SmallVectorImpl<const DeclContext *> &Contexts, - DeclarationName Name, - SmallVectorImpl<NamedDecl *> &Decls) - : Reader(Reader), Contexts(Contexts), Name(Name), Decls(Decls) { } - - static bool visit(ModuleFile &M, void *UserData) { - DeclContextNameLookupVisitor *This - = static_cast<DeclContextNameLookupVisitor *>(UserData); - - // Check whether we have any visible declaration information for - // this context in this module. - ModuleFile::DeclContextInfosMap::iterator Info; - bool FoundInfo = false; - for (unsigned I = 0, N = This->Contexts.size(); I != N; ++I) { - Info = M.DeclContextInfos.find(This->Contexts[I]); - if (Info != M.DeclContextInfos.end() && - Info->second.NameLookupTableData) { - FoundInfo = true; - break; - } - } - - if (!FoundInfo) - return false; - - // Look for this name within this module. - ASTDeclContextNameLookupTable *LookupTable = - Info->second.NameLookupTableData; - ASTDeclContextNameLookupTable::iterator Pos - = LookupTable->find(This->Name); - if (Pos == LookupTable->end()) - return false; - - bool FoundAnything = false; - ASTDeclContextNameLookupTrait::data_type Data = *Pos; - for (; Data.first != Data.second; ++Data.first) { - NamedDecl *ND = This->Reader.GetLocalDeclAs<NamedDecl>(M, *Data.first); - if (!ND) - continue; - - if (ND->getDeclName() != This->Name) { - // A name might be null because the decl's redeclarable part is - // currently read before reading its name. The lookup is triggered by - // building that decl (likely indirectly), and so it is later in the - // sense of "already existing" and can be ignored here. - continue; - } - - // Record this declaration. - FoundAnything = true; - This->Decls.push_back(ND); - } - - return FoundAnything; - } - }; -} - -DeclContext::lookup_result -ASTReader::FindExternalVisibleDeclsByName(const DeclContext *DC, - DeclarationName Name) { - assert(DC->hasExternalVisibleStorage() && - "DeclContext has no visible decls in storage"); - if (!Name) - return DeclContext::lookup_result(DeclContext::lookup_iterator(0), - DeclContext::lookup_iterator(0)); - - SmallVector<NamedDecl *, 64> Decls; - - // Compute the declaration contexts we need to look into. Multiple such - // declaration contexts occur when two declaration contexts from disjoint - // modules get merged, e.g., when two namespaces with the same name are - // independently defined in separate modules. - SmallVector<const DeclContext *, 2> Contexts; - Contexts.push_back(DC); - - if (DC->isNamespace()) { - MergedDeclsMap::iterator Merged - = MergedDecls.find(const_cast<Decl *>(cast<Decl>(DC))); - if (Merged != MergedDecls.end()) { - for (unsigned I = 0, N = Merged->second.size(); I != N; ++I) - Contexts.push_back(cast<DeclContext>(GetDecl(Merged->second[I]))); - } - } - - DeclContextNameLookupVisitor Visitor(*this, Contexts, Name, Decls); - ModuleMgr.visit(&DeclContextNameLookupVisitor::visit, &Visitor); - ++NumVisibleDeclContextsRead; - SetExternalVisibleDeclsForName(DC, Name, Decls); - return const_cast<DeclContext*>(DC)->lookup(Name); -} - -namespace { - /// \brief ModuleFile visitor used to retrieve all visible names in a - /// declaration context. - class DeclContextAllNamesVisitor { - ASTReader &Reader; - llvm::SmallVectorImpl<const DeclContext *> &Contexts; - llvm::DenseMap<DeclarationName, SmallVector<NamedDecl *, 8> > &Decls; - - public: - DeclContextAllNamesVisitor(ASTReader &Reader, - SmallVectorImpl<const DeclContext *> &Contexts, - llvm::DenseMap<DeclarationName, - SmallVector<NamedDecl *, 8> > &Decls) - : Reader(Reader), Contexts(Contexts), Decls(Decls) { } - - static bool visit(ModuleFile &M, void *UserData) { - DeclContextAllNamesVisitor *This - = static_cast<DeclContextAllNamesVisitor *>(UserData); - - // Check whether we have any visible declaration information for - // this context in this module. - ModuleFile::DeclContextInfosMap::iterator Info; - bool FoundInfo = false; - for (unsigned I = 0, N = This->Contexts.size(); I != N; ++I) { - Info = M.DeclContextInfos.find(This->Contexts[I]); - if (Info != M.DeclContextInfos.end() && - Info->second.NameLookupTableData) { - FoundInfo = true; - break; - } - } - - if (!FoundInfo) - return false; - - ASTDeclContextNameLookupTable *LookupTable = - Info->second.NameLookupTableData; - bool FoundAnything = false; - for (ASTDeclContextNameLookupTable::data_iterator - I = LookupTable->data_begin(), E = LookupTable->data_end(); - I != E; ++I) { - ASTDeclContextNameLookupTrait::data_type Data = *I; - for (; Data.first != Data.second; ++Data.first) { - NamedDecl *ND = This->Reader.GetLocalDeclAs<NamedDecl>(M, - *Data.first); - if (!ND) - continue; - - // Record this declaration. - FoundAnything = true; - This->Decls[ND->getDeclName()].push_back(ND); - } - } - - return FoundAnything; - } - }; -} - -void ASTReader::completeVisibleDeclsMap(const DeclContext *DC) { - if (!DC->hasExternalVisibleStorage()) - return; - llvm::DenseMap<DeclarationName, llvm::SmallVector<NamedDecl*, 8> > Decls; - - // Compute the declaration contexts we need to look into. Multiple such - // declaration contexts occur when two declaration contexts from disjoint - // modules get merged, e.g., when two namespaces with the same name are - // independently defined in separate modules. - SmallVector<const DeclContext *, 2> Contexts; - Contexts.push_back(DC); - - if (DC->isNamespace()) { - MergedDeclsMap::iterator Merged - = MergedDecls.find(const_cast<Decl *>(cast<Decl>(DC))); - if (Merged != MergedDecls.end()) { - for (unsigned I = 0, N = Merged->second.size(); I != N; ++I) - Contexts.push_back(cast<DeclContext>(GetDecl(Merged->second[I]))); - } - } - - DeclContextAllNamesVisitor Visitor(*this, Contexts, Decls); - ModuleMgr.visit(&DeclContextAllNamesVisitor::visit, &Visitor); - ++NumVisibleDeclContextsRead; - - for (llvm::DenseMap<DeclarationName, - llvm::SmallVector<NamedDecl*, 8> >::iterator - I = Decls.begin(), E = Decls.end(); I != E; ++I) { - SetExternalVisibleDeclsForName(DC, I->first, I->second); - } - const_cast<DeclContext *>(DC)->setHasExternalVisibleStorage(false); -} - -/// \brief Under non-PCH compilation the consumer receives the objc methods -/// before receiving the implementation, and codegen depends on this. -/// We simulate this by deserializing and passing to consumer the methods of the -/// implementation before passing the deserialized implementation decl. -static void PassObjCImplDeclToConsumer(ObjCImplDecl *ImplD, - ASTConsumer *Consumer) { - assert(ImplD && Consumer); - - for (ObjCImplDecl::method_iterator - I = ImplD->meth_begin(), E = ImplD->meth_end(); I != E; ++I) - Consumer->HandleInterestingDecl(DeclGroupRef(*I)); - - Consumer->HandleInterestingDecl(DeclGroupRef(ImplD)); -} - -void ASTReader::PassInterestingDeclsToConsumer() { - assert(Consumer); - while (!InterestingDecls.empty()) { - Decl *D = InterestingDecls.front(); - InterestingDecls.pop_front(); - - PassInterestingDeclToConsumer(D); - } -} - -void ASTReader::PassInterestingDeclToConsumer(Decl *D) { - if (ObjCImplDecl *ImplD = dyn_cast<ObjCImplDecl>(D)) - PassObjCImplDeclToConsumer(ImplD, Consumer); - else - Consumer->HandleInterestingDecl(DeclGroupRef(D)); -} - -void ASTReader::StartTranslationUnit(ASTConsumer *Consumer) { - this->Consumer = Consumer; - - if (!Consumer) - return; - - for (unsigned I = 0, N = ExternalDefinitions.size(); I != N; ++I) { - // Force deserialization of this decl, which will cause it to be queued for - // passing to the consumer. - GetDecl(ExternalDefinitions[I]); - } - ExternalDefinitions.clear(); - - PassInterestingDeclsToConsumer(); -} - -void ASTReader::PrintStats() { - std::fprintf(stderr, "*** AST File Statistics:\n"); - - unsigned NumTypesLoaded - = TypesLoaded.size() - std::count(TypesLoaded.begin(), TypesLoaded.end(), - QualType()); - unsigned NumDeclsLoaded - = DeclsLoaded.size() - std::count(DeclsLoaded.begin(), DeclsLoaded.end(), - (Decl *)0); - unsigned NumIdentifiersLoaded - = IdentifiersLoaded.size() - std::count(IdentifiersLoaded.begin(), - IdentifiersLoaded.end(), - (IdentifierInfo *)0); - unsigned NumMacrosLoaded - = MacrosLoaded.size() - std::count(MacrosLoaded.begin(), - MacrosLoaded.end(), - (MacroInfo *)0); - unsigned NumSelectorsLoaded - = SelectorsLoaded.size() - std::count(SelectorsLoaded.begin(), - SelectorsLoaded.end(), - Selector()); - - if (unsigned TotalNumSLocEntries = getTotalNumSLocs()) - std::fprintf(stderr, " %u/%u source location entries read (%f%%)\n", - NumSLocEntriesRead, TotalNumSLocEntries, - ((float)NumSLocEntriesRead/TotalNumSLocEntries * 100)); - if (!TypesLoaded.empty()) - std::fprintf(stderr, " %u/%u types read (%f%%)\n", - NumTypesLoaded, (unsigned)TypesLoaded.size(), - ((float)NumTypesLoaded/TypesLoaded.size() * 100)); - if (!DeclsLoaded.empty()) - std::fprintf(stderr, " %u/%u declarations read (%f%%)\n", - NumDeclsLoaded, (unsigned)DeclsLoaded.size(), - ((float)NumDeclsLoaded/DeclsLoaded.size() * 100)); - if (!IdentifiersLoaded.empty()) - std::fprintf(stderr, " %u/%u identifiers read (%f%%)\n", - NumIdentifiersLoaded, (unsigned)IdentifiersLoaded.size(), - ((float)NumIdentifiersLoaded/IdentifiersLoaded.size() * 100)); - if (!MacrosLoaded.empty()) - std::fprintf(stderr, " %u/%u macros read (%f%%)\n", - NumMacrosLoaded, (unsigned)MacrosLoaded.size(), - ((float)NumMacrosLoaded/MacrosLoaded.size() * 100)); - if (!SelectorsLoaded.empty()) - std::fprintf(stderr, " %u/%u selectors read (%f%%)\n", - NumSelectorsLoaded, (unsigned)SelectorsLoaded.size(), - ((float)NumSelectorsLoaded/SelectorsLoaded.size() * 100)); - if (TotalNumStatements) - std::fprintf(stderr, " %u/%u statements read (%f%%)\n", - NumStatementsRead, TotalNumStatements, - ((float)NumStatementsRead/TotalNumStatements * 100)); - if (TotalNumMacros) - std::fprintf(stderr, " %u/%u macros read (%f%%)\n", - NumMacrosRead, TotalNumMacros, - ((float)NumMacrosRead/TotalNumMacros * 100)); - if (TotalLexicalDeclContexts) - std::fprintf(stderr, " %u/%u lexical declcontexts read (%f%%)\n", - NumLexicalDeclContextsRead, TotalLexicalDeclContexts, - ((float)NumLexicalDeclContextsRead/TotalLexicalDeclContexts - * 100)); - if (TotalVisibleDeclContexts) - std::fprintf(stderr, " %u/%u visible declcontexts read (%f%%)\n", - NumVisibleDeclContextsRead, TotalVisibleDeclContexts, - ((float)NumVisibleDeclContextsRead/TotalVisibleDeclContexts - * 100)); - if (TotalNumMethodPoolEntries) { - std::fprintf(stderr, " %u/%u method pool entries read (%f%%)\n", - NumMethodPoolEntriesRead, TotalNumMethodPoolEntries, - ((float)NumMethodPoolEntriesRead/TotalNumMethodPoolEntries - * 100)); - std::fprintf(stderr, " %u method pool misses\n", NumMethodPoolMisses); - } - std::fprintf(stderr, "\n"); - dump(); - std::fprintf(stderr, "\n"); -} - -template<typename Key, typename ModuleFile, unsigned InitialCapacity> -static void -dumpModuleIDMap(StringRef Name, - const ContinuousRangeMap<Key, ModuleFile *, - InitialCapacity> &Map) { - if (Map.begin() == Map.end()) - return; - - typedef ContinuousRangeMap<Key, ModuleFile *, InitialCapacity> MapType; - llvm::errs() << Name << ":\n"; - for (typename MapType::const_iterator I = Map.begin(), IEnd = Map.end(); - I != IEnd; ++I) { - llvm::errs() << " " << I->first << " -> " << I->second->FileName - << "\n"; - } -} - -void ASTReader::dump() { - llvm::errs() << "*** PCH/ModuleFile Remappings:\n"; - dumpModuleIDMap("Global bit offset map", GlobalBitOffsetsMap); - dumpModuleIDMap("Global source location entry map", GlobalSLocEntryMap); - dumpModuleIDMap("Global type map", GlobalTypeMap); - dumpModuleIDMap("Global declaration map", GlobalDeclMap); - dumpModuleIDMap("Global identifier map", GlobalIdentifierMap); - dumpModuleIDMap("Global macro map", GlobalMacroMap); - dumpModuleIDMap("Global submodule map", GlobalSubmoduleMap); - dumpModuleIDMap("Global selector map", GlobalSelectorMap); - dumpModuleIDMap("Global preprocessed entity map", - GlobalPreprocessedEntityMap); - - llvm::errs() << "\n*** PCH/Modules Loaded:"; - for (ModuleManager::ModuleConstIterator M = ModuleMgr.begin(), - MEnd = ModuleMgr.end(); - M != MEnd; ++M) - (*M)->dump(); -} - -/// Return the amount of memory used by memory buffers, breaking down -/// by heap-backed versus mmap'ed memory. -void ASTReader::getMemoryBufferSizes(MemoryBufferSizes &sizes) const { - for (ModuleConstIterator I = ModuleMgr.begin(), - E = ModuleMgr.end(); I != E; ++I) { - if (llvm::MemoryBuffer *buf = (*I)->Buffer.get()) { - size_t bytes = buf->getBufferSize(); - switch (buf->getBufferKind()) { - case llvm::MemoryBuffer::MemoryBuffer_Malloc: - sizes.malloc_bytes += bytes; - break; - case llvm::MemoryBuffer::MemoryBuffer_MMap: - sizes.mmap_bytes += bytes; - break; - } - } - } -} - -void ASTReader::InitializeSema(Sema &S) { - SemaObj = &S; - S.addExternalSource(this); - - // Makes sure any declarations that were deserialized "too early" - // still get added to the identifier's declaration chains. - for (unsigned I = 0, N = PreloadedDecls.size(); I != N; ++I) { - SemaObj->pushExternalDeclIntoScope(PreloadedDecls[I], - PreloadedDecls[I]->getDeclName()); - } - PreloadedDecls.clear(); - - // Load the offsets of the declarations that Sema references. - // They will be lazily deserialized when needed. - if (!SemaDeclRefs.empty()) { - assert(SemaDeclRefs.size() == 2 && "More decl refs than expected!"); - if (!SemaObj->StdNamespace) - SemaObj->StdNamespace = SemaDeclRefs[0]; - if (!SemaObj->StdBadAlloc) - SemaObj->StdBadAlloc = SemaDeclRefs[1]; - } - - if (!FPPragmaOptions.empty()) { - assert(FPPragmaOptions.size() == 1 && "Wrong number of FP_PRAGMA_OPTIONS"); - SemaObj->FPFeatures.fp_contract = FPPragmaOptions[0]; - } - - if (!OpenCLExtensions.empty()) { - unsigned I = 0; -#define OPENCLEXT(nm) SemaObj->OpenCLFeatures.nm = OpenCLExtensions[I++]; -#include "clang/Basic/OpenCLExtensions.def" - - assert(OpenCLExtensions.size() == I && "Wrong number of OPENCL_EXTENSIONS"); - } -} - -IdentifierInfo* ASTReader::get(const char *NameStart, const char *NameEnd) { - // Note that we are loading an identifier. - Deserializing AnIdentifier(this); - - IdentifierLookupVisitor Visitor(StringRef(NameStart, NameEnd - NameStart), - /*PriorGeneration=*/0); - ModuleMgr.visit(IdentifierLookupVisitor::visit, &Visitor); - IdentifierInfo *II = Visitor.getIdentifierInfo(); - markIdentifierUpToDate(II); - return II; -} - -namespace clang { - /// \brief An identifier-lookup iterator that enumerates all of the - /// identifiers stored within a set of AST files. - class ASTIdentifierIterator : public IdentifierIterator { - /// \brief The AST reader whose identifiers are being enumerated. - const ASTReader &Reader; - - /// \brief The current index into the chain of AST files stored in - /// the AST reader. - unsigned Index; - - /// \brief The current position within the identifier lookup table - /// of the current AST file. - ASTIdentifierLookupTable::key_iterator Current; - - /// \brief The end position within the identifier lookup table of - /// the current AST file. - ASTIdentifierLookupTable::key_iterator End; - - public: - explicit ASTIdentifierIterator(const ASTReader &Reader); - - virtual StringRef Next(); - }; -} - -ASTIdentifierIterator::ASTIdentifierIterator(const ASTReader &Reader) - : Reader(Reader), Index(Reader.ModuleMgr.size() - 1) { - ASTIdentifierLookupTable *IdTable - = (ASTIdentifierLookupTable *)Reader.ModuleMgr[Index].IdentifierLookupTable; - Current = IdTable->key_begin(); - End = IdTable->key_end(); -} - -StringRef ASTIdentifierIterator::Next() { - while (Current == End) { - // If we have exhausted all of our AST files, we're done. - if (Index == 0) - return StringRef(); - - --Index; - ASTIdentifierLookupTable *IdTable - = (ASTIdentifierLookupTable *)Reader.ModuleMgr[Index]. - IdentifierLookupTable; - Current = IdTable->key_begin(); - End = IdTable->key_end(); - } - - // We have any identifiers remaining in the current AST file; return - // the next one. - std::pair<const char*, unsigned> Key = *Current; - ++Current; - return StringRef(Key.first, Key.second); -} - -IdentifierIterator *ASTReader::getIdentifiers() const { - return new ASTIdentifierIterator(*this); -} - -namespace clang { namespace serialization { - class ReadMethodPoolVisitor { - ASTReader &Reader; - Selector Sel; - unsigned PriorGeneration; - llvm::SmallVector<ObjCMethodDecl *, 4> InstanceMethods; - llvm::SmallVector<ObjCMethodDecl *, 4> FactoryMethods; - - public: - ReadMethodPoolVisitor(ASTReader &Reader, Selector Sel, - unsigned PriorGeneration) - : Reader(Reader), Sel(Sel), PriorGeneration(PriorGeneration) { } - - static bool visit(ModuleFile &M, void *UserData) { - ReadMethodPoolVisitor *This - = static_cast<ReadMethodPoolVisitor *>(UserData); - - if (!M.SelectorLookupTable) - return false; - - // If we've already searched this module file, skip it now. - if (M.Generation <= This->PriorGeneration) - return true; - - ASTSelectorLookupTable *PoolTable - = (ASTSelectorLookupTable*)M.SelectorLookupTable; - ASTSelectorLookupTable::iterator Pos = PoolTable->find(This->Sel); - if (Pos == PoolTable->end()) - return false; - - ++This->Reader.NumSelectorsRead; - // FIXME: Not quite happy with the statistics here. We probably should - // disable this tracking when called via LoadSelector. - // Also, should entries without methods count as misses? - ++This->Reader.NumMethodPoolEntriesRead; - ASTSelectorLookupTrait::data_type Data = *Pos; - if (This->Reader.DeserializationListener) - This->Reader.DeserializationListener->SelectorRead(Data.ID, - This->Sel); - - This->InstanceMethods.append(Data.Instance.begin(), Data.Instance.end()); - This->FactoryMethods.append(Data.Factory.begin(), Data.Factory.end()); - return true; - } - - /// \brief Retrieve the instance methods found by this visitor. - ArrayRef<ObjCMethodDecl *> getInstanceMethods() const { - return InstanceMethods; - } - - /// \brief Retrieve the instance methods found by this visitor. - ArrayRef<ObjCMethodDecl *> getFactoryMethods() const { - return FactoryMethods; - } - }; -} } // end namespace clang::serialization - -/// \brief Add the given set of methods to the method list. -static void addMethodsToPool(Sema &S, ArrayRef<ObjCMethodDecl *> Methods, - ObjCMethodList &List) { - for (unsigned I = 0, N = Methods.size(); I != N; ++I) { - S.addMethodToGlobalList(&List, Methods[I]); - } -} - -void ASTReader::ReadMethodPool(Selector Sel) { - // Get the selector generation and update it to the current generation. - unsigned &Generation = SelectorGeneration[Sel]; - unsigned PriorGeneration = Generation; - Generation = CurrentGeneration; - - // Search for methods defined with this selector. - ReadMethodPoolVisitor Visitor(*this, Sel, PriorGeneration); - ModuleMgr.visit(&ReadMethodPoolVisitor::visit, &Visitor); - - if (Visitor.getInstanceMethods().empty() && - Visitor.getFactoryMethods().empty()) { - ++NumMethodPoolMisses; - return; - } - - if (!getSema()) - return; - - Sema &S = *getSema(); - Sema::GlobalMethodPool::iterator Pos - = S.MethodPool.insert(std::make_pair(Sel, Sema::GlobalMethods())).first; - - addMethodsToPool(S, Visitor.getInstanceMethods(), Pos->second.first); - addMethodsToPool(S, Visitor.getFactoryMethods(), Pos->second.second); -} - -void ASTReader::ReadKnownNamespaces( - SmallVectorImpl<NamespaceDecl *> &Namespaces) { - Namespaces.clear(); - - for (unsigned I = 0, N = KnownNamespaces.size(); I != N; ++I) { - if (NamespaceDecl *Namespace - = dyn_cast_or_null<NamespaceDecl>(GetDecl(KnownNamespaces[I]))) - Namespaces.push_back(Namespace); - } -} - -void ASTReader::ReadTentativeDefinitions( - SmallVectorImpl<VarDecl *> &TentativeDefs) { - for (unsigned I = 0, N = TentativeDefinitions.size(); I != N; ++I) { - VarDecl *Var = dyn_cast_or_null<VarDecl>(GetDecl(TentativeDefinitions[I])); - if (Var) - TentativeDefs.push_back(Var); - } - TentativeDefinitions.clear(); -} - -void ASTReader::ReadUnusedFileScopedDecls( - SmallVectorImpl<const DeclaratorDecl *> &Decls) { - for (unsigned I = 0, N = UnusedFileScopedDecls.size(); I != N; ++I) { - DeclaratorDecl *D - = dyn_cast_or_null<DeclaratorDecl>(GetDecl(UnusedFileScopedDecls[I])); - if (D) - Decls.push_back(D); - } - UnusedFileScopedDecls.clear(); -} - -void ASTReader::ReadDelegatingConstructors( - SmallVectorImpl<CXXConstructorDecl *> &Decls) { - for (unsigned I = 0, N = DelegatingCtorDecls.size(); I != N; ++I) { - CXXConstructorDecl *D - = dyn_cast_or_null<CXXConstructorDecl>(GetDecl(DelegatingCtorDecls[I])); - if (D) - Decls.push_back(D); - } - DelegatingCtorDecls.clear(); -} - -void ASTReader::ReadExtVectorDecls(SmallVectorImpl<TypedefNameDecl *> &Decls) { - for (unsigned I = 0, N = ExtVectorDecls.size(); I != N; ++I) { - TypedefNameDecl *D - = dyn_cast_or_null<TypedefNameDecl>(GetDecl(ExtVectorDecls[I])); - if (D) - Decls.push_back(D); - } - ExtVectorDecls.clear(); -} - -void ASTReader::ReadDynamicClasses(SmallVectorImpl<CXXRecordDecl *> &Decls) { - for (unsigned I = 0, N = DynamicClasses.size(); I != N; ++I) { - CXXRecordDecl *D - = dyn_cast_or_null<CXXRecordDecl>(GetDecl(DynamicClasses[I])); - if (D) - Decls.push_back(D); - } - DynamicClasses.clear(); -} - -void -ASTReader::ReadLocallyScopedExternalDecls(SmallVectorImpl<NamedDecl *> &Decls) { - for (unsigned I = 0, N = LocallyScopedExternalDecls.size(); I != N; ++I) { - NamedDecl *D - = dyn_cast_or_null<NamedDecl>(GetDecl(LocallyScopedExternalDecls[I])); - if (D) - Decls.push_back(D); - } - LocallyScopedExternalDecls.clear(); -} - -void ASTReader::ReadReferencedSelectors( - SmallVectorImpl<std::pair<Selector, SourceLocation> > &Sels) { - if (ReferencedSelectorsData.empty()) - return; - - // If there are @selector references added them to its pool. This is for - // implementation of -Wselector. - unsigned int DataSize = ReferencedSelectorsData.size()-1; - unsigned I = 0; - while (I < DataSize) { - Selector Sel = DecodeSelector(ReferencedSelectorsData[I++]); - SourceLocation SelLoc - = SourceLocation::getFromRawEncoding(ReferencedSelectorsData[I++]); - Sels.push_back(std::make_pair(Sel, SelLoc)); - } - ReferencedSelectorsData.clear(); -} - -void ASTReader::ReadWeakUndeclaredIdentifiers( - SmallVectorImpl<std::pair<IdentifierInfo *, WeakInfo> > &WeakIDs) { - if (WeakUndeclaredIdentifiers.empty()) - return; - - for (unsigned I = 0, N = WeakUndeclaredIdentifiers.size(); I < N; /*none*/) { - IdentifierInfo *WeakId - = DecodeIdentifierInfo(WeakUndeclaredIdentifiers[I++]); - IdentifierInfo *AliasId - = DecodeIdentifierInfo(WeakUndeclaredIdentifiers[I++]); - SourceLocation Loc - = SourceLocation::getFromRawEncoding(WeakUndeclaredIdentifiers[I++]); - bool Used = WeakUndeclaredIdentifiers[I++]; - WeakInfo WI(AliasId, Loc); - WI.setUsed(Used); - WeakIDs.push_back(std::make_pair(WeakId, WI)); - } - WeakUndeclaredIdentifiers.clear(); -} - -void ASTReader::ReadUsedVTables(SmallVectorImpl<ExternalVTableUse> &VTables) { - for (unsigned Idx = 0, N = VTableUses.size(); Idx < N; /* In loop */) { - ExternalVTableUse VT; - VT.Record = dyn_cast_or_null<CXXRecordDecl>(GetDecl(VTableUses[Idx++])); - VT.Location = SourceLocation::getFromRawEncoding(VTableUses[Idx++]); - VT.DefinitionRequired = VTableUses[Idx++]; - VTables.push_back(VT); - } - - VTableUses.clear(); -} - -void ASTReader::ReadPendingInstantiations( - SmallVectorImpl<std::pair<ValueDecl *, SourceLocation> > &Pending) { - for (unsigned Idx = 0, N = PendingInstantiations.size(); Idx < N;) { - ValueDecl *D = cast<ValueDecl>(GetDecl(PendingInstantiations[Idx++])); - SourceLocation Loc - = SourceLocation::getFromRawEncoding(PendingInstantiations[Idx++]); - - Pending.push_back(std::make_pair(D, Loc)); - } - PendingInstantiations.clear(); -} - -void ASTReader::LoadSelector(Selector Sel) { - // It would be complicated to avoid reading the methods anyway. So don't. - ReadMethodPool(Sel); -} - -void ASTReader::SetIdentifierInfo(IdentifierID ID, IdentifierInfo *II) { - assert(ID && "Non-zero identifier ID required"); - assert(ID <= IdentifiersLoaded.size() && "identifier ID out of range"); - IdentifiersLoaded[ID - 1] = II; - if (DeserializationListener) - DeserializationListener->IdentifierRead(ID, II); -} - -/// \brief Set the globally-visible declarations associated with the given -/// identifier. -/// -/// If the AST reader is currently in a state where the given declaration IDs -/// cannot safely be resolved, they are queued until it is safe to resolve -/// them. -/// -/// \param II an IdentifierInfo that refers to one or more globally-visible -/// declarations. -/// -/// \param DeclIDs the set of declaration IDs with the name @p II that are -/// visible at global scope. -/// -/// \param Nonrecursive should be true to indicate that the caller knows that -/// this call is non-recursive, and therefore the globally-visible declarations -/// will not be placed onto the pending queue. -void -ASTReader::SetGloballyVisibleDecls(IdentifierInfo *II, - const SmallVectorImpl<uint32_t> &DeclIDs, - bool Nonrecursive) { - if (NumCurrentElementsDeserializing && !Nonrecursive) { - PendingIdentifierInfos.push_back(PendingIdentifierInfo()); - PendingIdentifierInfo &PII = PendingIdentifierInfos.back(); - PII.II = II; - PII.DeclIDs.append(DeclIDs.begin(), DeclIDs.end()); - return; - } - - for (unsigned I = 0, N = DeclIDs.size(); I != N; ++I) { - NamedDecl *D = cast<NamedDecl>(GetDecl(DeclIDs[I])); - if (SemaObj) { - // Introduce this declaration into the translation-unit scope - // and add it to the declaration chain for this identifier, so - // that (unqualified) name lookup will find it. - SemaObj->pushExternalDeclIntoScope(D, II); - } else { - // Queue this declaration so that it will be added to the - // translation unit scope and identifier's declaration chain - // once a Sema object is known. - PreloadedDecls.push_back(D); - } - } -} - -IdentifierInfo *ASTReader::DecodeIdentifierInfo(IdentifierID ID) { - if (ID == 0) - return 0; - - if (IdentifiersLoaded.empty()) { - Error("no identifier table in AST file"); - return 0; - } - - ID -= 1; - if (!IdentifiersLoaded[ID]) { - GlobalIdentifierMapType::iterator I = GlobalIdentifierMap.find(ID + 1); - assert(I != GlobalIdentifierMap.end() && "Corrupted global identifier map"); - ModuleFile *M = I->second; - unsigned Index = ID - M->BaseIdentifierID; - const char *Str = M->IdentifierTableData + M->IdentifierOffsets[Index]; - - // All of the strings in the AST file are preceded by a 16-bit length. - // Extract that 16-bit length to avoid having to execute strlen(). - // NOTE: 'StrLenPtr' is an 'unsigned char*' so that we load bytes as - // unsigned integers. This is important to avoid integer overflow when - // we cast them to 'unsigned'. - const unsigned char *StrLenPtr = (const unsigned char*) Str - 2; - unsigned StrLen = (((unsigned) StrLenPtr[0]) - | (((unsigned) StrLenPtr[1]) << 8)) - 1; - IdentifiersLoaded[ID] - = &PP.getIdentifierTable().get(StringRef(Str, StrLen)); - if (DeserializationListener) - DeserializationListener->IdentifierRead(ID + 1, IdentifiersLoaded[ID]); - } - - return IdentifiersLoaded[ID]; -} - -IdentifierInfo *ASTReader::getLocalIdentifier(ModuleFile &M, unsigned LocalID) { - return DecodeIdentifierInfo(getGlobalIdentifierID(M, LocalID)); -} - -IdentifierID ASTReader::getGlobalIdentifierID(ModuleFile &M, unsigned LocalID) { - if (LocalID < NUM_PREDEF_IDENT_IDS) - return LocalID; - - ContinuousRangeMap<uint32_t, int, 2>::iterator I - = M.IdentifierRemap.find(LocalID - NUM_PREDEF_IDENT_IDS); - assert(I != M.IdentifierRemap.end() - && "Invalid index into identifier index remap"); - - return LocalID + I->second; -} - -MacroInfo *ASTReader::getMacro(MacroID ID, MacroInfo *Hint) { - if (ID == 0) - return 0; - - if (MacrosLoaded.empty()) { - Error("no macro table in AST file"); - return 0; - } - - ID -= NUM_PREDEF_MACRO_IDS; - if (!MacrosLoaded[ID]) { - GlobalMacroMapType::iterator I - = GlobalMacroMap.find(ID + NUM_PREDEF_MACRO_IDS); - assert(I != GlobalMacroMap.end() && "Corrupted global macro map"); - ModuleFile *M = I->second; - unsigned Index = ID - M->BaseMacroID; - ReadMacroRecord(*M, M->MacroOffsets[Index], Hint); - } - - return MacrosLoaded[ID]; -} - -MacroID ASTReader::getGlobalMacroID(ModuleFile &M, unsigned LocalID) { - if (LocalID < NUM_PREDEF_MACRO_IDS) - return LocalID; - - ContinuousRangeMap<uint32_t, int, 2>::iterator I - = M.MacroRemap.find(LocalID - NUM_PREDEF_MACRO_IDS); - assert(I != M.MacroRemap.end() && "Invalid index into macro index remap"); - - return LocalID + I->second; -} - -serialization::SubmoduleID -ASTReader::getGlobalSubmoduleID(ModuleFile &M, unsigned LocalID) { - if (LocalID < NUM_PREDEF_SUBMODULE_IDS) - return LocalID; - - ContinuousRangeMap<uint32_t, int, 2>::iterator I - = M.SubmoduleRemap.find(LocalID - NUM_PREDEF_SUBMODULE_IDS); - assert(I != M.SubmoduleRemap.end() - && "Invalid index into submodule index remap"); - - return LocalID + I->second; -} - -Module *ASTReader::getSubmodule(SubmoduleID GlobalID) { - if (GlobalID < NUM_PREDEF_SUBMODULE_IDS) { - assert(GlobalID == 0 && "Unhandled global submodule ID"); - return 0; - } - - if (GlobalID > SubmodulesLoaded.size()) { - Error("submodule ID out of range in AST file"); - return 0; - } - - return SubmodulesLoaded[GlobalID - NUM_PREDEF_SUBMODULE_IDS]; -} - -Selector ASTReader::getLocalSelector(ModuleFile &M, unsigned LocalID) { - return DecodeSelector(getGlobalSelectorID(M, LocalID)); -} - -Selector ASTReader::DecodeSelector(serialization::SelectorID ID) { - if (ID == 0) - return Selector(); - - if (ID > SelectorsLoaded.size()) { - Error("selector ID out of range in AST file"); - return Selector(); - } - - if (SelectorsLoaded[ID - 1].getAsOpaquePtr() == 0) { - // Load this selector from the selector table. - GlobalSelectorMapType::iterator I = GlobalSelectorMap.find(ID); - assert(I != GlobalSelectorMap.end() && "Corrupted global selector map"); - ModuleFile &M = *I->second; - ASTSelectorLookupTrait Trait(*this, M); - unsigned Idx = ID - M.BaseSelectorID - NUM_PREDEF_SELECTOR_IDS; - SelectorsLoaded[ID - 1] = - Trait.ReadKey(M.SelectorLookupTableData + M.SelectorOffsets[Idx], 0); - if (DeserializationListener) - DeserializationListener->SelectorRead(ID, SelectorsLoaded[ID - 1]); - } - - return SelectorsLoaded[ID - 1]; -} - -Selector ASTReader::GetExternalSelector(serialization::SelectorID ID) { - return DecodeSelector(ID); -} - -uint32_t ASTReader::GetNumExternalSelectors() { - // ID 0 (the null selector) is considered an external selector. - return getTotalNumSelectors() + 1; -} - -serialization::SelectorID -ASTReader::getGlobalSelectorID(ModuleFile &M, unsigned LocalID) const { - if (LocalID < NUM_PREDEF_SELECTOR_IDS) - return LocalID; - - ContinuousRangeMap<uint32_t, int, 2>::iterator I - = M.SelectorRemap.find(LocalID - NUM_PREDEF_SELECTOR_IDS); - assert(I != M.SelectorRemap.end() - && "Invalid index into selector index remap"); - - return LocalID + I->second; -} - -DeclarationName -ASTReader::ReadDeclarationName(ModuleFile &F, - const RecordData &Record, unsigned &Idx) { - DeclarationName::NameKind Kind = (DeclarationName::NameKind)Record[Idx++]; - switch (Kind) { - case DeclarationName::Identifier: - return DeclarationName(GetIdentifierInfo(F, Record, Idx)); - - case DeclarationName::ObjCZeroArgSelector: - case DeclarationName::ObjCOneArgSelector: - case DeclarationName::ObjCMultiArgSelector: - return DeclarationName(ReadSelector(F, Record, Idx)); - - case DeclarationName::CXXConstructorName: - return Context.DeclarationNames.getCXXConstructorName( - Context.getCanonicalType(readType(F, Record, Idx))); - - case DeclarationName::CXXDestructorName: - return Context.DeclarationNames.getCXXDestructorName( - Context.getCanonicalType(readType(F, Record, Idx))); - - case DeclarationName::CXXConversionFunctionName: - return Context.DeclarationNames.getCXXConversionFunctionName( - Context.getCanonicalType(readType(F, Record, Idx))); - - case DeclarationName::CXXOperatorName: - return Context.DeclarationNames.getCXXOperatorName( - (OverloadedOperatorKind)Record[Idx++]); - - case DeclarationName::CXXLiteralOperatorName: - return Context.DeclarationNames.getCXXLiteralOperatorName( - GetIdentifierInfo(F, Record, Idx)); - - case DeclarationName::CXXUsingDirective: - return DeclarationName::getUsingDirectiveName(); - } - - llvm_unreachable("Invalid NameKind!"); -} - -void ASTReader::ReadDeclarationNameLoc(ModuleFile &F, - DeclarationNameLoc &DNLoc, - DeclarationName Name, - const RecordData &Record, unsigned &Idx) { - switch (Name.getNameKind()) { - case DeclarationName::CXXConstructorName: - case DeclarationName::CXXDestructorName: - case DeclarationName::CXXConversionFunctionName: - DNLoc.NamedType.TInfo = GetTypeSourceInfo(F, Record, Idx); - break; - - case DeclarationName::CXXOperatorName: - DNLoc.CXXOperatorName.BeginOpNameLoc - = ReadSourceLocation(F, Record, Idx).getRawEncoding(); - DNLoc.CXXOperatorName.EndOpNameLoc - = ReadSourceLocation(F, Record, Idx).getRawEncoding(); - break; - - case DeclarationName::CXXLiteralOperatorName: - DNLoc.CXXLiteralOperatorName.OpNameLoc - = ReadSourceLocation(F, Record, Idx).getRawEncoding(); - break; - - case DeclarationName::Identifier: - case DeclarationName::ObjCZeroArgSelector: - case DeclarationName::ObjCOneArgSelector: - case DeclarationName::ObjCMultiArgSelector: - case DeclarationName::CXXUsingDirective: - break; - } -} - -void ASTReader::ReadDeclarationNameInfo(ModuleFile &F, - DeclarationNameInfo &NameInfo, - const RecordData &Record, unsigned &Idx) { - NameInfo.setName(ReadDeclarationName(F, Record, Idx)); - NameInfo.setLoc(ReadSourceLocation(F, Record, Idx)); - DeclarationNameLoc DNLoc; - ReadDeclarationNameLoc(F, DNLoc, NameInfo.getName(), Record, Idx); - NameInfo.setInfo(DNLoc); -} - -void ASTReader::ReadQualifierInfo(ModuleFile &F, QualifierInfo &Info, - const RecordData &Record, unsigned &Idx) { - Info.QualifierLoc = ReadNestedNameSpecifierLoc(F, Record, Idx); - unsigned NumTPLists = Record[Idx++]; - Info.NumTemplParamLists = NumTPLists; - if (NumTPLists) { - Info.TemplParamLists = new (Context) TemplateParameterList*[NumTPLists]; - for (unsigned i=0; i != NumTPLists; ++i) - Info.TemplParamLists[i] = ReadTemplateParameterList(F, Record, Idx); - } -} - -TemplateName -ASTReader::ReadTemplateName(ModuleFile &F, const RecordData &Record, - unsigned &Idx) { - TemplateName::NameKind Kind = (TemplateName::NameKind)Record[Idx++]; - switch (Kind) { - case TemplateName::Template: - return TemplateName(ReadDeclAs<TemplateDecl>(F, Record, Idx)); - - case TemplateName::OverloadedTemplate: { - unsigned size = Record[Idx++]; - UnresolvedSet<8> Decls; - while (size--) - Decls.addDecl(ReadDeclAs<NamedDecl>(F, Record, Idx)); - - return Context.getOverloadedTemplateName(Decls.begin(), Decls.end()); - } - - case TemplateName::QualifiedTemplate: { - NestedNameSpecifier *NNS = ReadNestedNameSpecifier(F, Record, Idx); - bool hasTemplKeyword = Record[Idx++]; - TemplateDecl *Template = ReadDeclAs<TemplateDecl>(F, Record, Idx); - return Context.getQualifiedTemplateName(NNS, hasTemplKeyword, Template); - } - - case TemplateName::DependentTemplate: { - NestedNameSpecifier *NNS = ReadNestedNameSpecifier(F, Record, Idx); - if (Record[Idx++]) // isIdentifier - return Context.getDependentTemplateName(NNS, - GetIdentifierInfo(F, Record, - Idx)); - return Context.getDependentTemplateName(NNS, - (OverloadedOperatorKind)Record[Idx++]); - } - - case TemplateName::SubstTemplateTemplateParm: { - TemplateTemplateParmDecl *param - = ReadDeclAs<TemplateTemplateParmDecl>(F, Record, Idx); - if (!param) return TemplateName(); - TemplateName replacement = ReadTemplateName(F, Record, Idx); - return Context.getSubstTemplateTemplateParm(param, replacement); - } - - case TemplateName::SubstTemplateTemplateParmPack: { - TemplateTemplateParmDecl *Param - = ReadDeclAs<TemplateTemplateParmDecl>(F, Record, Idx); - if (!Param) - return TemplateName(); - - TemplateArgument ArgPack = ReadTemplateArgument(F, Record, Idx); - if (ArgPack.getKind() != TemplateArgument::Pack) - return TemplateName(); - - return Context.getSubstTemplateTemplateParmPack(Param, ArgPack); - } - } - - llvm_unreachable("Unhandled template name kind!"); -} - -TemplateArgument -ASTReader::ReadTemplateArgument(ModuleFile &F, - const RecordData &Record, unsigned &Idx) { - TemplateArgument::ArgKind Kind = (TemplateArgument::ArgKind)Record[Idx++]; - switch (Kind) { - case TemplateArgument::Null: - return TemplateArgument(); - case TemplateArgument::Type: - return TemplateArgument(readType(F, Record, Idx)); - case TemplateArgument::Declaration: { - ValueDecl *D = ReadDeclAs<ValueDecl>(F, Record, Idx); - bool ForReferenceParam = Record[Idx++]; - return TemplateArgument(D, ForReferenceParam); - } - case TemplateArgument::NullPtr: - return TemplateArgument(readType(F, Record, Idx), /*isNullPtr*/true); - case TemplateArgument::Integral: { - llvm::APSInt Value = ReadAPSInt(Record, Idx); - QualType T = readType(F, Record, Idx); - return TemplateArgument(Context, Value, T); - } - case TemplateArgument::Template: - return TemplateArgument(ReadTemplateName(F, Record, Idx)); - case TemplateArgument::TemplateExpansion: { - TemplateName Name = ReadTemplateName(F, Record, Idx); - llvm::Optional<unsigned> NumTemplateExpansions; - if (unsigned NumExpansions = Record[Idx++]) - NumTemplateExpansions = NumExpansions - 1; - return TemplateArgument(Name, NumTemplateExpansions); - } - case TemplateArgument::Expression: - return TemplateArgument(ReadExpr(F)); - case TemplateArgument::Pack: { - unsigned NumArgs = Record[Idx++]; - TemplateArgument *Args = new (Context) TemplateArgument[NumArgs]; - for (unsigned I = 0; I != NumArgs; ++I) - Args[I] = ReadTemplateArgument(F, Record, Idx); - return TemplateArgument(Args, NumArgs); - } - } - - llvm_unreachable("Unhandled template argument kind!"); -} - -TemplateParameterList * -ASTReader::ReadTemplateParameterList(ModuleFile &F, - const RecordData &Record, unsigned &Idx) { - SourceLocation TemplateLoc = ReadSourceLocation(F, Record, Idx); - SourceLocation LAngleLoc = ReadSourceLocation(F, Record, Idx); - SourceLocation RAngleLoc = ReadSourceLocation(F, Record, Idx); - - unsigned NumParams = Record[Idx++]; - SmallVector<NamedDecl *, 16> Params; - Params.reserve(NumParams); - while (NumParams--) - Params.push_back(ReadDeclAs<NamedDecl>(F, Record, Idx)); - - TemplateParameterList* TemplateParams = - TemplateParameterList::Create(Context, TemplateLoc, LAngleLoc, - Params.data(), Params.size(), RAngleLoc); - return TemplateParams; -} - -void -ASTReader:: -ReadTemplateArgumentList(SmallVector<TemplateArgument, 8> &TemplArgs, - ModuleFile &F, const RecordData &Record, - unsigned &Idx) { - unsigned NumTemplateArgs = Record[Idx++]; - TemplArgs.reserve(NumTemplateArgs); - while (NumTemplateArgs--) - TemplArgs.push_back(ReadTemplateArgument(F, Record, Idx)); -} - -/// \brief Read a UnresolvedSet structure. -void ASTReader::ReadUnresolvedSet(ModuleFile &F, ASTUnresolvedSet &Set, - const RecordData &Record, unsigned &Idx) { - unsigned NumDecls = Record[Idx++]; - Set.reserve(Context, NumDecls); - while (NumDecls--) { - NamedDecl *D = ReadDeclAs<NamedDecl>(F, Record, Idx); - AccessSpecifier AS = (AccessSpecifier)Record[Idx++]; - Set.addDecl(Context, D, AS); - } -} - -CXXBaseSpecifier -ASTReader::ReadCXXBaseSpecifier(ModuleFile &F, - const RecordData &Record, unsigned &Idx) { - bool isVirtual = static_cast<bool>(Record[Idx++]); - bool isBaseOfClass = static_cast<bool>(Record[Idx++]); - AccessSpecifier AS = static_cast<AccessSpecifier>(Record[Idx++]); - bool inheritConstructors = static_cast<bool>(Record[Idx++]); - TypeSourceInfo *TInfo = GetTypeSourceInfo(F, Record, Idx); - SourceRange Range = ReadSourceRange(F, Record, Idx); - SourceLocation EllipsisLoc = ReadSourceLocation(F, Record, Idx); - CXXBaseSpecifier Result(Range, isVirtual, isBaseOfClass, AS, TInfo, - EllipsisLoc); - Result.setInheritConstructors(inheritConstructors); - return Result; -} - -std::pair<CXXCtorInitializer **, unsigned> -ASTReader::ReadCXXCtorInitializers(ModuleFile &F, const RecordData &Record, - unsigned &Idx) { - CXXCtorInitializer **CtorInitializers = 0; - unsigned NumInitializers = Record[Idx++]; - if (NumInitializers) { - CtorInitializers - = new (Context) CXXCtorInitializer*[NumInitializers]; - for (unsigned i=0; i != NumInitializers; ++i) { - TypeSourceInfo *TInfo = 0; - bool IsBaseVirtual = false; - FieldDecl *Member = 0; - IndirectFieldDecl *IndirectMember = 0; - - CtorInitializerType Type = (CtorInitializerType)Record[Idx++]; - switch (Type) { - case CTOR_INITIALIZER_BASE: - TInfo = GetTypeSourceInfo(F, Record, Idx); - IsBaseVirtual = Record[Idx++]; - break; - - case CTOR_INITIALIZER_DELEGATING: - TInfo = GetTypeSourceInfo(F, Record, Idx); - break; - - case CTOR_INITIALIZER_MEMBER: - Member = ReadDeclAs<FieldDecl>(F, Record, Idx); - break; - - case CTOR_INITIALIZER_INDIRECT_MEMBER: - IndirectMember = ReadDeclAs<IndirectFieldDecl>(F, Record, Idx); - break; - } - - SourceLocation MemberOrEllipsisLoc = ReadSourceLocation(F, Record, Idx); - Expr *Init = ReadExpr(F); - SourceLocation LParenLoc = ReadSourceLocation(F, Record, Idx); - SourceLocation RParenLoc = ReadSourceLocation(F, Record, Idx); - bool IsWritten = Record[Idx++]; - unsigned SourceOrderOrNumArrayIndices; - SmallVector<VarDecl *, 8> Indices; - if (IsWritten) { - SourceOrderOrNumArrayIndices = Record[Idx++]; - } else { - SourceOrderOrNumArrayIndices = Record[Idx++]; - Indices.reserve(SourceOrderOrNumArrayIndices); - for (unsigned i=0; i != SourceOrderOrNumArrayIndices; ++i) - Indices.push_back(ReadDeclAs<VarDecl>(F, Record, Idx)); - } - - CXXCtorInitializer *BOMInit; - if (Type == CTOR_INITIALIZER_BASE) { - BOMInit = new (Context) CXXCtorInitializer(Context, TInfo, IsBaseVirtual, - LParenLoc, Init, RParenLoc, - MemberOrEllipsisLoc); - } else if (Type == CTOR_INITIALIZER_DELEGATING) { - BOMInit = new (Context) CXXCtorInitializer(Context, TInfo, LParenLoc, - Init, RParenLoc); - } else if (IsWritten) { - if (Member) - BOMInit = new (Context) CXXCtorInitializer(Context, Member, MemberOrEllipsisLoc, - LParenLoc, Init, RParenLoc); - else - BOMInit = new (Context) CXXCtorInitializer(Context, IndirectMember, - MemberOrEllipsisLoc, LParenLoc, - Init, RParenLoc); - } else { - BOMInit = CXXCtorInitializer::Create(Context, Member, MemberOrEllipsisLoc, - LParenLoc, Init, RParenLoc, - Indices.data(), Indices.size()); - } - - if (IsWritten) - BOMInit->setSourceOrder(SourceOrderOrNumArrayIndices); - CtorInitializers[i] = BOMInit; - } - } - - return std::make_pair(CtorInitializers, NumInitializers); -} - -NestedNameSpecifier * -ASTReader::ReadNestedNameSpecifier(ModuleFile &F, - const RecordData &Record, unsigned &Idx) { - unsigned N = Record[Idx++]; - NestedNameSpecifier *NNS = 0, *Prev = 0; - for (unsigned I = 0; I != N; ++I) { - NestedNameSpecifier::SpecifierKind Kind - = (NestedNameSpecifier::SpecifierKind)Record[Idx++]; - switch (Kind) { - case NestedNameSpecifier::Identifier: { - IdentifierInfo *II = GetIdentifierInfo(F, Record, Idx); - NNS = NestedNameSpecifier::Create(Context, Prev, II); - break; - } - - case NestedNameSpecifier::Namespace: { - NamespaceDecl *NS = ReadDeclAs<NamespaceDecl>(F, Record, Idx); - NNS = NestedNameSpecifier::Create(Context, Prev, NS); - break; - } - - case NestedNameSpecifier::NamespaceAlias: { - NamespaceAliasDecl *Alias =ReadDeclAs<NamespaceAliasDecl>(F, Record, Idx); - NNS = NestedNameSpecifier::Create(Context, Prev, Alias); - break; - } - - case NestedNameSpecifier::TypeSpec: - case NestedNameSpecifier::TypeSpecWithTemplate: { - const Type *T = readType(F, Record, Idx).getTypePtrOrNull(); - if (!T) - return 0; - - bool Template = Record[Idx++]; - NNS = NestedNameSpecifier::Create(Context, Prev, Template, T); - break; - } - - case NestedNameSpecifier::Global: { - NNS = NestedNameSpecifier::GlobalSpecifier(Context); - // No associated value, and there can't be a prefix. - break; - } - } - Prev = NNS; - } - return NNS; -} - -NestedNameSpecifierLoc -ASTReader::ReadNestedNameSpecifierLoc(ModuleFile &F, const RecordData &Record, - unsigned &Idx) { - unsigned N = Record[Idx++]; - NestedNameSpecifierLocBuilder Builder; - for (unsigned I = 0; I != N; ++I) { - NestedNameSpecifier::SpecifierKind Kind - = (NestedNameSpecifier::SpecifierKind)Record[Idx++]; - switch (Kind) { - case NestedNameSpecifier::Identifier: { - IdentifierInfo *II = GetIdentifierInfo(F, Record, Idx); - SourceRange Range = ReadSourceRange(F, Record, Idx); - Builder.Extend(Context, II, Range.getBegin(), Range.getEnd()); - break; - } - - case NestedNameSpecifier::Namespace: { - NamespaceDecl *NS = ReadDeclAs<NamespaceDecl>(F, Record, Idx); - SourceRange Range = ReadSourceRange(F, Record, Idx); - Builder.Extend(Context, NS, Range.getBegin(), Range.getEnd()); - break; - } - - case NestedNameSpecifier::NamespaceAlias: { - NamespaceAliasDecl *Alias =ReadDeclAs<NamespaceAliasDecl>(F, Record, Idx); - SourceRange Range = ReadSourceRange(F, Record, Idx); - Builder.Extend(Context, Alias, Range.getBegin(), Range.getEnd()); - break; - } - - case NestedNameSpecifier::TypeSpec: - case NestedNameSpecifier::TypeSpecWithTemplate: { - bool Template = Record[Idx++]; - TypeSourceInfo *T = GetTypeSourceInfo(F, Record, Idx); - if (!T) - return NestedNameSpecifierLoc(); - SourceLocation ColonColonLoc = ReadSourceLocation(F, Record, Idx); - - // FIXME: 'template' keyword location not saved anywhere, so we fake it. - Builder.Extend(Context, - Template? T->getTypeLoc().getBeginLoc() : SourceLocation(), - T->getTypeLoc(), ColonColonLoc); - break; - } - - case NestedNameSpecifier::Global: { - SourceLocation ColonColonLoc = ReadSourceLocation(F, Record, Idx); - Builder.MakeGlobal(Context, ColonColonLoc); - break; - } - } - } - - return Builder.getWithLocInContext(Context); -} - -SourceRange -ASTReader::ReadSourceRange(ModuleFile &F, const RecordData &Record, - unsigned &Idx) { - SourceLocation beg = ReadSourceLocation(F, Record, Idx); - SourceLocation end = ReadSourceLocation(F, Record, Idx); - return SourceRange(beg, end); -} - -/// \brief Read an integral value -llvm::APInt ASTReader::ReadAPInt(const RecordData &Record, unsigned &Idx) { - unsigned BitWidth = Record[Idx++]; - unsigned NumWords = llvm::APInt::getNumWords(BitWidth); - llvm::APInt Result(BitWidth, NumWords, &Record[Idx]); - Idx += NumWords; - return Result; -} - -/// \brief Read a signed integral value -llvm::APSInt ASTReader::ReadAPSInt(const RecordData &Record, unsigned &Idx) { - bool isUnsigned = Record[Idx++]; - return llvm::APSInt(ReadAPInt(Record, Idx), isUnsigned); -} - -/// \brief Read a floating-point value -llvm::APFloat ASTReader::ReadAPFloat(const RecordData &Record, unsigned &Idx) { - return llvm::APFloat(ReadAPInt(Record, Idx)); -} - -// \brief Read a string -std::string ASTReader::ReadString(const RecordData &Record, unsigned &Idx) { - unsigned Len = Record[Idx++]; - std::string Result(Record.data() + Idx, Record.data() + Idx + Len); - Idx += Len; - return Result; -} - -VersionTuple ASTReader::ReadVersionTuple(const RecordData &Record, - unsigned &Idx) { - unsigned Major = Record[Idx++]; - unsigned Minor = Record[Idx++]; - unsigned Subminor = Record[Idx++]; - if (Minor == 0) - return VersionTuple(Major); - if (Subminor == 0) - return VersionTuple(Major, Minor - 1); - return VersionTuple(Major, Minor - 1, Subminor - 1); -} - -CXXTemporary *ASTReader::ReadCXXTemporary(ModuleFile &F, - const RecordData &Record, - unsigned &Idx) { - CXXDestructorDecl *Decl = ReadDeclAs<CXXDestructorDecl>(F, Record, Idx); - return CXXTemporary::Create(Context, Decl); -} - -DiagnosticBuilder ASTReader::Diag(unsigned DiagID) { - return Diag(SourceLocation(), DiagID); -} - -DiagnosticBuilder ASTReader::Diag(SourceLocation Loc, unsigned DiagID) { - return Diags.Report(Loc, DiagID); -} - -/// \brief Retrieve the identifier table associated with the -/// preprocessor. -IdentifierTable &ASTReader::getIdentifierTable() { - return PP.getIdentifierTable(); -} - -/// \brief Record that the given ID maps to the given switch-case -/// statement. -void ASTReader::RecordSwitchCaseID(SwitchCase *SC, unsigned ID) { - assert((*CurrSwitchCaseStmts)[ID] == 0 && - "Already have a SwitchCase with this ID"); - (*CurrSwitchCaseStmts)[ID] = SC; -} - -/// \brief Retrieve the switch-case statement with the given ID. -SwitchCase *ASTReader::getSwitchCaseWithID(unsigned ID) { - assert((*CurrSwitchCaseStmts)[ID] != 0 && "No SwitchCase with this ID"); - return (*CurrSwitchCaseStmts)[ID]; -} - -void ASTReader::ClearSwitchCaseIDs() { - CurrSwitchCaseStmts->clear(); -} - -void ASTReader::ReadComments() { - std::vector<RawComment *> Comments; - for (SmallVectorImpl<std::pair<llvm::BitstreamCursor, - serialization::ModuleFile *> >::iterator - I = CommentsCursors.begin(), - E = CommentsCursors.end(); - I != E; ++I) { - llvm::BitstreamCursor &Cursor = I->first; - serialization::ModuleFile &F = *I->second; - SavedStreamPosition SavedPosition(Cursor); - - RecordData Record; - while (true) { - unsigned Code = Cursor.ReadCode(); - if (Code == llvm::bitc::END_BLOCK) - break; - - if (Code == llvm::bitc::ENTER_SUBBLOCK) { - // No known subblocks, always skip them. - Cursor.ReadSubBlockID(); - if (Cursor.SkipBlock()) { - Error("malformed block record in AST file"); - return; - } - continue; - } - - if (Code == llvm::bitc::DEFINE_ABBREV) { - Cursor.ReadAbbrevRecord(); - continue; - } - - // Read a record. - Record.clear(); - switch ((CommentRecordTypes) Cursor.ReadRecord(Code, Record)) { - case COMMENTS_RAW_COMMENT: { - unsigned Idx = 0; - SourceRange SR = ReadSourceRange(F, Record, Idx); - RawComment::CommentKind Kind = - (RawComment::CommentKind) Record[Idx++]; - bool IsTrailingComment = Record[Idx++]; - bool IsAlmostTrailingComment = Record[Idx++]; - Comments.push_back(new (Context) RawComment(SR, Kind, - IsTrailingComment, - IsAlmostTrailingComment)); - break; - } - } - } - } - Context.Comments.addCommentsToFront(Comments); -} - -void ASTReader::finishPendingActions() { - while (!PendingIdentifierInfos.empty() || !PendingDeclChains.empty() || - !PendingMacroIDs.empty()) { - // If any identifiers with corresponding top-level declarations have - // been loaded, load those declarations now. - while (!PendingIdentifierInfos.empty()) { - SetGloballyVisibleDecls(PendingIdentifierInfos.front().II, - PendingIdentifierInfos.front().DeclIDs, true); - PendingIdentifierInfos.pop_front(); - } - - // Load pending declaration chains. - for (unsigned I = 0; I != PendingDeclChains.size(); ++I) { - loadPendingDeclChain(PendingDeclChains[I]); - PendingDeclChainsKnown.erase(PendingDeclChains[I]); - } - PendingDeclChains.clear(); - - // Load any pending macro definitions. - for (unsigned I = 0; I != PendingMacroIDs.size(); ++I) { - // FIXME: std::move here - SmallVector<MacroID, 2> GlobalIDs = PendingMacroIDs.begin()[I].second; - MacroInfo *Hint = 0; - for (unsigned IDIdx = 0, NumIDs = GlobalIDs.size(); IDIdx != NumIDs; - ++IDIdx) { - Hint = getMacro(GlobalIDs[IDIdx], Hint); - } - } - PendingMacroIDs.clear(); - } - - // If we deserialized any C++ or Objective-C class definitions, any - // Objective-C protocol definitions, or any redeclarable templates, make sure - // that all redeclarations point to the definitions. Note that this can only - // happen now, after the redeclaration chains have been fully wired. - for (llvm::SmallPtrSet<Decl *, 4>::iterator D = PendingDefinitions.begin(), - DEnd = PendingDefinitions.end(); - D != DEnd; ++D) { - if (TagDecl *TD = dyn_cast<TagDecl>(*D)) { - if (const TagType *TagT = dyn_cast<TagType>(TD->TypeForDecl)) { - // Make sure that the TagType points at the definition. - const_cast<TagType*>(TagT)->decl = TD; - } - - if (CXXRecordDecl *RD = dyn_cast<CXXRecordDecl>(*D)) { - for (CXXRecordDecl::redecl_iterator R = RD->redecls_begin(), - REnd = RD->redecls_end(); - R != REnd; ++R) - cast<CXXRecordDecl>(*R)->DefinitionData = RD->DefinitionData; - - } - - continue; - } - - if (ObjCInterfaceDecl *ID = dyn_cast<ObjCInterfaceDecl>(*D)) { - // Make sure that the ObjCInterfaceType points at the definition. - const_cast<ObjCInterfaceType *>(cast<ObjCInterfaceType>(ID->TypeForDecl)) - ->Decl = ID; - - for (ObjCInterfaceDecl::redecl_iterator R = ID->redecls_begin(), - REnd = ID->redecls_end(); - R != REnd; ++R) - R->Data = ID->Data; - - continue; - } - - if (ObjCProtocolDecl *PD = dyn_cast<ObjCProtocolDecl>(*D)) { - for (ObjCProtocolDecl::redecl_iterator R = PD->redecls_begin(), - REnd = PD->redecls_end(); - R != REnd; ++R) - R->Data = PD->Data; - - continue; - } - - RedeclarableTemplateDecl *RTD - = cast<RedeclarableTemplateDecl>(*D)->getCanonicalDecl(); - for (RedeclarableTemplateDecl::redecl_iterator R = RTD->redecls_begin(), - REnd = RTD->redecls_end(); - R != REnd; ++R) - R->Common = RTD->Common; - } - PendingDefinitions.clear(); - - // Load the bodies of any functions or methods we've encountered. We do - // this now (delayed) so that we can be sure that the declaration chains - // have been fully wired up. - for (PendingBodiesMap::iterator PB = PendingBodies.begin(), - PBEnd = PendingBodies.end(); - PB != PBEnd; ++PB) { - if (FunctionDecl *FD = dyn_cast<FunctionDecl>(PB->first)) { - // FIXME: Check for =delete/=default? - // FIXME: Complain about ODR violations here? - if (!getContext().getLangOpts().Modules || !FD->hasBody()) - FD->setLazyBody(PB->second); - continue; - } - - ObjCMethodDecl *MD = cast<ObjCMethodDecl>(PB->first); - if (!getContext().getLangOpts().Modules || !MD->hasBody()) - MD->setLazyBody(PB->second); - } - PendingBodies.clear(); -} - -void ASTReader::FinishedDeserializing() { - assert(NumCurrentElementsDeserializing && - "FinishedDeserializing not paired with StartedDeserializing"); - if (NumCurrentElementsDeserializing == 1) { - // We decrease NumCurrentElementsDeserializing only after pending actions - // are finished, to avoid recursively re-calling finishPendingActions(). - finishPendingActions(); - } - --NumCurrentElementsDeserializing; - - if (NumCurrentElementsDeserializing == 0 && - Consumer && !PassingDeclsToConsumer) { - // Guard variable to avoid recursively redoing the process of passing - // decls to consumer. - SaveAndRestore<bool> GuardPassingDeclsToConsumer(PassingDeclsToConsumer, - true); - - while (!InterestingDecls.empty()) { - // We are not in recursive loading, so it's safe to pass the "interesting" - // decls to the consumer. - Decl *D = InterestingDecls.front(); - InterestingDecls.pop_front(); - PassInterestingDeclToConsumer(D); - } - } -} - -ASTReader::ASTReader(Preprocessor &PP, ASTContext &Context, - StringRef isysroot, bool DisableValidation, - bool AllowASTWithCompilerErrors) - : Listener(new PCHValidator(PP, *this)), DeserializationListener(0), - SourceMgr(PP.getSourceManager()), FileMgr(PP.getFileManager()), - Diags(PP.getDiagnostics()), SemaObj(0), PP(PP), Context(Context), - Consumer(0), ModuleMgr(PP.getFileManager()), - isysroot(isysroot), DisableValidation(DisableValidation), - AllowASTWithCompilerErrors(AllowASTWithCompilerErrors), - CurrentGeneration(0), CurrSwitchCaseStmts(&SwitchCaseStmts), - NumSLocEntriesRead(0), TotalNumSLocEntries(0), - NumStatementsRead(0), TotalNumStatements(0), NumMacrosRead(0), - TotalNumMacros(0), NumSelectorsRead(0), NumMethodPoolEntriesRead(0), - NumMethodPoolMisses(0), TotalNumMethodPoolEntries(0), - NumLexicalDeclContextsRead(0), TotalLexicalDeclContexts(0), - NumVisibleDeclContextsRead(0), TotalVisibleDeclContexts(0), - TotalModulesSizeInBits(0), NumCurrentElementsDeserializing(0), - PassingDeclsToConsumer(false), - NumCXXBaseSpecifiersLoaded(0) -{ - SourceMgr.setExternalSLocEntrySource(this); -} - -ASTReader::~ASTReader() { - for (DeclContextVisibleUpdatesPending::iterator - I = PendingVisibleUpdates.begin(), - E = PendingVisibleUpdates.end(); - I != E; ++I) { - for (DeclContextVisibleUpdates::iterator J = I->second.begin(), - F = I->second.end(); - J != F; ++J) - delete J->first; - } -} +//===--- ASTReader.cpp - AST File Reader ------------------------*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+//
+// This file defines the ASTReader class, which reads AST files.
+//
+//===----------------------------------------------------------------------===//
+
+#include "clang/Serialization/ASTReader.h"
+#include "ASTCommon.h"
+#include "ASTReaderInternals.h"
+#include "clang/AST/ASTConsumer.h"
+#include "clang/AST/ASTContext.h"
+#include "clang/AST/DeclTemplate.h"
+#include "clang/AST/Expr.h"
+#include "clang/AST/ExprCXX.h"
+#include "clang/AST/NestedNameSpecifier.h"
+#include "clang/AST/Type.h"
+#include "clang/AST/TypeLocVisitor.h"
+#include "clang/Basic/FileManager.h"
+#include "clang/Basic/FileSystemStatCache.h"
+#include "clang/Basic/OnDiskHashTable.h"
+#include "clang/Basic/SourceManager.h"
+#include "clang/Basic/SourceManagerInternals.h"
+#include "clang/Basic/TargetInfo.h"
+#include "clang/Basic/TargetOptions.h"
+#include "clang/Basic/Version.h"
+#include "clang/Basic/VersionTuple.h"
+#include "clang/Lex/HeaderSearch.h"
+#include "clang/Lex/HeaderSearchOptions.h"
+#include "clang/Lex/MacroInfo.h"
+#include "clang/Lex/PreprocessingRecord.h"
+#include "clang/Lex/Preprocessor.h"
+#include "clang/Lex/PreprocessorOptions.h"
+#include "clang/Sema/Scope.h"
+#include "clang/Sema/Sema.h"
+#include "clang/Serialization/ASTDeserializationListener.h"
+#include "clang/Serialization/ModuleManager.h"
+#include "clang/Serialization/SerializationDiagnostic.h"
+#include "llvm/ADT/StringExtras.h"
+#include "llvm/Bitcode/BitstreamReader.h"
+#include "llvm/Support/ErrorHandling.h"
+#include "llvm/Support/FileSystem.h"
+#include "llvm/Support/MemoryBuffer.h"
+#include "llvm/Support/Path.h"
+#include "llvm/Support/SaveAndRestore.h"
+#include "llvm/Support/system_error.h"
+#include <algorithm>
+#include <cstdio>
+#include <iterator>
+
+using namespace clang;
+using namespace clang::serialization;
+using namespace clang::serialization::reader;
+
+//===----------------------------------------------------------------------===//
+// PCH validator implementation
+//===----------------------------------------------------------------------===//
+
+ASTReaderListener::~ASTReaderListener() {}
+
+/// \brief Compare the given set of language options against an existing set of
+/// language options.
+///
+/// \param Diags If non-NULL, diagnostics will be emitted via this engine.
+///
+/// \returns true if the languagae options mis-match, false otherwise.
+static bool checkLanguageOptions(const LangOptions &LangOpts,
+ const LangOptions &ExistingLangOpts,
+ DiagnosticsEngine *Diags) {
+#define LANGOPT(Name, Bits, Default, Description) \
+ if (ExistingLangOpts.Name != LangOpts.Name) { \
+ if (Diags) \
+ Diags->Report(diag::err_pch_langopt_mismatch) \
+ << Description << LangOpts.Name << ExistingLangOpts.Name; \
+ return true; \
+ }
+
+#define VALUE_LANGOPT(Name, Bits, Default, Description) \
+ if (ExistingLangOpts.Name != LangOpts.Name) { \
+ if (Diags) \
+ Diags->Report(diag::err_pch_langopt_value_mismatch) \
+ << Description; \
+ return true; \
+ }
+
+#define ENUM_LANGOPT(Name, Type, Bits, Default, Description) \
+ if (ExistingLangOpts.get##Name() != LangOpts.get##Name()) { \
+ if (Diags) \
+ Diags->Report(diag::err_pch_langopt_value_mismatch) \
+ << Description; \
+ return true; \
+ }
+
+#define BENIGN_LANGOPT(Name, Bits, Default, Description)
+#define BENIGN_ENUM_LANGOPT(Name, Type, Bits, Default, Description)
+#include "clang/Basic/LangOptions.def"
+
+ if (ExistingLangOpts.ObjCRuntime != LangOpts.ObjCRuntime) {
+ if (Diags)
+ Diags->Report(diag::err_pch_langopt_value_mismatch)
+ << "target Objective-C runtime";
+ return true;
+ }
+
+ return false;
+}
+
+/// \brief Compare the given set of target options against an existing set of
+/// target options.
+///
+/// \param Diags If non-NULL, diagnostics will be emitted via this engine.
+///
+/// \returns true if the target options mis-match, false otherwise.
+static bool checkTargetOptions(const TargetOptions &TargetOpts,
+ const TargetOptions &ExistingTargetOpts,
+ DiagnosticsEngine *Diags) {
+#define CHECK_TARGET_OPT(Field, Name) \
+ if (TargetOpts.Field != ExistingTargetOpts.Field) { \
+ if (Diags) \
+ Diags->Report(diag::err_pch_targetopt_mismatch) \
+ << Name << TargetOpts.Field << ExistingTargetOpts.Field; \
+ return true; \
+ }
+
+ CHECK_TARGET_OPT(Triple, "target");
+ CHECK_TARGET_OPT(CPU, "target CPU");
+ CHECK_TARGET_OPT(ABI, "target ABI");
+ CHECK_TARGET_OPT(CXXABI, "target C++ ABI");
+ CHECK_TARGET_OPT(LinkerVersion, "target linker version");
+#undef CHECK_TARGET_OPT
+
+ // Compare feature sets.
+ SmallVector<StringRef, 4> ExistingFeatures(
+ ExistingTargetOpts.FeaturesAsWritten.begin(),
+ ExistingTargetOpts.FeaturesAsWritten.end());
+ SmallVector<StringRef, 4> ReadFeatures(TargetOpts.FeaturesAsWritten.begin(),
+ TargetOpts.FeaturesAsWritten.end());
+ std::sort(ExistingFeatures.begin(), ExistingFeatures.end());
+ std::sort(ReadFeatures.begin(), ReadFeatures.end());
+
+ unsigned ExistingIdx = 0, ExistingN = ExistingFeatures.size();
+ unsigned ReadIdx = 0, ReadN = ReadFeatures.size();
+ while (ExistingIdx < ExistingN && ReadIdx < ReadN) {
+ if (ExistingFeatures[ExistingIdx] == ReadFeatures[ReadIdx]) {
+ ++ExistingIdx;
+ ++ReadIdx;
+ continue;
+ }
+
+ if (ReadFeatures[ReadIdx] < ExistingFeatures[ExistingIdx]) {
+ if (Diags)
+ Diags->Report(diag::err_pch_targetopt_feature_mismatch)
+ << false << ReadFeatures[ReadIdx];
+ return true;
+ }
+
+ if (Diags)
+ Diags->Report(diag::err_pch_targetopt_feature_mismatch)
+ << true << ExistingFeatures[ExistingIdx];
+ return true;
+ }
+
+ if (ExistingIdx < ExistingN) {
+ if (Diags)
+ Diags->Report(diag::err_pch_targetopt_feature_mismatch)
+ << true << ExistingFeatures[ExistingIdx];
+ return true;
+ }
+
+ if (ReadIdx < ReadN) {
+ if (Diags)
+ Diags->Report(diag::err_pch_targetopt_feature_mismatch)
+ << false << ReadFeatures[ReadIdx];
+ return true;
+ }
+
+ return false;
+}
+
+bool
+PCHValidator::ReadLanguageOptions(const LangOptions &LangOpts,
+ bool Complain) {
+ const LangOptions &ExistingLangOpts = PP.getLangOpts();
+ return checkLanguageOptions(LangOpts, ExistingLangOpts,
+ Complain? &Reader.Diags : 0);
+}
+
+bool PCHValidator::ReadTargetOptions(const TargetOptions &TargetOpts,
+ bool Complain) {
+ const TargetOptions &ExistingTargetOpts = PP.getTargetInfo().getTargetOpts();
+ return checkTargetOptions(TargetOpts, ExistingTargetOpts,
+ Complain? &Reader.Diags : 0);
+}
+
+namespace {
+ typedef llvm::StringMap<std::pair<StringRef, bool /*IsUndef*/> >
+ MacroDefinitionsMap;
+}
+
+/// \brief Collect the macro definitions provided by the given preprocessor
+/// options.
+static void collectMacroDefinitions(const PreprocessorOptions &PPOpts,
+ MacroDefinitionsMap &Macros,
+ SmallVectorImpl<StringRef> *MacroNames = 0){
+ for (unsigned I = 0, N = PPOpts.Macros.size(); I != N; ++I) {
+ StringRef Macro = PPOpts.Macros[I].first;
+ bool IsUndef = PPOpts.Macros[I].second;
+
+ std::pair<StringRef, StringRef> MacroPair = Macro.split('=');
+ StringRef MacroName = MacroPair.first;
+ StringRef MacroBody = MacroPair.second;
+
+ // For an #undef'd macro, we only care about the name.
+ if (IsUndef) {
+ if (MacroNames && !Macros.count(MacroName))
+ MacroNames->push_back(MacroName);
+
+ Macros[MacroName] = std::make_pair("", true);
+ continue;
+ }
+
+ // For a #define'd macro, figure out the actual definition.
+ if (MacroName.size() == Macro.size())
+ MacroBody = "1";
+ else {
+ // Note: GCC drops anything following an end-of-line character.
+ StringRef::size_type End = MacroBody.find_first_of("\n\r");
+ MacroBody = MacroBody.substr(0, End);
+ }
+
+ if (MacroNames && !Macros.count(MacroName))
+ MacroNames->push_back(MacroName);
+ Macros[MacroName] = std::make_pair(MacroBody, false);
+ }
+}
+
+/// \brief Check the preprocessor options deserialized from the control block
+/// against the preprocessor options in an existing preprocessor.
+///
+/// \param Diags If non-null, produce diagnostics for any mismatches incurred.
+static bool checkPreprocessorOptions(const PreprocessorOptions &PPOpts,
+ const PreprocessorOptions &ExistingPPOpts,
+ DiagnosticsEngine *Diags,
+ FileManager &FileMgr,
+ std::string &SuggestedPredefines) {
+ // Check macro definitions.
+ MacroDefinitionsMap ASTFileMacros;
+ collectMacroDefinitions(PPOpts, ASTFileMacros);
+ MacroDefinitionsMap ExistingMacros;
+ SmallVector<StringRef, 4> ExistingMacroNames;
+ collectMacroDefinitions(ExistingPPOpts, ExistingMacros, &ExistingMacroNames);
+
+ for (unsigned I = 0, N = ExistingMacroNames.size(); I != N; ++I) {
+ // Dig out the macro definition in the existing preprocessor options.
+ StringRef MacroName = ExistingMacroNames[I];
+ std::pair<StringRef, bool> Existing = ExistingMacros[MacroName];
+
+ // Check whether we know anything about this macro name or not.
+ llvm::StringMap<std::pair<StringRef, bool /*IsUndef*/> >::iterator Known
+ = ASTFileMacros.find(MacroName);
+ if (Known == ASTFileMacros.end()) {
+ // FIXME: Check whether this identifier was referenced anywhere in the
+ // AST file. If so, we should reject the AST file. Unfortunately, this
+ // information isn't in the control block. What shall we do about it?
+
+ if (Existing.second) {
+ SuggestedPredefines += "#undef ";
+ SuggestedPredefines += MacroName.str();
+ SuggestedPredefines += '\n';
+ } else {
+ SuggestedPredefines += "#define ";
+ SuggestedPredefines += MacroName.str();
+ SuggestedPredefines += ' ';
+ SuggestedPredefines += Existing.first.str();
+ SuggestedPredefines += '\n';
+ }
+ continue;
+ }
+
+ // If the macro was defined in one but undef'd in the other, we have a
+ // conflict.
+ if (Existing.second != Known->second.second) {
+ if (Diags) {
+ Diags->Report(diag::err_pch_macro_def_undef)
+ << MacroName << Known->second.second;
+ }
+ return true;
+ }
+
+ // If the macro was #undef'd in both, or if the macro bodies are identical,
+ // it's fine.
+ if (Existing.second || Existing.first == Known->second.first)
+ continue;
+
+ // The macro bodies differ; complain.
+ if (Diags) {
+ Diags->Report(diag::err_pch_macro_def_conflict)
+ << MacroName << Known->second.first << Existing.first;
+ }
+ return true;
+ }
+
+ // Check whether we're using predefines.
+ if (PPOpts.UsePredefines != ExistingPPOpts.UsePredefines) {
+ if (Diags) {
+ Diags->Report(diag::err_pch_undef) << ExistingPPOpts.UsePredefines;
+ }
+ return true;
+ }
+
+ // Compute the #include and #include_macros lines we need.
+ for (unsigned I = 0, N = ExistingPPOpts.Includes.size(); I != N; ++I) {
+ StringRef File = ExistingPPOpts.Includes[I];
+ if (File == ExistingPPOpts.ImplicitPCHInclude)
+ continue;
+
+ if (std::find(PPOpts.Includes.begin(), PPOpts.Includes.end(), File)
+ != PPOpts.Includes.end())
+ continue;
+
+ SuggestedPredefines += "#include \"";
+ SuggestedPredefines +=
+ HeaderSearch::NormalizeDashIncludePath(File, FileMgr);
+ SuggestedPredefines += "\"\n";
+ }
+
+ for (unsigned I = 0, N = ExistingPPOpts.MacroIncludes.size(); I != N; ++I) {
+ StringRef File = ExistingPPOpts.MacroIncludes[I];
+ if (std::find(PPOpts.MacroIncludes.begin(), PPOpts.MacroIncludes.end(),
+ File)
+ != PPOpts.MacroIncludes.end())
+ continue;
+
+ SuggestedPredefines += "#__include_macros \"";
+ SuggestedPredefines +=
+ HeaderSearch::NormalizeDashIncludePath(File, FileMgr);
+ SuggestedPredefines += "\"\n##\n";
+ }
+
+ return false;
+}
+
+bool PCHValidator::ReadPreprocessorOptions(const PreprocessorOptions &PPOpts,
+ bool Complain,
+ std::string &SuggestedPredefines) {
+ const PreprocessorOptions &ExistingPPOpts = PP.getPreprocessorOpts();
+
+ return checkPreprocessorOptions(PPOpts, ExistingPPOpts,
+ Complain? &Reader.Diags : 0,
+ PP.getFileManager(),
+ SuggestedPredefines);
+}
+
+void PCHValidator::ReadHeaderFileInfo(const HeaderFileInfo &HFI,
+ unsigned ID) {
+ PP.getHeaderSearchInfo().setHeaderFileInfoForUID(HFI, ID);
+ ++NumHeaderInfos;
+}
+
+void PCHValidator::ReadCounter(const ModuleFile &M, unsigned Value) {
+ PP.setCounterValue(Value);
+}
+
+//===----------------------------------------------------------------------===//
+// AST reader implementation
+//===----------------------------------------------------------------------===//
+
+void
+ASTReader::setDeserializationListener(ASTDeserializationListener *Listener) {
+ DeserializationListener = Listener;
+}
+
+
+
+unsigned ASTSelectorLookupTrait::ComputeHash(Selector Sel) {
+ return serialization::ComputeHash(Sel);
+}
+
+
+std::pair<unsigned, unsigned>
+ASTSelectorLookupTrait::ReadKeyDataLength(const unsigned char*& d) {
+ using namespace clang::io;
+ unsigned KeyLen = ReadUnalignedLE16(d);
+ unsigned DataLen = ReadUnalignedLE16(d);
+ return std::make_pair(KeyLen, DataLen);
+}
+
+ASTSelectorLookupTrait::internal_key_type
+ASTSelectorLookupTrait::ReadKey(const unsigned char* d, unsigned) {
+ using namespace clang::io;
+ SelectorTable &SelTable = Reader.getContext().Selectors;
+ unsigned N = ReadUnalignedLE16(d);
+ IdentifierInfo *FirstII
+ = Reader.getLocalIdentifier(F, ReadUnalignedLE32(d));
+ if (N == 0)
+ return SelTable.getNullarySelector(FirstII);
+ else if (N == 1)
+ return SelTable.getUnarySelector(FirstII);
+
+ SmallVector<IdentifierInfo *, 16> Args;
+ Args.push_back(FirstII);
+ for (unsigned I = 1; I != N; ++I)
+ Args.push_back(Reader.getLocalIdentifier(F, ReadUnalignedLE32(d)));
+
+ return SelTable.getSelector(N, Args.data());
+}
+
+ASTSelectorLookupTrait::data_type
+ASTSelectorLookupTrait::ReadData(Selector, const unsigned char* d,
+ unsigned DataLen) {
+ using namespace clang::io;
+
+ data_type Result;
+
+ Result.ID = Reader.getGlobalSelectorID(F, ReadUnalignedLE32(d));
+ unsigned NumInstanceMethods = ReadUnalignedLE16(d);
+ unsigned NumFactoryMethods = ReadUnalignedLE16(d);
+
+ // Load instance methods
+ for (unsigned I = 0; I != NumInstanceMethods; ++I) {
+ if (ObjCMethodDecl *Method
+ = Reader.GetLocalDeclAs<ObjCMethodDecl>(F, ReadUnalignedLE32(d)))
+ Result.Instance.push_back(Method);
+ }
+
+ // Load factory methods
+ for (unsigned I = 0; I != NumFactoryMethods; ++I) {
+ if (ObjCMethodDecl *Method
+ = Reader.GetLocalDeclAs<ObjCMethodDecl>(F, ReadUnalignedLE32(d)))
+ Result.Factory.push_back(Method);
+ }
+
+ return Result;
+}
+
+unsigned ASTIdentifierLookupTrait::ComputeHash(const internal_key_type& a) {
+ return llvm::HashString(StringRef(a.first, a.second));
+}
+
+std::pair<unsigned, unsigned>
+ASTIdentifierLookupTrait::ReadKeyDataLength(const unsigned char*& d) {
+ using namespace clang::io;
+ unsigned DataLen = ReadUnalignedLE16(d);
+ unsigned KeyLen = ReadUnalignedLE16(d);
+ return std::make_pair(KeyLen, DataLen);
+}
+
+std::pair<const char*, unsigned>
+ASTIdentifierLookupTrait::ReadKey(const unsigned char* d, unsigned n) {
+ assert(n >= 2 && d[n-1] == '\0');
+ return std::make_pair((const char*) d, n-1);
+}
+
+IdentifierInfo *ASTIdentifierLookupTrait::ReadData(const internal_key_type& k,
+ const unsigned char* d,
+ unsigned DataLen) {
+ using namespace clang::io;
+ unsigned RawID = ReadUnalignedLE32(d);
+ bool IsInteresting = RawID & 0x01;
+
+ // Wipe out the "is interesting" bit.
+ RawID = RawID >> 1;
+
+ IdentID ID = Reader.getGlobalIdentifierID(F, RawID);
+ if (!IsInteresting) {
+ // For uninteresting identifiers, just build the IdentifierInfo
+ // and associate it with the persistent ID.
+ IdentifierInfo *II = KnownII;
+ if (!II) {
+ II = &Reader.getIdentifierTable().getOwn(StringRef(k.first, k.second));
+ KnownII = II;
+ }
+ Reader.SetIdentifierInfo(ID, II);
+ II->setIsFromAST();
+ Reader.markIdentifierUpToDate(II);
+ return II;
+ }
+
+ unsigned ObjCOrBuiltinID = ReadUnalignedLE16(d);
+ unsigned Bits = ReadUnalignedLE16(d);
+ bool CPlusPlusOperatorKeyword = Bits & 0x01;
+ Bits >>= 1;
+ bool HasRevertedTokenIDToIdentifier = Bits & 0x01;
+ Bits >>= 1;
+ bool Poisoned = Bits & 0x01;
+ Bits >>= 1;
+ bool ExtensionToken = Bits & 0x01;
+ Bits >>= 1;
+ bool hadMacroDefinition = Bits & 0x01;
+ Bits >>= 1;
+
+ assert(Bits == 0 && "Extra bits in the identifier?");
+ DataLen -= 8;
+
+ // Build the IdentifierInfo itself and link the identifier ID with
+ // the new IdentifierInfo.
+ IdentifierInfo *II = KnownII;
+ if (!II) {
+ II = &Reader.getIdentifierTable().getOwn(StringRef(k.first, k.second));
+ KnownII = II;
+ }
+ Reader.markIdentifierUpToDate(II);
+ II->setIsFromAST();
+
+ // Set or check the various bits in the IdentifierInfo structure.
+ // Token IDs are read-only.
+ if (HasRevertedTokenIDToIdentifier)
+ II->RevertTokenIDToIdentifier();
+ II->setObjCOrBuiltinID(ObjCOrBuiltinID);
+ assert(II->isExtensionToken() == ExtensionToken &&
+ "Incorrect extension token flag");
+ (void)ExtensionToken;
+ if (Poisoned)
+ II->setIsPoisoned(true);
+ assert(II->isCPlusPlusOperatorKeyword() == CPlusPlusOperatorKeyword &&
+ "Incorrect C++ operator keyword flag");
+ (void)CPlusPlusOperatorKeyword;
+
+ // If this identifier is a macro, deserialize the macro
+ // definition.
+ if (hadMacroDefinition) {
+ SmallVector<MacroID, 4> MacroIDs;
+ while (uint32_t LocalID = ReadUnalignedLE32(d)) {
+ MacroIDs.push_back(Reader.getGlobalMacroID(F, LocalID));
+ DataLen -= 4;
+ }
+ DataLen -= 4;
+ Reader.setIdentifierIsMacro(II, MacroIDs);
+ }
+
+ Reader.SetIdentifierInfo(ID, II);
+
+ // Read all of the declarations visible at global scope with this
+ // name.
+ if (DataLen > 0) {
+ SmallVector<uint32_t, 4> DeclIDs;
+ for (; DataLen > 0; DataLen -= 4)
+ DeclIDs.push_back(Reader.getGlobalDeclID(F, ReadUnalignedLE32(d)));
+ Reader.SetGloballyVisibleDecls(II, DeclIDs);
+ }
+
+ return II;
+}
+
+unsigned
+ASTDeclContextNameLookupTrait::ComputeHash(const DeclNameKey &Key) const {
+ llvm::FoldingSetNodeID ID;
+ ID.AddInteger(Key.Kind);
+
+ switch (Key.Kind) {
+ case DeclarationName::Identifier:
+ case DeclarationName::CXXLiteralOperatorName:
+ ID.AddString(((IdentifierInfo*)Key.Data)->getName());
+ break;
+ case DeclarationName::ObjCZeroArgSelector:
+ case DeclarationName::ObjCOneArgSelector:
+ case DeclarationName::ObjCMultiArgSelector:
+ ID.AddInteger(serialization::ComputeHash(Selector(Key.Data)));
+ break;
+ case DeclarationName::CXXOperatorName:
+ ID.AddInteger((OverloadedOperatorKind)Key.Data);
+ break;
+ case DeclarationName::CXXConstructorName:
+ case DeclarationName::CXXDestructorName:
+ case DeclarationName::CXXConversionFunctionName:
+ case DeclarationName::CXXUsingDirective:
+ break;
+ }
+
+ return ID.ComputeHash();
+}
+
+ASTDeclContextNameLookupTrait::internal_key_type
+ASTDeclContextNameLookupTrait::GetInternalKey(
+ const external_key_type& Name) const {
+ DeclNameKey Key;
+ Key.Kind = Name.getNameKind();
+ switch (Name.getNameKind()) {
+ case DeclarationName::Identifier:
+ Key.Data = (uint64_t)Name.getAsIdentifierInfo();
+ break;
+ case DeclarationName::ObjCZeroArgSelector:
+ case DeclarationName::ObjCOneArgSelector:
+ case DeclarationName::ObjCMultiArgSelector:
+ Key.Data = (uint64_t)Name.getObjCSelector().getAsOpaquePtr();
+ break;
+ case DeclarationName::CXXOperatorName:
+ Key.Data = Name.getCXXOverloadedOperator();
+ break;
+ case DeclarationName::CXXLiteralOperatorName:
+ Key.Data = (uint64_t)Name.getCXXLiteralIdentifier();
+ break;
+ case DeclarationName::CXXConstructorName:
+ case DeclarationName::CXXDestructorName:
+ case DeclarationName::CXXConversionFunctionName:
+ case DeclarationName::CXXUsingDirective:
+ Key.Data = 0;
+ break;
+ }
+
+ return Key;
+}
+
+std::pair<unsigned, unsigned>
+ASTDeclContextNameLookupTrait::ReadKeyDataLength(const unsigned char*& d) {
+ using namespace clang::io;
+ unsigned KeyLen = ReadUnalignedLE16(d);
+ unsigned DataLen = ReadUnalignedLE16(d);
+ return std::make_pair(KeyLen, DataLen);
+}
+
+ASTDeclContextNameLookupTrait::internal_key_type
+ASTDeclContextNameLookupTrait::ReadKey(const unsigned char* d, unsigned) {
+ using namespace clang::io;
+
+ DeclNameKey Key;
+ Key.Kind = (DeclarationName::NameKind)*d++;
+ switch (Key.Kind) {
+ case DeclarationName::Identifier:
+ Key.Data = (uint64_t)Reader.getLocalIdentifier(F, ReadUnalignedLE32(d));
+ break;
+ case DeclarationName::ObjCZeroArgSelector:
+ case DeclarationName::ObjCOneArgSelector:
+ case DeclarationName::ObjCMultiArgSelector:
+ Key.Data =
+ (uint64_t)Reader.getLocalSelector(F, ReadUnalignedLE32(d))
+ .getAsOpaquePtr();
+ break;
+ case DeclarationName::CXXOperatorName:
+ Key.Data = *d++; // OverloadedOperatorKind
+ break;
+ case DeclarationName::CXXLiteralOperatorName:
+ Key.Data = (uint64_t)Reader.getLocalIdentifier(F, ReadUnalignedLE32(d));
+ break;
+ case DeclarationName::CXXConstructorName:
+ case DeclarationName::CXXDestructorName:
+ case DeclarationName::CXXConversionFunctionName:
+ case DeclarationName::CXXUsingDirective:
+ Key.Data = 0;
+ break;
+ }
+
+ return Key;
+}
+
+ASTDeclContextNameLookupTrait::data_type
+ASTDeclContextNameLookupTrait::ReadData(internal_key_type,
+ const unsigned char* d,
+ unsigned DataLen) {
+ using namespace clang::io;
+ unsigned NumDecls = ReadUnalignedLE16(d);
+ LE32DeclID *Start = (LE32DeclID *)d;
+ return std::make_pair(Start, Start + NumDecls);
+}
+
+bool ASTReader::ReadDeclContextStorage(ModuleFile &M,
+ llvm::BitstreamCursor &Cursor,
+ const std::pair<uint64_t, uint64_t> &Offsets,
+ DeclContextInfo &Info) {
+ SavedStreamPosition SavedPosition(Cursor);
+ // First the lexical decls.
+ if (Offsets.first != 0) {
+ Cursor.JumpToBit(Offsets.first);
+
+ RecordData Record;
+ const char *Blob;
+ unsigned BlobLen;
+ unsigned Code = Cursor.ReadCode();
+ unsigned RecCode = Cursor.ReadRecord(Code, Record, &Blob, &BlobLen);
+ if (RecCode != DECL_CONTEXT_LEXICAL) {
+ Error("Expected lexical block");
+ return true;
+ }
+
+ Info.LexicalDecls = reinterpret_cast<const KindDeclIDPair*>(Blob);
+ Info.NumLexicalDecls = BlobLen / sizeof(KindDeclIDPair);
+ }
+
+ // Now the lookup table.
+ if (Offsets.second != 0) {
+ Cursor.JumpToBit(Offsets.second);
+
+ RecordData Record;
+ const char *Blob;
+ unsigned BlobLen;
+ unsigned Code = Cursor.ReadCode();
+ unsigned RecCode = Cursor.ReadRecord(Code, Record, &Blob, &BlobLen);
+ if (RecCode != DECL_CONTEXT_VISIBLE) {
+ Error("Expected visible lookup table block");
+ return true;
+ }
+ Info.NameLookupTableData
+ = ASTDeclContextNameLookupTable::Create(
+ (const unsigned char *)Blob + Record[0],
+ (const unsigned char *)Blob,
+ ASTDeclContextNameLookupTrait(*this, M));
+ }
+
+ return false;
+}
+
+void ASTReader::Error(StringRef Msg) {
+ Error(diag::err_fe_pch_malformed, Msg);
+}
+
+void ASTReader::Error(unsigned DiagID,
+ StringRef Arg1, StringRef Arg2) {
+ if (Diags.isDiagnosticInFlight())
+ Diags.SetDelayedDiagnostic(DiagID, Arg1, Arg2);
+ else
+ Diag(DiagID) << Arg1 << Arg2;
+}
+
+//===----------------------------------------------------------------------===//
+// Source Manager Deserialization
+//===----------------------------------------------------------------------===//
+
+/// \brief Read the line table in the source manager block.
+/// \returns true if there was an error.
+bool ASTReader::ParseLineTable(ModuleFile &F,
+ SmallVectorImpl<uint64_t> &Record) {
+ unsigned Idx = 0;
+ LineTableInfo &LineTable = SourceMgr.getLineTable();
+
+ // Parse the file names
+ std::map<int, int> FileIDs;
+ for (int I = 0, N = Record[Idx++]; I != N; ++I) {
+ // Extract the file name
+ unsigned FilenameLen = Record[Idx++];
+ std::string Filename(&Record[Idx], &Record[Idx] + FilenameLen);
+ Idx += FilenameLen;
+ MaybeAddSystemRootToFilename(F, Filename);
+ FileIDs[I] = LineTable.getLineTableFilenameID(Filename);
+ }
+
+ // Parse the line entries
+ std::vector<LineEntry> Entries;
+ while (Idx < Record.size()) {
+ int FID = Record[Idx++];
+ assert(FID >= 0 && "Serialized line entries for non-local file.");
+ // Remap FileID from 1-based old view.
+ FID += F.SLocEntryBaseID - 1;
+
+ // Extract the line entries
+ unsigned NumEntries = Record[Idx++];
+ assert(NumEntries && "Numentries is 00000");
+ Entries.clear();
+ Entries.reserve(NumEntries);
+ for (unsigned I = 0; I != NumEntries; ++I) {
+ unsigned FileOffset = Record[Idx++];
+ unsigned LineNo = Record[Idx++];
+ int FilenameID = FileIDs[Record[Idx++]];
+ SrcMgr::CharacteristicKind FileKind
+ = (SrcMgr::CharacteristicKind)Record[Idx++];
+ unsigned IncludeOffset = Record[Idx++];
+ Entries.push_back(LineEntry::get(FileOffset, LineNo, FilenameID,
+ FileKind, IncludeOffset));
+ }
+ LineTable.AddEntry(FileID::get(FID), Entries);
+ }
+
+ return false;
+}
+
+/// \brief Read a source manager block
+bool ASTReader::ReadSourceManagerBlock(ModuleFile &F) {
+ using namespace SrcMgr;
+
+ llvm::BitstreamCursor &SLocEntryCursor = F.SLocEntryCursor;
+
+ // Set the source-location entry cursor to the current position in
+ // the stream. This cursor will be used to read the contents of the
+ // source manager block initially, and then lazily read
+ // source-location entries as needed.
+ SLocEntryCursor = F.Stream;
+
+ // The stream itself is going to skip over the source manager block.
+ if (F.Stream.SkipBlock()) {
+ Error("malformed block record in AST file");
+ return true;
+ }
+
+ // Enter the source manager block.
+ if (SLocEntryCursor.EnterSubBlock(SOURCE_MANAGER_BLOCK_ID)) {
+ Error("malformed source manager block record in AST file");
+ return true;
+ }
+
+ RecordData Record;
+ while (true) {
+ unsigned Code = SLocEntryCursor.ReadCode();
+ if (Code == llvm::bitc::END_BLOCK) {
+ if (SLocEntryCursor.ReadBlockEnd()) {
+ Error("error at end of Source Manager block in AST file");
+ return true;
+ }
+ return false;
+ }
+
+ if (Code == llvm::bitc::ENTER_SUBBLOCK) {
+ // No known subblocks, always skip them.
+ SLocEntryCursor.ReadSubBlockID();
+ if (SLocEntryCursor.SkipBlock()) {
+ Error("malformed block record in AST file");
+ return true;
+ }
+ continue;
+ }
+
+ if (Code == llvm::bitc::DEFINE_ABBREV) {
+ SLocEntryCursor.ReadAbbrevRecord();
+ continue;
+ }
+
+ // Read a record.
+ const char *BlobStart;
+ unsigned BlobLen;
+ Record.clear();
+ switch (SLocEntryCursor.ReadRecord(Code, Record, &BlobStart, &BlobLen)) {
+ default: // Default behavior: ignore.
+ break;
+
+ case SM_SLOC_FILE_ENTRY:
+ case SM_SLOC_BUFFER_ENTRY:
+ case SM_SLOC_EXPANSION_ENTRY:
+ // Once we hit one of the source location entries, we're done.
+ return false;
+ }
+ }
+}
+
+/// \brief If a header file is not found at the path that we expect it to be
+/// and the PCH file was moved from its original location, try to resolve the
+/// file by assuming that header+PCH were moved together and the header is in
+/// the same place relative to the PCH.
+static std::string
+resolveFileRelativeToOriginalDir(const std::string &Filename,
+ const std::string &OriginalDir,
+ const std::string &CurrDir) {
+ assert(OriginalDir != CurrDir &&
+ "No point trying to resolve the file if the PCH dir didn't change");
+ using namespace llvm::sys;
+ SmallString<128> filePath(Filename);
+ fs::make_absolute(filePath);
+ assert(path::is_absolute(OriginalDir));
+ SmallString<128> currPCHPath(CurrDir);
+
+ path::const_iterator fileDirI = path::begin(path::parent_path(filePath)),
+ fileDirE = path::end(path::parent_path(filePath));
+ path::const_iterator origDirI = path::begin(OriginalDir),
+ origDirE = path::end(OriginalDir);
+ // Skip the common path components from filePath and OriginalDir.
+ while (fileDirI != fileDirE && origDirI != origDirE &&
+ *fileDirI == *origDirI) {
+ ++fileDirI;
+ ++origDirI;
+ }
+ for (; origDirI != origDirE; ++origDirI)
+ path::append(currPCHPath, "..");
+ path::append(currPCHPath, fileDirI, fileDirE);
+ path::append(currPCHPath, path::filename(Filename));
+ return currPCHPath.str();
+}
+
+bool ASTReader::ReadSLocEntry(int ID) {
+ if (ID == 0)
+ return false;
+
+ if (unsigned(-ID) - 2 >= getTotalNumSLocs() || ID > 0) {
+ Error("source location entry ID out-of-range for AST file");
+ return true;
+ }
+
+ ModuleFile *F = GlobalSLocEntryMap.find(-ID)->second;
+ F->SLocEntryCursor.JumpToBit(F->SLocEntryOffsets[ID - F->SLocEntryBaseID]);
+ llvm::BitstreamCursor &SLocEntryCursor = F->SLocEntryCursor;
+ unsigned BaseOffset = F->SLocEntryBaseOffset;
+
+ ++NumSLocEntriesRead;
+ unsigned Code = SLocEntryCursor.ReadCode();
+ if (Code == llvm::bitc::END_BLOCK ||
+ Code == llvm::bitc::ENTER_SUBBLOCK ||
+ Code == llvm::bitc::DEFINE_ABBREV) {
+ Error("incorrectly-formatted source location entry in AST file");
+ return true;
+ }
+
+ RecordData Record;
+ const char *BlobStart;
+ unsigned BlobLen;
+ switch (SLocEntryCursor.ReadRecord(Code, Record, &BlobStart, &BlobLen)) {
+ default:
+ Error("incorrectly-formatted source location entry in AST file");
+ return true;
+
+ case SM_SLOC_FILE_ENTRY: {
+ // We will detect whether a file changed and return 'Failure' for it, but
+ // we will also try to fail gracefully by setting up the SLocEntry.
+ unsigned InputID = Record[4];
+ InputFile IF = getInputFile(*F, InputID);
+ const FileEntry *File = IF.getPointer();
+ bool OverriddenBuffer = IF.getInt();
+
+ if (!IF.getPointer())
+ return true;
+
+ SourceLocation IncludeLoc = ReadSourceLocation(*F, Record[1]);
+ if (IncludeLoc.isInvalid() && F->Kind != MK_MainFile) {
+ // This is the module's main file.
+ IncludeLoc = getImportLocation(F);
+ }
+ SrcMgr::CharacteristicKind
+ FileCharacter = (SrcMgr::CharacteristicKind)Record[2];
+ FileID FID = SourceMgr.createFileID(File, IncludeLoc, FileCharacter,
+ ID, BaseOffset + Record[0]);
+ SrcMgr::FileInfo &FileInfo =
+ const_cast<SrcMgr::FileInfo&>(SourceMgr.getSLocEntry(FID).getFile());
+ FileInfo.NumCreatedFIDs = Record[5];
+ if (Record[3])
+ FileInfo.setHasLineDirectives();
+
+ const DeclID *FirstDecl = F->FileSortedDecls + Record[6];
+ unsigned NumFileDecls = Record[7];
+ if (NumFileDecls) {
+ assert(F->FileSortedDecls && "FILE_SORTED_DECLS not encountered yet ?");
+ FileDeclIDs[FID] = FileDeclsInfo(F, llvm::makeArrayRef(FirstDecl,
+ NumFileDecls));
+ }
+
+ const SrcMgr::ContentCache *ContentCache
+ = SourceMgr.getOrCreateContentCache(File,
+ /*isSystemFile=*/FileCharacter != SrcMgr::C_User);
+ if (OverriddenBuffer && !ContentCache->BufferOverridden &&
+ ContentCache->ContentsEntry == ContentCache->OrigEntry) {
+ unsigned Code = SLocEntryCursor.ReadCode();
+ Record.clear();
+ unsigned RecCode
+ = SLocEntryCursor.ReadRecord(Code, Record, &BlobStart, &BlobLen);
+
+ if (RecCode != SM_SLOC_BUFFER_BLOB) {
+ Error("AST record has invalid code");
+ return true;
+ }
+
+ llvm::MemoryBuffer *Buffer
+ = llvm::MemoryBuffer::getMemBuffer(StringRef(BlobStart, BlobLen - 1),
+ File->getName());
+ SourceMgr.overrideFileContents(File, Buffer);
+ }
+
+ break;
+ }
+
+ case SM_SLOC_BUFFER_ENTRY: {
+ const char *Name = BlobStart;
+ unsigned Offset = Record[0];
+ SrcMgr::CharacteristicKind
+ FileCharacter = (SrcMgr::CharacteristicKind)Record[2];
+ SourceLocation IncludeLoc = ReadSourceLocation(*F, Record[1]);
+ if (IncludeLoc.isInvalid() && F->Kind == MK_Module) {
+ IncludeLoc = getImportLocation(F);
+ }
+ unsigned Code = SLocEntryCursor.ReadCode();
+ Record.clear();
+ unsigned RecCode
+ = SLocEntryCursor.ReadRecord(Code, Record, &BlobStart, &BlobLen);
+
+ if (RecCode != SM_SLOC_BUFFER_BLOB) {
+ Error("AST record has invalid code");
+ return true;
+ }
+
+ llvm::MemoryBuffer *Buffer
+ = llvm::MemoryBuffer::getMemBuffer(StringRef(BlobStart, BlobLen - 1),
+ Name);
+ SourceMgr.createFileIDForMemBuffer(Buffer, FileCharacter, ID,
+ BaseOffset + Offset, IncludeLoc);
+ break;
+ }
+
+ case SM_SLOC_EXPANSION_ENTRY: {
+ SourceLocation SpellingLoc = ReadSourceLocation(*F, Record[1]);
+ SourceMgr.createExpansionLoc(SpellingLoc,
+ ReadSourceLocation(*F, Record[2]),
+ ReadSourceLocation(*F, Record[3]),
+ Record[4],
+ ID,
+ BaseOffset + Record[0]);
+ break;
+ }
+ }
+
+ return false;
+}
+
+std::pair<SourceLocation, StringRef> ASTReader::getModuleImportLoc(int ID) {
+ if (ID == 0)
+ return std::make_pair(SourceLocation(), "");
+
+ if (unsigned(-ID) - 2 >= getTotalNumSLocs() || ID > 0) {
+ Error("source location entry ID out-of-range for AST file");
+ return std::make_pair(SourceLocation(), "");
+ }
+
+ // Find which module file this entry lands in.
+ ModuleFile *M = GlobalSLocEntryMap.find(-ID)->second;
+ if (M->Kind != MK_Module)
+ return std::make_pair(SourceLocation(), "");
+
+ // FIXME: Can we map this down to a particular submodule? That would be
+ // ideal.
+ return std::make_pair(M->ImportLoc, llvm::sys::path::stem(M->FileName));
+}
+
+/// \brief Find the location where the module F is imported.
+SourceLocation ASTReader::getImportLocation(ModuleFile *F) {
+ if (F->ImportLoc.isValid())
+ return F->ImportLoc;
+
+ // Otherwise we have a PCH. It's considered to be "imported" at the first
+ // location of its includer.
+ if (F->ImportedBy.empty() || !F->ImportedBy[0]) {
+ // Main file is the importer. We assume that it is the first entry in the
+ // entry table. We can't ask the manager, because at the time of PCH loading
+ // the main file entry doesn't exist yet.
+ // The very first entry is the invalid instantiation loc, which takes up
+ // offsets 0 and 1.
+ return SourceLocation::getFromRawEncoding(2U);
+ }
+ //return F->Loaders[0]->FirstLoc;
+ return F->ImportedBy[0]->FirstLoc;
+}
+
+/// ReadBlockAbbrevs - Enter a subblock of the specified BlockID with the
+/// specified cursor. Read the abbreviations that are at the top of the block
+/// and then leave the cursor pointing into the block.
+bool ASTReader::ReadBlockAbbrevs(llvm::BitstreamCursor &Cursor,
+ unsigned BlockID) {
+ if (Cursor.EnterSubBlock(BlockID)) {
+ Error("malformed block record in AST file");
+ return Failure;
+ }
+
+ while (true) {
+ uint64_t Offset = Cursor.GetCurrentBitNo();
+ unsigned Code = Cursor.ReadCode();
+
+ // We expect all abbrevs to be at the start of the block.
+ if (Code != llvm::bitc::DEFINE_ABBREV) {
+ Cursor.JumpToBit(Offset);
+ return false;
+ }
+ Cursor.ReadAbbrevRecord();
+ }
+}
+
+void ASTReader::ReadMacroRecord(ModuleFile &F, uint64_t Offset,
+ MacroInfo *Hint) {
+ llvm::BitstreamCursor &Stream = F.MacroCursor;
+
+ // Keep track of where we are in the stream, then jump back there
+ // after reading this macro.
+ SavedStreamPosition SavedPosition(Stream);
+
+ Stream.JumpToBit(Offset);
+ RecordData Record;
+ SmallVector<IdentifierInfo*, 16> MacroArgs;
+ MacroInfo *Macro = 0;
+
+ // RAII object to add the loaded macro information once we're done
+ // adding tokens.
+ struct AddLoadedMacroInfoRAII {
+ Preprocessor &PP;
+ MacroInfo *Hint;
+ MacroInfo *MI;
+ IdentifierInfo *II;
+
+ AddLoadedMacroInfoRAII(Preprocessor &PP, MacroInfo *Hint)
+ : PP(PP), Hint(Hint), MI(), II() { }
+ ~AddLoadedMacroInfoRAII( ) {
+ if (MI) {
+ // Finally, install the macro.
+ PP.addLoadedMacroInfo(II, MI, Hint);
+ }
+ }
+ } AddLoadedMacroInfo(PP, Hint);
+
+ while (true) {
+ unsigned Code = Stream.ReadCode();
+ switch (Code) {
+ case llvm::bitc::END_BLOCK:
+ return;
+
+ case llvm::bitc::ENTER_SUBBLOCK:
+ // No known subblocks, always skip them.
+ Stream.ReadSubBlockID();
+ if (Stream.SkipBlock()) {
+ Error("malformed block record in AST file");
+ return;
+ }
+ continue;
+
+ case llvm::bitc::DEFINE_ABBREV:
+ Stream.ReadAbbrevRecord();
+ continue;
+ default: break;
+ }
+
+ // Read a record.
+ const char *BlobStart = 0;
+ unsigned BlobLen = 0;
+ Record.clear();
+ PreprocessorRecordTypes RecType =
+ (PreprocessorRecordTypes)Stream.ReadRecord(Code, Record, BlobStart,
+ BlobLen);
+ switch (RecType) {
+ case PP_MACRO_OBJECT_LIKE:
+ case PP_MACRO_FUNCTION_LIKE: {
+ // If we already have a macro, that means that we've hit the end
+ // of the definition of the macro we were looking for. We're
+ // done.
+ if (Macro)
+ return;
+
+ IdentifierInfo *II = getLocalIdentifier(F, Record[0]);
+ if (II == 0) {
+ Error("macro must have a name in AST file");
+ return;
+ }
+
+ unsigned GlobalID = getGlobalMacroID(F, Record[1]);
+
+ // If this macro has already been loaded, don't do so again.
+ if (MacrosLoaded[GlobalID - NUM_PREDEF_MACRO_IDS])
+ return;
+
+ SubmoduleID GlobalSubmoduleID = getGlobalSubmoduleID(F, Record[2]);
+ unsigned NextIndex = 3;
+ SourceLocation Loc = ReadSourceLocation(F, Record, NextIndex);
+ MacroInfo *MI = PP.AllocateMacroInfo(Loc);
+
+ // Record this macro.
+ MacrosLoaded[GlobalID - NUM_PREDEF_MACRO_IDS] = MI;
+
+ SourceLocation UndefLoc = ReadSourceLocation(F, Record, NextIndex);
+ if (UndefLoc.isValid())
+ MI->setUndefLoc(UndefLoc);
+
+ MI->setIsUsed(Record[NextIndex++]);
+ MI->setIsFromAST();
+
+ bool IsPublic = Record[NextIndex++];
+ MI->setVisibility(IsPublic, ReadSourceLocation(F, Record, NextIndex));
+
+ if (RecType == PP_MACRO_FUNCTION_LIKE) {
+ // Decode function-like macro info.
+ bool isC99VarArgs = Record[NextIndex++];
+ bool isGNUVarArgs = Record[NextIndex++];
+ bool hasCommaPasting = Record[NextIndex++];
+ MacroArgs.clear();
+ unsigned NumArgs = Record[NextIndex++];
+ for (unsigned i = 0; i != NumArgs; ++i)
+ MacroArgs.push_back(getLocalIdentifier(F, Record[NextIndex++]));
+
+ // Install function-like macro info.
+ MI->setIsFunctionLike();
+ if (isC99VarArgs) MI->setIsC99Varargs();
+ if (isGNUVarArgs) MI->setIsGNUVarargs();
+ if (hasCommaPasting) MI->setHasCommaPasting();
+ MI->setArgumentList(MacroArgs.data(), MacroArgs.size(),
+ PP.getPreprocessorAllocator());
+ }
+
+ if (DeserializationListener)
+ DeserializationListener->MacroRead(GlobalID, MI);
+
+ // If an update record marked this as undefined, do so now.
+ // FIXME: Only if the submodule this update came from is visible?
+ MacroUpdatesMap::iterator Update = MacroUpdates.find(GlobalID);
+ if (Update != MacroUpdates.end()) {
+ if (MI->getUndefLoc().isInvalid()) {
+ for (unsigned I = 0, N = Update->second.size(); I != N; ++I) {
+ bool Hidden = false;
+ if (unsigned SubmoduleID = Update->second[I].first) {
+ if (Module *Owner = getSubmodule(SubmoduleID)) {
+ if (Owner->NameVisibility == Module::Hidden) {
+ // Note that this #undef is hidden.
+ Hidden = true;
+
+ // Record this hiding for later.
+ HiddenNamesMap[Owner].push_back(
+ HiddenName(II, MI, Update->second[I].second.UndefLoc));
+ }
+ }
+ }
+
+ if (!Hidden) {
+ MI->setUndefLoc(Update->second[I].second.UndefLoc);
+ if (PPMutationListener *Listener = PP.getPPMutationListener())
+ Listener->UndefinedMacro(MI);
+ break;
+ }
+ }
+ }
+ MacroUpdates.erase(Update);
+ }
+
+ // Determine whether this macro definition is visible.
+ bool Hidden = !MI->isPublic();
+ if (!Hidden && GlobalSubmoduleID) {
+ if (Module *Owner = getSubmodule(GlobalSubmoduleID)) {
+ if (Owner->NameVisibility == Module::Hidden) {
+ // The owning module is not visible, and this macro definition
+ // should not be, either.
+ Hidden = true;
+
+ // Note that this macro definition was hidden because its owning
+ // module is not yet visible.
+ HiddenNamesMap[Owner].push_back(HiddenName(II, MI));
+ }
+ }
+ }
+ MI->setHidden(Hidden);
+
+ // Make sure we install the macro once we're done.
+ AddLoadedMacroInfo.MI = MI;
+ AddLoadedMacroInfo.II = II;
+
+ // Remember that we saw this macro last so that we add the tokens that
+ // form its body to it.
+ Macro = MI;
+
+ if (NextIndex + 1 == Record.size() && PP.getPreprocessingRecord() &&
+ Record[NextIndex]) {
+ // We have a macro definition. Register the association
+ PreprocessedEntityID
+ GlobalID = getGlobalPreprocessedEntityID(F, Record[NextIndex]);
+ PreprocessingRecord &PPRec = *PP.getPreprocessingRecord();
+ PPRec.RegisterMacroDefinition(Macro,
+ PPRec.getPPEntityID(GlobalID-1, /*isLoaded=*/true));
+ }
+
+ ++NumMacrosRead;
+ break;
+ }
+
+ case PP_TOKEN: {
+ // If we see a TOKEN before a PP_MACRO_*, then the file is
+ // erroneous, just pretend we didn't see this.
+ if (Macro == 0) break;
+
+ Token Tok;
+ Tok.startToken();
+ Tok.setLocation(ReadSourceLocation(F, Record[0]));
+ Tok.setLength(Record[1]);
+ if (IdentifierInfo *II = getLocalIdentifier(F, Record[2]))
+ Tok.setIdentifierInfo(II);
+ Tok.setKind((tok::TokenKind)Record[3]);
+ Tok.setFlag((Token::TokenFlags)Record[4]);
+ Macro->AddTokenToBody(Tok);
+ break;
+ }
+ }
+ }
+}
+
+PreprocessedEntityID
+ASTReader::getGlobalPreprocessedEntityID(ModuleFile &M, unsigned LocalID) const {
+ ContinuousRangeMap<uint32_t, int, 2>::const_iterator
+ I = M.PreprocessedEntityRemap.find(LocalID - NUM_PREDEF_PP_ENTITY_IDS);
+ assert(I != M.PreprocessedEntityRemap.end()
+ && "Invalid index into preprocessed entity index remap");
+
+ return LocalID + I->second;
+}
+
+unsigned HeaderFileInfoTrait::ComputeHash(const char *path) {
+ return llvm::HashString(llvm::sys::path::filename(path));
+}
+
+HeaderFileInfoTrait::internal_key_type
+HeaderFileInfoTrait::GetInternalKey(const char *path) { return path; }
+
+bool HeaderFileInfoTrait::EqualKey(internal_key_type a, internal_key_type b) {
+ if (strcmp(a, b) == 0)
+ return true;
+
+ if (llvm::sys::path::filename(a) != llvm::sys::path::filename(b))
+ return false;
+
+ // Determine whether the actual files are equivalent.
+ bool Result = false;
+ if (llvm::sys::fs::equivalent(a, b, Result))
+ return false;
+
+ return Result;
+}
+
+std::pair<unsigned, unsigned>
+HeaderFileInfoTrait::ReadKeyDataLength(const unsigned char*& d) {
+ unsigned KeyLen = (unsigned) clang::io::ReadUnalignedLE16(d);
+ unsigned DataLen = (unsigned) *d++;
+ return std::make_pair(KeyLen + 1, DataLen);
+}
+
+HeaderFileInfoTrait::data_type
+HeaderFileInfoTrait::ReadData(const internal_key_type, const unsigned char *d,
+ unsigned DataLen) {
+ const unsigned char *End = d + DataLen;
+ using namespace clang::io;
+ HeaderFileInfo HFI;
+ unsigned Flags = *d++;
+ HFI.isImport = (Flags >> 5) & 0x01;
+ HFI.isPragmaOnce = (Flags >> 4) & 0x01;
+ HFI.DirInfo = (Flags >> 2) & 0x03;
+ HFI.Resolved = (Flags >> 1) & 0x01;
+ HFI.IndexHeaderMapHeader = Flags & 0x01;
+ HFI.NumIncludes = ReadUnalignedLE16(d);
+ HFI.ControllingMacroID = Reader.getGlobalIdentifierID(M,
+ ReadUnalignedLE32(d));
+ if (unsigned FrameworkOffset = ReadUnalignedLE32(d)) {
+ // The framework offset is 1 greater than the actual offset,
+ // since 0 is used as an indicator for "no framework name".
+ StringRef FrameworkName(FrameworkStrings + FrameworkOffset - 1);
+ HFI.Framework = HS->getUniqueFrameworkName(FrameworkName);
+ }
+
+ assert(End == d && "Wrong data length in HeaderFileInfo deserialization");
+ (void)End;
+
+ // This HeaderFileInfo was externally loaded.
+ HFI.External = true;
+ return HFI;
+}
+
+void ASTReader::setIdentifierIsMacro(IdentifierInfo *II, ArrayRef<MacroID> IDs){
+ II->setHadMacroDefinition(true);
+ assert(NumCurrentElementsDeserializing > 0 &&"Missing deserialization guard");
+ PendingMacroIDs[II].append(IDs.begin(), IDs.end());
+}
+
+void ASTReader::ReadDefinedMacros() {
+ // Note that we are loading defined macros.
+ Deserializing Macros(this);
+
+ for (ModuleReverseIterator I = ModuleMgr.rbegin(),
+ E = ModuleMgr.rend(); I != E; ++I) {
+ llvm::BitstreamCursor &MacroCursor = (*I)->MacroCursor;
+
+ // If there was no preprocessor block, skip this file.
+ if (!MacroCursor.getBitStreamReader())
+ continue;
+
+ llvm::BitstreamCursor Cursor = MacroCursor;
+ Cursor.JumpToBit((*I)->MacroStartOffset);
+
+ RecordData Record;
+ while (true) {
+ unsigned Code = Cursor.ReadCode();
+ if (Code == llvm::bitc::END_BLOCK)
+ break;
+
+ if (Code == llvm::bitc::ENTER_SUBBLOCK) {
+ // No known subblocks, always skip them.
+ Cursor.ReadSubBlockID();
+ if (Cursor.SkipBlock()) {
+ Error("malformed block record in AST file");
+ return;
+ }
+ continue;
+ }
+
+ if (Code == llvm::bitc::DEFINE_ABBREV) {
+ Cursor.ReadAbbrevRecord();
+ continue;
+ }
+
+ // Read a record.
+ const char *BlobStart;
+ unsigned BlobLen;
+ Record.clear();
+ switch (Cursor.ReadRecord(Code, Record, &BlobStart, &BlobLen)) {
+ default: // Default behavior: ignore.
+ break;
+
+ case PP_MACRO_OBJECT_LIKE:
+ case PP_MACRO_FUNCTION_LIKE:
+ getLocalIdentifier(**I, Record[0]);
+ break;
+
+ case PP_TOKEN:
+ // Ignore tokens.
+ break;
+ }
+ }
+ }
+}
+
+namespace {
+ /// \brief Visitor class used to look up identifirs in an AST file.
+ class IdentifierLookupVisitor {
+ StringRef Name;
+ unsigned PriorGeneration;
+ IdentifierInfo *Found;
+ public:
+ IdentifierLookupVisitor(StringRef Name, unsigned PriorGeneration)
+ : Name(Name), PriorGeneration(PriorGeneration), Found() { }
+
+ static bool visit(ModuleFile &M, void *UserData) {
+ IdentifierLookupVisitor *This
+ = static_cast<IdentifierLookupVisitor *>(UserData);
+
+ // If we've already searched this module file, skip it now.
+ if (M.Generation <= This->PriorGeneration)
+ return true;
+
+ ASTIdentifierLookupTable *IdTable
+ = (ASTIdentifierLookupTable *)M.IdentifierLookupTable;
+ if (!IdTable)
+ return false;
+
+ ASTIdentifierLookupTrait Trait(IdTable->getInfoObj().getReader(),
+ M, This->Found);
+
+ std::pair<const char*, unsigned> Key(This->Name.begin(),
+ This->Name.size());
+ ASTIdentifierLookupTable::iterator Pos = IdTable->find(Key, &Trait);
+ if (Pos == IdTable->end())
+ return false;
+
+ // Dereferencing the iterator has the effect of building the
+ // IdentifierInfo node and populating it with the various
+ // declarations it needs.
+ This->Found = *Pos;
+ return true;
+ }
+
+ // \brief Retrieve the identifier info found within the module
+ // files.
+ IdentifierInfo *getIdentifierInfo() const { return Found; }
+ };
+}
+
+void ASTReader::updateOutOfDateIdentifier(IdentifierInfo &II) {
+ // Note that we are loading an identifier.
+ Deserializing AnIdentifier(this);
+
+ unsigned PriorGeneration = 0;
+ if (getContext().getLangOpts().Modules)
+ PriorGeneration = IdentifierGeneration[&II];
+
+ IdentifierLookupVisitor Visitor(II.getName(), PriorGeneration);
+ ModuleMgr.visit(IdentifierLookupVisitor::visit, &Visitor);
+ markIdentifierUpToDate(&II);
+}
+
+void ASTReader::markIdentifierUpToDate(IdentifierInfo *II) {
+ if (!II)
+ return;
+
+ II->setOutOfDate(false);
+
+ // Update the generation for this identifier.
+ if (getContext().getLangOpts().Modules)
+ IdentifierGeneration[II] = CurrentGeneration;
+}
+
+llvm::PointerIntPair<const FileEntry *, 1, bool>
+ASTReader::getInputFile(ModuleFile &F, unsigned ID, bool Complain) {
+ // If this ID is bogus, just return an empty input file.
+ if (ID == 0 || ID > F.InputFilesLoaded.size())
+ return InputFile();
+
+ // If we've already loaded this input file, return it.
+ if (F.InputFilesLoaded[ID-1].getPointer())
+ return F.InputFilesLoaded[ID-1];
+
+ // Go find this input file.
+ llvm::BitstreamCursor &Cursor = F.InputFilesCursor;
+ SavedStreamPosition SavedPosition(Cursor);
+ Cursor.JumpToBit(F.InputFileOffsets[ID-1]);
+
+ unsigned Code = Cursor.ReadCode();
+ RecordData Record;
+ const char *BlobStart = 0;
+ unsigned BlobLen = 0;
+ switch ((InputFileRecordTypes)Cursor.ReadRecord(Code, Record,
+ &BlobStart, &BlobLen)) {
+ case INPUT_FILE: {
+ unsigned StoredID = Record[0];
+ assert(ID == StoredID && "Bogus stored ID or offset");
+ (void)StoredID;
+ off_t StoredSize = (off_t)Record[1];
+ time_t StoredTime = (time_t)Record[2];
+ bool Overridden = (bool)Record[3];
+
+ // Get the file entry for this input file.
+ StringRef OrigFilename(BlobStart, BlobLen);
+ std::string Filename = OrigFilename;
+ MaybeAddSystemRootToFilename(F, Filename);
+ const FileEntry *File
+ = Overridden? FileMgr.getVirtualFile(Filename, StoredSize, StoredTime)
+ : FileMgr.getFile(Filename, /*OpenFile=*/false);
+
+ // If we didn't find the file, resolve it relative to the
+ // original directory from which this AST file was created.
+ if (File == 0 && !F.OriginalDir.empty() && !CurrentDir.empty() &&
+ F.OriginalDir != CurrentDir) {
+ std::string Resolved = resolveFileRelativeToOriginalDir(Filename,
+ F.OriginalDir,
+ CurrentDir);
+ if (!Resolved.empty())
+ File = FileMgr.getFile(Resolved);
+ }
+
+ // For an overridden file, create a virtual file with the stored
+ // size/timestamp.
+ if (Overridden && File == 0) {
+ File = FileMgr.getVirtualFile(Filename, StoredSize, StoredTime);
+ }
+
+ if (File == 0) {
+ if (Complain) {
+ std::string ErrorStr = "could not find file '";
+ ErrorStr += Filename;
+ ErrorStr += "' referenced by AST file";
+ Error(ErrorStr.c_str());
+ }
+ return InputFile();
+ }
+
+ // Note that we've loaded this input file.
+ F.InputFilesLoaded[ID-1] = InputFile(File, Overridden);
+
+ // Check if there was a request to override the contents of the file
+ // that was part of the precompiled header. Overridding such a file
+ // can lead to problems when lexing using the source locations from the
+ // PCH.
+ SourceManager &SM = getSourceManager();
+ if (!Overridden && SM.isFileOverridden(File)) {
+ Error(diag::err_fe_pch_file_overridden, Filename);
+ // After emitting the diagnostic, recover by disabling the override so
+ // that the original file will be used.
+ SM.disableFileContentsOverride(File);
+ // The FileEntry is a virtual file entry with the size of the contents
+ // that would override the original contents. Set it to the original's
+ // size/time.
+ FileMgr.modifyFileEntry(const_cast<FileEntry*>(File),
+ StoredSize, StoredTime);
+ }
+
+ // For an overridden file, there is nothing to validate.
+ if (Overridden)
+ return InputFile(File, Overridden);
+
+ if ((StoredSize != File->getSize()
+#if !defined(LLVM_ON_WIN32)
+ // In our regression testing, the Windows file system seems to
+ // have inconsistent modification times that sometimes
+ // erroneously trigger this error-handling path.
+ || StoredTime != File->getModificationTime()
+#endif
+ )) {
+ if (Complain)
+ Error(diag::err_fe_pch_file_modified, Filename);
+
+ return InputFile();
+ }
+
+ return InputFile(File, Overridden);
+ }
+ }
+
+ return InputFile();
+}
+
+const FileEntry *ASTReader::getFileEntry(StringRef filenameStrRef) {
+ ModuleFile &M = ModuleMgr.getPrimaryModule();
+ std::string Filename = filenameStrRef;
+ MaybeAddSystemRootToFilename(M, Filename);
+ const FileEntry *File = FileMgr.getFile(Filename);
+ if (File == 0 && !M.OriginalDir.empty() && !CurrentDir.empty() &&
+ M.OriginalDir != CurrentDir) {
+ std::string resolved = resolveFileRelativeToOriginalDir(Filename,
+ M.OriginalDir,
+ CurrentDir);
+ if (!resolved.empty())
+ File = FileMgr.getFile(resolved);
+ }
+
+ return File;
+}
+
+/// \brief If we are loading a relocatable PCH file, and the filename is
+/// not an absolute path, add the system root to the beginning of the file
+/// name.
+void ASTReader::MaybeAddSystemRootToFilename(ModuleFile &M,
+ std::string &Filename) {
+ // If this is not a relocatable PCH file, there's nothing to do.
+ if (!M.RelocatablePCH)
+ return;
+
+ if (Filename.empty() || llvm::sys::path::is_absolute(Filename))
+ return;
+
+ if (isysroot.empty()) {
+ // If no system root was given, default to '/'
+ Filename.insert(Filename.begin(), '/');
+ return;
+ }
+
+ unsigned Length = isysroot.size();
+ if (isysroot[Length - 1] != '/')
+ Filename.insert(Filename.begin(), '/');
+
+ Filename.insert(Filename.begin(), isysroot.begin(), isysroot.end());
+}
+
+ASTReader::ASTReadResult
+ASTReader::ReadControlBlock(ModuleFile &F,
+ llvm::SmallVectorImpl<ImportedModule> &Loaded,
+ unsigned ClientLoadCapabilities) {
+ llvm::BitstreamCursor &Stream = F.Stream;
+
+ if (Stream.EnterSubBlock(CONTROL_BLOCK_ID)) {
+ Error("malformed block record in AST file");
+ return Failure;
+ }
+
+ // Read all of the records and blocks in the control block.
+ RecordData Record;
+ while (!Stream.AtEndOfStream()) {
+ unsigned Code = Stream.ReadCode();
+ if (Code == llvm::bitc::END_BLOCK) {
+ if (Stream.ReadBlockEnd()) {
+ Error("error at end of control block in AST file");
+ return Failure;
+ }
+
+ // Validate all of the input files.
+ if (!DisableValidation) {
+ bool Complain = (ClientLoadCapabilities & ARR_OutOfDate) == 0;
+ for (unsigned I = 0, N = Record[0]; I < N; ++I)
+ if (!getInputFile(F, I+1, Complain).getPointer())
+ return OutOfDate;
+ }
+
+ return Success;
+ }
+
+ if (Code == llvm::bitc::ENTER_SUBBLOCK) {
+ switch (Stream.ReadSubBlockID()) {
+ case INPUT_FILES_BLOCK_ID:
+ F.InputFilesCursor = Stream;
+ if (Stream.SkipBlock() || // Skip with the main cursor
+ // Read the abbreviations
+ ReadBlockAbbrevs(F.InputFilesCursor, INPUT_FILES_BLOCK_ID)) {
+ Error("malformed block record in AST file");
+ return Failure;
+ }
+ continue;
+
+ default:
+ if (!Stream.SkipBlock())
+ continue;
+ break;
+ }
+
+ Error("malformed block record in AST file");
+ return Failure;
+ }
+
+ if (Code == llvm::bitc::DEFINE_ABBREV) {
+ Stream.ReadAbbrevRecord();
+ continue;
+ }
+
+ // Read and process a record.
+ Record.clear();
+ const char *BlobStart = 0;
+ unsigned BlobLen = 0;
+ switch ((ControlRecordTypes)Stream.ReadRecord(Code, Record,
+ &BlobStart, &BlobLen)) {
+ case METADATA: {
+ if (Record[0] != VERSION_MAJOR && !DisableValidation) {
+ if ((ClientLoadCapabilities & ARR_VersionMismatch) == 0)
+ Diag(Record[0] < VERSION_MAJOR? diag::warn_pch_version_too_old
+ : diag::warn_pch_version_too_new);
+ return VersionMismatch;
+ }
+
+ bool hasErrors = Record[5];
+ if (hasErrors && !DisableValidation && !AllowASTWithCompilerErrors) {
+ Diag(diag::err_pch_with_compiler_errors);
+ return HadErrors;
+ }
+
+ F.RelocatablePCH = Record[4];
+
+ const std::string &CurBranch = getClangFullRepositoryVersion();
+ StringRef ASTBranch(BlobStart, BlobLen);
+ if (StringRef(CurBranch) != ASTBranch && !DisableValidation) {
+ if ((ClientLoadCapabilities & ARR_VersionMismatch) == 0)
+ Diag(diag::warn_pch_different_branch) << ASTBranch << CurBranch;
+ return VersionMismatch;
+ }
+ break;
+ }
+
+ case IMPORTS: {
+ // Load each of the imported PCH files.
+ unsigned Idx = 0, N = Record.size();
+ while (Idx < N) {
+ // Read information about the AST file.
+ ModuleKind ImportedKind = (ModuleKind)Record[Idx++];
+ // The import location will be the local one for now; we will adjust
+ // all import locations of module imports after the global source
+ // location info are setup.
+ SourceLocation ImportLoc =
+ SourceLocation::getFromRawEncoding(Record[Idx++]);
+ unsigned Length = Record[Idx++];
+ SmallString<128> ImportedFile(Record.begin() + Idx,
+ Record.begin() + Idx + Length);
+ Idx += Length;
+
+ // Load the AST file.
+ switch(ReadASTCore(ImportedFile, ImportedKind, ImportLoc, &F, Loaded,
+ ClientLoadCapabilities)) {
+ case Failure: return Failure;
+ // If we have to ignore the dependency, we'll have to ignore this too.
+ case OutOfDate: return OutOfDate;
+ case VersionMismatch: return VersionMismatch;
+ case ConfigurationMismatch: return ConfigurationMismatch;
+ case HadErrors: return HadErrors;
+ case Success: break;
+ }
+ }
+ break;
+ }
+
+ case LANGUAGE_OPTIONS: {
+ bool Complain = (ClientLoadCapabilities & ARR_ConfigurationMismatch) == 0;
+ if (Listener && &F == *ModuleMgr.begin() &&
+ ParseLanguageOptions(Record, Complain, *Listener) &&
+ !DisableValidation)
+ return ConfigurationMismatch;
+ break;
+ }
+
+ case TARGET_OPTIONS: {
+ bool Complain = (ClientLoadCapabilities & ARR_ConfigurationMismatch)==0;
+ if (Listener && &F == *ModuleMgr.begin() &&
+ ParseTargetOptions(Record, Complain, *Listener) &&
+ !DisableValidation)
+ return ConfigurationMismatch;
+ break;
+ }
+
+ case DIAGNOSTIC_OPTIONS: {
+ bool Complain = (ClientLoadCapabilities & ARR_ConfigurationMismatch)==0;
+ if (Listener && &F == *ModuleMgr.begin() &&
+ ParseDiagnosticOptions(Record, Complain, *Listener) &&
+ !DisableValidation)
+ return ConfigurationMismatch;
+ break;
+ }
+
+ case FILE_SYSTEM_OPTIONS: {
+ bool Complain = (ClientLoadCapabilities & ARR_ConfigurationMismatch)==0;
+ if (Listener && &F == *ModuleMgr.begin() &&
+ ParseFileSystemOptions(Record, Complain, *Listener) &&
+ !DisableValidation)
+ return ConfigurationMismatch;
+ break;
+ }
+
+ case HEADER_SEARCH_OPTIONS: {
+ bool Complain = (ClientLoadCapabilities & ARR_ConfigurationMismatch)==0;
+ if (Listener && &F == *ModuleMgr.begin() &&
+ ParseHeaderSearchOptions(Record, Complain, *Listener) &&
+ !DisableValidation)
+ return ConfigurationMismatch;
+ break;
+ }
+
+ case PREPROCESSOR_OPTIONS: {
+ bool Complain = (ClientLoadCapabilities & ARR_ConfigurationMismatch)==0;
+ if (Listener && &F == *ModuleMgr.begin() &&
+ ParsePreprocessorOptions(Record, Complain, *Listener,
+ SuggestedPredefines) &&
+ !DisableValidation)
+ return ConfigurationMismatch;
+ break;
+ }
+
+ case ORIGINAL_FILE:
+ F.OriginalSourceFileID = FileID::get(Record[0]);
+ F.ActualOriginalSourceFileName.assign(BlobStart, BlobLen);
+ F.OriginalSourceFileName = F.ActualOriginalSourceFileName;
+ MaybeAddSystemRootToFilename(F, F.OriginalSourceFileName);
+ break;
+
+ case ORIGINAL_FILE_ID:
+ F.OriginalSourceFileID = FileID::get(Record[0]);
+ break;
+
+ case ORIGINAL_PCH_DIR:
+ F.OriginalDir.assign(BlobStart, BlobLen);
+ break;
+
+ case INPUT_FILE_OFFSETS:
+ F.InputFileOffsets = (const uint32_t *)BlobStart;
+ F.InputFilesLoaded.resize(Record[0]);
+ break;
+ }
+ }
+
+ Error("premature end of bitstream in AST file");
+ return Failure;
+}
+
+bool ASTReader::ReadASTBlock(ModuleFile &F) {
+ llvm::BitstreamCursor &Stream = F.Stream;
+
+ if (Stream.EnterSubBlock(AST_BLOCK_ID)) {
+ Error("malformed block record in AST file");
+ return true;
+ }
+
+ // Read all of the records and blocks for the AST file.
+ RecordData Record;
+ while (!Stream.AtEndOfStream()) {
+ unsigned Code = Stream.ReadCode();
+ if (Code == llvm::bitc::END_BLOCK) {
+ if (Stream.ReadBlockEnd()) {
+ Error("error at end of module block in AST file");
+ return true;
+ }
+
+ DeclContext *DC = Context.getTranslationUnitDecl();
+ if (!DC->hasExternalVisibleStorage() && DC->hasExternalLexicalStorage())
+ DC->setMustBuildLookupTable();
+
+ return false;
+ }
+
+ if (Code == llvm::bitc::ENTER_SUBBLOCK) {
+ switch (Stream.ReadSubBlockID()) {
+ case DECLTYPES_BLOCK_ID:
+ // We lazily load the decls block, but we want to set up the
+ // DeclsCursor cursor to point into it. Clone our current bitcode
+ // cursor to it, enter the block and read the abbrevs in that block.
+ // With the main cursor, we just skip over it.
+ F.DeclsCursor = Stream;
+ if (Stream.SkipBlock() || // Skip with the main cursor.
+ // Read the abbrevs.
+ ReadBlockAbbrevs(F.DeclsCursor, DECLTYPES_BLOCK_ID)) {
+ Error("malformed block record in AST file");
+ return true;
+ }
+ break;
+
+ case DECL_UPDATES_BLOCK_ID:
+ if (Stream.SkipBlock()) {
+ Error("malformed block record in AST file");
+ return true;
+ }
+ break;
+
+ case PREPROCESSOR_BLOCK_ID:
+ F.MacroCursor = Stream;
+ if (!PP.getExternalSource())
+ PP.setExternalSource(this);
+
+ if (Stream.SkipBlock() ||
+ ReadBlockAbbrevs(F.MacroCursor, PREPROCESSOR_BLOCK_ID)) {
+ Error("malformed block record in AST file");
+ return true;
+ }
+ F.MacroStartOffset = F.MacroCursor.GetCurrentBitNo();
+ break;
+
+ case PREPROCESSOR_DETAIL_BLOCK_ID:
+ F.PreprocessorDetailCursor = Stream;
+ if (Stream.SkipBlock() ||
+ ReadBlockAbbrevs(F.PreprocessorDetailCursor,
+ PREPROCESSOR_DETAIL_BLOCK_ID)) {
+ Error("malformed preprocessor detail record in AST file");
+ return true;
+ }
+ F.PreprocessorDetailStartOffset
+ = F.PreprocessorDetailCursor.GetCurrentBitNo();
+
+ if (!PP.getPreprocessingRecord())
+ PP.createPreprocessingRecord();
+ if (!PP.getPreprocessingRecord()->getExternalSource())
+ PP.getPreprocessingRecord()->SetExternalSource(*this);
+ break;
+
+ case SOURCE_MANAGER_BLOCK_ID:
+ if (ReadSourceManagerBlock(F))
+ return true;
+ break;
+
+ case SUBMODULE_BLOCK_ID:
+ if (ReadSubmoduleBlock(F))
+ return true;
+ break;
+
+ case COMMENTS_BLOCK_ID: {
+ llvm::BitstreamCursor C = Stream;
+ if (Stream.SkipBlock() ||
+ ReadBlockAbbrevs(C, COMMENTS_BLOCK_ID)) {
+ Error("malformed comments block in AST file");
+ return true;
+ }
+ CommentsCursors.push_back(std::make_pair(C, &F));
+ break;
+ }
+
+ default:
+ if (!Stream.SkipBlock())
+ break;
+ Error("malformed block record in AST file");
+ return true;
+ }
+ continue;
+ }
+
+ if (Code == llvm::bitc::DEFINE_ABBREV) {
+ Stream.ReadAbbrevRecord();
+ continue;
+ }
+
+ // Read and process a record.
+ Record.clear();
+ const char *BlobStart = 0;
+ unsigned BlobLen = 0;
+ switch ((ASTRecordTypes)Stream.ReadRecord(Code, Record,
+ &BlobStart, &BlobLen)) {
+ default: // Default behavior: ignore.
+ break;
+
+ case TYPE_OFFSET: {
+ if (F.LocalNumTypes != 0) {
+ Error("duplicate TYPE_OFFSET record in AST file");
+ return true;
+ }
+ F.TypeOffsets = (const uint32_t *)BlobStart;
+ F.LocalNumTypes = Record[0];
+ unsigned LocalBaseTypeIndex = Record[1];
+ F.BaseTypeIndex = getTotalNumTypes();
+
+ if (F.LocalNumTypes > 0) {
+ // Introduce the global -> local mapping for types within this module.
+ GlobalTypeMap.insert(std::make_pair(getTotalNumTypes(), &F));
+
+ // Introduce the local -> global mapping for types within this module.
+ F.TypeRemap.insertOrReplace(
+ std::make_pair(LocalBaseTypeIndex,
+ F.BaseTypeIndex - LocalBaseTypeIndex));
+
+ TypesLoaded.resize(TypesLoaded.size() + F.LocalNumTypes);
+ }
+ break;
+ }
+
+ case DECL_OFFSET: {
+ if (F.LocalNumDecls != 0) {
+ Error("duplicate DECL_OFFSET record in AST file");
+ return true;
+ }
+ F.DeclOffsets = (const DeclOffset *)BlobStart;
+ F.LocalNumDecls = Record[0];
+ unsigned LocalBaseDeclID = Record[1];
+ F.BaseDeclID = getTotalNumDecls();
+
+ if (F.LocalNumDecls > 0) {
+ // Introduce the global -> local mapping for declarations within this
+ // module.
+ GlobalDeclMap.insert(
+ std::make_pair(getTotalNumDecls() + NUM_PREDEF_DECL_IDS, &F));
+
+ // Introduce the local -> global mapping for declarations within this
+ // module.
+ F.DeclRemap.insertOrReplace(
+ std::make_pair(LocalBaseDeclID, F.BaseDeclID - LocalBaseDeclID));
+
+ // Introduce the global -> local mapping for declarations within this
+ // module.
+ F.GlobalToLocalDeclIDs[&F] = LocalBaseDeclID;
+
+ DeclsLoaded.resize(DeclsLoaded.size() + F.LocalNumDecls);
+ }
+ break;
+ }
+
+ case TU_UPDATE_LEXICAL: {
+ DeclContext *TU = Context.getTranslationUnitDecl();
+ DeclContextInfo &Info = F.DeclContextInfos[TU];
+ Info.LexicalDecls = reinterpret_cast<const KindDeclIDPair *>(BlobStart);
+ Info.NumLexicalDecls
+ = static_cast<unsigned int>(BlobLen / sizeof(KindDeclIDPair));
+ TU->setHasExternalLexicalStorage(true);
+ break;
+ }
+
+ case UPDATE_VISIBLE: {
+ unsigned Idx = 0;
+ serialization::DeclID ID = ReadDeclID(F, Record, Idx);
+ ASTDeclContextNameLookupTable *Table =
+ ASTDeclContextNameLookupTable::Create(
+ (const unsigned char *)BlobStart + Record[Idx++],
+ (const unsigned char *)BlobStart,
+ ASTDeclContextNameLookupTrait(*this, F));
+ if (ID == PREDEF_DECL_TRANSLATION_UNIT_ID) { // Is it the TU?
+ DeclContext *TU = Context.getTranslationUnitDecl();
+ F.DeclContextInfos[TU].NameLookupTableData = Table;
+ TU->setHasExternalVisibleStorage(true);
+ } else
+ PendingVisibleUpdates[ID].push_back(std::make_pair(Table, &F));
+ break;
+ }
+
+ case IDENTIFIER_TABLE:
+ F.IdentifierTableData = BlobStart;
+ if (Record[0]) {
+ F.IdentifierLookupTable
+ = ASTIdentifierLookupTable::Create(
+ (const unsigned char *)F.IdentifierTableData + Record[0],
+ (const unsigned char *)F.IdentifierTableData,
+ ASTIdentifierLookupTrait(*this, F));
+
+ PP.getIdentifierTable().setExternalIdentifierLookup(this);
+ }
+ break;
+
+ case IDENTIFIER_OFFSET: {
+ if (F.LocalNumIdentifiers != 0) {
+ Error("duplicate IDENTIFIER_OFFSET record in AST file");
+ return true;
+ }
+ F.IdentifierOffsets = (const uint32_t *)BlobStart;
+ F.LocalNumIdentifiers = Record[0];
+ unsigned LocalBaseIdentifierID = Record[1];
+ F.BaseIdentifierID = getTotalNumIdentifiers();
+
+ if (F.LocalNumIdentifiers > 0) {
+ // Introduce the global -> local mapping for identifiers within this
+ // module.
+ GlobalIdentifierMap.insert(std::make_pair(getTotalNumIdentifiers() + 1,
+ &F));
+
+ // Introduce the local -> global mapping for identifiers within this
+ // module.
+ F.IdentifierRemap.insertOrReplace(
+ std::make_pair(LocalBaseIdentifierID,
+ F.BaseIdentifierID - LocalBaseIdentifierID));
+
+ IdentifiersLoaded.resize(IdentifiersLoaded.size()
+ + F.LocalNumIdentifiers);
+ }
+ break;
+ }
+
+ case EXTERNAL_DEFINITIONS:
+ for (unsigned I = 0, N = Record.size(); I != N; ++I)
+ ExternalDefinitions.push_back(getGlobalDeclID(F, Record[I]));
+ break;
+
+ case SPECIAL_TYPES:
+ for (unsigned I = 0, N = Record.size(); I != N; ++I)
+ SpecialTypes.push_back(getGlobalTypeID(F, Record[I]));
+ break;
+
+ case STATISTICS:
+ TotalNumStatements += Record[0];
+ TotalNumMacros += Record[1];
+ TotalLexicalDeclContexts += Record[2];
+ TotalVisibleDeclContexts += Record[3];
+ break;
+
+ case UNUSED_FILESCOPED_DECLS:
+ for (unsigned I = 0, N = Record.size(); I != N; ++I)
+ UnusedFileScopedDecls.push_back(getGlobalDeclID(F, Record[I]));
+ break;
+
+ case DELEGATING_CTORS:
+ for (unsigned I = 0, N = Record.size(); I != N; ++I)
+ DelegatingCtorDecls.push_back(getGlobalDeclID(F, Record[I]));
+ break;
+
+ case WEAK_UNDECLARED_IDENTIFIERS:
+ if (Record.size() % 4 != 0) {
+ Error("invalid weak identifiers record");
+ return true;
+ }
+
+ // FIXME: Ignore weak undeclared identifiers from non-original PCH
+ // files. This isn't the way to do it :)
+ WeakUndeclaredIdentifiers.clear();
+
+ // Translate the weak, undeclared identifiers into global IDs.
+ for (unsigned I = 0, N = Record.size(); I < N; /* in loop */) {
+ WeakUndeclaredIdentifiers.push_back(
+ getGlobalIdentifierID(F, Record[I++]));
+ WeakUndeclaredIdentifiers.push_back(
+ getGlobalIdentifierID(F, Record[I++]));
+ WeakUndeclaredIdentifiers.push_back(
+ ReadSourceLocation(F, Record, I).getRawEncoding());
+ WeakUndeclaredIdentifiers.push_back(Record[I++]);
+ }
+ break;
+
+ case LOCALLY_SCOPED_EXTERNAL_DECLS:
+ for (unsigned I = 0, N = Record.size(); I != N; ++I)
+ LocallyScopedExternalDecls.push_back(getGlobalDeclID(F, Record[I]));
+ break;
+
+ case SELECTOR_OFFSETS: {
+ F.SelectorOffsets = (const uint32_t *)BlobStart;
+ F.LocalNumSelectors = Record[0];
+ unsigned LocalBaseSelectorID = Record[1];
+ F.BaseSelectorID = getTotalNumSelectors();
+
+ if (F.LocalNumSelectors > 0) {
+ // Introduce the global -> local mapping for selectors within this
+ // module.
+ GlobalSelectorMap.insert(std::make_pair(getTotalNumSelectors()+1, &F));
+
+ // Introduce the local -> global mapping for selectors within this
+ // module.
+ F.SelectorRemap.insertOrReplace(
+ std::make_pair(LocalBaseSelectorID,
+ F.BaseSelectorID - LocalBaseSelectorID));
+
+ SelectorsLoaded.resize(SelectorsLoaded.size() + F.LocalNumSelectors);
+ }
+ break;
+ }
+
+ case METHOD_POOL:
+ F.SelectorLookupTableData = (const unsigned char *)BlobStart;
+ if (Record[0])
+ F.SelectorLookupTable
+ = ASTSelectorLookupTable::Create(
+ F.SelectorLookupTableData + Record[0],
+ F.SelectorLookupTableData,
+ ASTSelectorLookupTrait(*this, F));
+ TotalNumMethodPoolEntries += Record[1];
+ break;
+
+ case REFERENCED_SELECTOR_POOL:
+ if (!Record.empty()) {
+ for (unsigned Idx = 0, N = Record.size() - 1; Idx < N; /* in loop */) {
+ ReferencedSelectorsData.push_back(getGlobalSelectorID(F,
+ Record[Idx++]));
+ ReferencedSelectorsData.push_back(ReadSourceLocation(F, Record, Idx).
+ getRawEncoding());
+ }
+ }
+ break;
+
+ case PP_COUNTER_VALUE:
+ if (!Record.empty() && Listener)
+ Listener->ReadCounter(F, Record[0]);
+ break;
+
+ case FILE_SORTED_DECLS:
+ F.FileSortedDecls = (const DeclID *)BlobStart;
+ F.NumFileSortedDecls = Record[0];
+ break;
+
+ case SOURCE_LOCATION_OFFSETS: {
+ F.SLocEntryOffsets = (const uint32_t *)BlobStart;
+ F.LocalNumSLocEntries = Record[0];
+ unsigned SLocSpaceSize = Record[1];
+ llvm::tie(F.SLocEntryBaseID, F.SLocEntryBaseOffset) =
+ SourceMgr.AllocateLoadedSLocEntries(F.LocalNumSLocEntries,
+ SLocSpaceSize);
+ // Make our entry in the range map. BaseID is negative and growing, so
+ // we invert it. Because we invert it, though, we need the other end of
+ // the range.
+ unsigned RangeStart =
+ unsigned(-F.SLocEntryBaseID) - F.LocalNumSLocEntries + 1;
+ GlobalSLocEntryMap.insert(std::make_pair(RangeStart, &F));
+ F.FirstLoc = SourceLocation::getFromRawEncoding(F.SLocEntryBaseOffset);
+
+ // SLocEntryBaseOffset is lower than MaxLoadedOffset and decreasing.
+ assert((F.SLocEntryBaseOffset & (1U << 31U)) == 0);
+ GlobalSLocOffsetMap.insert(
+ std::make_pair(SourceManager::MaxLoadedOffset - F.SLocEntryBaseOffset
+ - SLocSpaceSize,&F));
+
+ // Initialize the remapping table.
+ // Invalid stays invalid.
+ F.SLocRemap.insert(std::make_pair(0U, 0));
+ // This module. Base was 2 when being compiled.
+ F.SLocRemap.insert(std::make_pair(2U,
+ static_cast<int>(F.SLocEntryBaseOffset - 2)));
+
+ TotalNumSLocEntries += F.LocalNumSLocEntries;
+ break;
+ }
+
+ case MODULE_OFFSET_MAP: {
+ // Additional remapping information.
+ const unsigned char *Data = (const unsigned char*)BlobStart;
+ const unsigned char *DataEnd = Data + BlobLen;
+
+ // Continuous range maps we may be updating in our module.
+ ContinuousRangeMap<uint32_t, int, 2>::Builder SLocRemap(F.SLocRemap);
+ ContinuousRangeMap<uint32_t, int, 2>::Builder
+ IdentifierRemap(F.IdentifierRemap);
+ ContinuousRangeMap<uint32_t, int, 2>::Builder
+ MacroRemap(F.MacroRemap);
+ ContinuousRangeMap<uint32_t, int, 2>::Builder
+ PreprocessedEntityRemap(F.PreprocessedEntityRemap);
+ ContinuousRangeMap<uint32_t, int, 2>::Builder
+ SubmoduleRemap(F.SubmoduleRemap);
+ ContinuousRangeMap<uint32_t, int, 2>::Builder
+ SelectorRemap(F.SelectorRemap);
+ ContinuousRangeMap<uint32_t, int, 2>::Builder DeclRemap(F.DeclRemap);
+ ContinuousRangeMap<uint32_t, int, 2>::Builder TypeRemap(F.TypeRemap);
+
+ while(Data < DataEnd) {
+ uint16_t Len = io::ReadUnalignedLE16(Data);
+ StringRef Name = StringRef((const char*)Data, Len);
+ Data += Len;
+ ModuleFile *OM = ModuleMgr.lookup(Name);
+ if (!OM) {
+ Error("SourceLocation remap refers to unknown module");
+ return true;
+ }
+
+ uint32_t SLocOffset = io::ReadUnalignedLE32(Data);
+ uint32_t IdentifierIDOffset = io::ReadUnalignedLE32(Data);
+ uint32_t MacroIDOffset = io::ReadUnalignedLE32(Data);
+ uint32_t PreprocessedEntityIDOffset = io::ReadUnalignedLE32(Data);
+ uint32_t SubmoduleIDOffset = io::ReadUnalignedLE32(Data);
+ uint32_t SelectorIDOffset = io::ReadUnalignedLE32(Data);
+ uint32_t DeclIDOffset = io::ReadUnalignedLE32(Data);
+ uint32_t TypeIndexOffset = io::ReadUnalignedLE32(Data);
+
+ // Source location offset is mapped to OM->SLocEntryBaseOffset.
+ SLocRemap.insert(std::make_pair(SLocOffset,
+ static_cast<int>(OM->SLocEntryBaseOffset - SLocOffset)));
+ IdentifierRemap.insert(
+ std::make_pair(IdentifierIDOffset,
+ OM->BaseIdentifierID - IdentifierIDOffset));
+ MacroRemap.insert(std::make_pair(MacroIDOffset,
+ OM->BaseMacroID - MacroIDOffset));
+ PreprocessedEntityRemap.insert(
+ std::make_pair(PreprocessedEntityIDOffset,
+ OM->BasePreprocessedEntityID - PreprocessedEntityIDOffset));
+ SubmoduleRemap.insert(std::make_pair(SubmoduleIDOffset,
+ OM->BaseSubmoduleID - SubmoduleIDOffset));
+ SelectorRemap.insert(std::make_pair(SelectorIDOffset,
+ OM->BaseSelectorID - SelectorIDOffset));
+ DeclRemap.insert(std::make_pair(DeclIDOffset,
+ OM->BaseDeclID - DeclIDOffset));
+
+ TypeRemap.insert(std::make_pair(TypeIndexOffset,
+ OM->BaseTypeIndex - TypeIndexOffset));
+
+ // Global -> local mappings.
+ F.GlobalToLocalDeclIDs[OM] = DeclIDOffset;
+ }
+ break;
+ }
+
+ case SOURCE_MANAGER_LINE_TABLE:
+ if (ParseLineTable(F, Record))
+ return true;
+ break;
+
+ case SOURCE_LOCATION_PRELOADS: {
+ // Need to transform from the local view (1-based IDs) to the global view,
+ // which is based off F.SLocEntryBaseID.
+ if (!F.PreloadSLocEntries.empty()) {
+ Error("Multiple SOURCE_LOCATION_PRELOADS records in AST file");
+ return true;
+ }
+
+ F.PreloadSLocEntries.swap(Record);
+ break;
+ }
+
+ case EXT_VECTOR_DECLS:
+ for (unsigned I = 0, N = Record.size(); I != N; ++I)
+ ExtVectorDecls.push_back(getGlobalDeclID(F, Record[I]));
+ break;
+
+ case VTABLE_USES:
+ if (Record.size() % 3 != 0) {
+ Error("Invalid VTABLE_USES record");
+ return true;
+ }
+
+ // Later tables overwrite earlier ones.
+ // FIXME: Modules will have some trouble with this. This is clearly not
+ // the right way to do this.
+ VTableUses.clear();
+
+ for (unsigned Idx = 0, N = Record.size(); Idx != N; /* In loop */) {
+ VTableUses.push_back(getGlobalDeclID(F, Record[Idx++]));
+ VTableUses.push_back(
+ ReadSourceLocation(F, Record, Idx).getRawEncoding());
+ VTableUses.push_back(Record[Idx++]);
+ }
+ break;
+
+ case DYNAMIC_CLASSES:
+ for (unsigned I = 0, N = Record.size(); I != N; ++I)
+ DynamicClasses.push_back(getGlobalDeclID(F, Record[I]));
+ break;
+
+ case PENDING_IMPLICIT_INSTANTIATIONS:
+ if (PendingInstantiations.size() % 2 != 0) {
+ Error("Invalid existing PendingInstantiations");
+ return true;
+ }
+
+ if (Record.size() % 2 != 0) {
+ Error("Invalid PENDING_IMPLICIT_INSTANTIATIONS block");
+ return true;
+ }
+
+ for (unsigned I = 0, N = Record.size(); I != N; /* in loop */) {
+ PendingInstantiations.push_back(getGlobalDeclID(F, Record[I++]));
+ PendingInstantiations.push_back(
+ ReadSourceLocation(F, Record, I).getRawEncoding());
+ }
+ break;
+
+ case SEMA_DECL_REFS:
+ // Later tables overwrite earlier ones.
+ // FIXME: Modules will have some trouble with this.
+ SemaDeclRefs.clear();
+ for (unsigned I = 0, N = Record.size(); I != N; ++I)
+ SemaDeclRefs.push_back(getGlobalDeclID(F, Record[I]));
+ break;
+
+ case PPD_ENTITIES_OFFSETS: {
+ F.PreprocessedEntityOffsets = (const PPEntityOffset *)BlobStart;
+ assert(BlobLen % sizeof(PPEntityOffset) == 0);
+ F.NumPreprocessedEntities = BlobLen / sizeof(PPEntityOffset);
+
+ unsigned LocalBasePreprocessedEntityID = Record[0];
+
+ unsigned StartingID;
+ if (!PP.getPreprocessingRecord())
+ PP.createPreprocessingRecord();
+ if (!PP.getPreprocessingRecord()->getExternalSource())
+ PP.getPreprocessingRecord()->SetExternalSource(*this);
+ StartingID
+ = PP.getPreprocessingRecord()
+ ->allocateLoadedEntities(F.NumPreprocessedEntities);
+ F.BasePreprocessedEntityID = StartingID;
+
+ if (F.NumPreprocessedEntities > 0) {
+ // Introduce the global -> local mapping for preprocessed entities in
+ // this module.
+ GlobalPreprocessedEntityMap.insert(std::make_pair(StartingID, &F));
+
+ // Introduce the local -> global mapping for preprocessed entities in
+ // this module.
+ F.PreprocessedEntityRemap.insertOrReplace(
+ std::make_pair(LocalBasePreprocessedEntityID,
+ F.BasePreprocessedEntityID - LocalBasePreprocessedEntityID));
+ }
+
+ break;
+ }
+
+ case DECL_UPDATE_OFFSETS: {
+ if (Record.size() % 2 != 0) {
+ Error("invalid DECL_UPDATE_OFFSETS block in AST file");
+ return true;
+ }
+ for (unsigned I = 0, N = Record.size(); I != N; I += 2)
+ DeclUpdateOffsets[getGlobalDeclID(F, Record[I])]
+ .push_back(std::make_pair(&F, Record[I+1]));
+ break;
+ }
+
+ case DECL_REPLACEMENTS: {
+ if (Record.size() % 3 != 0) {
+ Error("invalid DECL_REPLACEMENTS block in AST file");
+ return true;
+ }
+ for (unsigned I = 0, N = Record.size(); I != N; I += 3)
+ ReplacedDecls[getGlobalDeclID(F, Record[I])]
+ = ReplacedDeclInfo(&F, Record[I+1], Record[I+2]);
+ break;
+ }
+
+ case OBJC_CATEGORIES_MAP: {
+ if (F.LocalNumObjCCategoriesInMap != 0) {
+ Error("duplicate OBJC_CATEGORIES_MAP record in AST file");
+ return true;
+ }
+
+ F.LocalNumObjCCategoriesInMap = Record[0];
+ F.ObjCCategoriesMap = (const ObjCCategoriesInfo *)BlobStart;
+ break;
+ }
+
+ case OBJC_CATEGORIES:
+ F.ObjCCategories.swap(Record);
+ break;
+
+ case CXX_BASE_SPECIFIER_OFFSETS: {
+ if (F.LocalNumCXXBaseSpecifiers != 0) {
+ Error("duplicate CXX_BASE_SPECIFIER_OFFSETS record in AST file");
+ return true;
+ }
+
+ F.LocalNumCXXBaseSpecifiers = Record[0];
+ F.CXXBaseSpecifiersOffsets = (const uint32_t *)BlobStart;
+ NumCXXBaseSpecifiersLoaded += F.LocalNumCXXBaseSpecifiers;
+ break;
+ }
+
+ case DIAG_PRAGMA_MAPPINGS:
+ if (F.PragmaDiagMappings.empty())
+ F.PragmaDiagMappings.swap(Record);
+ else
+ F.PragmaDiagMappings.insert(F.PragmaDiagMappings.end(),
+ Record.begin(), Record.end());
+ break;
+
+ case CUDA_SPECIAL_DECL_REFS:
+ // Later tables overwrite earlier ones.
+ // FIXME: Modules will have trouble with this.
+ CUDASpecialDeclRefs.clear();
+ for (unsigned I = 0, N = Record.size(); I != N; ++I)
+ CUDASpecialDeclRefs.push_back(getGlobalDeclID(F, Record[I]));
+ break;
+
+ case HEADER_SEARCH_TABLE: {
+ F.HeaderFileInfoTableData = BlobStart;
+ F.LocalNumHeaderFileInfos = Record[1];
+ F.HeaderFileFrameworkStrings = BlobStart + Record[2];
+ if (Record[0]) {
+ F.HeaderFileInfoTable
+ = HeaderFileInfoLookupTable::Create(
+ (const unsigned char *)F.HeaderFileInfoTableData + Record[0],
+ (const unsigned char *)F.HeaderFileInfoTableData,
+ HeaderFileInfoTrait(*this, F,
+ &PP.getHeaderSearchInfo(),
+ BlobStart + Record[2]));
+
+ PP.getHeaderSearchInfo().SetExternalSource(this);
+ if (!PP.getHeaderSearchInfo().getExternalLookup())
+ PP.getHeaderSearchInfo().SetExternalLookup(this);
+ }
+ break;
+ }
+
+ case FP_PRAGMA_OPTIONS:
+ // Later tables overwrite earlier ones.
+ FPPragmaOptions.swap(Record);
+ break;
+
+ case OPENCL_EXTENSIONS:
+ // Later tables overwrite earlier ones.
+ OpenCLExtensions.swap(Record);
+ break;
+
+ case TENTATIVE_DEFINITIONS:
+ for (unsigned I = 0, N = Record.size(); I != N; ++I)
+ TentativeDefinitions.push_back(getGlobalDeclID(F, Record[I]));
+ break;
+
+ case KNOWN_NAMESPACES:
+ for (unsigned I = 0, N = Record.size(); I != N; ++I)
+ KnownNamespaces.push_back(getGlobalDeclID(F, Record[I]));
+ break;
+
+ case IMPORTED_MODULES: {
+ if (F.Kind != MK_Module) {
+ // If we aren't loading a module (which has its own exports), make
+ // all of the imported modules visible.
+ // FIXME: Deal with macros-only imports.
+ for (unsigned I = 0, N = Record.size(); I != N; ++I) {
+ if (unsigned GlobalID = getGlobalSubmoduleID(F, Record[I]))
+ ImportedModules.push_back(GlobalID);
+ }
+ }
+ break;
+ }
+
+ case LOCAL_REDECLARATIONS: {
+ F.RedeclarationChains.swap(Record);
+ break;
+ }
+
+ case LOCAL_REDECLARATIONS_MAP: {
+ if (F.LocalNumRedeclarationsInMap != 0) {
+ Error("duplicate LOCAL_REDECLARATIONS_MAP record in AST file");
+ return true;
+ }
+
+ F.LocalNumRedeclarationsInMap = Record[0];
+ F.RedeclarationsMap = (const LocalRedeclarationsInfo *)BlobStart;
+ break;
+ }
+
+ case MERGED_DECLARATIONS: {
+ for (unsigned Idx = 0; Idx < Record.size(); /* increment in loop */) {
+ GlobalDeclID CanonID = getGlobalDeclID(F, Record[Idx++]);
+ SmallVectorImpl<GlobalDeclID> &Decls = StoredMergedDecls[CanonID];
+ for (unsigned N = Record[Idx++]; N > 0; --N)
+ Decls.push_back(getGlobalDeclID(F, Record[Idx++]));
+ }
+ break;
+ }
+
+ case MACRO_OFFSET: {
+ if (F.LocalNumMacros != 0) {
+ Error("duplicate MACRO_OFFSET record in AST file");
+ return true;
+ }
+ F.MacroOffsets = (const uint32_t *)BlobStart;
+ F.LocalNumMacros = Record[0];
+ unsigned LocalBaseMacroID = Record[1];
+ F.BaseMacroID = getTotalNumMacros();
+
+ if (F.LocalNumMacros > 0) {
+ // Introduce the global -> local mapping for macros within this module.
+ GlobalMacroMap.insert(std::make_pair(getTotalNumMacros() + 1, &F));
+
+ // Introduce the local -> global mapping for macros within this module.
+ F.MacroRemap.insertOrReplace(
+ std::make_pair(LocalBaseMacroID,
+ F.BaseMacroID - LocalBaseMacroID));
+
+ MacrosLoaded.resize(MacrosLoaded.size() + F.LocalNumMacros);
+ }
+ break;
+ }
+
+ case MACRO_UPDATES: {
+ for (unsigned I = 0, N = Record.size(); I != N; /* in loop */) {
+ MacroID ID = getGlobalMacroID(F, Record[I++]);
+ if (I == N)
+ break;
+
+ SourceLocation UndefLoc = ReadSourceLocation(F, Record, I);
+ SubmoduleID SubmoduleID = getGlobalSubmoduleID(F, Record[I++]);;
+ MacroUpdate Update;
+ Update.UndefLoc = UndefLoc;
+ MacroUpdates[ID].push_back(std::make_pair(SubmoduleID, Update));
+ }
+ break;
+ }
+ }
+ }
+ Error("premature end of bitstream in AST file");
+ return true;
+}
+
+void ASTReader::makeNamesVisible(const HiddenNames &Names) {
+ for (unsigned I = 0, N = Names.size(); I != N; ++I) {
+ switch (Names[I].getKind()) {
+ case HiddenName::Declaration:
+ Names[I].getDecl()->Hidden = false;
+ break;
+
+ case HiddenName::MacroVisibility: {
+ std::pair<IdentifierInfo *, MacroInfo *> Macro = Names[I].getMacro();
+ Macro.second->setHidden(!Macro.second->isPublic());
+ if (Macro.second->isDefined()) {
+ PP.makeLoadedMacroInfoVisible(Macro.first, Macro.second);
+ }
+ break;
+ }
+
+ case HiddenName::MacroUndef: {
+ std::pair<IdentifierInfo *, MacroInfo *> Macro = Names[I].getMacro();
+ if (Macro.second->isDefined()) {
+ Macro.second->setUndefLoc(Names[I].getMacroUndefLoc());
+ if (PPMutationListener *Listener = PP.getPPMutationListener())
+ Listener->UndefinedMacro(Macro.second);
+ PP.makeLoadedMacroInfoVisible(Macro.first, Macro.second);
+ }
+ break;
+ }
+ }
+ }
+}
+
+void ASTReader::makeModuleVisible(Module *Mod,
+ Module::NameVisibilityKind NameVisibility) {
+ llvm::SmallPtrSet<Module *, 4> Visited;
+ llvm::SmallVector<Module *, 4> Stack;
+ Stack.push_back(Mod);
+ while (!Stack.empty()) {
+ Mod = Stack.back();
+ Stack.pop_back();
+
+ if (NameVisibility <= Mod->NameVisibility) {
+ // This module already has this level of visibility (or greater), so
+ // there is nothing more to do.
+ continue;
+ }
+
+ if (!Mod->isAvailable()) {
+ // Modules that aren't available cannot be made visible.
+ continue;
+ }
+
+ // Update the module's name visibility.
+ Mod->NameVisibility = NameVisibility;
+
+ // If we've already deserialized any names from this module,
+ // mark them as visible.
+ HiddenNamesMapType::iterator Hidden = HiddenNamesMap.find(Mod);
+ if (Hidden != HiddenNamesMap.end()) {
+ makeNamesVisible(Hidden->second);
+ HiddenNamesMap.erase(Hidden);
+ }
+
+ // Push any non-explicit submodules onto the stack to be marked as
+ // visible.
+ for (Module::submodule_iterator Sub = Mod->submodule_begin(),
+ SubEnd = Mod->submodule_end();
+ Sub != SubEnd; ++Sub) {
+ if (!(*Sub)->IsExplicit && Visited.insert(*Sub))
+ Stack.push_back(*Sub);
+ }
+
+ // Push any exported modules onto the stack to be marked as visible.
+ bool AnyWildcard = false;
+ bool UnrestrictedWildcard = false;
+ llvm::SmallVector<Module *, 4> WildcardRestrictions;
+ for (unsigned I = 0, N = Mod->Exports.size(); I != N; ++I) {
+ Module *Exported = Mod->Exports[I].getPointer();
+ if (!Mod->Exports[I].getInt()) {
+ // Export a named module directly; no wildcards involved.
+ if (Visited.insert(Exported))
+ Stack.push_back(Exported);
+
+ continue;
+ }
+
+ // Wildcard export: export all of the imported modules that match
+ // the given pattern.
+ AnyWildcard = true;
+ if (UnrestrictedWildcard)
+ continue;
+
+ if (Module *Restriction = Mod->Exports[I].getPointer())
+ WildcardRestrictions.push_back(Restriction);
+ else {
+ WildcardRestrictions.clear();
+ UnrestrictedWildcard = true;
+ }
+ }
+
+ // If there were any wildcards, push any imported modules that were
+ // re-exported by the wildcard restriction.
+ if (!AnyWildcard)
+ continue;
+
+ for (unsigned I = 0, N = Mod->Imports.size(); I != N; ++I) {
+ Module *Imported = Mod->Imports[I];
+ if (!Visited.insert(Imported))
+ continue;
+
+ bool Acceptable = UnrestrictedWildcard;
+ if (!Acceptable) {
+ // Check whether this module meets one of the restrictions.
+ for (unsigned R = 0, NR = WildcardRestrictions.size(); R != NR; ++R) {
+ Module *Restriction = WildcardRestrictions[R];
+ if (Imported == Restriction || Imported->isSubModuleOf(Restriction)) {
+ Acceptable = true;
+ break;
+ }
+ }
+ }
+
+ if (!Acceptable)
+ continue;
+
+ Stack.push_back(Imported);
+ }
+ }
+}
+
+ASTReader::ASTReadResult ASTReader::ReadAST(const std::string &FileName,
+ ModuleKind Type,
+ SourceLocation ImportLoc,
+ unsigned ClientLoadCapabilities) {
+ // Bump the generation number.
+ unsigned PreviousGeneration = CurrentGeneration++;
+
+ unsigned NumModules = ModuleMgr.size();
+ llvm::SmallVector<ImportedModule, 4> Loaded;
+ switch(ASTReadResult ReadResult = ReadASTCore(FileName, Type, ImportLoc,
+ /*ImportedBy=*/0, Loaded,
+ ClientLoadCapabilities)) {
+ case Failure:
+ case OutOfDate:
+ case VersionMismatch:
+ case ConfigurationMismatch:
+ case HadErrors:
+ ModuleMgr.removeModules(ModuleMgr.begin() + NumModules, ModuleMgr.end());
+ return ReadResult;
+
+ case Success:
+ break;
+ }
+
+ // Here comes stuff that we only do once the entire chain is loaded.
+
+ // Load the AST blocks of all of the modules that we loaded.
+ for (llvm::SmallVectorImpl<ImportedModule>::iterator M = Loaded.begin(),
+ MEnd = Loaded.end();
+ M != MEnd; ++M) {
+ ModuleFile &F = *M->Mod;
+
+ // Read the AST block.
+ if (ReadASTBlock(F))
+ return Failure;
+
+ // Once read, set the ModuleFile bit base offset and update the size in
+ // bits of all files we've seen.
+ F.GlobalBitOffset = TotalModulesSizeInBits;
+ TotalModulesSizeInBits += F.SizeInBits;
+ GlobalBitOffsetsMap.insert(std::make_pair(F.GlobalBitOffset, &F));
+
+ // Preload SLocEntries.
+ for (unsigned I = 0, N = F.PreloadSLocEntries.size(); I != N; ++I) {
+ int Index = int(F.PreloadSLocEntries[I] - 1) + F.SLocEntryBaseID;
+ // Load it through the SourceManager and don't call ReadSLocEntry()
+ // directly because the entry may have already been loaded in which case
+ // calling ReadSLocEntry() directly would trigger an assertion in
+ // SourceManager.
+ SourceMgr.getLoadedSLocEntryByID(Index);
+ }
+ }
+
+ // Setup the import locations.
+ for (llvm::SmallVectorImpl<ImportedModule>::iterator M = Loaded.begin(),
+ MEnd = Loaded.end();
+ M != MEnd; ++M) {
+ ModuleFile &F = *M->Mod;
+ if (!M->ImportedBy)
+ F.ImportLoc = M->ImportLoc;
+ else
+ F.ImportLoc = ReadSourceLocation(*M->ImportedBy,
+ M->ImportLoc.getRawEncoding());
+ }
+
+ // Mark all of the identifiers in the identifier table as being out of date,
+ // so that various accessors know to check the loaded modules when the
+ // identifier is used.
+ for (IdentifierTable::iterator Id = PP.getIdentifierTable().begin(),
+ IdEnd = PP.getIdentifierTable().end();
+ Id != IdEnd; ++Id)
+ Id->second->setOutOfDate(true);
+
+ // Resolve any unresolved module exports.
+ for (unsigned I = 0, N = UnresolvedModuleImportExports.size(); I != N; ++I) {
+ UnresolvedModuleImportExport &Unresolved = UnresolvedModuleImportExports[I];
+ SubmoduleID GlobalID = getGlobalSubmoduleID(*Unresolved.File,Unresolved.ID);
+ Module *ResolvedMod = getSubmodule(GlobalID);
+
+ if (Unresolved.IsImport) {
+ if (ResolvedMod)
+ Unresolved.Mod->Imports.push_back(ResolvedMod);
+ continue;
+ }
+
+ if (ResolvedMod || Unresolved.IsWildcard)
+ Unresolved.Mod->Exports.push_back(
+ Module::ExportDecl(ResolvedMod, Unresolved.IsWildcard));
+ }
+ UnresolvedModuleImportExports.clear();
+
+ InitializeContext();
+
+ if (DeserializationListener)
+ DeserializationListener->ReaderInitialized(this);
+
+ ModuleFile &PrimaryModule = ModuleMgr.getPrimaryModule();
+ if (!PrimaryModule.OriginalSourceFileID.isInvalid()) {
+ PrimaryModule.OriginalSourceFileID
+ = FileID::get(PrimaryModule.SLocEntryBaseID
+ + PrimaryModule.OriginalSourceFileID.getOpaqueValue() - 1);
+
+ // If this AST file is a precompiled preamble, then set the
+ // preamble file ID of the source manager to the file source file
+ // from which the preamble was built.
+ if (Type == MK_Preamble) {
+ SourceMgr.setPreambleFileID(PrimaryModule.OriginalSourceFileID);
+ } else if (Type == MK_MainFile) {
+ SourceMgr.setMainFileID(PrimaryModule.OriginalSourceFileID);
+ }
+ }
+
+ // For any Objective-C class definitions we have already loaded, make sure
+ // that we load any additional categories.
+ for (unsigned I = 0, N = ObjCClassesLoaded.size(); I != N; ++I) {
+ loadObjCCategories(ObjCClassesLoaded[I]->getGlobalID(),
+ ObjCClassesLoaded[I],
+ PreviousGeneration);
+ }
+
+ return Success;
+}
+
+ASTReader::ASTReadResult
+ASTReader::ReadASTCore(StringRef FileName,
+ ModuleKind Type,
+ SourceLocation ImportLoc,
+ ModuleFile *ImportedBy,
+ llvm::SmallVectorImpl<ImportedModule> &Loaded,
+ unsigned ClientLoadCapabilities) {
+ ModuleFile *M;
+ bool NewModule;
+ std::string ErrorStr;
+ llvm::tie(M, NewModule) = ModuleMgr.addModule(FileName, Type, ImportLoc,
+ ImportedBy, CurrentGeneration,
+ ErrorStr);
+
+ if (!M) {
+ // We couldn't load the module.
+ std::string Msg = "Unable to load module \"" + FileName.str() + "\": "
+ + ErrorStr;
+ Error(Msg);
+ return Failure;
+ }
+
+ if (!NewModule) {
+ // We've already loaded this module.
+ return Success;
+ }
+
+ // FIXME: This seems rather a hack. Should CurrentDir be part of the
+ // module?
+ if (FileName != "-") {
+ CurrentDir = llvm::sys::path::parent_path(FileName);
+ if (CurrentDir.empty()) CurrentDir = ".";
+ }
+
+ ModuleFile &F = *M;
+ llvm::BitstreamCursor &Stream = F.Stream;
+ Stream.init(F.StreamFile);
+ F.SizeInBits = F.Buffer->getBufferSize() * 8;
+
+ // Sniff for the signature.
+ if (Stream.Read(8) != 'C' ||
+ Stream.Read(8) != 'P' ||
+ Stream.Read(8) != 'C' ||
+ Stream.Read(8) != 'H') {
+ Diag(diag::err_not_a_pch_file) << FileName;
+ return Failure;
+ }
+
+ // This is used for compatibility with older PCH formats.
+ bool HaveReadControlBlock = false;
+
+ while (!Stream.AtEndOfStream()) {
+ unsigned Code = Stream.ReadCode();
+
+ if (Code != llvm::bitc::ENTER_SUBBLOCK) {
+ Error("invalid record at top-level of AST file");
+ return Failure;
+ }
+
+ unsigned BlockID = Stream.ReadSubBlockID();
+
+ // We only know the control subblock ID.
+ switch (BlockID) {
+ case llvm::bitc::BLOCKINFO_BLOCK_ID:
+ if (Stream.ReadBlockInfoBlock()) {
+ Error("malformed BlockInfoBlock in AST file");
+ return Failure;
+ }
+ break;
+ case CONTROL_BLOCK_ID:
+ HaveReadControlBlock = true;
+ switch (ReadControlBlock(F, Loaded, ClientLoadCapabilities)) {
+ case Success:
+ break;
+
+ case Failure: return Failure;
+ case OutOfDate: return OutOfDate;
+ case VersionMismatch: return VersionMismatch;
+ case ConfigurationMismatch: return ConfigurationMismatch;
+ case HadErrors: return HadErrors;
+ }
+ break;
+ case AST_BLOCK_ID:
+ if (!HaveReadControlBlock) {
+ if ((ClientLoadCapabilities & ARR_VersionMismatch) == 0)
+ Diag(diag::warn_pch_version_too_old);
+ return VersionMismatch;
+ }
+
+ // Record that we've loaded this module.
+ Loaded.push_back(ImportedModule(M, ImportedBy, ImportLoc));
+ return Success;
+
+ default:
+ if (Stream.SkipBlock()) {
+ Error("malformed block record in AST file");
+ return Failure;
+ }
+ break;
+ }
+ }
+
+ return Success;
+}
+
+void ASTReader::InitializeContext() {
+ // If there's a listener, notify them that we "read" the translation unit.
+ if (DeserializationListener)
+ DeserializationListener->DeclRead(PREDEF_DECL_TRANSLATION_UNIT_ID,
+ Context.getTranslationUnitDecl());
+
+ // Make sure we load the declaration update records for the translation unit,
+ // if there are any.
+ loadDeclUpdateRecords(PREDEF_DECL_TRANSLATION_UNIT_ID,
+ Context.getTranslationUnitDecl());
+
+ // FIXME: Find a better way to deal with collisions between these
+ // built-in types. Right now, we just ignore the problem.
+
+ // Load the special types.
+ if (SpecialTypes.size() >= NumSpecialTypeIDs) {
+ if (unsigned String = SpecialTypes[SPECIAL_TYPE_CF_CONSTANT_STRING]) {
+ if (!Context.CFConstantStringTypeDecl)
+ Context.setCFConstantStringType(GetType(String));
+ }
+
+ if (unsigned File = SpecialTypes[SPECIAL_TYPE_FILE]) {
+ QualType FileType = GetType(File);
+ if (FileType.isNull()) {
+ Error("FILE type is NULL");
+ return;
+ }
+
+ if (!Context.FILEDecl) {
+ if (const TypedefType *Typedef = FileType->getAs<TypedefType>())
+ Context.setFILEDecl(Typedef->getDecl());
+ else {
+ const TagType *Tag = FileType->getAs<TagType>();
+ if (!Tag) {
+ Error("Invalid FILE type in AST file");
+ return;
+ }
+ Context.setFILEDecl(Tag->getDecl());
+ }
+ }
+ }
+
+ if (unsigned Jmp_buf = SpecialTypes[SPECIAL_TYPE_JMP_BUF]) {
+ QualType Jmp_bufType = GetType(Jmp_buf);
+ if (Jmp_bufType.isNull()) {
+ Error("jmp_buf type is NULL");
+ return;
+ }
+
+ if (!Context.jmp_bufDecl) {
+ if (const TypedefType *Typedef = Jmp_bufType->getAs<TypedefType>())
+ Context.setjmp_bufDecl(Typedef->getDecl());
+ else {
+ const TagType *Tag = Jmp_bufType->getAs<TagType>();
+ if (!Tag) {
+ Error("Invalid jmp_buf type in AST file");
+ return;
+ }
+ Context.setjmp_bufDecl(Tag->getDecl());
+ }
+ }
+ }
+
+ if (unsigned Sigjmp_buf = SpecialTypes[SPECIAL_TYPE_SIGJMP_BUF]) {
+ QualType Sigjmp_bufType = GetType(Sigjmp_buf);
+ if (Sigjmp_bufType.isNull()) {
+ Error("sigjmp_buf type is NULL");
+ return;
+ }
+
+ if (!Context.sigjmp_bufDecl) {
+ if (const TypedefType *Typedef = Sigjmp_bufType->getAs<TypedefType>())
+ Context.setsigjmp_bufDecl(Typedef->getDecl());
+ else {
+ const TagType *Tag = Sigjmp_bufType->getAs<TagType>();
+ assert(Tag && "Invalid sigjmp_buf type in AST file");
+ Context.setsigjmp_bufDecl(Tag->getDecl());
+ }
+ }
+ }
+
+ if (unsigned ObjCIdRedef
+ = SpecialTypes[SPECIAL_TYPE_OBJC_ID_REDEFINITION]) {
+ if (Context.ObjCIdRedefinitionType.isNull())
+ Context.ObjCIdRedefinitionType = GetType(ObjCIdRedef);
+ }
+
+ if (unsigned ObjCClassRedef
+ = SpecialTypes[SPECIAL_TYPE_OBJC_CLASS_REDEFINITION]) {
+ if (Context.ObjCClassRedefinitionType.isNull())
+ Context.ObjCClassRedefinitionType = GetType(ObjCClassRedef);
+ }
+
+ if (unsigned ObjCSelRedef
+ = SpecialTypes[SPECIAL_TYPE_OBJC_SEL_REDEFINITION]) {
+ if (Context.ObjCSelRedefinitionType.isNull())
+ Context.ObjCSelRedefinitionType = GetType(ObjCSelRedef);
+ }
+
+ if (unsigned Ucontext_t = SpecialTypes[SPECIAL_TYPE_UCONTEXT_T]) {
+ QualType Ucontext_tType = GetType(Ucontext_t);
+ if (Ucontext_tType.isNull()) {
+ Error("ucontext_t type is NULL");
+ return;
+ }
+
+ if (!Context.ucontext_tDecl) {
+ if (const TypedefType *Typedef = Ucontext_tType->getAs<TypedefType>())
+ Context.setucontext_tDecl(Typedef->getDecl());
+ else {
+ const TagType *Tag = Ucontext_tType->getAs<TagType>();
+ assert(Tag && "Invalid ucontext_t type in AST file");
+ Context.setucontext_tDecl(Tag->getDecl());
+ }
+ }
+ }
+ }
+
+ ReadPragmaDiagnosticMappings(Context.getDiagnostics());
+
+ // If there were any CUDA special declarations, deserialize them.
+ if (!CUDASpecialDeclRefs.empty()) {
+ assert(CUDASpecialDeclRefs.size() == 1 && "More decl refs than expected!");
+ Context.setcudaConfigureCallDecl(
+ cast<FunctionDecl>(GetDecl(CUDASpecialDeclRefs[0])));
+ }
+
+ // Re-export any modules that were imported by a non-module AST file.
+ for (unsigned I = 0, N = ImportedModules.size(); I != N; ++I) {
+ if (Module *Imported = getSubmodule(ImportedModules[I]))
+ makeModuleVisible(Imported, Module::AllVisible);
+ }
+ ImportedModules.clear();
+}
+
+void ASTReader::finalizeForWriting() {
+ for (HiddenNamesMapType::iterator Hidden = HiddenNamesMap.begin(),
+ HiddenEnd = HiddenNamesMap.end();
+ Hidden != HiddenEnd; ++Hidden) {
+ makeNamesVisible(Hidden->second);
+ }
+ HiddenNamesMap.clear();
+}
+
+/// \brief Retrieve the name of the original source file name
+/// directly from the AST file, without actually loading the AST
+/// file.
+std::string ASTReader::getOriginalSourceFile(const std::string &ASTFileName,
+ FileManager &FileMgr,
+ DiagnosticsEngine &Diags) {
+ // Open the AST file.
+ std::string ErrStr;
+ OwningPtr<llvm::MemoryBuffer> Buffer;
+ Buffer.reset(FileMgr.getBufferForFile(ASTFileName, &ErrStr));
+ if (!Buffer) {
+ Diags.Report(diag::err_fe_unable_to_read_pch_file) << ASTFileName << ErrStr;
+ return std::string();
+ }
+
+ // Initialize the stream
+ llvm::BitstreamReader StreamFile;
+ llvm::BitstreamCursor Stream;
+ StreamFile.init((const unsigned char *)Buffer->getBufferStart(),
+ (const unsigned char *)Buffer->getBufferEnd());
+ Stream.init(StreamFile);
+
+ // Sniff for the signature.
+ if (Stream.Read(8) != 'C' ||
+ Stream.Read(8) != 'P' ||
+ Stream.Read(8) != 'C' ||
+ Stream.Read(8) != 'H') {
+ Diags.Report(diag::err_fe_not_a_pch_file) << ASTFileName;
+ return std::string();
+ }
+
+ RecordData Record;
+ while (!Stream.AtEndOfStream()) {
+ unsigned Code = Stream.ReadCode();
+
+ if (Code == llvm::bitc::ENTER_SUBBLOCK) {
+ unsigned BlockID = Stream.ReadSubBlockID();
+
+ // We only know the AST subblock ID.
+ switch (BlockID) {
+ case CONTROL_BLOCK_ID:
+ if (Stream.EnterSubBlock(CONTROL_BLOCK_ID)) {
+ Diags.Report(diag::err_fe_pch_malformed_block) << ASTFileName;
+ return std::string();
+ }
+ break;
+
+ default:
+ if (Stream.SkipBlock()) {
+ Diags.Report(diag::err_fe_pch_malformed_block) << ASTFileName;
+ return std::string();
+ }
+ break;
+ }
+ continue;
+ }
+
+ if (Code == llvm::bitc::END_BLOCK) {
+ if (Stream.ReadBlockEnd()) {
+ Diags.Report(diag::err_fe_pch_error_at_end_block) << ASTFileName;
+ return std::string();
+ }
+ continue;
+ }
+
+ if (Code == llvm::bitc::DEFINE_ABBREV) {
+ Stream.ReadAbbrevRecord();
+ continue;
+ }
+
+ Record.clear();
+ const char *BlobStart = 0;
+ unsigned BlobLen = 0;
+ if (Stream.ReadRecord(Code, Record, &BlobStart, &BlobLen) == ORIGINAL_FILE)
+ return std::string(BlobStart, BlobLen);
+ }
+
+ return std::string();
+}
+
+namespace {
+ class SimplePCHValidator : public ASTReaderListener {
+ const LangOptions &ExistingLangOpts;
+ const TargetOptions &ExistingTargetOpts;
+ const PreprocessorOptions &ExistingPPOpts;
+ FileManager &FileMgr;
+
+ public:
+ SimplePCHValidator(const LangOptions &ExistingLangOpts,
+ const TargetOptions &ExistingTargetOpts,
+ const PreprocessorOptions &ExistingPPOpts,
+ FileManager &FileMgr)
+ : ExistingLangOpts(ExistingLangOpts),
+ ExistingTargetOpts(ExistingTargetOpts),
+ ExistingPPOpts(ExistingPPOpts),
+ FileMgr(FileMgr)
+ {
+ }
+
+ virtual bool ReadLanguageOptions(const LangOptions &LangOpts,
+ bool Complain) {
+ return checkLanguageOptions(ExistingLangOpts, LangOpts, 0);
+ }
+ virtual bool ReadTargetOptions(const TargetOptions &TargetOpts,
+ bool Complain) {
+ return checkTargetOptions(ExistingTargetOpts, TargetOpts, 0);
+ }
+ virtual bool ReadPreprocessorOptions(const PreprocessorOptions &PPOpts,
+ bool Complain,
+ std::string &SuggestedPredefines) {
+ return checkPreprocessorOptions(ExistingPPOpts, PPOpts, 0, FileMgr,
+ SuggestedPredefines);
+ }
+ };
+}
+
+bool ASTReader::readASTFileControlBlock(StringRef Filename,
+ FileManager &FileMgr,
+ ASTReaderListener &Listener) {
+ // Open the AST file.
+ std::string ErrStr;
+ OwningPtr<llvm::MemoryBuffer> Buffer;
+ Buffer.reset(FileMgr.getBufferForFile(Filename, &ErrStr));
+ if (!Buffer) {
+ return true;
+ }
+
+ // Initialize the stream
+ llvm::BitstreamReader StreamFile;
+ llvm::BitstreamCursor Stream;
+ StreamFile.init((const unsigned char *)Buffer->getBufferStart(),
+ (const unsigned char *)Buffer->getBufferEnd());
+ Stream.init(StreamFile);
+
+ // Sniff for the signature.
+ if (Stream.Read(8) != 'C' ||
+ Stream.Read(8) != 'P' ||
+ Stream.Read(8) != 'C' ||
+ Stream.Read(8) != 'H') {
+ return true;
+ }
+
+ RecordData Record;
+ bool InControlBlock = false;
+ while (!Stream.AtEndOfStream()) {
+ unsigned Code = Stream.ReadCode();
+
+ if (Code == llvm::bitc::ENTER_SUBBLOCK) {
+ unsigned BlockID = Stream.ReadSubBlockID();
+
+ // We only know the control subblock ID.
+ switch (BlockID) {
+ case CONTROL_BLOCK_ID:
+ if (Stream.EnterSubBlock(CONTROL_BLOCK_ID)) {
+ return true;
+ } else {
+ InControlBlock = true;
+ }
+ break;
+
+ default:
+ if (Stream.SkipBlock())
+ return true;
+ break;
+ }
+ continue;
+ }
+
+ if (Code == llvm::bitc::END_BLOCK) {
+ if (Stream.ReadBlockEnd()) {
+ return true;
+ }
+
+ InControlBlock = false;
+ continue;
+ }
+
+ if (Code == llvm::bitc::DEFINE_ABBREV) {
+ Stream.ReadAbbrevRecord();
+ continue;
+ }
+
+ Record.clear();
+ const char *BlobStart = 0;
+ unsigned BlobLen = 0;
+ unsigned RecCode = Stream.ReadRecord(Code, Record, &BlobStart, &BlobLen);
+ if (InControlBlock) {
+ switch ((ControlRecordTypes)RecCode) {
+ case METADATA: {
+ if (Record[0] != VERSION_MAJOR) {
+ return true;
+ }
+
+ const std::string &CurBranch = getClangFullRepositoryVersion();
+ StringRef ASTBranch(BlobStart, BlobLen);
+ if (StringRef(CurBranch) != ASTBranch)
+ return true;
+
+ break;
+ }
+ case LANGUAGE_OPTIONS:
+ if (ParseLanguageOptions(Record, false, Listener))
+ return true;
+ break;
+
+ case TARGET_OPTIONS:
+ if (ParseTargetOptions(Record, false, Listener))
+ return true;
+ break;
+
+ case DIAGNOSTIC_OPTIONS:
+ if (ParseDiagnosticOptions(Record, false, Listener))
+ return true;
+ break;
+
+ case FILE_SYSTEM_OPTIONS:
+ if (ParseFileSystemOptions(Record, false, Listener))
+ return true;
+ break;
+
+ case HEADER_SEARCH_OPTIONS:
+ if (ParseHeaderSearchOptions(Record, false, Listener))
+ return true;
+ break;
+
+ case PREPROCESSOR_OPTIONS: {
+ std::string IgnoredSuggestedPredefines;
+ if (ParsePreprocessorOptions(Record, false, Listener,
+ IgnoredSuggestedPredefines))
+ return true;
+ break;
+ }
+
+ default:
+ // No other validation to perform.
+ break;
+ }
+ }
+ }
+
+ return false;
+}
+
+
+bool ASTReader::isAcceptableASTFile(StringRef Filename,
+ FileManager &FileMgr,
+ const LangOptions &LangOpts,
+ const TargetOptions &TargetOpts,
+ const PreprocessorOptions &PPOpts) {
+ SimplePCHValidator validator(LangOpts, TargetOpts, PPOpts, FileMgr);
+ return !readASTFileControlBlock(Filename, FileMgr, validator);
+}
+
+bool ASTReader::ReadSubmoduleBlock(ModuleFile &F) {
+ // Enter the submodule block.
+ if (F.Stream.EnterSubBlock(SUBMODULE_BLOCK_ID)) {
+ Error("malformed submodule block record in AST file");
+ return true;
+ }
+
+ ModuleMap &ModMap = PP.getHeaderSearchInfo().getModuleMap();
+ bool First = true;
+ Module *CurrentModule = 0;
+ RecordData Record;
+ while (true) {
+ unsigned Code = F.Stream.ReadCode();
+ if (Code == llvm::bitc::END_BLOCK) {
+ if (F.Stream.ReadBlockEnd()) {
+ Error("error at end of submodule block in AST file");
+ return true;
+ }
+ return false;
+ }
+
+ if (Code == llvm::bitc::ENTER_SUBBLOCK) {
+ // No known subblocks, always skip them.
+ F.Stream.ReadSubBlockID();
+ if (F.Stream.SkipBlock()) {
+ Error("malformed block record in AST file");
+ return true;
+ }
+ continue;
+ }
+
+ if (Code == llvm::bitc::DEFINE_ABBREV) {
+ F.Stream.ReadAbbrevRecord();
+ continue;
+ }
+
+ // Read a record.
+ const char *BlobStart;
+ unsigned BlobLen;
+ Record.clear();
+ switch (F.Stream.ReadRecord(Code, Record, &BlobStart, &BlobLen)) {
+ default: // Default behavior: ignore.
+ break;
+
+ case SUBMODULE_DEFINITION: {
+ if (First) {
+ Error("missing submodule metadata record at beginning of block");
+ return true;
+ }
+
+ if (Record.size() < 7) {
+ Error("malformed module definition");
+ return true;
+ }
+
+ StringRef Name(BlobStart, BlobLen);
+ SubmoduleID GlobalID = getGlobalSubmoduleID(F, Record[0]);
+ SubmoduleID Parent = getGlobalSubmoduleID(F, Record[1]);
+ bool IsFramework = Record[2];
+ bool IsExplicit = Record[3];
+ bool IsSystem = Record[4];
+ bool InferSubmodules = Record[5];
+ bool InferExplicitSubmodules = Record[6];
+ bool InferExportWildcard = Record[7];
+
+ Module *ParentModule = 0;
+ if (Parent)
+ ParentModule = getSubmodule(Parent);
+
+ // Retrieve this (sub)module from the module map, creating it if
+ // necessary.
+ CurrentModule = ModMap.findOrCreateModule(Name, ParentModule,
+ IsFramework,
+ IsExplicit).first;
+ SubmoduleID GlobalIndex = GlobalID - NUM_PREDEF_SUBMODULE_IDS;
+ if (GlobalIndex >= SubmodulesLoaded.size() ||
+ SubmodulesLoaded[GlobalIndex]) {
+ Error("too many submodules");
+ return true;
+ }
+
+ CurrentModule->setASTFile(F.File);
+ CurrentModule->IsFromModuleFile = true;
+ CurrentModule->IsSystem = IsSystem || CurrentModule->IsSystem;
+ CurrentModule->InferSubmodules = InferSubmodules;
+ CurrentModule->InferExplicitSubmodules = InferExplicitSubmodules;
+ CurrentModule->InferExportWildcard = InferExportWildcard;
+ if (DeserializationListener)
+ DeserializationListener->ModuleRead(GlobalID, CurrentModule);
+
+ SubmodulesLoaded[GlobalIndex] = CurrentModule;
+ break;
+ }
+
+ case SUBMODULE_UMBRELLA_HEADER: {
+ if (First) {
+ Error("missing submodule metadata record at beginning of block");
+ return true;
+ }
+
+ if (!CurrentModule)
+ break;
+
+ StringRef FileName(BlobStart, BlobLen);
+ if (const FileEntry *Umbrella = PP.getFileManager().getFile(FileName)) {
+ if (!CurrentModule->getUmbrellaHeader())
+ ModMap.setUmbrellaHeader(CurrentModule, Umbrella);
+ else if (CurrentModule->getUmbrellaHeader() != Umbrella) {
+ Error("mismatched umbrella headers in submodule");
+ return true;
+ }
+ }
+ break;
+ }
+
+ case SUBMODULE_HEADER: {
+ if (First) {
+ Error("missing submodule metadata record at beginning of block");
+ return true;
+ }
+
+ if (!CurrentModule)
+ break;
+
+ // FIXME: Be more lazy about this!
+ StringRef FileName(BlobStart, BlobLen);
+ if (const FileEntry *File = PP.getFileManager().getFile(FileName)) {
+ if (std::find(CurrentModule->Headers.begin(),
+ CurrentModule->Headers.end(),
+ File) == CurrentModule->Headers.end())
+ ModMap.addHeader(CurrentModule, File, false);
+ }
+ break;
+ }
+
+ case SUBMODULE_EXCLUDED_HEADER: {
+ if (First) {
+ Error("missing submodule metadata record at beginning of block");
+ return true;
+ }
+
+ if (!CurrentModule)
+ break;
+
+ // FIXME: Be more lazy about this!
+ StringRef FileName(BlobStart, BlobLen);
+ if (const FileEntry *File = PP.getFileManager().getFile(FileName)) {
+ if (std::find(CurrentModule->Headers.begin(),
+ CurrentModule->Headers.end(),
+ File) == CurrentModule->Headers.end())
+ ModMap.addHeader(CurrentModule, File, true);
+ }
+ break;
+ }
+
+ case SUBMODULE_TOPHEADER: {
+ if (First) {
+ Error("missing submodule metadata record at beginning of block");
+ return true;
+ }
+
+ if (!CurrentModule)
+ break;
+
+ // FIXME: Be more lazy about this!
+ StringRef FileName(BlobStart, BlobLen);
+ if (const FileEntry *File = PP.getFileManager().getFile(FileName))
+ CurrentModule->TopHeaders.insert(File);
+ break;
+ }
+
+ case SUBMODULE_UMBRELLA_DIR: {
+ if (First) {
+ Error("missing submodule metadata record at beginning of block");
+ return true;
+ }
+
+ if (!CurrentModule)
+ break;
+
+ StringRef DirName(BlobStart, BlobLen);
+ if (const DirectoryEntry *Umbrella
+ = PP.getFileManager().getDirectory(DirName)) {
+ if (!CurrentModule->getUmbrellaDir())
+ ModMap.setUmbrellaDir(CurrentModule, Umbrella);
+ else if (CurrentModule->getUmbrellaDir() != Umbrella) {
+ Error("mismatched umbrella directories in submodule");
+ return true;
+ }
+ }
+ break;
+ }
+
+ case SUBMODULE_METADATA: {
+ if (!First) {
+ Error("submodule metadata record not at beginning of block");
+ return true;
+ }
+ First = false;
+
+ F.BaseSubmoduleID = getTotalNumSubmodules();
+ F.LocalNumSubmodules = Record[0];
+ unsigned LocalBaseSubmoduleID = Record[1];
+ if (F.LocalNumSubmodules > 0) {
+ // Introduce the global -> local mapping for submodules within this
+ // module.
+ GlobalSubmoduleMap.insert(std::make_pair(getTotalNumSubmodules()+1,&F));
+
+ // Introduce the local -> global mapping for submodules within this
+ // module.
+ F.SubmoduleRemap.insertOrReplace(
+ std::make_pair(LocalBaseSubmoduleID,
+ F.BaseSubmoduleID - LocalBaseSubmoduleID));
+
+ SubmodulesLoaded.resize(SubmodulesLoaded.size() + F.LocalNumSubmodules);
+ }
+ break;
+ }
+
+ case SUBMODULE_IMPORTS: {
+ if (First) {
+ Error("missing submodule metadata record at beginning of block");
+ return true;
+ }
+
+ if (!CurrentModule)
+ break;
+
+ for (unsigned Idx = 0; Idx != Record.size(); ++Idx) {
+ UnresolvedModuleImportExport Unresolved;
+ Unresolved.File = &F;
+ Unresolved.Mod = CurrentModule;
+ Unresolved.ID = Record[Idx];
+ Unresolved.IsImport = true;
+ Unresolved.IsWildcard = false;
+ UnresolvedModuleImportExports.push_back(Unresolved);
+ }
+ break;
+ }
+
+ case SUBMODULE_EXPORTS: {
+ if (First) {
+ Error("missing submodule metadata record at beginning of block");
+ return true;
+ }
+
+ if (!CurrentModule)
+ break;
+
+ for (unsigned Idx = 0; Idx + 1 < Record.size(); Idx += 2) {
+ UnresolvedModuleImportExport Unresolved;
+ Unresolved.File = &F;
+ Unresolved.Mod = CurrentModule;
+ Unresolved.ID = Record[Idx];
+ Unresolved.IsImport = false;
+ Unresolved.IsWildcard = Record[Idx + 1];
+ UnresolvedModuleImportExports.push_back(Unresolved);
+ }
+
+ // Once we've loaded the set of exports, there's no reason to keep
+ // the parsed, unresolved exports around.
+ CurrentModule->UnresolvedExports.clear();
+ break;
+ }
+ case SUBMODULE_REQUIRES: {
+ if (First) {
+ Error("missing submodule metadata record at beginning of block");
+ return true;
+ }
+
+ if (!CurrentModule)
+ break;
+
+ CurrentModule->addRequirement(StringRef(BlobStart, BlobLen),
+ Context.getLangOpts(),
+ Context.getTargetInfo());
+ break;
+ }
+ }
+ }
+}
+
+/// \brief Parse the record that corresponds to a LangOptions data
+/// structure.
+///
+/// This routine parses the language options from the AST file and then gives
+/// them to the AST listener if one is set.
+///
+/// \returns true if the listener deems the file unacceptable, false otherwise.
+bool ASTReader::ParseLanguageOptions(const RecordData &Record,
+ bool Complain,
+ ASTReaderListener &Listener) {
+ LangOptions LangOpts;
+ unsigned Idx = 0;
+#define LANGOPT(Name, Bits, Default, Description) \
+ LangOpts.Name = Record[Idx++];
+#define ENUM_LANGOPT(Name, Type, Bits, Default, Description) \
+ LangOpts.set##Name(static_cast<LangOptions::Type>(Record[Idx++]));
+#include "clang/Basic/LangOptions.def"
+
+ ObjCRuntime::Kind runtimeKind = (ObjCRuntime::Kind) Record[Idx++];
+ VersionTuple runtimeVersion = ReadVersionTuple(Record, Idx);
+ LangOpts.ObjCRuntime = ObjCRuntime(runtimeKind, runtimeVersion);
+
+ unsigned Length = Record[Idx++];
+ LangOpts.CurrentModule.assign(Record.begin() + Idx,
+ Record.begin() + Idx + Length);
+ return Listener.ReadLanguageOptions(LangOpts, Complain);
+}
+
+bool ASTReader::ParseTargetOptions(const RecordData &Record,
+ bool Complain,
+ ASTReaderListener &Listener) {
+ unsigned Idx = 0;
+ TargetOptions TargetOpts;
+ TargetOpts.Triple = ReadString(Record, Idx);
+ TargetOpts.CPU = ReadString(Record, Idx);
+ TargetOpts.ABI = ReadString(Record, Idx);
+ TargetOpts.CXXABI = ReadString(Record, Idx);
+ TargetOpts.LinkerVersion = ReadString(Record, Idx);
+ for (unsigned N = Record[Idx++]; N; --N) {
+ TargetOpts.FeaturesAsWritten.push_back(ReadString(Record, Idx));
+ }
+ for (unsigned N = Record[Idx++]; N; --N) {
+ TargetOpts.Features.push_back(ReadString(Record, Idx));
+ }
+
+ return Listener.ReadTargetOptions(TargetOpts, Complain);
+}
+
+bool ASTReader::ParseDiagnosticOptions(const RecordData &Record, bool Complain,
+ ASTReaderListener &Listener) {
+ DiagnosticOptions DiagOpts;
+ unsigned Idx = 0;
+#define DIAGOPT(Name, Bits, Default) DiagOpts.Name = Record[Idx++];
+#define ENUM_DIAGOPT(Name, Type, Bits, Default) \
+ DiagOpts.set##Name(static_cast<Type>(Record[Idx++]));
+#include "clang/Basic/DiagnosticOptions.def"
+
+ for (unsigned N = Record[Idx++]; N; --N) {
+ DiagOpts.Warnings.push_back(ReadString(Record, Idx));
+ }
+
+ return Listener.ReadDiagnosticOptions(DiagOpts, Complain);
+}
+
+bool ASTReader::ParseFileSystemOptions(const RecordData &Record, bool Complain,
+ ASTReaderListener &Listener) {
+ FileSystemOptions FSOpts;
+ unsigned Idx = 0;
+ FSOpts.WorkingDir = ReadString(Record, Idx);
+ return Listener.ReadFileSystemOptions(FSOpts, Complain);
+}
+
+bool ASTReader::ParseHeaderSearchOptions(const RecordData &Record,
+ bool Complain,
+ ASTReaderListener &Listener) {
+ HeaderSearchOptions HSOpts;
+ unsigned Idx = 0;
+ HSOpts.Sysroot = ReadString(Record, Idx);
+
+ // Include entries.
+ for (unsigned N = Record[Idx++]; N; --N) {
+ std::string Path = ReadString(Record, Idx);
+ frontend::IncludeDirGroup Group
+ = static_cast<frontend::IncludeDirGroup>(Record[Idx++]);
+ bool IsUserSupplied = Record[Idx++];
+ bool IsFramework = Record[Idx++];
+ bool IgnoreSysRoot = Record[Idx++];
+ bool IsInternal = Record[Idx++];
+ bool ImplicitExternC = Record[Idx++];
+ HSOpts.UserEntries.push_back(
+ HeaderSearchOptions::Entry(Path, Group, IsUserSupplied, IsFramework,
+ IgnoreSysRoot, IsInternal, ImplicitExternC));
+ }
+
+ // System header prefixes.
+ for (unsigned N = Record[Idx++]; N; --N) {
+ std::string Prefix = ReadString(Record, Idx);
+ bool IsSystemHeader = Record[Idx++];
+ HSOpts.SystemHeaderPrefixes.push_back(
+ HeaderSearchOptions::SystemHeaderPrefix(Prefix, IsSystemHeader));
+ }
+
+ HSOpts.ResourceDir = ReadString(Record, Idx);
+ HSOpts.ModuleCachePath = ReadString(Record, Idx);
+ HSOpts.DisableModuleHash = Record[Idx++];
+ HSOpts.UseBuiltinIncludes = Record[Idx++];
+ HSOpts.UseStandardSystemIncludes = Record[Idx++];
+ HSOpts.UseStandardCXXIncludes = Record[Idx++];
+ HSOpts.UseLibcxx = Record[Idx++];
+
+ return Listener.ReadHeaderSearchOptions(HSOpts, Complain);
+}
+
+bool ASTReader::ParsePreprocessorOptions(const RecordData &Record,
+ bool Complain,
+ ASTReaderListener &Listener,
+ std::string &SuggestedPredefines) {
+ PreprocessorOptions PPOpts;
+ unsigned Idx = 0;
+
+ // Macro definitions/undefs
+ for (unsigned N = Record[Idx++]; N; --N) {
+ std::string Macro = ReadString(Record, Idx);
+ bool IsUndef = Record[Idx++];
+ PPOpts.Macros.push_back(std::make_pair(Macro, IsUndef));
+ }
+
+ // Includes
+ for (unsigned N = Record[Idx++]; N; --N) {
+ PPOpts.Includes.push_back(ReadString(Record, Idx));
+ }
+
+ // Macro Includes
+ for (unsigned N = Record[Idx++]; N; --N) {
+ PPOpts.MacroIncludes.push_back(ReadString(Record, Idx));
+ }
+
+ PPOpts.UsePredefines = Record[Idx++];
+ PPOpts.ImplicitPCHInclude = ReadString(Record, Idx);
+ PPOpts.ImplicitPTHInclude = ReadString(Record, Idx);
+ PPOpts.ObjCXXARCStandardLibrary =
+ static_cast<ObjCXXARCStandardLibraryKind>(Record[Idx++]);
+ SuggestedPredefines.clear();
+ return Listener.ReadPreprocessorOptions(PPOpts, Complain,
+ SuggestedPredefines);
+}
+
+std::pair<ModuleFile *, unsigned>
+ASTReader::getModulePreprocessedEntity(unsigned GlobalIndex) {
+ GlobalPreprocessedEntityMapType::iterator
+ I = GlobalPreprocessedEntityMap.find(GlobalIndex);
+ assert(I != GlobalPreprocessedEntityMap.end() &&
+ "Corrupted global preprocessed entity map");
+ ModuleFile *M = I->second;
+ unsigned LocalIndex = GlobalIndex - M->BasePreprocessedEntityID;
+ return std::make_pair(M, LocalIndex);
+}
+
+std::pair<PreprocessingRecord::iterator, PreprocessingRecord::iterator>
+ASTReader::getModulePreprocessedEntities(ModuleFile &Mod) const {
+ if (PreprocessingRecord *PPRec = PP.getPreprocessingRecord())
+ return PPRec->getIteratorsForLoadedRange(Mod.BasePreprocessedEntityID,
+ Mod.NumPreprocessedEntities);
+
+ return std::make_pair(PreprocessingRecord::iterator(),
+ PreprocessingRecord::iterator());
+}
+
+std::pair<ASTReader::ModuleDeclIterator, ASTReader::ModuleDeclIterator>
+ASTReader::getModuleFileLevelDecls(ModuleFile &Mod) {
+ return std::make_pair(ModuleDeclIterator(this, &Mod, Mod.FileSortedDecls),
+ ModuleDeclIterator(this, &Mod,
+ Mod.FileSortedDecls + Mod.NumFileSortedDecls));
+}
+
+PreprocessedEntity *ASTReader::ReadPreprocessedEntity(unsigned Index) {
+ PreprocessedEntityID PPID = Index+1;
+ std::pair<ModuleFile *, unsigned> PPInfo = getModulePreprocessedEntity(Index);
+ ModuleFile &M = *PPInfo.first;
+ unsigned LocalIndex = PPInfo.second;
+ const PPEntityOffset &PPOffs = M.PreprocessedEntityOffsets[LocalIndex];
+
+ SavedStreamPosition SavedPosition(M.PreprocessorDetailCursor);
+ M.PreprocessorDetailCursor.JumpToBit(PPOffs.BitOffset);
+
+ unsigned Code = M.PreprocessorDetailCursor.ReadCode();
+ switch (Code) {
+ case llvm::bitc::END_BLOCK:
+ return 0;
+
+ case llvm::bitc::ENTER_SUBBLOCK:
+ Error("unexpected subblock record in preprocessor detail block");
+ return 0;
+
+ case llvm::bitc::DEFINE_ABBREV:
+ Error("unexpected abbrevation record in preprocessor detail block");
+ return 0;
+
+ default:
+ break;
+ }
+
+ if (!PP.getPreprocessingRecord()) {
+ Error("no preprocessing record");
+ return 0;
+ }
+
+ // Read the record.
+ SourceRange Range(ReadSourceLocation(M, PPOffs.Begin),
+ ReadSourceLocation(M, PPOffs.End));
+ PreprocessingRecord &PPRec = *PP.getPreprocessingRecord();
+ const char *BlobStart = 0;
+ unsigned BlobLen = 0;
+ RecordData Record;
+ PreprocessorDetailRecordTypes RecType =
+ (PreprocessorDetailRecordTypes)M.PreprocessorDetailCursor.ReadRecord(
+ Code, Record, BlobStart, BlobLen);
+ switch (RecType) {
+ case PPD_MACRO_EXPANSION: {
+ bool isBuiltin = Record[0];
+ IdentifierInfo *Name = 0;
+ MacroDefinition *Def = 0;
+ if (isBuiltin)
+ Name = getLocalIdentifier(M, Record[1]);
+ else {
+ PreprocessedEntityID
+ GlobalID = getGlobalPreprocessedEntityID(M, Record[1]);
+ Def =cast<MacroDefinition>(PPRec.getLoadedPreprocessedEntity(GlobalID-1));
+ }
+
+ MacroExpansion *ME;
+ if (isBuiltin)
+ ME = new (PPRec) MacroExpansion(Name, Range);
+ else
+ ME = new (PPRec) MacroExpansion(Def, Range);
+
+ return ME;
+ }
+
+ case PPD_MACRO_DEFINITION: {
+ // Decode the identifier info and then check again; if the macro is
+ // still defined and associated with the identifier,
+ IdentifierInfo *II = getLocalIdentifier(M, Record[0]);
+ MacroDefinition *MD
+ = new (PPRec) MacroDefinition(II, Range);
+
+ if (DeserializationListener)
+ DeserializationListener->MacroDefinitionRead(PPID, MD);
+
+ return MD;
+ }
+
+ case PPD_INCLUSION_DIRECTIVE: {
+ const char *FullFileNameStart = BlobStart + Record[0];
+ StringRef FullFileName(FullFileNameStart, BlobLen - Record[0]);
+ const FileEntry *File = 0;
+ if (!FullFileName.empty())
+ File = PP.getFileManager().getFile(FullFileName);
+
+ // FIXME: Stable encoding
+ InclusionDirective::InclusionKind Kind
+ = static_cast<InclusionDirective::InclusionKind>(Record[2]);
+ InclusionDirective *ID
+ = new (PPRec) InclusionDirective(PPRec, Kind,
+ StringRef(BlobStart, Record[0]),
+ Record[1], Record[3],
+ File,
+ Range);
+ return ID;
+ }
+ }
+
+ llvm_unreachable("Invalid PreprocessorDetailRecordTypes");
+}
+
+/// \brief \arg SLocMapI points at a chunk of a module that contains no
+/// preprocessed entities or the entities it contains are not the ones we are
+/// looking for. Find the next module that contains entities and return the ID
+/// of the first entry.
+PreprocessedEntityID ASTReader::findNextPreprocessedEntity(
+ GlobalSLocOffsetMapType::const_iterator SLocMapI) const {
+ ++SLocMapI;
+ for (GlobalSLocOffsetMapType::const_iterator
+ EndI = GlobalSLocOffsetMap.end(); SLocMapI != EndI; ++SLocMapI) {
+ ModuleFile &M = *SLocMapI->second;
+ if (M.NumPreprocessedEntities)
+ return M.BasePreprocessedEntityID;
+ }
+
+ return getTotalNumPreprocessedEntities();
+}
+
+namespace {
+
+template <unsigned PPEntityOffset::*PPLoc>
+struct PPEntityComp {
+ const ASTReader &Reader;
+ ModuleFile &M;
+
+ PPEntityComp(const ASTReader &Reader, ModuleFile &M) : Reader(Reader), M(M) { }
+
+ bool operator()(const PPEntityOffset &L, const PPEntityOffset &R) const {
+ SourceLocation LHS = getLoc(L);
+ SourceLocation RHS = getLoc(R);
+ return Reader.getSourceManager().isBeforeInTranslationUnit(LHS, RHS);
+ }
+
+ bool operator()(const PPEntityOffset &L, SourceLocation RHS) const {
+ SourceLocation LHS = getLoc(L);
+ return Reader.getSourceManager().isBeforeInTranslationUnit(LHS, RHS);
+ }
+
+ bool operator()(SourceLocation LHS, const PPEntityOffset &R) const {
+ SourceLocation RHS = getLoc(R);
+ return Reader.getSourceManager().isBeforeInTranslationUnit(LHS, RHS);
+ }
+
+ SourceLocation getLoc(const PPEntityOffset &PPE) const {
+ return Reader.ReadSourceLocation(M, PPE.*PPLoc);
+ }
+};
+
+}
+
+/// \brief Returns the first preprocessed entity ID that ends after \arg BLoc.
+PreprocessedEntityID
+ASTReader::findBeginPreprocessedEntity(SourceLocation BLoc) const {
+ if (SourceMgr.isLocalSourceLocation(BLoc))
+ return getTotalNumPreprocessedEntities();
+
+ GlobalSLocOffsetMapType::const_iterator
+ SLocMapI = GlobalSLocOffsetMap.find(SourceManager::MaxLoadedOffset -
+ BLoc.getOffset());
+ assert(SLocMapI != GlobalSLocOffsetMap.end() &&
+ "Corrupted global sloc offset map");
+
+ if (SLocMapI->second->NumPreprocessedEntities == 0)
+ return findNextPreprocessedEntity(SLocMapI);
+
+ ModuleFile &M = *SLocMapI->second;
+ typedef const PPEntityOffset *pp_iterator;
+ pp_iterator pp_begin = M.PreprocessedEntityOffsets;
+ pp_iterator pp_end = pp_begin + M.NumPreprocessedEntities;
+
+ size_t Count = M.NumPreprocessedEntities;
+ size_t Half;
+ pp_iterator First = pp_begin;
+ pp_iterator PPI;
+
+ // Do a binary search manually instead of using std::lower_bound because
+ // The end locations of entities may be unordered (when a macro expansion
+ // is inside another macro argument), but for this case it is not important
+ // whether we get the first macro expansion or its containing macro.
+ while (Count > 0) {
+ Half = Count/2;
+ PPI = First;
+ std::advance(PPI, Half);
+ if (SourceMgr.isBeforeInTranslationUnit(ReadSourceLocation(M, PPI->End),
+ BLoc)){
+ First = PPI;
+ ++First;
+ Count = Count - Half - 1;
+ } else
+ Count = Half;
+ }
+
+ if (PPI == pp_end)
+ return findNextPreprocessedEntity(SLocMapI);
+
+ return M.BasePreprocessedEntityID + (PPI - pp_begin);
+}
+
+/// \brief Returns the first preprocessed entity ID that begins after \arg ELoc.
+PreprocessedEntityID
+ASTReader::findEndPreprocessedEntity(SourceLocation ELoc) const {
+ if (SourceMgr.isLocalSourceLocation(ELoc))
+ return getTotalNumPreprocessedEntities();
+
+ GlobalSLocOffsetMapType::const_iterator
+ SLocMapI = GlobalSLocOffsetMap.find(SourceManager::MaxLoadedOffset -
+ ELoc.getOffset());
+ assert(SLocMapI != GlobalSLocOffsetMap.end() &&
+ "Corrupted global sloc offset map");
+
+ if (SLocMapI->second->NumPreprocessedEntities == 0)
+ return findNextPreprocessedEntity(SLocMapI);
+
+ ModuleFile &M = *SLocMapI->second;
+ typedef const PPEntityOffset *pp_iterator;
+ pp_iterator pp_begin = M.PreprocessedEntityOffsets;
+ pp_iterator pp_end = pp_begin + M.NumPreprocessedEntities;
+ pp_iterator PPI =
+ std::upper_bound(pp_begin, pp_end, ELoc,
+ PPEntityComp<&PPEntityOffset::Begin>(*this, M));
+
+ if (PPI == pp_end)
+ return findNextPreprocessedEntity(SLocMapI);
+
+ return M.BasePreprocessedEntityID + (PPI - pp_begin);
+}
+
+/// \brief Returns a pair of [Begin, End) indices of preallocated
+/// preprocessed entities that \arg Range encompasses.
+std::pair<unsigned, unsigned>
+ ASTReader::findPreprocessedEntitiesInRange(SourceRange Range) {
+ if (Range.isInvalid())
+ return std::make_pair(0,0);
+ assert(!SourceMgr.isBeforeInTranslationUnit(Range.getEnd(),Range.getBegin()));
+
+ PreprocessedEntityID BeginID = findBeginPreprocessedEntity(Range.getBegin());
+ PreprocessedEntityID EndID = findEndPreprocessedEntity(Range.getEnd());
+ return std::make_pair(BeginID, EndID);
+}
+
+/// \brief Optionally returns true or false if the preallocated preprocessed
+/// entity with index \arg Index came from file \arg FID.
+llvm::Optional<bool> ASTReader::isPreprocessedEntityInFileID(unsigned Index,
+ FileID FID) {
+ if (FID.isInvalid())
+ return false;
+
+ std::pair<ModuleFile *, unsigned> PPInfo = getModulePreprocessedEntity(Index);
+ ModuleFile &M = *PPInfo.first;
+ unsigned LocalIndex = PPInfo.second;
+ const PPEntityOffset &PPOffs = M.PreprocessedEntityOffsets[LocalIndex];
+
+ SourceLocation Loc = ReadSourceLocation(M, PPOffs.Begin);
+ if (Loc.isInvalid())
+ return false;
+
+ if (SourceMgr.isInFileID(SourceMgr.getFileLoc(Loc), FID))
+ return true;
+ else
+ return false;
+}
+
+namespace {
+ /// \brief Visitor used to search for information about a header file.
+ class HeaderFileInfoVisitor {
+ ASTReader &Reader;
+ const FileEntry *FE;
+
+ llvm::Optional<HeaderFileInfo> HFI;
+
+ public:
+ HeaderFileInfoVisitor(ASTReader &Reader, const FileEntry *FE)
+ : Reader(Reader), FE(FE) { }
+
+ static bool visit(ModuleFile &M, void *UserData) {
+ HeaderFileInfoVisitor *This
+ = static_cast<HeaderFileInfoVisitor *>(UserData);
+
+ HeaderFileInfoTrait Trait(This->Reader, M,
+ &This->Reader.getPreprocessor().getHeaderSearchInfo(),
+ M.HeaderFileFrameworkStrings,
+ This->FE->getName());
+
+ HeaderFileInfoLookupTable *Table
+ = static_cast<HeaderFileInfoLookupTable *>(M.HeaderFileInfoTable);
+ if (!Table)
+ return false;
+
+ // Look in the on-disk hash table for an entry for this file name.
+ HeaderFileInfoLookupTable::iterator Pos = Table->find(This->FE->getName(),
+ &Trait);
+ if (Pos == Table->end())
+ return false;
+
+ This->HFI = *Pos;
+ return true;
+ }
+
+ llvm::Optional<HeaderFileInfo> getHeaderFileInfo() const { return HFI; }
+ };
+}
+
+HeaderFileInfo ASTReader::GetHeaderFileInfo(const FileEntry *FE) {
+ HeaderFileInfoVisitor Visitor(*this, FE);
+ ModuleMgr.visit(&HeaderFileInfoVisitor::visit, &Visitor);
+ if (llvm::Optional<HeaderFileInfo> HFI = Visitor.getHeaderFileInfo()) {
+ if (Listener)
+ Listener->ReadHeaderFileInfo(*HFI, FE->getUID());
+ return *HFI;
+ }
+
+ return HeaderFileInfo();
+}
+
+void ASTReader::ReadPragmaDiagnosticMappings(DiagnosticsEngine &Diag) {
+ // FIXME: Make it work properly with modules.
+ llvm::SmallVector<DiagnosticsEngine::DiagState *, 32> DiagStates;
+ for (ModuleIterator I = ModuleMgr.begin(), E = ModuleMgr.end(); I != E; ++I) {
+ ModuleFile &F = *(*I);
+ unsigned Idx = 0;
+ DiagStates.clear();
+ assert(!Diag.DiagStates.empty());
+ DiagStates.push_back(&Diag.DiagStates.front()); // the command-line one.
+ while (Idx < F.PragmaDiagMappings.size()) {
+ SourceLocation Loc = ReadSourceLocation(F, F.PragmaDiagMappings[Idx++]);
+ unsigned DiagStateID = F.PragmaDiagMappings[Idx++];
+ if (DiagStateID != 0) {
+ Diag.DiagStatePoints.push_back(
+ DiagnosticsEngine::DiagStatePoint(DiagStates[DiagStateID-1],
+ FullSourceLoc(Loc, SourceMgr)));
+ continue;
+ }
+
+ assert(DiagStateID == 0);
+ // A new DiagState was created here.
+ Diag.DiagStates.push_back(*Diag.GetCurDiagState());
+ DiagnosticsEngine::DiagState *NewState = &Diag.DiagStates.back();
+ DiagStates.push_back(NewState);
+ Diag.DiagStatePoints.push_back(
+ DiagnosticsEngine::DiagStatePoint(NewState,
+ FullSourceLoc(Loc, SourceMgr)));
+ while (1) {
+ assert(Idx < F.PragmaDiagMappings.size() &&
+ "Invalid data, didn't find '-1' marking end of diag/map pairs");
+ if (Idx >= F.PragmaDiagMappings.size()) {
+ break; // Something is messed up but at least avoid infinite loop in
+ // release build.
+ }
+ unsigned DiagID = F.PragmaDiagMappings[Idx++];
+ if (DiagID == (unsigned)-1) {
+ break; // no more diag/map pairs for this location.
+ }
+ diag::Mapping Map = (diag::Mapping)F.PragmaDiagMappings[Idx++];
+ DiagnosticMappingInfo MappingInfo = Diag.makeMappingInfo(Map, Loc);
+ Diag.GetCurDiagState()->setMappingInfo(DiagID, MappingInfo);
+ }
+ }
+ }
+}
+
+/// \brief Get the correct cursor and offset for loading a type.
+ASTReader::RecordLocation ASTReader::TypeCursorForIndex(unsigned Index) {
+ GlobalTypeMapType::iterator I = GlobalTypeMap.find(Index);
+ assert(I != GlobalTypeMap.end() && "Corrupted global type map");
+ ModuleFile *M = I->second;
+ return RecordLocation(M, M->TypeOffsets[Index - M->BaseTypeIndex]);
+}
+
+/// \brief Read and return the type with the given index..
+///
+/// The index is the type ID, shifted and minus the number of predefs. This
+/// routine actually reads the record corresponding to the type at the given
+/// location. It is a helper routine for GetType, which deals with reading type
+/// IDs.
+QualType ASTReader::readTypeRecord(unsigned Index) {
+ RecordLocation Loc = TypeCursorForIndex(Index);
+ llvm::BitstreamCursor &DeclsCursor = Loc.F->DeclsCursor;
+
+ // Keep track of where we are in the stream, then jump back there
+ // after reading this type.
+ SavedStreamPosition SavedPosition(DeclsCursor);
+
+ ReadingKindTracker ReadingKind(Read_Type, *this);
+
+ // Note that we are loading a type record.
+ Deserializing AType(this);
+
+ unsigned Idx = 0;
+ DeclsCursor.JumpToBit(Loc.Offset);
+ RecordData Record;
+ unsigned Code = DeclsCursor.ReadCode();
+ switch ((TypeCode)DeclsCursor.ReadRecord(Code, Record)) {
+ case TYPE_EXT_QUAL: {
+ if (Record.size() != 2) {
+ Error("Incorrect encoding of extended qualifier type");
+ return QualType();
+ }
+ QualType Base = readType(*Loc.F, Record, Idx);
+ Qualifiers Quals = Qualifiers::fromOpaqueValue(Record[Idx++]);
+ return Context.getQualifiedType(Base, Quals);
+ }
+
+ case TYPE_COMPLEX: {
+ if (Record.size() != 1) {
+ Error("Incorrect encoding of complex type");
+ return QualType();
+ }
+ QualType ElemType = readType(*Loc.F, Record, Idx);
+ return Context.getComplexType(ElemType);
+ }
+
+ case TYPE_POINTER: {
+ if (Record.size() != 1) {
+ Error("Incorrect encoding of pointer type");
+ return QualType();
+ }
+ QualType PointeeType = readType(*Loc.F, Record, Idx);
+ return Context.getPointerType(PointeeType);
+ }
+
+ case TYPE_BLOCK_POINTER: {
+ if (Record.size() != 1) {
+ Error("Incorrect encoding of block pointer type");
+ return QualType();
+ }
+ QualType PointeeType = readType(*Loc.F, Record, Idx);
+ return Context.getBlockPointerType(PointeeType);
+ }
+
+ case TYPE_LVALUE_REFERENCE: {
+ if (Record.size() != 2) {
+ Error("Incorrect encoding of lvalue reference type");
+ return QualType();
+ }
+ QualType PointeeType = readType(*Loc.F, Record, Idx);
+ return Context.getLValueReferenceType(PointeeType, Record[1]);
+ }
+
+ case TYPE_RVALUE_REFERENCE: {
+ if (Record.size() != 1) {
+ Error("Incorrect encoding of rvalue reference type");
+ return QualType();
+ }
+ QualType PointeeType = readType(*Loc.F, Record, Idx);
+ return Context.getRValueReferenceType(PointeeType);
+ }
+
+ case TYPE_MEMBER_POINTER: {
+ if (Record.size() != 2) {
+ Error("Incorrect encoding of member pointer type");
+ return QualType();
+ }
+ QualType PointeeType = readType(*Loc.F, Record, Idx);
+ QualType ClassType = readType(*Loc.F, Record, Idx);
+ if (PointeeType.isNull() || ClassType.isNull())
+ return QualType();
+
+ return Context.getMemberPointerType(PointeeType, ClassType.getTypePtr());
+ }
+
+ case TYPE_CONSTANT_ARRAY: {
+ QualType ElementType = readType(*Loc.F, Record, Idx);
+ ArrayType::ArraySizeModifier ASM = (ArrayType::ArraySizeModifier)Record[1];
+ unsigned IndexTypeQuals = Record[2];
+ unsigned Idx = 3;
+ llvm::APInt Size = ReadAPInt(Record, Idx);
+ return Context.getConstantArrayType(ElementType, Size,
+ ASM, IndexTypeQuals);
+ }
+
+ case TYPE_INCOMPLETE_ARRAY: {
+ QualType ElementType = readType(*Loc.F, Record, Idx);
+ ArrayType::ArraySizeModifier ASM = (ArrayType::ArraySizeModifier)Record[1];
+ unsigned IndexTypeQuals = Record[2];
+ return Context.getIncompleteArrayType(ElementType, ASM, IndexTypeQuals);
+ }
+
+ case TYPE_VARIABLE_ARRAY: {
+ QualType ElementType = readType(*Loc.F, Record, Idx);
+ ArrayType::ArraySizeModifier ASM = (ArrayType::ArraySizeModifier)Record[1];
+ unsigned IndexTypeQuals = Record[2];
+ SourceLocation LBLoc = ReadSourceLocation(*Loc.F, Record[3]);
+ SourceLocation RBLoc = ReadSourceLocation(*Loc.F, Record[4]);
+ return Context.getVariableArrayType(ElementType, ReadExpr(*Loc.F),
+ ASM, IndexTypeQuals,
+ SourceRange(LBLoc, RBLoc));
+ }
+
+ case TYPE_VECTOR: {
+ if (Record.size() != 3) {
+ Error("incorrect encoding of vector type in AST file");
+ return QualType();
+ }
+
+ QualType ElementType = readType(*Loc.F, Record, Idx);
+ unsigned NumElements = Record[1];
+ unsigned VecKind = Record[2];
+ return Context.getVectorType(ElementType, NumElements,
+ (VectorType::VectorKind)VecKind);
+ }
+
+ case TYPE_EXT_VECTOR: {
+ if (Record.size() != 3) {
+ Error("incorrect encoding of extended vector type in AST file");
+ return QualType();
+ }
+
+ QualType ElementType = readType(*Loc.F, Record, Idx);
+ unsigned NumElements = Record[1];
+ return Context.getExtVectorType(ElementType, NumElements);
+ }
+
+ case TYPE_FUNCTION_NO_PROTO: {
+ if (Record.size() != 6) {
+ Error("incorrect encoding of no-proto function type");
+ return QualType();
+ }
+ QualType ResultType = readType(*Loc.F, Record, Idx);
+ FunctionType::ExtInfo Info(Record[1], Record[2], Record[3],
+ (CallingConv)Record[4], Record[5]);
+ return Context.getFunctionNoProtoType(ResultType, Info);
+ }
+
+ case TYPE_FUNCTION_PROTO: {
+ QualType ResultType = readType(*Loc.F, Record, Idx);
+
+ FunctionProtoType::ExtProtoInfo EPI;
+ EPI.ExtInfo = FunctionType::ExtInfo(/*noreturn*/ Record[1],
+ /*hasregparm*/ Record[2],
+ /*regparm*/ Record[3],
+ static_cast<CallingConv>(Record[4]),
+ /*produces*/ Record[5]);
+
+ unsigned Idx = 6;
+ unsigned NumParams = Record[Idx++];
+ SmallVector<QualType, 16> ParamTypes;
+ for (unsigned I = 0; I != NumParams; ++I)
+ ParamTypes.push_back(readType(*Loc.F, Record, Idx));
+
+ EPI.Variadic = Record[Idx++];
+ EPI.HasTrailingReturn = Record[Idx++];
+ EPI.TypeQuals = Record[Idx++];
+ EPI.RefQualifier = static_cast<RefQualifierKind>(Record[Idx++]);
+ ExceptionSpecificationType EST =
+ static_cast<ExceptionSpecificationType>(Record[Idx++]);
+ EPI.ExceptionSpecType = EST;
+ SmallVector<QualType, 2> Exceptions;
+ if (EST == EST_Dynamic) {
+ EPI.NumExceptions = Record[Idx++];
+ for (unsigned I = 0; I != EPI.NumExceptions; ++I)
+ Exceptions.push_back(readType(*Loc.F, Record, Idx));
+ EPI.Exceptions = Exceptions.data();
+ } else if (EST == EST_ComputedNoexcept) {
+ EPI.NoexceptExpr = ReadExpr(*Loc.F);
+ } else if (EST == EST_Uninstantiated) {
+ EPI.ExceptionSpecDecl = ReadDeclAs<FunctionDecl>(*Loc.F, Record, Idx);
+ EPI.ExceptionSpecTemplate = ReadDeclAs<FunctionDecl>(*Loc.F, Record, Idx);
+ } else if (EST == EST_Unevaluated) {
+ EPI.ExceptionSpecDecl = ReadDeclAs<FunctionDecl>(*Loc.F, Record, Idx);
+ }
+ return Context.getFunctionType(ResultType, ParamTypes.data(), NumParams,
+ EPI);
+ }
+
+ case TYPE_UNRESOLVED_USING: {
+ unsigned Idx = 0;
+ return Context.getTypeDeclType(
+ ReadDeclAs<UnresolvedUsingTypenameDecl>(*Loc.F, Record, Idx));
+ }
+
+ case TYPE_TYPEDEF: {
+ if (Record.size() != 2) {
+ Error("incorrect encoding of typedef type");
+ return QualType();
+ }
+ unsigned Idx = 0;
+ TypedefNameDecl *Decl = ReadDeclAs<TypedefNameDecl>(*Loc.F, Record, Idx);
+ QualType Canonical = readType(*Loc.F, Record, Idx);
+ if (!Canonical.isNull())
+ Canonical = Context.getCanonicalType(Canonical);
+ return Context.getTypedefType(Decl, Canonical);
+ }
+
+ case TYPE_TYPEOF_EXPR:
+ return Context.getTypeOfExprType(ReadExpr(*Loc.F));
+
+ case TYPE_TYPEOF: {
+ if (Record.size() != 1) {
+ Error("incorrect encoding of typeof(type) in AST file");
+ return QualType();
+ }
+ QualType UnderlyingType = readType(*Loc.F, Record, Idx);
+ return Context.getTypeOfType(UnderlyingType);
+ }
+
+ case TYPE_DECLTYPE: {
+ QualType UnderlyingType = readType(*Loc.F, Record, Idx);
+ return Context.getDecltypeType(ReadExpr(*Loc.F), UnderlyingType);
+ }
+
+ case TYPE_UNARY_TRANSFORM: {
+ QualType BaseType = readType(*Loc.F, Record, Idx);
+ QualType UnderlyingType = readType(*Loc.F, Record, Idx);
+ UnaryTransformType::UTTKind UKind = (UnaryTransformType::UTTKind)Record[2];
+ return Context.getUnaryTransformType(BaseType, UnderlyingType, UKind);
+ }
+
+ case TYPE_AUTO:
+ return Context.getAutoType(readType(*Loc.F, Record, Idx));
+
+ case TYPE_RECORD: {
+ if (Record.size() != 2) {
+ Error("incorrect encoding of record type");
+ return QualType();
+ }
+ unsigned Idx = 0;
+ bool IsDependent = Record[Idx++];
+ RecordDecl *RD = ReadDeclAs<RecordDecl>(*Loc.F, Record, Idx);
+ RD = cast_or_null<RecordDecl>(RD->getCanonicalDecl());
+ QualType T = Context.getRecordType(RD);
+ const_cast<Type*>(T.getTypePtr())->setDependent(IsDependent);
+ return T;
+ }
+
+ case TYPE_ENUM: {
+ if (Record.size() != 2) {
+ Error("incorrect encoding of enum type");
+ return QualType();
+ }
+ unsigned Idx = 0;
+ bool IsDependent = Record[Idx++];
+ QualType T
+ = Context.getEnumType(ReadDeclAs<EnumDecl>(*Loc.F, Record, Idx));
+ const_cast<Type*>(T.getTypePtr())->setDependent(IsDependent);
+ return T;
+ }
+
+ case TYPE_ATTRIBUTED: {
+ if (Record.size() != 3) {
+ Error("incorrect encoding of attributed type");
+ return QualType();
+ }
+ QualType modifiedType = readType(*Loc.F, Record, Idx);
+ QualType equivalentType = readType(*Loc.F, Record, Idx);
+ AttributedType::Kind kind = static_cast<AttributedType::Kind>(Record[2]);
+ return Context.getAttributedType(kind, modifiedType, equivalentType);
+ }
+
+ case TYPE_PAREN: {
+ if (Record.size() != 1) {
+ Error("incorrect encoding of paren type");
+ return QualType();
+ }
+ QualType InnerType = readType(*Loc.F, Record, Idx);
+ return Context.getParenType(InnerType);
+ }
+
+ case TYPE_PACK_EXPANSION: {
+ if (Record.size() != 2) {
+ Error("incorrect encoding of pack expansion type");
+ return QualType();
+ }
+ QualType Pattern = readType(*Loc.F, Record, Idx);
+ if (Pattern.isNull())
+ return QualType();
+ llvm::Optional<unsigned> NumExpansions;
+ if (Record[1])
+ NumExpansions = Record[1] - 1;
+ return Context.getPackExpansionType(Pattern, NumExpansions);
+ }
+
+ case TYPE_ELABORATED: {
+ unsigned Idx = 0;
+ ElaboratedTypeKeyword Keyword = (ElaboratedTypeKeyword)Record[Idx++];
+ NestedNameSpecifier *NNS = ReadNestedNameSpecifier(*Loc.F, Record, Idx);
+ QualType NamedType = readType(*Loc.F, Record, Idx);
+ return Context.getElaboratedType(Keyword, NNS, NamedType);
+ }
+
+ case TYPE_OBJC_INTERFACE: {
+ unsigned Idx = 0;
+ ObjCInterfaceDecl *ItfD
+ = ReadDeclAs<ObjCInterfaceDecl>(*Loc.F, Record, Idx);
+ return Context.getObjCInterfaceType(ItfD->getCanonicalDecl());
+ }
+
+ case TYPE_OBJC_OBJECT: {
+ unsigned Idx = 0;
+ QualType Base = readType(*Loc.F, Record, Idx);
+ unsigned NumProtos = Record[Idx++];
+ SmallVector<ObjCProtocolDecl*, 4> Protos;
+ for (unsigned I = 0; I != NumProtos; ++I)
+ Protos.push_back(ReadDeclAs<ObjCProtocolDecl>(*Loc.F, Record, Idx));
+ return Context.getObjCObjectType(Base, Protos.data(), NumProtos);
+ }
+
+ case TYPE_OBJC_OBJECT_POINTER: {
+ unsigned Idx = 0;
+ QualType Pointee = readType(*Loc.F, Record, Idx);
+ return Context.getObjCObjectPointerType(Pointee);
+ }
+
+ case TYPE_SUBST_TEMPLATE_TYPE_PARM: {
+ unsigned Idx = 0;
+ QualType Parm = readType(*Loc.F, Record, Idx);
+ QualType Replacement = readType(*Loc.F, Record, Idx);
+ return
+ Context.getSubstTemplateTypeParmType(cast<TemplateTypeParmType>(Parm),
+ Replacement);
+ }
+
+ case TYPE_SUBST_TEMPLATE_TYPE_PARM_PACK: {
+ unsigned Idx = 0;
+ QualType Parm = readType(*Loc.F, Record, Idx);
+ TemplateArgument ArgPack = ReadTemplateArgument(*Loc.F, Record, Idx);
+ return Context.getSubstTemplateTypeParmPackType(
+ cast<TemplateTypeParmType>(Parm),
+ ArgPack);
+ }
+
+ case TYPE_INJECTED_CLASS_NAME: {
+ CXXRecordDecl *D = ReadDeclAs<CXXRecordDecl>(*Loc.F, Record, Idx);
+ QualType TST = readType(*Loc.F, Record, Idx); // probably derivable
+ // FIXME: ASTContext::getInjectedClassNameType is not currently suitable
+ // for AST reading, too much interdependencies.
+ return
+ QualType(new (Context, TypeAlignment) InjectedClassNameType(D, TST), 0);
+ }
+
+ case TYPE_TEMPLATE_TYPE_PARM: {
+ unsigned Idx = 0;
+ unsigned Depth = Record[Idx++];
+ unsigned Index = Record[Idx++];
+ bool Pack = Record[Idx++];
+ TemplateTypeParmDecl *D
+ = ReadDeclAs<TemplateTypeParmDecl>(*Loc.F, Record, Idx);
+ return Context.getTemplateTypeParmType(Depth, Index, Pack, D);
+ }
+
+ case TYPE_DEPENDENT_NAME: {
+ unsigned Idx = 0;
+ ElaboratedTypeKeyword Keyword = (ElaboratedTypeKeyword)Record[Idx++];
+ NestedNameSpecifier *NNS = ReadNestedNameSpecifier(*Loc.F, Record, Idx);
+ const IdentifierInfo *Name = this->GetIdentifierInfo(*Loc.F, Record, Idx);
+ QualType Canon = readType(*Loc.F, Record, Idx);
+ if (!Canon.isNull())
+ Canon = Context.getCanonicalType(Canon);
+ return Context.getDependentNameType(Keyword, NNS, Name, Canon);
+ }
+
+ case TYPE_DEPENDENT_TEMPLATE_SPECIALIZATION: {
+ unsigned Idx = 0;
+ ElaboratedTypeKeyword Keyword = (ElaboratedTypeKeyword)Record[Idx++];
+ NestedNameSpecifier *NNS = ReadNestedNameSpecifier(*Loc.F, Record, Idx);
+ const IdentifierInfo *Name = this->GetIdentifierInfo(*Loc.F, Record, Idx);
+ unsigned NumArgs = Record[Idx++];
+ SmallVector<TemplateArgument, 8> Args;
+ Args.reserve(NumArgs);
+ while (NumArgs--)
+ Args.push_back(ReadTemplateArgument(*Loc.F, Record, Idx));
+ return Context.getDependentTemplateSpecializationType(Keyword, NNS, Name,
+ Args.size(), Args.data());
+ }
+
+ case TYPE_DEPENDENT_SIZED_ARRAY: {
+ unsigned Idx = 0;
+
+ // ArrayType
+ QualType ElementType = readType(*Loc.F, Record, Idx);
+ ArrayType::ArraySizeModifier ASM
+ = (ArrayType::ArraySizeModifier)Record[Idx++];
+ unsigned IndexTypeQuals = Record[Idx++];
+
+ // DependentSizedArrayType
+ Expr *NumElts = ReadExpr(*Loc.F);
+ SourceRange Brackets = ReadSourceRange(*Loc.F, Record, Idx);
+
+ return Context.getDependentSizedArrayType(ElementType, NumElts, ASM,
+ IndexTypeQuals, Brackets);
+ }
+
+ case TYPE_TEMPLATE_SPECIALIZATION: {
+ unsigned Idx = 0;
+ bool IsDependent = Record[Idx++];
+ TemplateName Name = ReadTemplateName(*Loc.F, Record, Idx);
+ SmallVector<TemplateArgument, 8> Args;
+ ReadTemplateArgumentList(Args, *Loc.F, Record, Idx);
+ QualType Underlying = readType(*Loc.F, Record, Idx);
+ QualType T;
+ if (Underlying.isNull())
+ T = Context.getCanonicalTemplateSpecializationType(Name, Args.data(),
+ Args.size());
+ else
+ T = Context.getTemplateSpecializationType(Name, Args.data(),
+ Args.size(), Underlying);
+ const_cast<Type*>(T.getTypePtr())->setDependent(IsDependent);
+ return T;
+ }
+
+ case TYPE_ATOMIC: {
+ if (Record.size() != 1) {
+ Error("Incorrect encoding of atomic type");
+ return QualType();
+ }
+ QualType ValueType = readType(*Loc.F, Record, Idx);
+ return Context.getAtomicType(ValueType);
+ }
+ }
+ llvm_unreachable("Invalid TypeCode!");
+}
+
+class clang::TypeLocReader : public TypeLocVisitor<TypeLocReader> {
+ ASTReader &Reader;
+ ModuleFile &F;
+ const ASTReader::RecordData &Record;
+ unsigned &Idx;
+
+ SourceLocation ReadSourceLocation(const ASTReader::RecordData &R,
+ unsigned &I) {
+ return Reader.ReadSourceLocation(F, R, I);
+ }
+
+ template<typename T>
+ T *ReadDeclAs(const ASTReader::RecordData &Record, unsigned &Idx) {
+ return Reader.ReadDeclAs<T>(F, Record, Idx);
+ }
+
+public:
+ TypeLocReader(ASTReader &Reader, ModuleFile &F,
+ const ASTReader::RecordData &Record, unsigned &Idx)
+ : Reader(Reader), F(F), Record(Record), Idx(Idx)
+ { }
+
+ // We want compile-time assurance that we've enumerated all of
+ // these, so unfortunately we have to declare them first, then
+ // define them out-of-line.
+#define ABSTRACT_TYPELOC(CLASS, PARENT)
+#define TYPELOC(CLASS, PARENT) \
+ void Visit##CLASS##TypeLoc(CLASS##TypeLoc TyLoc);
+#include "clang/AST/TypeLocNodes.def"
+
+ void VisitFunctionTypeLoc(FunctionTypeLoc);
+ void VisitArrayTypeLoc(ArrayTypeLoc);
+};
+
+void TypeLocReader::VisitQualifiedTypeLoc(QualifiedTypeLoc TL) {
+ // nothing to do
+}
+void TypeLocReader::VisitBuiltinTypeLoc(BuiltinTypeLoc TL) {
+ TL.setBuiltinLoc(ReadSourceLocation(Record, Idx));
+ if (TL.needsExtraLocalData()) {
+ TL.setWrittenTypeSpec(static_cast<DeclSpec::TST>(Record[Idx++]));
+ TL.setWrittenSignSpec(static_cast<DeclSpec::TSS>(Record[Idx++]));
+ TL.setWrittenWidthSpec(static_cast<DeclSpec::TSW>(Record[Idx++]));
+ TL.setModeAttr(Record[Idx++]);
+ }
+}
+void TypeLocReader::VisitComplexTypeLoc(ComplexTypeLoc TL) {
+ TL.setNameLoc(ReadSourceLocation(Record, Idx));
+}
+void TypeLocReader::VisitPointerTypeLoc(PointerTypeLoc TL) {
+ TL.setStarLoc(ReadSourceLocation(Record, Idx));
+}
+void TypeLocReader::VisitBlockPointerTypeLoc(BlockPointerTypeLoc TL) {
+ TL.setCaretLoc(ReadSourceLocation(Record, Idx));
+}
+void TypeLocReader::VisitLValueReferenceTypeLoc(LValueReferenceTypeLoc TL) {
+ TL.setAmpLoc(ReadSourceLocation(Record, Idx));
+}
+void TypeLocReader::VisitRValueReferenceTypeLoc(RValueReferenceTypeLoc TL) {
+ TL.setAmpAmpLoc(ReadSourceLocation(Record, Idx));
+}
+void TypeLocReader::VisitMemberPointerTypeLoc(MemberPointerTypeLoc TL) {
+ TL.setStarLoc(ReadSourceLocation(Record, Idx));
+ TL.setClassTInfo(Reader.GetTypeSourceInfo(F, Record, Idx));
+}
+void TypeLocReader::VisitArrayTypeLoc(ArrayTypeLoc TL) {
+ TL.setLBracketLoc(ReadSourceLocation(Record, Idx));
+ TL.setRBracketLoc(ReadSourceLocation(Record, Idx));
+ if (Record[Idx++])
+ TL.setSizeExpr(Reader.ReadExpr(F));
+ else
+ TL.setSizeExpr(0);
+}
+void TypeLocReader::VisitConstantArrayTypeLoc(ConstantArrayTypeLoc TL) {
+ VisitArrayTypeLoc(TL);
+}
+void TypeLocReader::VisitIncompleteArrayTypeLoc(IncompleteArrayTypeLoc TL) {
+ VisitArrayTypeLoc(TL);
+}
+void TypeLocReader::VisitVariableArrayTypeLoc(VariableArrayTypeLoc TL) {
+ VisitArrayTypeLoc(TL);
+}
+void TypeLocReader::VisitDependentSizedArrayTypeLoc(
+ DependentSizedArrayTypeLoc TL) {
+ VisitArrayTypeLoc(TL);
+}
+void TypeLocReader::VisitDependentSizedExtVectorTypeLoc(
+ DependentSizedExtVectorTypeLoc TL) {
+ TL.setNameLoc(ReadSourceLocation(Record, Idx));
+}
+void TypeLocReader::VisitVectorTypeLoc(VectorTypeLoc TL) {
+ TL.setNameLoc(ReadSourceLocation(Record, Idx));
+}
+void TypeLocReader::VisitExtVectorTypeLoc(ExtVectorTypeLoc TL) {
+ TL.setNameLoc(ReadSourceLocation(Record, Idx));
+}
+void TypeLocReader::VisitFunctionTypeLoc(FunctionTypeLoc TL) {
+ TL.setLocalRangeBegin(ReadSourceLocation(Record, Idx));
+ TL.setLParenLoc(ReadSourceLocation(Record, Idx));
+ TL.setRParenLoc(ReadSourceLocation(Record, Idx));
+ TL.setLocalRangeEnd(ReadSourceLocation(Record, Idx));
+ for (unsigned i = 0, e = TL.getNumArgs(); i != e; ++i) {
+ TL.setArg(i, ReadDeclAs<ParmVarDecl>(Record, Idx));
+ }
+}
+void TypeLocReader::VisitFunctionProtoTypeLoc(FunctionProtoTypeLoc TL) {
+ VisitFunctionTypeLoc(TL);
+}
+void TypeLocReader::VisitFunctionNoProtoTypeLoc(FunctionNoProtoTypeLoc TL) {
+ VisitFunctionTypeLoc(TL);
+}
+void TypeLocReader::VisitUnresolvedUsingTypeLoc(UnresolvedUsingTypeLoc TL) {
+ TL.setNameLoc(ReadSourceLocation(Record, Idx));
+}
+void TypeLocReader::VisitTypedefTypeLoc(TypedefTypeLoc TL) {
+ TL.setNameLoc(ReadSourceLocation(Record, Idx));
+}
+void TypeLocReader::VisitTypeOfExprTypeLoc(TypeOfExprTypeLoc TL) {
+ TL.setTypeofLoc(ReadSourceLocation(Record, Idx));
+ TL.setLParenLoc(ReadSourceLocation(Record, Idx));
+ TL.setRParenLoc(ReadSourceLocation(Record, Idx));
+}
+void TypeLocReader::VisitTypeOfTypeLoc(TypeOfTypeLoc TL) {
+ TL.setTypeofLoc(ReadSourceLocation(Record, Idx));
+ TL.setLParenLoc(ReadSourceLocation(Record, Idx));
+ TL.setRParenLoc(ReadSourceLocation(Record, Idx));
+ TL.setUnderlyingTInfo(Reader.GetTypeSourceInfo(F, Record, Idx));
+}
+void TypeLocReader::VisitDecltypeTypeLoc(DecltypeTypeLoc TL) {
+ TL.setNameLoc(ReadSourceLocation(Record, Idx));
+}
+void TypeLocReader::VisitUnaryTransformTypeLoc(UnaryTransformTypeLoc TL) {
+ TL.setKWLoc(ReadSourceLocation(Record, Idx));
+ TL.setLParenLoc(ReadSourceLocation(Record, Idx));
+ TL.setRParenLoc(ReadSourceLocation(Record, Idx));
+ TL.setUnderlyingTInfo(Reader.GetTypeSourceInfo(F, Record, Idx));
+}
+void TypeLocReader::VisitAutoTypeLoc(AutoTypeLoc TL) {
+ TL.setNameLoc(ReadSourceLocation(Record, Idx));
+}
+void TypeLocReader::VisitRecordTypeLoc(RecordTypeLoc TL) {
+ TL.setNameLoc(ReadSourceLocation(Record, Idx));
+}
+void TypeLocReader::VisitEnumTypeLoc(EnumTypeLoc TL) {
+ TL.setNameLoc(ReadSourceLocation(Record, Idx));
+}
+void TypeLocReader::VisitAttributedTypeLoc(AttributedTypeLoc TL) {
+ TL.setAttrNameLoc(ReadSourceLocation(Record, Idx));
+ if (TL.hasAttrOperand()) {
+ SourceRange range;
+ range.setBegin(ReadSourceLocation(Record, Idx));
+ range.setEnd(ReadSourceLocation(Record, Idx));
+ TL.setAttrOperandParensRange(range);
+ }
+ if (TL.hasAttrExprOperand()) {
+ if (Record[Idx++])
+ TL.setAttrExprOperand(Reader.ReadExpr(F));
+ else
+ TL.setAttrExprOperand(0);
+ } else if (TL.hasAttrEnumOperand())
+ TL.setAttrEnumOperandLoc(ReadSourceLocation(Record, Idx));
+}
+void TypeLocReader::VisitTemplateTypeParmTypeLoc(TemplateTypeParmTypeLoc TL) {
+ TL.setNameLoc(ReadSourceLocation(Record, Idx));
+}
+void TypeLocReader::VisitSubstTemplateTypeParmTypeLoc(
+ SubstTemplateTypeParmTypeLoc TL) {
+ TL.setNameLoc(ReadSourceLocation(Record, Idx));
+}
+void TypeLocReader::VisitSubstTemplateTypeParmPackTypeLoc(
+ SubstTemplateTypeParmPackTypeLoc TL) {
+ TL.setNameLoc(ReadSourceLocation(Record, Idx));
+}
+void TypeLocReader::VisitTemplateSpecializationTypeLoc(
+ TemplateSpecializationTypeLoc TL) {
+ TL.setTemplateKeywordLoc(ReadSourceLocation(Record, Idx));
+ TL.setTemplateNameLoc(ReadSourceLocation(Record, Idx));
+ TL.setLAngleLoc(ReadSourceLocation(Record, Idx));
+ TL.setRAngleLoc(ReadSourceLocation(Record, Idx));
+ for (unsigned i = 0, e = TL.getNumArgs(); i != e; ++i)
+ TL.setArgLocInfo(i,
+ Reader.GetTemplateArgumentLocInfo(F,
+ TL.getTypePtr()->getArg(i).getKind(),
+ Record, Idx));
+}
+void TypeLocReader::VisitParenTypeLoc(ParenTypeLoc TL) {
+ TL.setLParenLoc(ReadSourceLocation(Record, Idx));
+ TL.setRParenLoc(ReadSourceLocation(Record, Idx));
+}
+void TypeLocReader::VisitElaboratedTypeLoc(ElaboratedTypeLoc TL) {
+ TL.setElaboratedKeywordLoc(ReadSourceLocation(Record, Idx));
+ TL.setQualifierLoc(Reader.ReadNestedNameSpecifierLoc(F, Record, Idx));
+}
+void TypeLocReader::VisitInjectedClassNameTypeLoc(InjectedClassNameTypeLoc TL) {
+ TL.setNameLoc(ReadSourceLocation(Record, Idx));
+}
+void TypeLocReader::VisitDependentNameTypeLoc(DependentNameTypeLoc TL) {
+ TL.setElaboratedKeywordLoc(ReadSourceLocation(Record, Idx));
+ TL.setQualifierLoc(Reader.ReadNestedNameSpecifierLoc(F, Record, Idx));
+ TL.setNameLoc(ReadSourceLocation(Record, Idx));
+}
+void TypeLocReader::VisitDependentTemplateSpecializationTypeLoc(
+ DependentTemplateSpecializationTypeLoc TL) {
+ TL.setElaboratedKeywordLoc(ReadSourceLocation(Record, Idx));
+ TL.setQualifierLoc(Reader.ReadNestedNameSpecifierLoc(F, Record, Idx));
+ TL.setTemplateKeywordLoc(ReadSourceLocation(Record, Idx));
+ TL.setTemplateNameLoc(ReadSourceLocation(Record, Idx));
+ TL.setLAngleLoc(ReadSourceLocation(Record, Idx));
+ TL.setRAngleLoc(ReadSourceLocation(Record, Idx));
+ for (unsigned I = 0, E = TL.getNumArgs(); I != E; ++I)
+ TL.setArgLocInfo(I,
+ Reader.GetTemplateArgumentLocInfo(F,
+ TL.getTypePtr()->getArg(I).getKind(),
+ Record, Idx));
+}
+void TypeLocReader::VisitPackExpansionTypeLoc(PackExpansionTypeLoc TL) {
+ TL.setEllipsisLoc(ReadSourceLocation(Record, Idx));
+}
+void TypeLocReader::VisitObjCInterfaceTypeLoc(ObjCInterfaceTypeLoc TL) {
+ TL.setNameLoc(ReadSourceLocation(Record, Idx));
+}
+void TypeLocReader::VisitObjCObjectTypeLoc(ObjCObjectTypeLoc TL) {
+ TL.setHasBaseTypeAsWritten(Record[Idx++]);
+ TL.setLAngleLoc(ReadSourceLocation(Record, Idx));
+ TL.setRAngleLoc(ReadSourceLocation(Record, Idx));
+ for (unsigned i = 0, e = TL.getNumProtocols(); i != e; ++i)
+ TL.setProtocolLoc(i, ReadSourceLocation(Record, Idx));
+}
+void TypeLocReader::VisitObjCObjectPointerTypeLoc(ObjCObjectPointerTypeLoc TL) {
+ TL.setStarLoc(ReadSourceLocation(Record, Idx));
+}
+void TypeLocReader::VisitAtomicTypeLoc(AtomicTypeLoc TL) {
+ TL.setKWLoc(ReadSourceLocation(Record, Idx));
+ TL.setLParenLoc(ReadSourceLocation(Record, Idx));
+ TL.setRParenLoc(ReadSourceLocation(Record, Idx));
+}
+
+TypeSourceInfo *ASTReader::GetTypeSourceInfo(ModuleFile &F,
+ const RecordData &Record,
+ unsigned &Idx) {
+ QualType InfoTy = readType(F, Record, Idx);
+ if (InfoTy.isNull())
+ return 0;
+
+ TypeSourceInfo *TInfo = getContext().CreateTypeSourceInfo(InfoTy);
+ TypeLocReader TLR(*this, F, Record, Idx);
+ for (TypeLoc TL = TInfo->getTypeLoc(); !TL.isNull(); TL = TL.getNextTypeLoc())
+ TLR.Visit(TL);
+ return TInfo;
+}
+
+QualType ASTReader::GetType(TypeID ID) {
+ unsigned FastQuals = ID & Qualifiers::FastMask;
+ unsigned Index = ID >> Qualifiers::FastWidth;
+
+ if (Index < NUM_PREDEF_TYPE_IDS) {
+ QualType T;
+ switch ((PredefinedTypeIDs)Index) {
+ case PREDEF_TYPE_NULL_ID: return QualType();
+ case PREDEF_TYPE_VOID_ID: T = Context.VoidTy; break;
+ case PREDEF_TYPE_BOOL_ID: T = Context.BoolTy; break;
+
+ case PREDEF_TYPE_CHAR_U_ID:
+ case PREDEF_TYPE_CHAR_S_ID:
+ // FIXME: Check that the signedness of CharTy is correct!
+ T = Context.CharTy;
+ break;
+
+ case PREDEF_TYPE_UCHAR_ID: T = Context.UnsignedCharTy; break;
+ case PREDEF_TYPE_USHORT_ID: T = Context.UnsignedShortTy; break;
+ case PREDEF_TYPE_UINT_ID: T = Context.UnsignedIntTy; break;
+ case PREDEF_TYPE_ULONG_ID: T = Context.UnsignedLongTy; break;
+ case PREDEF_TYPE_ULONGLONG_ID: T = Context.UnsignedLongLongTy; break;
+ case PREDEF_TYPE_UINT128_ID: T = Context.UnsignedInt128Ty; break;
+ case PREDEF_TYPE_SCHAR_ID: T = Context.SignedCharTy; break;
+ case PREDEF_TYPE_WCHAR_ID: T = Context.WCharTy; break;
+ case PREDEF_TYPE_SHORT_ID: T = Context.ShortTy; break;
+ case PREDEF_TYPE_INT_ID: T = Context.IntTy; break;
+ case PREDEF_TYPE_LONG_ID: T = Context.LongTy; break;
+ case PREDEF_TYPE_LONGLONG_ID: T = Context.LongLongTy; break;
+ case PREDEF_TYPE_INT128_ID: T = Context.Int128Ty; break;
+ case PREDEF_TYPE_HALF_ID: T = Context.HalfTy; break;
+ case PREDEF_TYPE_FLOAT_ID: T = Context.FloatTy; break;
+ case PREDEF_TYPE_DOUBLE_ID: T = Context.DoubleTy; break;
+ case PREDEF_TYPE_LONGDOUBLE_ID: T = Context.LongDoubleTy; break;
+ case PREDEF_TYPE_OVERLOAD_ID: T = Context.OverloadTy; break;
+ case PREDEF_TYPE_BOUND_MEMBER: T = Context.BoundMemberTy; break;
+ case PREDEF_TYPE_PSEUDO_OBJECT: T = Context.PseudoObjectTy; break;
+ case PREDEF_TYPE_DEPENDENT_ID: T = Context.DependentTy; break;
+ case PREDEF_TYPE_UNKNOWN_ANY: T = Context.UnknownAnyTy; break;
+ case PREDEF_TYPE_NULLPTR_ID: T = Context.NullPtrTy; break;
+ case PREDEF_TYPE_CHAR16_ID: T = Context.Char16Ty; break;
+ case PREDEF_TYPE_CHAR32_ID: T = Context.Char32Ty; break;
+ case PREDEF_TYPE_OBJC_ID: T = Context.ObjCBuiltinIdTy; break;
+ case PREDEF_TYPE_OBJC_CLASS: T = Context.ObjCBuiltinClassTy; break;
+ case PREDEF_TYPE_OBJC_SEL: T = Context.ObjCBuiltinSelTy; break;
+ case PREDEF_TYPE_IMAGE1D_ID: T = Context.OCLImage1dTy; break;
+ case PREDEF_TYPE_IMAGE1D_ARR_ID: T = Context.OCLImage1dArrayTy; break;
+ case PREDEF_TYPE_IMAGE1D_BUFF_ID: T = Context.OCLImage1dBufferTy; break;
+ case PREDEF_TYPE_IMAGE2D_ID: T = Context.OCLImage2dTy; break;
+ case PREDEF_TYPE_IMAGE2D_ARR_ID: T = Context.OCLImage2dArrayTy; break;
+ case PREDEF_TYPE_IMAGE3D_ID: T = Context.OCLImage3dTy; break;
+ case PREDEF_TYPE_AUTO_DEDUCT: T = Context.getAutoDeductType(); break;
+
+ case PREDEF_TYPE_AUTO_RREF_DEDUCT:
+ T = Context.getAutoRRefDeductType();
+ break;
+
+ case PREDEF_TYPE_ARC_UNBRIDGED_CAST:
+ T = Context.ARCUnbridgedCastTy;
+ break;
+
+ case PREDEF_TYPE_VA_LIST_TAG:
+ T = Context.getVaListTagType();
+ break;
+
+ case PREDEF_TYPE_BUILTIN_FN:
+ T = Context.BuiltinFnTy;
+ break;
+ }
+
+ assert(!T.isNull() && "Unknown predefined type");
+ return T.withFastQualifiers(FastQuals);
+ }
+
+ Index -= NUM_PREDEF_TYPE_IDS;
+ assert(Index < TypesLoaded.size() && "Type index out-of-range");
+ if (TypesLoaded[Index].isNull()) {
+ TypesLoaded[Index] = readTypeRecord(Index);
+ if (TypesLoaded[Index].isNull())
+ return QualType();
+
+ TypesLoaded[Index]->setFromAST();
+ if (DeserializationListener)
+ DeserializationListener->TypeRead(TypeIdx::fromTypeID(ID),
+ TypesLoaded[Index]);
+ }
+
+ return TypesLoaded[Index].withFastQualifiers(FastQuals);
+}
+
+QualType ASTReader::getLocalType(ModuleFile &F, unsigned LocalID) {
+ return GetType(getGlobalTypeID(F, LocalID));
+}
+
+serialization::TypeID
+ASTReader::getGlobalTypeID(ModuleFile &F, unsigned LocalID) const {
+ unsigned FastQuals = LocalID & Qualifiers::FastMask;
+ unsigned LocalIndex = LocalID >> Qualifiers::FastWidth;
+
+ if (LocalIndex < NUM_PREDEF_TYPE_IDS)
+ return LocalID;
+
+ ContinuousRangeMap<uint32_t, int, 2>::iterator I
+ = F.TypeRemap.find(LocalIndex - NUM_PREDEF_TYPE_IDS);
+ assert(I != F.TypeRemap.end() && "Invalid index into type index remap");
+
+ unsigned GlobalIndex = LocalIndex + I->second;
+ return (GlobalIndex << Qualifiers::FastWidth) | FastQuals;
+}
+
+TemplateArgumentLocInfo
+ASTReader::GetTemplateArgumentLocInfo(ModuleFile &F,
+ TemplateArgument::ArgKind Kind,
+ const RecordData &Record,
+ unsigned &Index) {
+ switch (Kind) {
+ case TemplateArgument::Expression:
+ return ReadExpr(F);
+ case TemplateArgument::Type:
+ return GetTypeSourceInfo(F, Record, Index);
+ case TemplateArgument::Template: {
+ NestedNameSpecifierLoc QualifierLoc = ReadNestedNameSpecifierLoc(F, Record,
+ Index);
+ SourceLocation TemplateNameLoc = ReadSourceLocation(F, Record, Index);
+ return TemplateArgumentLocInfo(QualifierLoc, TemplateNameLoc,
+ SourceLocation());
+ }
+ case TemplateArgument::TemplateExpansion: {
+ NestedNameSpecifierLoc QualifierLoc = ReadNestedNameSpecifierLoc(F, Record,
+ Index);
+ SourceLocation TemplateNameLoc = ReadSourceLocation(F, Record, Index);
+ SourceLocation EllipsisLoc = ReadSourceLocation(F, Record, Index);
+ return TemplateArgumentLocInfo(QualifierLoc, TemplateNameLoc,
+ EllipsisLoc);
+ }
+ case TemplateArgument::Null:
+ case TemplateArgument::Integral:
+ case TemplateArgument::Declaration:
+ case TemplateArgument::NullPtr:
+ case TemplateArgument::Pack:
+ // FIXME: Is this right?
+ return TemplateArgumentLocInfo();
+ }
+ llvm_unreachable("unexpected template argument loc");
+}
+
+TemplateArgumentLoc
+ASTReader::ReadTemplateArgumentLoc(ModuleFile &F,
+ const RecordData &Record, unsigned &Index) {
+ TemplateArgument Arg = ReadTemplateArgument(F, Record, Index);
+
+ if (Arg.getKind() == TemplateArgument::Expression) {
+ if (Record[Index++]) // bool InfoHasSameExpr.
+ return TemplateArgumentLoc(Arg, TemplateArgumentLocInfo(Arg.getAsExpr()));
+ }
+ return TemplateArgumentLoc(Arg, GetTemplateArgumentLocInfo(F, Arg.getKind(),
+ Record, Index));
+}
+
+Decl *ASTReader::GetExternalDecl(uint32_t ID) {
+ return GetDecl(ID);
+}
+
+uint64_t ASTReader::readCXXBaseSpecifiers(ModuleFile &M, const RecordData &Record,
+ unsigned &Idx){
+ if (Idx >= Record.size())
+ return 0;
+
+ unsigned LocalID = Record[Idx++];
+ return getGlobalBitOffset(M, M.CXXBaseSpecifiersOffsets[LocalID - 1]);
+}
+
+CXXBaseSpecifier *ASTReader::GetExternalCXXBaseSpecifiers(uint64_t Offset) {
+ RecordLocation Loc = getLocalBitOffset(Offset);
+ llvm::BitstreamCursor &Cursor = Loc.F->DeclsCursor;
+ SavedStreamPosition SavedPosition(Cursor);
+ Cursor.JumpToBit(Loc.Offset);
+ ReadingKindTracker ReadingKind(Read_Decl, *this);
+ RecordData Record;
+ unsigned Code = Cursor.ReadCode();
+ unsigned RecCode = Cursor.ReadRecord(Code, Record);
+ if (RecCode != DECL_CXX_BASE_SPECIFIERS) {
+ Error("Malformed AST file: missing C++ base specifiers");
+ return 0;
+ }
+
+ unsigned Idx = 0;
+ unsigned NumBases = Record[Idx++];
+ void *Mem = Context.Allocate(sizeof(CXXBaseSpecifier) * NumBases);
+ CXXBaseSpecifier *Bases = new (Mem) CXXBaseSpecifier [NumBases];
+ for (unsigned I = 0; I != NumBases; ++I)
+ Bases[I] = ReadCXXBaseSpecifier(*Loc.F, Record, Idx);
+ return Bases;
+}
+
+serialization::DeclID
+ASTReader::getGlobalDeclID(ModuleFile &F, LocalDeclID LocalID) const {
+ if (LocalID < NUM_PREDEF_DECL_IDS)
+ return LocalID;
+
+ ContinuousRangeMap<uint32_t, int, 2>::iterator I
+ = F.DeclRemap.find(LocalID - NUM_PREDEF_DECL_IDS);
+ assert(I != F.DeclRemap.end() && "Invalid index into decl index remap");
+
+ return LocalID + I->second;
+}
+
+bool ASTReader::isDeclIDFromModule(serialization::GlobalDeclID ID,
+ ModuleFile &M) const {
+ GlobalDeclMapType::const_iterator I = GlobalDeclMap.find(ID);
+ assert(I != GlobalDeclMap.end() && "Corrupted global declaration map");
+ return &M == I->second;
+}
+
+ModuleFile *ASTReader::getOwningModuleFile(Decl *D) {
+ if (!D->isFromASTFile())
+ return 0;
+ GlobalDeclMapType::const_iterator I = GlobalDeclMap.find(D->getGlobalID());
+ assert(I != GlobalDeclMap.end() && "Corrupted global declaration map");
+ return I->second;
+}
+
+SourceLocation ASTReader::getSourceLocationForDeclID(GlobalDeclID ID) {
+ if (ID < NUM_PREDEF_DECL_IDS)
+ return SourceLocation();
+
+ unsigned Index = ID - NUM_PREDEF_DECL_IDS;
+
+ if (Index > DeclsLoaded.size()) {
+ Error("declaration ID out-of-range for AST file");
+ return SourceLocation();
+ }
+
+ if (Decl *D = DeclsLoaded[Index])
+ return D->getLocation();
+
+ unsigned RawLocation = 0;
+ RecordLocation Rec = DeclCursorForID(ID, RawLocation);
+ return ReadSourceLocation(*Rec.F, RawLocation);
+}
+
+Decl *ASTReader::GetDecl(DeclID ID) {
+ if (ID < NUM_PREDEF_DECL_IDS) {
+ switch ((PredefinedDeclIDs)ID) {
+ case PREDEF_DECL_NULL_ID:
+ return 0;
+
+ case PREDEF_DECL_TRANSLATION_UNIT_ID:
+ return Context.getTranslationUnitDecl();
+
+ case PREDEF_DECL_OBJC_ID_ID:
+ return Context.getObjCIdDecl();
+
+ case PREDEF_DECL_OBJC_SEL_ID:
+ return Context.getObjCSelDecl();
+
+ case PREDEF_DECL_OBJC_CLASS_ID:
+ return Context.getObjCClassDecl();
+
+ case PREDEF_DECL_OBJC_PROTOCOL_ID:
+ return Context.getObjCProtocolDecl();
+
+ case PREDEF_DECL_INT_128_ID:
+ return Context.getInt128Decl();
+
+ case PREDEF_DECL_UNSIGNED_INT_128_ID:
+ return Context.getUInt128Decl();
+
+ case PREDEF_DECL_OBJC_INSTANCETYPE_ID:
+ return Context.getObjCInstanceTypeDecl();
+
+ case PREDEF_DECL_BUILTIN_VA_LIST_ID:
+ return Context.getBuiltinVaListDecl();
+ }
+ }
+
+ unsigned Index = ID - NUM_PREDEF_DECL_IDS;
+
+ if (Index >= DeclsLoaded.size()) {
+ assert(0 && "declaration ID out-of-range for AST file");
+ Error("declaration ID out-of-range for AST file");
+ return 0;
+ }
+
+ if (!DeclsLoaded[Index]) {
+ ReadDeclRecord(ID);
+ if (DeserializationListener)
+ DeserializationListener->DeclRead(ID, DeclsLoaded[Index]);
+ }
+
+ return DeclsLoaded[Index];
+}
+
+DeclID ASTReader::mapGlobalIDToModuleFileGlobalID(ModuleFile &M,
+ DeclID GlobalID) {
+ if (GlobalID < NUM_PREDEF_DECL_IDS)
+ return GlobalID;
+
+ GlobalDeclMapType::const_iterator I = GlobalDeclMap.find(GlobalID);
+ assert(I != GlobalDeclMap.end() && "Corrupted global declaration map");
+ ModuleFile *Owner = I->second;
+
+ llvm::DenseMap<ModuleFile *, serialization::DeclID>::iterator Pos
+ = M.GlobalToLocalDeclIDs.find(Owner);
+ if (Pos == M.GlobalToLocalDeclIDs.end())
+ return 0;
+
+ return GlobalID - Owner->BaseDeclID + Pos->second;
+}
+
+serialization::DeclID ASTReader::ReadDeclID(ModuleFile &F,
+ const RecordData &Record,
+ unsigned &Idx) {
+ if (Idx >= Record.size()) {
+ Error("Corrupted AST file");
+ return 0;
+ }
+
+ return getGlobalDeclID(F, Record[Idx++]);
+}
+
+/// \brief Resolve the offset of a statement into a statement.
+///
+/// This operation will read a new statement from the external
+/// source each time it is called, and is meant to be used via a
+/// LazyOffsetPtr (which is used by Decls for the body of functions, etc).
+Stmt *ASTReader::GetExternalDeclStmt(uint64_t Offset) {
+ // Switch case IDs are per Decl.
+ ClearSwitchCaseIDs();
+
+ // Offset here is a global offset across the entire chain.
+ RecordLocation Loc = getLocalBitOffset(Offset);
+ Loc.F->DeclsCursor.JumpToBit(Loc.Offset);
+ return ReadStmtFromStream(*Loc.F);
+}
+
+namespace {
+ class FindExternalLexicalDeclsVisitor {
+ ASTReader &Reader;
+ const DeclContext *DC;
+ bool (*isKindWeWant)(Decl::Kind);
+
+ SmallVectorImpl<Decl*> &Decls;
+ bool PredefsVisited[NUM_PREDEF_DECL_IDS];
+
+ public:
+ FindExternalLexicalDeclsVisitor(ASTReader &Reader, const DeclContext *DC,
+ bool (*isKindWeWant)(Decl::Kind),
+ SmallVectorImpl<Decl*> &Decls)
+ : Reader(Reader), DC(DC), isKindWeWant(isKindWeWant), Decls(Decls)
+ {
+ for (unsigned I = 0; I != NUM_PREDEF_DECL_IDS; ++I)
+ PredefsVisited[I] = false;
+ }
+
+ static bool visit(ModuleFile &M, bool Preorder, void *UserData) {
+ if (Preorder)
+ return false;
+
+ FindExternalLexicalDeclsVisitor *This
+ = static_cast<FindExternalLexicalDeclsVisitor *>(UserData);
+
+ ModuleFile::DeclContextInfosMap::iterator Info
+ = M.DeclContextInfos.find(This->DC);
+ if (Info == M.DeclContextInfos.end() || !Info->second.LexicalDecls)
+ return false;
+
+ // Load all of the declaration IDs
+ for (const KindDeclIDPair *ID = Info->second.LexicalDecls,
+ *IDE = ID + Info->second.NumLexicalDecls;
+ ID != IDE; ++ID) {
+ if (This->isKindWeWant && !This->isKindWeWant((Decl::Kind)ID->first))
+ continue;
+
+ // Don't add predefined declarations to the lexical context more
+ // than once.
+ if (ID->second < NUM_PREDEF_DECL_IDS) {
+ if (This->PredefsVisited[ID->second])
+ continue;
+
+ This->PredefsVisited[ID->second] = true;
+ }
+
+ if (Decl *D = This->Reader.GetLocalDecl(M, ID->second)) {
+ if (!This->DC->isDeclInLexicalTraversal(D))
+ This->Decls.push_back(D);
+ }
+ }
+
+ return false;
+ }
+ };
+}
+
+ExternalLoadResult ASTReader::FindExternalLexicalDecls(const DeclContext *DC,
+ bool (*isKindWeWant)(Decl::Kind),
+ SmallVectorImpl<Decl*> &Decls) {
+ // There might be lexical decls in multiple modules, for the TU at
+ // least. Walk all of the modules in the order they were loaded.
+ FindExternalLexicalDeclsVisitor Visitor(*this, DC, isKindWeWant, Decls);
+ ModuleMgr.visitDepthFirst(&FindExternalLexicalDeclsVisitor::visit, &Visitor);
+ ++NumLexicalDeclContextsRead;
+ return ELR_Success;
+}
+
+namespace {
+
+class DeclIDComp {
+ ASTReader &Reader;
+ ModuleFile &Mod;
+
+public:
+ DeclIDComp(ASTReader &Reader, ModuleFile &M) : Reader(Reader), Mod(M) {}
+
+ bool operator()(LocalDeclID L, LocalDeclID R) const {
+ SourceLocation LHS = getLocation(L);
+ SourceLocation RHS = getLocation(R);
+ return Reader.getSourceManager().isBeforeInTranslationUnit(LHS, RHS);
+ }
+
+ bool operator()(SourceLocation LHS, LocalDeclID R) const {
+ SourceLocation RHS = getLocation(R);
+ return Reader.getSourceManager().isBeforeInTranslationUnit(LHS, RHS);
+ }
+
+ bool operator()(LocalDeclID L, SourceLocation RHS) const {
+ SourceLocation LHS = getLocation(L);
+ return Reader.getSourceManager().isBeforeInTranslationUnit(LHS, RHS);
+ }
+
+ SourceLocation getLocation(LocalDeclID ID) const {
+ return Reader.getSourceManager().getFileLoc(
+ Reader.getSourceLocationForDeclID(Reader.getGlobalDeclID(Mod, ID)));
+ }
+};
+
+}
+
+void ASTReader::FindFileRegionDecls(FileID File,
+ unsigned Offset, unsigned Length,
+ SmallVectorImpl<Decl *> &Decls) {
+ SourceManager &SM = getSourceManager();
+
+ llvm::DenseMap<FileID, FileDeclsInfo>::iterator I = FileDeclIDs.find(File);
+ if (I == FileDeclIDs.end())
+ return;
+
+ FileDeclsInfo &DInfo = I->second;
+ if (DInfo.Decls.empty())
+ return;
+
+ SourceLocation
+ BeginLoc = SM.getLocForStartOfFile(File).getLocWithOffset(Offset);
+ SourceLocation EndLoc = BeginLoc.getLocWithOffset(Length);
+
+ DeclIDComp DIDComp(*this, *DInfo.Mod);
+ ArrayRef<serialization::LocalDeclID>::iterator
+ BeginIt = std::lower_bound(DInfo.Decls.begin(), DInfo.Decls.end(),
+ BeginLoc, DIDComp);
+ if (BeginIt != DInfo.Decls.begin())
+ --BeginIt;
+
+ // If we are pointing at a top-level decl inside an objc container, we need
+ // to backtrack until we find it otherwise we will fail to report that the
+ // region overlaps with an objc container.
+ while (BeginIt != DInfo.Decls.begin() &&
+ GetDecl(getGlobalDeclID(*DInfo.Mod, *BeginIt))
+ ->isTopLevelDeclInObjCContainer())
+ --BeginIt;
+
+ ArrayRef<serialization::LocalDeclID>::iterator
+ EndIt = std::upper_bound(DInfo.Decls.begin(), DInfo.Decls.end(),
+ EndLoc, DIDComp);
+ if (EndIt != DInfo.Decls.end())
+ ++EndIt;
+
+ for (ArrayRef<serialization::LocalDeclID>::iterator
+ DIt = BeginIt; DIt != EndIt; ++DIt)
+ Decls.push_back(GetDecl(getGlobalDeclID(*DInfo.Mod, *DIt)));
+}
+
+namespace {
+ /// \brief ModuleFile visitor used to perform name lookup into a
+ /// declaration context.
+ class DeclContextNameLookupVisitor {
+ ASTReader &Reader;
+ llvm::SmallVectorImpl<const DeclContext *> &Contexts;
+ DeclarationName Name;
+ SmallVectorImpl<NamedDecl *> &Decls;
+
+ public:
+ DeclContextNameLookupVisitor(ASTReader &Reader,
+ SmallVectorImpl<const DeclContext *> &Contexts,
+ DeclarationName Name,
+ SmallVectorImpl<NamedDecl *> &Decls)
+ : Reader(Reader), Contexts(Contexts), Name(Name), Decls(Decls) { }
+
+ static bool visit(ModuleFile &M, void *UserData) {
+ DeclContextNameLookupVisitor *This
+ = static_cast<DeclContextNameLookupVisitor *>(UserData);
+
+ // Check whether we have any visible declaration information for
+ // this context in this module.
+ ModuleFile::DeclContextInfosMap::iterator Info;
+ bool FoundInfo = false;
+ for (unsigned I = 0, N = This->Contexts.size(); I != N; ++I) {
+ Info = M.DeclContextInfos.find(This->Contexts[I]);
+ if (Info != M.DeclContextInfos.end() &&
+ Info->second.NameLookupTableData) {
+ FoundInfo = true;
+ break;
+ }
+ }
+
+ if (!FoundInfo)
+ return false;
+
+ // Look for this name within this module.
+ ASTDeclContextNameLookupTable *LookupTable =
+ Info->second.NameLookupTableData;
+ ASTDeclContextNameLookupTable::iterator Pos
+ = LookupTable->find(This->Name);
+ if (Pos == LookupTable->end())
+ return false;
+
+ bool FoundAnything = false;
+ ASTDeclContextNameLookupTrait::data_type Data = *Pos;
+ for (; Data.first != Data.second; ++Data.first) {
+ NamedDecl *ND = This->Reader.GetLocalDeclAs<NamedDecl>(M, *Data.first);
+ if (!ND)
+ continue;
+
+ if (ND->getDeclName() != This->Name) {
+ // A name might be null because the decl's redeclarable part is
+ // currently read before reading its name. The lookup is triggered by
+ // building that decl (likely indirectly), and so it is later in the
+ // sense of "already existing" and can be ignored here.
+ continue;
+ }
+
+ // Record this declaration.
+ FoundAnything = true;
+ This->Decls.push_back(ND);
+ }
+
+ return FoundAnything;
+ }
+ };
+}
+
+DeclContext::lookup_result
+ASTReader::FindExternalVisibleDeclsByName(const DeclContext *DC,
+ DeclarationName Name) {
+ assert(DC->hasExternalVisibleStorage() &&
+ "DeclContext has no visible decls in storage");
+ if (!Name)
+ return DeclContext::lookup_result(DeclContext::lookup_iterator(0),
+ DeclContext::lookup_iterator(0));
+
+ SmallVector<NamedDecl *, 64> Decls;
+
+ // Compute the declaration contexts we need to look into. Multiple such
+ // declaration contexts occur when two declaration contexts from disjoint
+ // modules get merged, e.g., when two namespaces with the same name are
+ // independently defined in separate modules.
+ SmallVector<const DeclContext *, 2> Contexts;
+ Contexts.push_back(DC);
+
+ if (DC->isNamespace()) {
+ MergedDeclsMap::iterator Merged
+ = MergedDecls.find(const_cast<Decl *>(cast<Decl>(DC)));
+ if (Merged != MergedDecls.end()) {
+ for (unsigned I = 0, N = Merged->second.size(); I != N; ++I)
+ Contexts.push_back(cast<DeclContext>(GetDecl(Merged->second[I])));
+ }
+ }
+
+ DeclContextNameLookupVisitor Visitor(*this, Contexts, Name, Decls);
+ ModuleMgr.visit(&DeclContextNameLookupVisitor::visit, &Visitor);
+ ++NumVisibleDeclContextsRead;
+ SetExternalVisibleDeclsForName(DC, Name, Decls);
+ return const_cast<DeclContext*>(DC)->lookup(Name);
+}
+
+namespace {
+ /// \brief ModuleFile visitor used to retrieve all visible names in a
+ /// declaration context.
+ class DeclContextAllNamesVisitor {
+ ASTReader &Reader;
+ llvm::SmallVectorImpl<const DeclContext *> &Contexts;
+ llvm::DenseMap<DeclarationName, SmallVector<NamedDecl *, 8> > &Decls;
+
+ public:
+ DeclContextAllNamesVisitor(ASTReader &Reader,
+ SmallVectorImpl<const DeclContext *> &Contexts,
+ llvm::DenseMap<DeclarationName,
+ SmallVector<NamedDecl *, 8> > &Decls)
+ : Reader(Reader), Contexts(Contexts), Decls(Decls) { }
+
+ static bool visit(ModuleFile &M, void *UserData) {
+ DeclContextAllNamesVisitor *This
+ = static_cast<DeclContextAllNamesVisitor *>(UserData);
+
+ // Check whether we have any visible declaration information for
+ // this context in this module.
+ ModuleFile::DeclContextInfosMap::iterator Info;
+ bool FoundInfo = false;
+ for (unsigned I = 0, N = This->Contexts.size(); I != N; ++I) {
+ Info = M.DeclContextInfos.find(This->Contexts[I]);
+ if (Info != M.DeclContextInfos.end() &&
+ Info->second.NameLookupTableData) {
+ FoundInfo = true;
+ break;
+ }
+ }
+
+ if (!FoundInfo)
+ return false;
+
+ ASTDeclContextNameLookupTable *LookupTable =
+ Info->second.NameLookupTableData;
+ bool FoundAnything = false;
+ for (ASTDeclContextNameLookupTable::data_iterator
+ I = LookupTable->data_begin(), E = LookupTable->data_end();
+ I != E; ++I) {
+ ASTDeclContextNameLookupTrait::data_type Data = *I;
+ for (; Data.first != Data.second; ++Data.first) {
+ NamedDecl *ND = This->Reader.GetLocalDeclAs<NamedDecl>(M,
+ *Data.first);
+ if (!ND)
+ continue;
+
+ // Record this declaration.
+ FoundAnything = true;
+ This->Decls[ND->getDeclName()].push_back(ND);
+ }
+ }
+
+ return FoundAnything;
+ }
+ };
+}
+
+void ASTReader::completeVisibleDeclsMap(const DeclContext *DC) {
+ if (!DC->hasExternalVisibleStorage())
+ return;
+ llvm::DenseMap<DeclarationName, llvm::SmallVector<NamedDecl*, 8> > Decls;
+
+ // Compute the declaration contexts we need to look into. Multiple such
+ // declaration contexts occur when two declaration contexts from disjoint
+ // modules get merged, e.g., when two namespaces with the same name are
+ // independently defined in separate modules.
+ SmallVector<const DeclContext *, 2> Contexts;
+ Contexts.push_back(DC);
+
+ if (DC->isNamespace()) {
+ MergedDeclsMap::iterator Merged
+ = MergedDecls.find(const_cast<Decl *>(cast<Decl>(DC)));
+ if (Merged != MergedDecls.end()) {
+ for (unsigned I = 0, N = Merged->second.size(); I != N; ++I)
+ Contexts.push_back(cast<DeclContext>(GetDecl(Merged->second[I])));
+ }
+ }
+
+ DeclContextAllNamesVisitor Visitor(*this, Contexts, Decls);
+ ModuleMgr.visit(&DeclContextAllNamesVisitor::visit, &Visitor);
+ ++NumVisibleDeclContextsRead;
+
+ for (llvm::DenseMap<DeclarationName,
+ llvm::SmallVector<NamedDecl*, 8> >::iterator
+ I = Decls.begin(), E = Decls.end(); I != E; ++I) {
+ SetExternalVisibleDeclsForName(DC, I->first, I->second);
+ }
+ const_cast<DeclContext *>(DC)->setHasExternalVisibleStorage(false);
+}
+
+/// \brief Under non-PCH compilation the consumer receives the objc methods
+/// before receiving the implementation, and codegen depends on this.
+/// We simulate this by deserializing and passing to consumer the methods of the
+/// implementation before passing the deserialized implementation decl.
+static void PassObjCImplDeclToConsumer(ObjCImplDecl *ImplD,
+ ASTConsumer *Consumer) {
+ assert(ImplD && Consumer);
+
+ for (ObjCImplDecl::method_iterator
+ I = ImplD->meth_begin(), E = ImplD->meth_end(); I != E; ++I)
+ Consumer->HandleInterestingDecl(DeclGroupRef(*I));
+
+ Consumer->HandleInterestingDecl(DeclGroupRef(ImplD));
+}
+
+void ASTReader::PassInterestingDeclsToConsumer() {
+ assert(Consumer);
+ while (!InterestingDecls.empty()) {
+ Decl *D = InterestingDecls.front();
+ InterestingDecls.pop_front();
+
+ PassInterestingDeclToConsumer(D);
+ }
+}
+
+void ASTReader::PassInterestingDeclToConsumer(Decl *D) {
+ if (ObjCImplDecl *ImplD = dyn_cast<ObjCImplDecl>(D))
+ PassObjCImplDeclToConsumer(ImplD, Consumer);
+ else
+ Consumer->HandleInterestingDecl(DeclGroupRef(D));
+}
+
+void ASTReader::StartTranslationUnit(ASTConsumer *Consumer) {
+ this->Consumer = Consumer;
+
+ if (!Consumer)
+ return;
+
+ for (unsigned I = 0, N = ExternalDefinitions.size(); I != N; ++I) {
+ // Force deserialization of this decl, which will cause it to be queued for
+ // passing to the consumer.
+ GetDecl(ExternalDefinitions[I]);
+ }
+ ExternalDefinitions.clear();
+
+ PassInterestingDeclsToConsumer();
+}
+
+void ASTReader::PrintStats() {
+ std::fprintf(stderr, "*** AST File Statistics:\n");
+
+ unsigned NumTypesLoaded
+ = TypesLoaded.size() - std::count(TypesLoaded.begin(), TypesLoaded.end(),
+ QualType());
+ unsigned NumDeclsLoaded
+ = DeclsLoaded.size() - std::count(DeclsLoaded.begin(), DeclsLoaded.end(),
+ (Decl *)0);
+ unsigned NumIdentifiersLoaded
+ = IdentifiersLoaded.size() - std::count(IdentifiersLoaded.begin(),
+ IdentifiersLoaded.end(),
+ (IdentifierInfo *)0);
+ unsigned NumMacrosLoaded
+ = MacrosLoaded.size() - std::count(MacrosLoaded.begin(),
+ MacrosLoaded.end(),
+ (MacroInfo *)0);
+ unsigned NumSelectorsLoaded
+ = SelectorsLoaded.size() - std::count(SelectorsLoaded.begin(),
+ SelectorsLoaded.end(),
+ Selector());
+
+ if (unsigned TotalNumSLocEntries = getTotalNumSLocs())
+ std::fprintf(stderr, " %u/%u source location entries read (%f%%)\n",
+ NumSLocEntriesRead, TotalNumSLocEntries,
+ ((float)NumSLocEntriesRead/TotalNumSLocEntries * 100));
+ if (!TypesLoaded.empty())
+ std::fprintf(stderr, " %u/%u types read (%f%%)\n",
+ NumTypesLoaded, (unsigned)TypesLoaded.size(),
+ ((float)NumTypesLoaded/TypesLoaded.size() * 100));
+ if (!DeclsLoaded.empty())
+ std::fprintf(stderr, " %u/%u declarations read (%f%%)\n",
+ NumDeclsLoaded, (unsigned)DeclsLoaded.size(),
+ ((float)NumDeclsLoaded/DeclsLoaded.size() * 100));
+ if (!IdentifiersLoaded.empty())
+ std::fprintf(stderr, " %u/%u identifiers read (%f%%)\n",
+ NumIdentifiersLoaded, (unsigned)IdentifiersLoaded.size(),
+ ((float)NumIdentifiersLoaded/IdentifiersLoaded.size() * 100));
+ if (!MacrosLoaded.empty())
+ std::fprintf(stderr, " %u/%u macros read (%f%%)\n",
+ NumMacrosLoaded, (unsigned)MacrosLoaded.size(),
+ ((float)NumMacrosLoaded/MacrosLoaded.size() * 100));
+ if (!SelectorsLoaded.empty())
+ std::fprintf(stderr, " %u/%u selectors read (%f%%)\n",
+ NumSelectorsLoaded, (unsigned)SelectorsLoaded.size(),
+ ((float)NumSelectorsLoaded/SelectorsLoaded.size() * 100));
+ if (TotalNumStatements)
+ std::fprintf(stderr, " %u/%u statements read (%f%%)\n",
+ NumStatementsRead, TotalNumStatements,
+ ((float)NumStatementsRead/TotalNumStatements * 100));
+ if (TotalNumMacros)
+ std::fprintf(stderr, " %u/%u macros read (%f%%)\n",
+ NumMacrosRead, TotalNumMacros,
+ ((float)NumMacrosRead/TotalNumMacros * 100));
+ if (TotalLexicalDeclContexts)
+ std::fprintf(stderr, " %u/%u lexical declcontexts read (%f%%)\n",
+ NumLexicalDeclContextsRead, TotalLexicalDeclContexts,
+ ((float)NumLexicalDeclContextsRead/TotalLexicalDeclContexts
+ * 100));
+ if (TotalVisibleDeclContexts)
+ std::fprintf(stderr, " %u/%u visible declcontexts read (%f%%)\n",
+ NumVisibleDeclContextsRead, TotalVisibleDeclContexts,
+ ((float)NumVisibleDeclContextsRead/TotalVisibleDeclContexts
+ * 100));
+ if (TotalNumMethodPoolEntries) {
+ std::fprintf(stderr, " %u/%u method pool entries read (%f%%)\n",
+ NumMethodPoolEntriesRead, TotalNumMethodPoolEntries,
+ ((float)NumMethodPoolEntriesRead/TotalNumMethodPoolEntries
+ * 100));
+ std::fprintf(stderr, " %u method pool misses\n", NumMethodPoolMisses);
+ }
+ std::fprintf(stderr, "\n");
+ dump();
+ std::fprintf(stderr, "\n");
+}
+
+template<typename Key, typename ModuleFile, unsigned InitialCapacity>
+static void
+dumpModuleIDMap(StringRef Name,
+ const ContinuousRangeMap<Key, ModuleFile *,
+ InitialCapacity> &Map) {
+ if (Map.begin() == Map.end())
+ return;
+
+ typedef ContinuousRangeMap<Key, ModuleFile *, InitialCapacity> MapType;
+ llvm::errs() << Name << ":\n";
+ for (typename MapType::const_iterator I = Map.begin(), IEnd = Map.end();
+ I != IEnd; ++I) {
+ llvm::errs() << " " << I->first << " -> " << I->second->FileName
+ << "\n";
+ }
+}
+
+void ASTReader::dump() {
+ llvm::errs() << "*** PCH/ModuleFile Remappings:\n";
+ dumpModuleIDMap("Global bit offset map", GlobalBitOffsetsMap);
+ dumpModuleIDMap("Global source location entry map", GlobalSLocEntryMap);
+ dumpModuleIDMap("Global type map", GlobalTypeMap);
+ dumpModuleIDMap("Global declaration map", GlobalDeclMap);
+ dumpModuleIDMap("Global identifier map", GlobalIdentifierMap);
+ dumpModuleIDMap("Global macro map", GlobalMacroMap);
+ dumpModuleIDMap("Global submodule map", GlobalSubmoduleMap);
+ dumpModuleIDMap("Global selector map", GlobalSelectorMap);
+ dumpModuleIDMap("Global preprocessed entity map",
+ GlobalPreprocessedEntityMap);
+
+ llvm::errs() << "\n*** PCH/Modules Loaded:";
+ for (ModuleManager::ModuleConstIterator M = ModuleMgr.begin(),
+ MEnd = ModuleMgr.end();
+ M != MEnd; ++M)
+ (*M)->dump();
+}
+
+/// Return the amount of memory used by memory buffers, breaking down
+/// by heap-backed versus mmap'ed memory.
+void ASTReader::getMemoryBufferSizes(MemoryBufferSizes &sizes) const {
+ for (ModuleConstIterator I = ModuleMgr.begin(),
+ E = ModuleMgr.end(); I != E; ++I) {
+ if (llvm::MemoryBuffer *buf = (*I)->Buffer.get()) {
+ size_t bytes = buf->getBufferSize();
+ switch (buf->getBufferKind()) {
+ case llvm::MemoryBuffer::MemoryBuffer_Malloc:
+ sizes.malloc_bytes += bytes;
+ break;
+ case llvm::MemoryBuffer::MemoryBuffer_MMap:
+ sizes.mmap_bytes += bytes;
+ break;
+ }
+ }
+ }
+}
+
+void ASTReader::InitializeSema(Sema &S) {
+ SemaObj = &S;
+ S.addExternalSource(this);
+
+ // Makes sure any declarations that were deserialized "too early"
+ // still get added to the identifier's declaration chains.
+ for (unsigned I = 0, N = PreloadedDecls.size(); I != N; ++I) {
+ SemaObj->pushExternalDeclIntoScope(PreloadedDecls[I],
+ PreloadedDecls[I]->getDeclName());
+ }
+ PreloadedDecls.clear();
+
+ // Load the offsets of the declarations that Sema references.
+ // They will be lazily deserialized when needed.
+ if (!SemaDeclRefs.empty()) {
+ assert(SemaDeclRefs.size() == 2 && "More decl refs than expected!");
+ if (!SemaObj->StdNamespace)
+ SemaObj->StdNamespace = SemaDeclRefs[0];
+ if (!SemaObj->StdBadAlloc)
+ SemaObj->StdBadAlloc = SemaDeclRefs[1];
+ }
+
+ if (!FPPragmaOptions.empty()) {
+ assert(FPPragmaOptions.size() == 1 && "Wrong number of FP_PRAGMA_OPTIONS");
+ SemaObj->FPFeatures.fp_contract = FPPragmaOptions[0];
+ }
+
+ if (!OpenCLExtensions.empty()) {
+ unsigned I = 0;
+#define OPENCLEXT(nm) SemaObj->OpenCLFeatures.nm = OpenCLExtensions[I++];
+#include "clang/Basic/OpenCLExtensions.def"
+
+ assert(OpenCLExtensions.size() == I && "Wrong number of OPENCL_EXTENSIONS");
+ }
+}
+
+IdentifierInfo* ASTReader::get(const char *NameStart, const char *NameEnd) {
+ // Note that we are loading an identifier.
+ Deserializing AnIdentifier(this);
+
+ IdentifierLookupVisitor Visitor(StringRef(NameStart, NameEnd - NameStart),
+ /*PriorGeneration=*/0);
+ ModuleMgr.visit(IdentifierLookupVisitor::visit, &Visitor);
+ IdentifierInfo *II = Visitor.getIdentifierInfo();
+ markIdentifierUpToDate(II);
+ return II;
+}
+
+namespace clang {
+ /// \brief An identifier-lookup iterator that enumerates all of the
+ /// identifiers stored within a set of AST files.
+ class ASTIdentifierIterator : public IdentifierIterator {
+ /// \brief The AST reader whose identifiers are being enumerated.
+ const ASTReader &Reader;
+
+ /// \brief The current index into the chain of AST files stored in
+ /// the AST reader.
+ unsigned Index;
+
+ /// \brief The current position within the identifier lookup table
+ /// of the current AST file.
+ ASTIdentifierLookupTable::key_iterator Current;
+
+ /// \brief The end position within the identifier lookup table of
+ /// the current AST file.
+ ASTIdentifierLookupTable::key_iterator End;
+
+ public:
+ explicit ASTIdentifierIterator(const ASTReader &Reader);
+
+ virtual StringRef Next();
+ };
+}
+
+ASTIdentifierIterator::ASTIdentifierIterator(const ASTReader &Reader)
+ : Reader(Reader), Index(Reader.ModuleMgr.size() - 1) {
+ ASTIdentifierLookupTable *IdTable
+ = (ASTIdentifierLookupTable *)Reader.ModuleMgr[Index].IdentifierLookupTable;
+ Current = IdTable->key_begin();
+ End = IdTable->key_end();
+}
+
+StringRef ASTIdentifierIterator::Next() {
+ while (Current == End) {
+ // If we have exhausted all of our AST files, we're done.
+ if (Index == 0)
+ return StringRef();
+
+ --Index;
+ ASTIdentifierLookupTable *IdTable
+ = (ASTIdentifierLookupTable *)Reader.ModuleMgr[Index].
+ IdentifierLookupTable;
+ Current = IdTable->key_begin();
+ End = IdTable->key_end();
+ }
+
+ // We have any identifiers remaining in the current AST file; return
+ // the next one.
+ std::pair<const char*, unsigned> Key = *Current;
+ ++Current;
+ return StringRef(Key.first, Key.second);
+}
+
+IdentifierIterator *ASTReader::getIdentifiers() const {
+ return new ASTIdentifierIterator(*this);
+}
+
+namespace clang { namespace serialization {
+ class ReadMethodPoolVisitor {
+ ASTReader &Reader;
+ Selector Sel;
+ unsigned PriorGeneration;
+ llvm::SmallVector<ObjCMethodDecl *, 4> InstanceMethods;
+ llvm::SmallVector<ObjCMethodDecl *, 4> FactoryMethods;
+
+ public:
+ ReadMethodPoolVisitor(ASTReader &Reader, Selector Sel,
+ unsigned PriorGeneration)
+ : Reader(Reader), Sel(Sel), PriorGeneration(PriorGeneration) { }
+
+ static bool visit(ModuleFile &M, void *UserData) {
+ ReadMethodPoolVisitor *This
+ = static_cast<ReadMethodPoolVisitor *>(UserData);
+
+ if (!M.SelectorLookupTable)
+ return false;
+
+ // If we've already searched this module file, skip it now.
+ if (M.Generation <= This->PriorGeneration)
+ return true;
+
+ ASTSelectorLookupTable *PoolTable
+ = (ASTSelectorLookupTable*)M.SelectorLookupTable;
+ ASTSelectorLookupTable::iterator Pos = PoolTable->find(This->Sel);
+ if (Pos == PoolTable->end())
+ return false;
+
+ ++This->Reader.NumSelectorsRead;
+ // FIXME: Not quite happy with the statistics here. We probably should
+ // disable this tracking when called via LoadSelector.
+ // Also, should entries without methods count as misses?
+ ++This->Reader.NumMethodPoolEntriesRead;
+ ASTSelectorLookupTrait::data_type Data = *Pos;
+ if (This->Reader.DeserializationListener)
+ This->Reader.DeserializationListener->SelectorRead(Data.ID,
+ This->Sel);
+
+ This->InstanceMethods.append(Data.Instance.begin(), Data.Instance.end());
+ This->FactoryMethods.append(Data.Factory.begin(), Data.Factory.end());
+ return true;
+ }
+
+ /// \brief Retrieve the instance methods found by this visitor.
+ ArrayRef<ObjCMethodDecl *> getInstanceMethods() const {
+ return InstanceMethods;
+ }
+
+ /// \brief Retrieve the instance methods found by this visitor.
+ ArrayRef<ObjCMethodDecl *> getFactoryMethods() const {
+ return FactoryMethods;
+ }
+ };
+} } // end namespace clang::serialization
+
+/// \brief Add the given set of methods to the method list.
+static void addMethodsToPool(Sema &S, ArrayRef<ObjCMethodDecl *> Methods,
+ ObjCMethodList &List) {
+ for (unsigned I = 0, N = Methods.size(); I != N; ++I) {
+ S.addMethodToGlobalList(&List, Methods[I]);
+ }
+}
+
+void ASTReader::ReadMethodPool(Selector Sel) {
+ // Get the selector generation and update it to the current generation.
+ unsigned &Generation = SelectorGeneration[Sel];
+ unsigned PriorGeneration = Generation;
+ Generation = CurrentGeneration;
+
+ // Search for methods defined with this selector.
+ ReadMethodPoolVisitor Visitor(*this, Sel, PriorGeneration);
+ ModuleMgr.visit(&ReadMethodPoolVisitor::visit, &Visitor);
+
+ if (Visitor.getInstanceMethods().empty() &&
+ Visitor.getFactoryMethods().empty()) {
+ ++NumMethodPoolMisses;
+ return;
+ }
+
+ if (!getSema())
+ return;
+
+ Sema &S = *getSema();
+ Sema::GlobalMethodPool::iterator Pos
+ = S.MethodPool.insert(std::make_pair(Sel, Sema::GlobalMethods())).first;
+
+ addMethodsToPool(S, Visitor.getInstanceMethods(), Pos->second.first);
+ addMethodsToPool(S, Visitor.getFactoryMethods(), Pos->second.second);
+}
+
+void ASTReader::ReadKnownNamespaces(
+ SmallVectorImpl<NamespaceDecl *> &Namespaces) {
+ Namespaces.clear();
+
+ for (unsigned I = 0, N = KnownNamespaces.size(); I != N; ++I) {
+ if (NamespaceDecl *Namespace
+ = dyn_cast_or_null<NamespaceDecl>(GetDecl(KnownNamespaces[I])))
+ Namespaces.push_back(Namespace);
+ }
+}
+
+void ASTReader::ReadTentativeDefinitions(
+ SmallVectorImpl<VarDecl *> &TentativeDefs) {
+ for (unsigned I = 0, N = TentativeDefinitions.size(); I != N; ++I) {
+ VarDecl *Var = dyn_cast_or_null<VarDecl>(GetDecl(TentativeDefinitions[I]));
+ if (Var)
+ TentativeDefs.push_back(Var);
+ }
+ TentativeDefinitions.clear();
+}
+
+void ASTReader::ReadUnusedFileScopedDecls(
+ SmallVectorImpl<const DeclaratorDecl *> &Decls) {
+ for (unsigned I = 0, N = UnusedFileScopedDecls.size(); I != N; ++I) {
+ DeclaratorDecl *D
+ = dyn_cast_or_null<DeclaratorDecl>(GetDecl(UnusedFileScopedDecls[I]));
+ if (D)
+ Decls.push_back(D);
+ }
+ UnusedFileScopedDecls.clear();
+}
+
+void ASTReader::ReadDelegatingConstructors(
+ SmallVectorImpl<CXXConstructorDecl *> &Decls) {
+ for (unsigned I = 0, N = DelegatingCtorDecls.size(); I != N; ++I) {
+ CXXConstructorDecl *D
+ = dyn_cast_or_null<CXXConstructorDecl>(GetDecl(DelegatingCtorDecls[I]));
+ if (D)
+ Decls.push_back(D);
+ }
+ DelegatingCtorDecls.clear();
+}
+
+void ASTReader::ReadExtVectorDecls(SmallVectorImpl<TypedefNameDecl *> &Decls) {
+ for (unsigned I = 0, N = ExtVectorDecls.size(); I != N; ++I) {
+ TypedefNameDecl *D
+ = dyn_cast_or_null<TypedefNameDecl>(GetDecl(ExtVectorDecls[I]));
+ if (D)
+ Decls.push_back(D);
+ }
+ ExtVectorDecls.clear();
+}
+
+void ASTReader::ReadDynamicClasses(SmallVectorImpl<CXXRecordDecl *> &Decls) {
+ for (unsigned I = 0, N = DynamicClasses.size(); I != N; ++I) {
+ CXXRecordDecl *D
+ = dyn_cast_or_null<CXXRecordDecl>(GetDecl(DynamicClasses[I]));
+ if (D)
+ Decls.push_back(D);
+ }
+ DynamicClasses.clear();
+}
+
+void
+ASTReader::ReadLocallyScopedExternalDecls(SmallVectorImpl<NamedDecl *> &Decls) {
+ for (unsigned I = 0, N = LocallyScopedExternalDecls.size(); I != N; ++I) {
+ NamedDecl *D
+ = dyn_cast_or_null<NamedDecl>(GetDecl(LocallyScopedExternalDecls[I]));
+ if (D)
+ Decls.push_back(D);
+ }
+ LocallyScopedExternalDecls.clear();
+}
+
+void ASTReader::ReadReferencedSelectors(
+ SmallVectorImpl<std::pair<Selector, SourceLocation> > &Sels) {
+ if (ReferencedSelectorsData.empty())
+ return;
+
+ // If there are @selector references added them to its pool. This is for
+ // implementation of -Wselector.
+ unsigned int DataSize = ReferencedSelectorsData.size()-1;
+ unsigned I = 0;
+ while (I < DataSize) {
+ Selector Sel = DecodeSelector(ReferencedSelectorsData[I++]);
+ SourceLocation SelLoc
+ = SourceLocation::getFromRawEncoding(ReferencedSelectorsData[I++]);
+ Sels.push_back(std::make_pair(Sel, SelLoc));
+ }
+ ReferencedSelectorsData.clear();
+}
+
+void ASTReader::ReadWeakUndeclaredIdentifiers(
+ SmallVectorImpl<std::pair<IdentifierInfo *, WeakInfo> > &WeakIDs) {
+ if (WeakUndeclaredIdentifiers.empty())
+ return;
+
+ for (unsigned I = 0, N = WeakUndeclaredIdentifiers.size(); I < N; /*none*/) {
+ IdentifierInfo *WeakId
+ = DecodeIdentifierInfo(WeakUndeclaredIdentifiers[I++]);
+ IdentifierInfo *AliasId
+ = DecodeIdentifierInfo(WeakUndeclaredIdentifiers[I++]);
+ SourceLocation Loc
+ = SourceLocation::getFromRawEncoding(WeakUndeclaredIdentifiers[I++]);
+ bool Used = WeakUndeclaredIdentifiers[I++];
+ WeakInfo WI(AliasId, Loc);
+ WI.setUsed(Used);
+ WeakIDs.push_back(std::make_pair(WeakId, WI));
+ }
+ WeakUndeclaredIdentifiers.clear();
+}
+
+void ASTReader::ReadUsedVTables(SmallVectorImpl<ExternalVTableUse> &VTables) {
+ for (unsigned Idx = 0, N = VTableUses.size(); Idx < N; /* In loop */) {
+ ExternalVTableUse VT;
+ VT.Record = dyn_cast_or_null<CXXRecordDecl>(GetDecl(VTableUses[Idx++]));
+ VT.Location = SourceLocation::getFromRawEncoding(VTableUses[Idx++]);
+ VT.DefinitionRequired = VTableUses[Idx++];
+ VTables.push_back(VT);
+ }
+
+ VTableUses.clear();
+}
+
+void ASTReader::ReadPendingInstantiations(
+ SmallVectorImpl<std::pair<ValueDecl *, SourceLocation> > &Pending) {
+ for (unsigned Idx = 0, N = PendingInstantiations.size(); Idx < N;) {
+ ValueDecl *D = cast<ValueDecl>(GetDecl(PendingInstantiations[Idx++]));
+ SourceLocation Loc
+ = SourceLocation::getFromRawEncoding(PendingInstantiations[Idx++]);
+
+ Pending.push_back(std::make_pair(D, Loc));
+ }
+ PendingInstantiations.clear();
+}
+
+void ASTReader::LoadSelector(Selector Sel) {
+ // It would be complicated to avoid reading the methods anyway. So don't.
+ ReadMethodPool(Sel);
+}
+
+void ASTReader::SetIdentifierInfo(IdentifierID ID, IdentifierInfo *II) {
+ assert(ID && "Non-zero identifier ID required");
+ assert(ID <= IdentifiersLoaded.size() && "identifier ID out of range");
+ IdentifiersLoaded[ID - 1] = II;
+ if (DeserializationListener)
+ DeserializationListener->IdentifierRead(ID, II);
+}
+
+/// \brief Set the globally-visible declarations associated with the given
+/// identifier.
+///
+/// If the AST reader is currently in a state where the given declaration IDs
+/// cannot safely be resolved, they are queued until it is safe to resolve
+/// them.
+///
+/// \param II an IdentifierInfo that refers to one or more globally-visible
+/// declarations.
+///
+/// \param DeclIDs the set of declaration IDs with the name @p II that are
+/// visible at global scope.
+///
+/// \param Nonrecursive should be true to indicate that the caller knows that
+/// this call is non-recursive, and therefore the globally-visible declarations
+/// will not be placed onto the pending queue.
+void
+ASTReader::SetGloballyVisibleDecls(IdentifierInfo *II,
+ const SmallVectorImpl<uint32_t> &DeclIDs,
+ bool Nonrecursive) {
+ if (NumCurrentElementsDeserializing && !Nonrecursive) {
+ PendingIdentifierInfos.push_back(PendingIdentifierInfo());
+ PendingIdentifierInfo &PII = PendingIdentifierInfos.back();
+ PII.II = II;
+ PII.DeclIDs.append(DeclIDs.begin(), DeclIDs.end());
+ return;
+ }
+
+ for (unsigned I = 0, N = DeclIDs.size(); I != N; ++I) {
+ NamedDecl *D = cast<NamedDecl>(GetDecl(DeclIDs[I]));
+ if (SemaObj) {
+ // Introduce this declaration into the translation-unit scope
+ // and add it to the declaration chain for this identifier, so
+ // that (unqualified) name lookup will find it.
+ SemaObj->pushExternalDeclIntoScope(D, II);
+ } else {
+ // Queue this declaration so that it will be added to the
+ // translation unit scope and identifier's declaration chain
+ // once a Sema object is known.
+ PreloadedDecls.push_back(D);
+ }
+ }
+}
+
+IdentifierInfo *ASTReader::DecodeIdentifierInfo(IdentifierID ID) {
+ if (ID == 0)
+ return 0;
+
+ if (IdentifiersLoaded.empty()) {
+ Error("no identifier table in AST file");
+ return 0;
+ }
+
+ ID -= 1;
+ if (!IdentifiersLoaded[ID]) {
+ GlobalIdentifierMapType::iterator I = GlobalIdentifierMap.find(ID + 1);
+ assert(I != GlobalIdentifierMap.end() && "Corrupted global identifier map");
+ ModuleFile *M = I->second;
+ unsigned Index = ID - M->BaseIdentifierID;
+ const char *Str = M->IdentifierTableData + M->IdentifierOffsets[Index];
+
+ // All of the strings in the AST file are preceded by a 16-bit length.
+ // Extract that 16-bit length to avoid having to execute strlen().
+ // NOTE: 'StrLenPtr' is an 'unsigned char*' so that we load bytes as
+ // unsigned integers. This is important to avoid integer overflow when
+ // we cast them to 'unsigned'.
+ const unsigned char *StrLenPtr = (const unsigned char*) Str - 2;
+ unsigned StrLen = (((unsigned) StrLenPtr[0])
+ | (((unsigned) StrLenPtr[1]) << 8)) - 1;
+ IdentifiersLoaded[ID]
+ = &PP.getIdentifierTable().get(StringRef(Str, StrLen));
+ if (DeserializationListener)
+ DeserializationListener->IdentifierRead(ID + 1, IdentifiersLoaded[ID]);
+ }
+
+ return IdentifiersLoaded[ID];
+}
+
+IdentifierInfo *ASTReader::getLocalIdentifier(ModuleFile &M, unsigned LocalID) {
+ return DecodeIdentifierInfo(getGlobalIdentifierID(M, LocalID));
+}
+
+IdentifierID ASTReader::getGlobalIdentifierID(ModuleFile &M, unsigned LocalID) {
+ if (LocalID < NUM_PREDEF_IDENT_IDS)
+ return LocalID;
+
+ ContinuousRangeMap<uint32_t, int, 2>::iterator I
+ = M.IdentifierRemap.find(LocalID - NUM_PREDEF_IDENT_IDS);
+ assert(I != M.IdentifierRemap.end()
+ && "Invalid index into identifier index remap");
+
+ return LocalID + I->second;
+}
+
+MacroInfo *ASTReader::getMacro(MacroID ID, MacroInfo *Hint) {
+ if (ID == 0)
+ return 0;
+
+ if (MacrosLoaded.empty()) {
+ Error("no macro table in AST file");
+ return 0;
+ }
+
+ ID -= NUM_PREDEF_MACRO_IDS;
+ if (!MacrosLoaded[ID]) {
+ GlobalMacroMapType::iterator I
+ = GlobalMacroMap.find(ID + NUM_PREDEF_MACRO_IDS);
+ assert(I != GlobalMacroMap.end() && "Corrupted global macro map");
+ ModuleFile *M = I->second;
+ unsigned Index = ID - M->BaseMacroID;
+ ReadMacroRecord(*M, M->MacroOffsets[Index], Hint);
+ }
+
+ return MacrosLoaded[ID];
+}
+
+MacroID ASTReader::getGlobalMacroID(ModuleFile &M, unsigned LocalID) {
+ if (LocalID < NUM_PREDEF_MACRO_IDS)
+ return LocalID;
+
+ ContinuousRangeMap<uint32_t, int, 2>::iterator I
+ = M.MacroRemap.find(LocalID - NUM_PREDEF_MACRO_IDS);
+ assert(I != M.MacroRemap.end() && "Invalid index into macro index remap");
+
+ return LocalID + I->second;
+}
+
+serialization::SubmoduleID
+ASTReader::getGlobalSubmoduleID(ModuleFile &M, unsigned LocalID) {
+ if (LocalID < NUM_PREDEF_SUBMODULE_IDS)
+ return LocalID;
+
+ ContinuousRangeMap<uint32_t, int, 2>::iterator I
+ = M.SubmoduleRemap.find(LocalID - NUM_PREDEF_SUBMODULE_IDS);
+ assert(I != M.SubmoduleRemap.end()
+ && "Invalid index into submodule index remap");
+
+ return LocalID + I->second;
+}
+
+Module *ASTReader::getSubmodule(SubmoduleID GlobalID) {
+ if (GlobalID < NUM_PREDEF_SUBMODULE_IDS) {
+ assert(GlobalID == 0 && "Unhandled global submodule ID");
+ return 0;
+ }
+
+ if (GlobalID > SubmodulesLoaded.size()) {
+ Error("submodule ID out of range in AST file");
+ return 0;
+ }
+
+ return SubmodulesLoaded[GlobalID - NUM_PREDEF_SUBMODULE_IDS];
+}
+
+Selector ASTReader::getLocalSelector(ModuleFile &M, unsigned LocalID) {
+ return DecodeSelector(getGlobalSelectorID(M, LocalID));
+}
+
+Selector ASTReader::DecodeSelector(serialization::SelectorID ID) {
+ if (ID == 0)
+ return Selector();
+
+ if (ID > SelectorsLoaded.size()) {
+ Error("selector ID out of range in AST file");
+ return Selector();
+ }
+
+ if (SelectorsLoaded[ID - 1].getAsOpaquePtr() == 0) {
+ // Load this selector from the selector table.
+ GlobalSelectorMapType::iterator I = GlobalSelectorMap.find(ID);
+ assert(I != GlobalSelectorMap.end() && "Corrupted global selector map");
+ ModuleFile &M = *I->second;
+ ASTSelectorLookupTrait Trait(*this, M);
+ unsigned Idx = ID - M.BaseSelectorID - NUM_PREDEF_SELECTOR_IDS;
+ SelectorsLoaded[ID - 1] =
+ Trait.ReadKey(M.SelectorLookupTableData + M.SelectorOffsets[Idx], 0);
+ if (DeserializationListener)
+ DeserializationListener->SelectorRead(ID, SelectorsLoaded[ID - 1]);
+ }
+
+ return SelectorsLoaded[ID - 1];
+}
+
+Selector ASTReader::GetExternalSelector(serialization::SelectorID ID) {
+ return DecodeSelector(ID);
+}
+
+uint32_t ASTReader::GetNumExternalSelectors() {
+ // ID 0 (the null selector) is considered an external selector.
+ return getTotalNumSelectors() + 1;
+}
+
+serialization::SelectorID
+ASTReader::getGlobalSelectorID(ModuleFile &M, unsigned LocalID) const {
+ if (LocalID < NUM_PREDEF_SELECTOR_IDS)
+ return LocalID;
+
+ ContinuousRangeMap<uint32_t, int, 2>::iterator I
+ = M.SelectorRemap.find(LocalID - NUM_PREDEF_SELECTOR_IDS);
+ assert(I != M.SelectorRemap.end()
+ && "Invalid index into selector index remap");
+
+ return LocalID + I->second;
+}
+
+DeclarationName
+ASTReader::ReadDeclarationName(ModuleFile &F,
+ const RecordData &Record, unsigned &Idx) {
+ DeclarationName::NameKind Kind = (DeclarationName::NameKind)Record[Idx++];
+ switch (Kind) {
+ case DeclarationName::Identifier:
+ return DeclarationName(GetIdentifierInfo(F, Record, Idx));
+
+ case DeclarationName::ObjCZeroArgSelector:
+ case DeclarationName::ObjCOneArgSelector:
+ case DeclarationName::ObjCMultiArgSelector:
+ return DeclarationName(ReadSelector(F, Record, Idx));
+
+ case DeclarationName::CXXConstructorName:
+ return Context.DeclarationNames.getCXXConstructorName(
+ Context.getCanonicalType(readType(F, Record, Idx)));
+
+ case DeclarationName::CXXDestructorName:
+ return Context.DeclarationNames.getCXXDestructorName(
+ Context.getCanonicalType(readType(F, Record, Idx)));
+
+ case DeclarationName::CXXConversionFunctionName:
+ return Context.DeclarationNames.getCXXConversionFunctionName(
+ Context.getCanonicalType(readType(F, Record, Idx)));
+
+ case DeclarationName::CXXOperatorName:
+ return Context.DeclarationNames.getCXXOperatorName(
+ (OverloadedOperatorKind)Record[Idx++]);
+
+ case DeclarationName::CXXLiteralOperatorName:
+ return Context.DeclarationNames.getCXXLiteralOperatorName(
+ GetIdentifierInfo(F, Record, Idx));
+
+ case DeclarationName::CXXUsingDirective:
+ return DeclarationName::getUsingDirectiveName();
+ }
+
+ llvm_unreachable("Invalid NameKind!");
+}
+
+void ASTReader::ReadDeclarationNameLoc(ModuleFile &F,
+ DeclarationNameLoc &DNLoc,
+ DeclarationName Name,
+ const RecordData &Record, unsigned &Idx) {
+ switch (Name.getNameKind()) {
+ case DeclarationName::CXXConstructorName:
+ case DeclarationName::CXXDestructorName:
+ case DeclarationName::CXXConversionFunctionName:
+ DNLoc.NamedType.TInfo = GetTypeSourceInfo(F, Record, Idx);
+ break;
+
+ case DeclarationName::CXXOperatorName:
+ DNLoc.CXXOperatorName.BeginOpNameLoc
+ = ReadSourceLocation(F, Record, Idx).getRawEncoding();
+ DNLoc.CXXOperatorName.EndOpNameLoc
+ = ReadSourceLocation(F, Record, Idx).getRawEncoding();
+ break;
+
+ case DeclarationName::CXXLiteralOperatorName:
+ DNLoc.CXXLiteralOperatorName.OpNameLoc
+ = ReadSourceLocation(F, Record, Idx).getRawEncoding();
+ break;
+
+ case DeclarationName::Identifier:
+ case DeclarationName::ObjCZeroArgSelector:
+ case DeclarationName::ObjCOneArgSelector:
+ case DeclarationName::ObjCMultiArgSelector:
+ case DeclarationName::CXXUsingDirective:
+ break;
+ }
+}
+
+void ASTReader::ReadDeclarationNameInfo(ModuleFile &F,
+ DeclarationNameInfo &NameInfo,
+ const RecordData &Record, unsigned &Idx) {
+ NameInfo.setName(ReadDeclarationName(F, Record, Idx));
+ NameInfo.setLoc(ReadSourceLocation(F, Record, Idx));
+ DeclarationNameLoc DNLoc;
+ ReadDeclarationNameLoc(F, DNLoc, NameInfo.getName(), Record, Idx);
+ NameInfo.setInfo(DNLoc);
+}
+
+void ASTReader::ReadQualifierInfo(ModuleFile &F, QualifierInfo &Info,
+ const RecordData &Record, unsigned &Idx) {
+ Info.QualifierLoc = ReadNestedNameSpecifierLoc(F, Record, Idx);
+ unsigned NumTPLists = Record[Idx++];
+ Info.NumTemplParamLists = NumTPLists;
+ if (NumTPLists) {
+ Info.TemplParamLists = new (Context) TemplateParameterList*[NumTPLists];
+ for (unsigned i=0; i != NumTPLists; ++i)
+ Info.TemplParamLists[i] = ReadTemplateParameterList(F, Record, Idx);
+ }
+}
+
+TemplateName
+ASTReader::ReadTemplateName(ModuleFile &F, const RecordData &Record,
+ unsigned &Idx) {
+ TemplateName::NameKind Kind = (TemplateName::NameKind)Record[Idx++];
+ switch (Kind) {
+ case TemplateName::Template:
+ return TemplateName(ReadDeclAs<TemplateDecl>(F, Record, Idx));
+
+ case TemplateName::OverloadedTemplate: {
+ unsigned size = Record[Idx++];
+ UnresolvedSet<8> Decls;
+ while (size--)
+ Decls.addDecl(ReadDeclAs<NamedDecl>(F, Record, Idx));
+
+ return Context.getOverloadedTemplateName(Decls.begin(), Decls.end());
+ }
+
+ case TemplateName::QualifiedTemplate: {
+ NestedNameSpecifier *NNS = ReadNestedNameSpecifier(F, Record, Idx);
+ bool hasTemplKeyword = Record[Idx++];
+ TemplateDecl *Template = ReadDeclAs<TemplateDecl>(F, Record, Idx);
+ return Context.getQualifiedTemplateName(NNS, hasTemplKeyword, Template);
+ }
+
+ case TemplateName::DependentTemplate: {
+ NestedNameSpecifier *NNS = ReadNestedNameSpecifier(F, Record, Idx);
+ if (Record[Idx++]) // isIdentifier
+ return Context.getDependentTemplateName(NNS,
+ GetIdentifierInfo(F, Record,
+ Idx));
+ return Context.getDependentTemplateName(NNS,
+ (OverloadedOperatorKind)Record[Idx++]);
+ }
+
+ case TemplateName::SubstTemplateTemplateParm: {
+ TemplateTemplateParmDecl *param
+ = ReadDeclAs<TemplateTemplateParmDecl>(F, Record, Idx);
+ if (!param) return TemplateName();
+ TemplateName replacement = ReadTemplateName(F, Record, Idx);
+ return Context.getSubstTemplateTemplateParm(param, replacement);
+ }
+
+ case TemplateName::SubstTemplateTemplateParmPack: {
+ TemplateTemplateParmDecl *Param
+ = ReadDeclAs<TemplateTemplateParmDecl>(F, Record, Idx);
+ if (!Param)
+ return TemplateName();
+
+ TemplateArgument ArgPack = ReadTemplateArgument(F, Record, Idx);
+ if (ArgPack.getKind() != TemplateArgument::Pack)
+ return TemplateName();
+
+ return Context.getSubstTemplateTemplateParmPack(Param, ArgPack);
+ }
+ }
+
+ llvm_unreachable("Unhandled template name kind!");
+}
+
+TemplateArgument
+ASTReader::ReadTemplateArgument(ModuleFile &F,
+ const RecordData &Record, unsigned &Idx) {
+ TemplateArgument::ArgKind Kind = (TemplateArgument::ArgKind)Record[Idx++];
+ switch (Kind) {
+ case TemplateArgument::Null:
+ return TemplateArgument();
+ case TemplateArgument::Type:
+ return TemplateArgument(readType(F, Record, Idx));
+ case TemplateArgument::Declaration: {
+ ValueDecl *D = ReadDeclAs<ValueDecl>(F, Record, Idx);
+ bool ForReferenceParam = Record[Idx++];
+ return TemplateArgument(D, ForReferenceParam);
+ }
+ case TemplateArgument::NullPtr:
+ return TemplateArgument(readType(F, Record, Idx), /*isNullPtr*/true);
+ case TemplateArgument::Integral: {
+ llvm::APSInt Value = ReadAPSInt(Record, Idx);
+ QualType T = readType(F, Record, Idx);
+ return TemplateArgument(Context, Value, T);
+ }
+ case TemplateArgument::Template:
+ return TemplateArgument(ReadTemplateName(F, Record, Idx));
+ case TemplateArgument::TemplateExpansion: {
+ TemplateName Name = ReadTemplateName(F, Record, Idx);
+ llvm::Optional<unsigned> NumTemplateExpansions;
+ if (unsigned NumExpansions = Record[Idx++])
+ NumTemplateExpansions = NumExpansions - 1;
+ return TemplateArgument(Name, NumTemplateExpansions);
+ }
+ case TemplateArgument::Expression:
+ return TemplateArgument(ReadExpr(F));
+ case TemplateArgument::Pack: {
+ unsigned NumArgs = Record[Idx++];
+ TemplateArgument *Args = new (Context) TemplateArgument[NumArgs];
+ for (unsigned I = 0; I != NumArgs; ++I)
+ Args[I] = ReadTemplateArgument(F, Record, Idx);
+ return TemplateArgument(Args, NumArgs);
+ }
+ }
+
+ llvm_unreachable("Unhandled template argument kind!");
+}
+
+TemplateParameterList *
+ASTReader::ReadTemplateParameterList(ModuleFile &F,
+ const RecordData &Record, unsigned &Idx) {
+ SourceLocation TemplateLoc = ReadSourceLocation(F, Record, Idx);
+ SourceLocation LAngleLoc = ReadSourceLocation(F, Record, Idx);
+ SourceLocation RAngleLoc = ReadSourceLocation(F, Record, Idx);
+
+ unsigned NumParams = Record[Idx++];
+ SmallVector<NamedDecl *, 16> Params;
+ Params.reserve(NumParams);
+ while (NumParams--)
+ Params.push_back(ReadDeclAs<NamedDecl>(F, Record, Idx));
+
+ TemplateParameterList* TemplateParams =
+ TemplateParameterList::Create(Context, TemplateLoc, LAngleLoc,
+ Params.data(), Params.size(), RAngleLoc);
+ return TemplateParams;
+}
+
+void
+ASTReader::
+ReadTemplateArgumentList(SmallVector<TemplateArgument, 8> &TemplArgs,
+ ModuleFile &F, const RecordData &Record,
+ unsigned &Idx) {
+ unsigned NumTemplateArgs = Record[Idx++];
+ TemplArgs.reserve(NumTemplateArgs);
+ while (NumTemplateArgs--)
+ TemplArgs.push_back(ReadTemplateArgument(F, Record, Idx));
+}
+
+/// \brief Read a UnresolvedSet structure.
+void ASTReader::ReadUnresolvedSet(ModuleFile &F, ASTUnresolvedSet &Set,
+ const RecordData &Record, unsigned &Idx) {
+ unsigned NumDecls = Record[Idx++];
+ Set.reserve(Context, NumDecls);
+ while (NumDecls--) {
+ NamedDecl *D = ReadDeclAs<NamedDecl>(F, Record, Idx);
+ AccessSpecifier AS = (AccessSpecifier)Record[Idx++];
+ Set.addDecl(Context, D, AS);
+ }
+}
+
+CXXBaseSpecifier
+ASTReader::ReadCXXBaseSpecifier(ModuleFile &F,
+ const RecordData &Record, unsigned &Idx) {
+ bool isVirtual = static_cast<bool>(Record[Idx++]);
+ bool isBaseOfClass = static_cast<bool>(Record[Idx++]);
+ AccessSpecifier AS = static_cast<AccessSpecifier>(Record[Idx++]);
+ bool inheritConstructors = static_cast<bool>(Record[Idx++]);
+ TypeSourceInfo *TInfo = GetTypeSourceInfo(F, Record, Idx);
+ SourceRange Range = ReadSourceRange(F, Record, Idx);
+ SourceLocation EllipsisLoc = ReadSourceLocation(F, Record, Idx);
+ CXXBaseSpecifier Result(Range, isVirtual, isBaseOfClass, AS, TInfo,
+ EllipsisLoc);
+ Result.setInheritConstructors(inheritConstructors);
+ return Result;
+}
+
+std::pair<CXXCtorInitializer **, unsigned>
+ASTReader::ReadCXXCtorInitializers(ModuleFile &F, const RecordData &Record,
+ unsigned &Idx) {
+ CXXCtorInitializer **CtorInitializers = 0;
+ unsigned NumInitializers = Record[Idx++];
+ if (NumInitializers) {
+ CtorInitializers
+ = new (Context) CXXCtorInitializer*[NumInitializers];
+ for (unsigned i=0; i != NumInitializers; ++i) {
+ TypeSourceInfo *TInfo = 0;
+ bool IsBaseVirtual = false;
+ FieldDecl *Member = 0;
+ IndirectFieldDecl *IndirectMember = 0;
+
+ CtorInitializerType Type = (CtorInitializerType)Record[Idx++];
+ switch (Type) {
+ case CTOR_INITIALIZER_BASE:
+ TInfo = GetTypeSourceInfo(F, Record, Idx);
+ IsBaseVirtual = Record[Idx++];
+ break;
+
+ case CTOR_INITIALIZER_DELEGATING:
+ TInfo = GetTypeSourceInfo(F, Record, Idx);
+ break;
+
+ case CTOR_INITIALIZER_MEMBER:
+ Member = ReadDeclAs<FieldDecl>(F, Record, Idx);
+ break;
+
+ case CTOR_INITIALIZER_INDIRECT_MEMBER:
+ IndirectMember = ReadDeclAs<IndirectFieldDecl>(F, Record, Idx);
+ break;
+ }
+
+ SourceLocation MemberOrEllipsisLoc = ReadSourceLocation(F, Record, Idx);
+ Expr *Init = ReadExpr(F);
+ SourceLocation LParenLoc = ReadSourceLocation(F, Record, Idx);
+ SourceLocation RParenLoc = ReadSourceLocation(F, Record, Idx);
+ bool IsWritten = Record[Idx++];
+ unsigned SourceOrderOrNumArrayIndices;
+ SmallVector<VarDecl *, 8> Indices;
+ if (IsWritten) {
+ SourceOrderOrNumArrayIndices = Record[Idx++];
+ } else {
+ SourceOrderOrNumArrayIndices = Record[Idx++];
+ Indices.reserve(SourceOrderOrNumArrayIndices);
+ for (unsigned i=0; i != SourceOrderOrNumArrayIndices; ++i)
+ Indices.push_back(ReadDeclAs<VarDecl>(F, Record, Idx));
+ }
+
+ CXXCtorInitializer *BOMInit;
+ if (Type == CTOR_INITIALIZER_BASE) {
+ BOMInit = new (Context) CXXCtorInitializer(Context, TInfo, IsBaseVirtual,
+ LParenLoc, Init, RParenLoc,
+ MemberOrEllipsisLoc);
+ } else if (Type == CTOR_INITIALIZER_DELEGATING) {
+ BOMInit = new (Context) CXXCtorInitializer(Context, TInfo, LParenLoc,
+ Init, RParenLoc);
+ } else if (IsWritten) {
+ if (Member)
+ BOMInit = new (Context) CXXCtorInitializer(Context, Member, MemberOrEllipsisLoc,
+ LParenLoc, Init, RParenLoc);
+ else
+ BOMInit = new (Context) CXXCtorInitializer(Context, IndirectMember,
+ MemberOrEllipsisLoc, LParenLoc,
+ Init, RParenLoc);
+ } else {
+ BOMInit = CXXCtorInitializer::Create(Context, Member, MemberOrEllipsisLoc,
+ LParenLoc, Init, RParenLoc,
+ Indices.data(), Indices.size());
+ }
+
+ if (IsWritten)
+ BOMInit->setSourceOrder(SourceOrderOrNumArrayIndices);
+ CtorInitializers[i] = BOMInit;
+ }
+ }
+
+ return std::make_pair(CtorInitializers, NumInitializers);
+}
+
+NestedNameSpecifier *
+ASTReader::ReadNestedNameSpecifier(ModuleFile &F,
+ const RecordData &Record, unsigned &Idx) {
+ unsigned N = Record[Idx++];
+ NestedNameSpecifier *NNS = 0, *Prev = 0;
+ for (unsigned I = 0; I != N; ++I) {
+ NestedNameSpecifier::SpecifierKind Kind
+ = (NestedNameSpecifier::SpecifierKind)Record[Idx++];
+ switch (Kind) {
+ case NestedNameSpecifier::Identifier: {
+ IdentifierInfo *II = GetIdentifierInfo(F, Record, Idx);
+ NNS = NestedNameSpecifier::Create(Context, Prev, II);
+ break;
+ }
+
+ case NestedNameSpecifier::Namespace: {
+ NamespaceDecl *NS = ReadDeclAs<NamespaceDecl>(F, Record, Idx);
+ NNS = NestedNameSpecifier::Create(Context, Prev, NS);
+ break;
+ }
+
+ case NestedNameSpecifier::NamespaceAlias: {
+ NamespaceAliasDecl *Alias =ReadDeclAs<NamespaceAliasDecl>(F, Record, Idx);
+ NNS = NestedNameSpecifier::Create(Context, Prev, Alias);
+ break;
+ }
+
+ case NestedNameSpecifier::TypeSpec:
+ case NestedNameSpecifier::TypeSpecWithTemplate: {
+ const Type *T = readType(F, Record, Idx).getTypePtrOrNull();
+ if (!T)
+ return 0;
+
+ bool Template = Record[Idx++];
+ NNS = NestedNameSpecifier::Create(Context, Prev, Template, T);
+ break;
+ }
+
+ case NestedNameSpecifier::Global: {
+ NNS = NestedNameSpecifier::GlobalSpecifier(Context);
+ // No associated value, and there can't be a prefix.
+ break;
+ }
+ }
+ Prev = NNS;
+ }
+ return NNS;
+}
+
+NestedNameSpecifierLoc
+ASTReader::ReadNestedNameSpecifierLoc(ModuleFile &F, const RecordData &Record,
+ unsigned &Idx) {
+ unsigned N = Record[Idx++];
+ NestedNameSpecifierLocBuilder Builder;
+ for (unsigned I = 0; I != N; ++I) {
+ NestedNameSpecifier::SpecifierKind Kind
+ = (NestedNameSpecifier::SpecifierKind)Record[Idx++];
+ switch (Kind) {
+ case NestedNameSpecifier::Identifier: {
+ IdentifierInfo *II = GetIdentifierInfo(F, Record, Idx);
+ SourceRange Range = ReadSourceRange(F, Record, Idx);
+ Builder.Extend(Context, II, Range.getBegin(), Range.getEnd());
+ break;
+ }
+
+ case NestedNameSpecifier::Namespace: {
+ NamespaceDecl *NS = ReadDeclAs<NamespaceDecl>(F, Record, Idx);
+ SourceRange Range = ReadSourceRange(F, Record, Idx);
+ Builder.Extend(Context, NS, Range.getBegin(), Range.getEnd());
+ break;
+ }
+
+ case NestedNameSpecifier::NamespaceAlias: {
+ NamespaceAliasDecl *Alias =ReadDeclAs<NamespaceAliasDecl>(F, Record, Idx);
+ SourceRange Range = ReadSourceRange(F, Record, Idx);
+ Builder.Extend(Context, Alias, Range.getBegin(), Range.getEnd());
+ break;
+ }
+
+ case NestedNameSpecifier::TypeSpec:
+ case NestedNameSpecifier::TypeSpecWithTemplate: {
+ bool Template = Record[Idx++];
+ TypeSourceInfo *T = GetTypeSourceInfo(F, Record, Idx);
+ if (!T)
+ return NestedNameSpecifierLoc();
+ SourceLocation ColonColonLoc = ReadSourceLocation(F, Record, Idx);
+
+ // FIXME: 'template' keyword location not saved anywhere, so we fake it.
+ Builder.Extend(Context,
+ Template? T->getTypeLoc().getBeginLoc() : SourceLocation(),
+ T->getTypeLoc(), ColonColonLoc);
+ break;
+ }
+
+ case NestedNameSpecifier::Global: {
+ SourceLocation ColonColonLoc = ReadSourceLocation(F, Record, Idx);
+ Builder.MakeGlobal(Context, ColonColonLoc);
+ break;
+ }
+ }
+ }
+
+ return Builder.getWithLocInContext(Context);
+}
+
+SourceRange
+ASTReader::ReadSourceRange(ModuleFile &F, const RecordData &Record,
+ unsigned &Idx) {
+ SourceLocation beg = ReadSourceLocation(F, Record, Idx);
+ SourceLocation end = ReadSourceLocation(F, Record, Idx);
+ return SourceRange(beg, end);
+}
+
+/// \brief Read an integral value
+llvm::APInt ASTReader::ReadAPInt(const RecordData &Record, unsigned &Idx) {
+ unsigned BitWidth = Record[Idx++];
+ unsigned NumWords = llvm::APInt::getNumWords(BitWidth);
+ llvm::APInt Result(BitWidth, NumWords, &Record[Idx]);
+ Idx += NumWords;
+ return Result;
+}
+
+/// \brief Read a signed integral value
+llvm::APSInt ASTReader::ReadAPSInt(const RecordData &Record, unsigned &Idx) {
+ bool isUnsigned = Record[Idx++];
+ return llvm::APSInt(ReadAPInt(Record, Idx), isUnsigned);
+}
+
+/// \brief Read a floating-point value
+llvm::APFloat ASTReader::ReadAPFloat(const RecordData &Record, unsigned &Idx) {
+ return llvm::APFloat(ReadAPInt(Record, Idx));
+}
+
+// \brief Read a string
+std::string ASTReader::ReadString(const RecordData &Record, unsigned &Idx) {
+ unsigned Len = Record[Idx++];
+ std::string Result(Record.data() + Idx, Record.data() + Idx + Len);
+ Idx += Len;
+ return Result;
+}
+
+VersionTuple ASTReader::ReadVersionTuple(const RecordData &Record,
+ unsigned &Idx) {
+ unsigned Major = Record[Idx++];
+ unsigned Minor = Record[Idx++];
+ unsigned Subminor = Record[Idx++];
+ if (Minor == 0)
+ return VersionTuple(Major);
+ if (Subminor == 0)
+ return VersionTuple(Major, Minor - 1);
+ return VersionTuple(Major, Minor - 1, Subminor - 1);
+}
+
+CXXTemporary *ASTReader::ReadCXXTemporary(ModuleFile &F,
+ const RecordData &Record,
+ unsigned &Idx) {
+ CXXDestructorDecl *Decl = ReadDeclAs<CXXDestructorDecl>(F, Record, Idx);
+ return CXXTemporary::Create(Context, Decl);
+}
+
+DiagnosticBuilder ASTReader::Diag(unsigned DiagID) {
+ return Diag(SourceLocation(), DiagID);
+}
+
+DiagnosticBuilder ASTReader::Diag(SourceLocation Loc, unsigned DiagID) {
+ return Diags.Report(Loc, DiagID);
+}
+
+/// \brief Retrieve the identifier table associated with the
+/// preprocessor.
+IdentifierTable &ASTReader::getIdentifierTable() {
+ return PP.getIdentifierTable();
+}
+
+/// \brief Record that the given ID maps to the given switch-case
+/// statement.
+void ASTReader::RecordSwitchCaseID(SwitchCase *SC, unsigned ID) {
+ assert((*CurrSwitchCaseStmts)[ID] == 0 &&
+ "Already have a SwitchCase with this ID");
+ (*CurrSwitchCaseStmts)[ID] = SC;
+}
+
+/// \brief Retrieve the switch-case statement with the given ID.
+SwitchCase *ASTReader::getSwitchCaseWithID(unsigned ID) {
+ assert((*CurrSwitchCaseStmts)[ID] != 0 && "No SwitchCase with this ID");
+ return (*CurrSwitchCaseStmts)[ID];
+}
+
+void ASTReader::ClearSwitchCaseIDs() {
+ CurrSwitchCaseStmts->clear();
+}
+
+void ASTReader::ReadComments() {
+ std::vector<RawComment *> Comments;
+ for (SmallVectorImpl<std::pair<llvm::BitstreamCursor,
+ serialization::ModuleFile *> >::iterator
+ I = CommentsCursors.begin(),
+ E = CommentsCursors.end();
+ I != E; ++I) {
+ llvm::BitstreamCursor &Cursor = I->first;
+ serialization::ModuleFile &F = *I->second;
+ SavedStreamPosition SavedPosition(Cursor);
+
+ RecordData Record;
+ while (true) {
+ unsigned Code = Cursor.ReadCode();
+ if (Code == llvm::bitc::END_BLOCK)
+ break;
+
+ if (Code == llvm::bitc::ENTER_SUBBLOCK) {
+ // No known subblocks, always skip them.
+ Cursor.ReadSubBlockID();
+ if (Cursor.SkipBlock()) {
+ Error("malformed block record in AST file");
+ return;
+ }
+ continue;
+ }
+
+ if (Code == llvm::bitc::DEFINE_ABBREV) {
+ Cursor.ReadAbbrevRecord();
+ continue;
+ }
+
+ // Read a record.
+ Record.clear();
+ switch ((CommentRecordTypes) Cursor.ReadRecord(Code, Record)) {
+ case COMMENTS_RAW_COMMENT: {
+ unsigned Idx = 0;
+ SourceRange SR = ReadSourceRange(F, Record, Idx);
+ RawComment::CommentKind Kind =
+ (RawComment::CommentKind) Record[Idx++];
+ bool IsTrailingComment = Record[Idx++];
+ bool IsAlmostTrailingComment = Record[Idx++];
+ Comments.push_back(new (Context) RawComment(SR, Kind,
+ IsTrailingComment,
+ IsAlmostTrailingComment));
+ break;
+ }
+ }
+ }
+ }
+ Context.Comments.addCommentsToFront(Comments);
+}
+
+void ASTReader::finishPendingActions() {
+ while (!PendingIdentifierInfos.empty() || !PendingDeclChains.empty() ||
+ !PendingMacroIDs.empty()) {
+ // If any identifiers with corresponding top-level declarations have
+ // been loaded, load those declarations now.
+ while (!PendingIdentifierInfos.empty()) {
+ SetGloballyVisibleDecls(PendingIdentifierInfos.front().II,
+ PendingIdentifierInfos.front().DeclIDs, true);
+ PendingIdentifierInfos.pop_front();
+ }
+
+ // Load pending declaration chains.
+ for (unsigned I = 0; I != PendingDeclChains.size(); ++I) {
+ loadPendingDeclChain(PendingDeclChains[I]);
+ PendingDeclChainsKnown.erase(PendingDeclChains[I]);
+ }
+ PendingDeclChains.clear();
+
+ // Load any pending macro definitions.
+ for (unsigned I = 0; I != PendingMacroIDs.size(); ++I) {
+ // FIXME: std::move here
+ SmallVector<MacroID, 2> GlobalIDs = PendingMacroIDs.begin()[I].second;
+ MacroInfo *Hint = 0;
+ for (unsigned IDIdx = 0, NumIDs = GlobalIDs.size(); IDIdx != NumIDs;
+ ++IDIdx) {
+ Hint = getMacro(GlobalIDs[IDIdx], Hint);
+ }
+ }
+ PendingMacroIDs.clear();
+ }
+
+ // If we deserialized any C++ or Objective-C class definitions, any
+ // Objective-C protocol definitions, or any redeclarable templates, make sure
+ // that all redeclarations point to the definitions. Note that this can only
+ // happen now, after the redeclaration chains have been fully wired.
+ for (llvm::SmallPtrSet<Decl *, 4>::iterator D = PendingDefinitions.begin(),
+ DEnd = PendingDefinitions.end();
+ D != DEnd; ++D) {
+ if (TagDecl *TD = dyn_cast<TagDecl>(*D)) {
+ if (const TagType *TagT = dyn_cast<TagType>(TD->TypeForDecl)) {
+ // Make sure that the TagType points at the definition.
+ const_cast<TagType*>(TagT)->decl = TD;
+ }
+
+ if (CXXRecordDecl *RD = dyn_cast<CXXRecordDecl>(*D)) {
+ for (CXXRecordDecl::redecl_iterator R = RD->redecls_begin(),
+ REnd = RD->redecls_end();
+ R != REnd; ++R)
+ cast<CXXRecordDecl>(*R)->DefinitionData = RD->DefinitionData;
+
+ }
+
+ continue;
+ }
+
+ if (ObjCInterfaceDecl *ID = dyn_cast<ObjCInterfaceDecl>(*D)) {
+ // Make sure that the ObjCInterfaceType points at the definition.
+ const_cast<ObjCInterfaceType *>(cast<ObjCInterfaceType>(ID->TypeForDecl))
+ ->Decl = ID;
+
+ for (ObjCInterfaceDecl::redecl_iterator R = ID->redecls_begin(),
+ REnd = ID->redecls_end();
+ R != REnd; ++R)
+ R->Data = ID->Data;
+
+ continue;
+ }
+
+ if (ObjCProtocolDecl *PD = dyn_cast<ObjCProtocolDecl>(*D)) {
+ for (ObjCProtocolDecl::redecl_iterator R = PD->redecls_begin(),
+ REnd = PD->redecls_end();
+ R != REnd; ++R)
+ R->Data = PD->Data;
+
+ continue;
+ }
+
+ RedeclarableTemplateDecl *RTD
+ = cast<RedeclarableTemplateDecl>(*D)->getCanonicalDecl();
+ for (RedeclarableTemplateDecl::redecl_iterator R = RTD->redecls_begin(),
+ REnd = RTD->redecls_end();
+ R != REnd; ++R)
+ R->Common = RTD->Common;
+ }
+ PendingDefinitions.clear();
+
+ // Load the bodies of any functions or methods we've encountered. We do
+ // this now (delayed) so that we can be sure that the declaration chains
+ // have been fully wired up.
+ for (PendingBodiesMap::iterator PB = PendingBodies.begin(),
+ PBEnd = PendingBodies.end();
+ PB != PBEnd; ++PB) {
+ if (FunctionDecl *FD = dyn_cast<FunctionDecl>(PB->first)) {
+ // FIXME: Check for =delete/=default?
+ // FIXME: Complain about ODR violations here?
+ if (!getContext().getLangOpts().Modules || !FD->hasBody())
+ FD->setLazyBody(PB->second);
+ continue;
+ }
+
+ ObjCMethodDecl *MD = cast<ObjCMethodDecl>(PB->first);
+ if (!getContext().getLangOpts().Modules || !MD->hasBody())
+ MD->setLazyBody(PB->second);
+ }
+ PendingBodies.clear();
+}
+
+void ASTReader::FinishedDeserializing() {
+ assert(NumCurrentElementsDeserializing &&
+ "FinishedDeserializing not paired with StartedDeserializing");
+ if (NumCurrentElementsDeserializing == 1) {
+ // We decrease NumCurrentElementsDeserializing only after pending actions
+ // are finished, to avoid recursively re-calling finishPendingActions().
+ finishPendingActions();
+ }
+ --NumCurrentElementsDeserializing;
+
+ if (NumCurrentElementsDeserializing == 0 &&
+ Consumer && !PassingDeclsToConsumer) {
+ // Guard variable to avoid recursively redoing the process of passing
+ // decls to consumer.
+ SaveAndRestore<bool> GuardPassingDeclsToConsumer(PassingDeclsToConsumer,
+ true);
+
+ while (!InterestingDecls.empty()) {
+ // We are not in recursive loading, so it's safe to pass the "interesting"
+ // decls to the consumer.
+ Decl *D = InterestingDecls.front();
+ InterestingDecls.pop_front();
+ PassInterestingDeclToConsumer(D);
+ }
+ }
+}
+
+ASTReader::ASTReader(Preprocessor &PP, ASTContext &Context,
+ StringRef isysroot, bool DisableValidation,
+ bool AllowASTWithCompilerErrors)
+ : Listener(new PCHValidator(PP, *this)), DeserializationListener(0),
+ SourceMgr(PP.getSourceManager()), FileMgr(PP.getFileManager()),
+ Diags(PP.getDiagnostics()), SemaObj(0), PP(PP), Context(Context),
+ Consumer(0), ModuleMgr(PP.getFileManager()),
+ isysroot(isysroot), DisableValidation(DisableValidation),
+ AllowASTWithCompilerErrors(AllowASTWithCompilerErrors),
+ CurrentGeneration(0), CurrSwitchCaseStmts(&SwitchCaseStmts),
+ NumSLocEntriesRead(0), TotalNumSLocEntries(0),
+ NumStatementsRead(0), TotalNumStatements(0), NumMacrosRead(0),
+ TotalNumMacros(0), NumSelectorsRead(0), NumMethodPoolEntriesRead(0),
+ NumMethodPoolMisses(0), TotalNumMethodPoolEntries(0),
+ NumLexicalDeclContextsRead(0), TotalLexicalDeclContexts(0),
+ NumVisibleDeclContextsRead(0), TotalVisibleDeclContexts(0),
+ TotalModulesSizeInBits(0), NumCurrentElementsDeserializing(0),
+ PassingDeclsToConsumer(false),
+ NumCXXBaseSpecifiersLoaded(0)
+{
+ SourceMgr.setExternalSLocEntrySource(this);
+}
+
+ASTReader::~ASTReader() {
+ for (DeclContextVisibleUpdatesPending::iterator
+ I = PendingVisibleUpdates.begin(),
+ E = PendingVisibleUpdates.end();
+ I != E; ++I) {
+ for (DeclContextVisibleUpdates::iterator J = I->second.begin(),
+ F = I->second.end();
+ J != F; ++J)
+ delete J->first;
+ }
+}
diff --git a/clang/test/CodeGenOpenCL/opencl_types.cl b/clang/test/CodeGenOpenCL/opencl_types.cl new file mode 100644 index 00000000000..5bebc5e2881 --- /dev/null +++ b/clang/test/CodeGenOpenCL/opencl_types.cl @@ -0,0 +1,22 @@ +// RUN: %clang_cc1 %s -emit-llvm -o - -O0 | FileCheck %s
+
+void fnc1(image1d_t img) {}
+// CHECK: @fnc1(%opencl.image1d_t*
+
+void fnc1arr(image1d_array_t img) {}
+// CHECK: @fnc1arr(%opencl.image1d_array_t*
+
+void fnc1buff(image1d_buffer_t img) {}
+// CHECK: @fnc1buff(%opencl.image1d_buffer_t*
+
+void fnc2(image2d_t img) {}
+// CHECK: @fnc2(%opencl.image2d_t*
+
+void fnc2arr(image2d_array_t img) {}
+// CHECK: @fnc2arr(%opencl.image2d_array_t*
+
+void fnc3(image3d_t img) {}
+// CHECK: @fnc3(%opencl.image3d_t*
+
+kernel void foo(image1d_t img) {
+}
diff --git a/clang/test/PCH/ocl_types.cl b/clang/test/PCH/ocl_types.cl new file mode 100644 index 00000000000..d5c4428f981 --- /dev/null +++ b/clang/test/PCH/ocl_types.cl @@ -0,0 +1,18 @@ +// Test this without pch.
+// RUN: %clang_cc1 -include %S/ocl_types.h -fsyntax-only %s
+
+// Test with pch.
+// RUN: %clang_cc1 -x cl -emit-pch -o %t %S/ocl_types.h
+// RUN: %clang_cc1 -include-pch %t -fsyntax-only %s -ast-print
+
+void foo1(img1d_t img);
+
+void foo2(img1darr_t img);
+
+void foo3(img1dbuff_t img);
+
+void foo4(img2d_t img);
+
+void foo5(img2darr_t img);
+
+void foo6(img3d_t img);
diff --git a/clang/test/PCH/ocl_types.h b/clang/test/PCH/ocl_types.h new file mode 100644 index 00000000000..6afa016032e --- /dev/null +++ b/clang/test/PCH/ocl_types.h @@ -0,0 +1,19 @@ +/* Used with the ocl_types.cl test */
+
+// image1d_t
+typedef image1d_t img1d_t;
+
+// image1d_array_t
+typedef image1d_array_t img1darr_t;
+
+// image1d_buffer_t
+typedef image1d_buffer_t img1dbuff_t;
+
+// image2d_t
+typedef image2d_t img2d_t;
+
+// image2d_array_t
+typedef image2d_array_t img2darr_t;
+
+// image3d_t
+typedef image3d_t img3d_t;
diff --git a/clang/test/Parser/opencl-image-access.cl b/clang/test/Parser/opencl-image-access.cl index 313587c1d22..3496d12a3e5 100644 --- a/clang/test/Parser/opencl-image-access.cl +++ b/clang/test/Parser/opencl-image-access.cl @@ -1,16 +1,14 @@ -// RUN: %clang_cc1 %s -fsyntax-only - -typedef void* image2d_t; - -__kernel void f__ro(__read_only image2d_t a) { } - -__kernel void f__wo(__write_only image2d_t a) { } - -__kernel void f__rw(__read_write image2d_t a) { } - - -__kernel void fro(read_only image2d_t a) { } - -__kernel void fwo(write_only image2d_t a) { } - -__kernel void frw(read_write image2d_t a) { } +// RUN: %clang_cc1 %s -fsyntax-only
+
+__kernel void f__ro(__read_only image2d_t a) { }
+
+__kernel void f__wo(__write_only image2d_t a) { }
+
+__kernel void f__rw(__read_write image2d_t a) { }
+
+
+__kernel void fro(read_only image2d_t a) { }
+
+__kernel void fwo(write_only image2d_t a) { }
+
+__kernel void frw(read_write image2d_t a) { }
diff --git a/clang/tools/libclang/CIndex.cpp b/clang/tools/libclang/CIndex.cpp index 1fb9a70336a..c28c181dae8 100644 --- a/clang/tools/libclang/CIndex.cpp +++ b/clang/tools/libclang/CIndex.cpp @@ -1,6169 +1,6175 @@ -//===- CIndex.cpp - Clang-C Source Indexing Library -----------------------===// -// -// The LLVM Compiler Infrastructure -// -// This file is distributed under the University of Illinois Open Source -// License. See LICENSE.TXT for details. -// -//===----------------------------------------------------------------------===// -// -// This file implements the main API hooks in the Clang-C Source Indexing -// library. -// -//===----------------------------------------------------------------------===// - -#include "CIndexer.h" -#include "CIndexDiagnostic.h" -#include "CXComment.h" -#include "CXCursor.h" -#include "CXSourceLocation.h" -#include "CXString.h" -#include "CXTranslationUnit.h" -#include "CXType.h" -#include "CursorVisitor.h" -#include "clang/AST/StmtVisitor.h" -#include "clang/Basic/Diagnostic.h" -#include "clang/Basic/Version.h" -#include "clang/Frontend/ASTUnit.h" -#include "clang/Frontend/CompilerInstance.h" -#include "clang/Frontend/FrontendDiagnostic.h" -#include "clang/Lex/HeaderSearch.h" -#include "clang/Lex/Lexer.h" -#include "clang/Lex/PreprocessingRecord.h" -#include "clang/Lex/Preprocessor.h" -#include "llvm/ADT/Optional.h" -#include "llvm/ADT/STLExtras.h" -#include "llvm/ADT/StringSwitch.h" -#include "llvm/Support/Compiler.h" -#include "llvm/Support/CrashRecoveryContext.h" -#include "llvm/Support/MemoryBuffer.h" -#include "llvm/Support/Mutex.h" -#include "llvm/Support/PrettyStackTrace.h" -#include "llvm/Support/Program.h" -#include "llvm/Support/SaveAndRestore.h" -#include "llvm/Support/Signals.h" -#include "llvm/Support/Threading.h" -#include "llvm/Support/Timer.h" -#include "llvm/Support/raw_ostream.h" - -using namespace clang; -using namespace clang::cxcursor; -using namespace clang::cxstring; -using namespace clang::cxtu; -using namespace clang::cxindex; - -CXTranslationUnit cxtu::MakeCXTranslationUnit(CIndexer *CIdx, ASTUnit *TU) { - if (!TU) - return 0; - CXTranslationUnit D = new CXTranslationUnitImpl(); - D->CIdx = CIdx; - D->TUData = TU; - D->StringPool = createCXStringPool(); - D->Diagnostics = 0; - D->OverridenCursorsPool = createOverridenCXCursorsPool(); - return D; -} - -cxtu::CXTUOwner::~CXTUOwner() { - if (TU) - clang_disposeTranslationUnit(TU); -} - -/// \brief Compare two source ranges to determine their relative position in -/// the translation unit. -static RangeComparisonResult RangeCompare(SourceManager &SM, - SourceRange R1, - SourceRange R2) { - assert(R1.isValid() && "First range is invalid?"); - assert(R2.isValid() && "Second range is invalid?"); - if (R1.getEnd() != R2.getBegin() && - SM.isBeforeInTranslationUnit(R1.getEnd(), R2.getBegin())) - return RangeBefore; - if (R2.getEnd() != R1.getBegin() && - SM.isBeforeInTranslationUnit(R2.getEnd(), R1.getBegin())) - return RangeAfter; - return RangeOverlap; -} - -/// \brief Determine if a source location falls within, before, or after a -/// a given source range. -static RangeComparisonResult LocationCompare(SourceManager &SM, - SourceLocation L, SourceRange R) { - assert(R.isValid() && "First range is invalid?"); - assert(L.isValid() && "Second range is invalid?"); - if (L == R.getBegin() || L == R.getEnd()) - return RangeOverlap; - if (SM.isBeforeInTranslationUnit(L, R.getBegin())) - return RangeBefore; - if (SM.isBeforeInTranslationUnit(R.getEnd(), L)) - return RangeAfter; - return RangeOverlap; -} - -/// \brief Translate a Clang source range into a CIndex source range. -/// -/// Clang internally represents ranges where the end location points to the -/// start of the token at the end. However, for external clients it is more -/// useful to have a CXSourceRange be a proper half-open interval. This routine -/// does the appropriate translation. -CXSourceRange cxloc::translateSourceRange(const SourceManager &SM, - const LangOptions &LangOpts, - const CharSourceRange &R) { - // We want the last character in this location, so we will adjust the - // location accordingly. - SourceLocation EndLoc = R.getEnd(); - if (EndLoc.isValid() && EndLoc.isMacroID() && !SM.isMacroArgExpansion(EndLoc)) - EndLoc = SM.getExpansionRange(EndLoc).second; - if (R.isTokenRange() && !EndLoc.isInvalid()) { - unsigned Length = Lexer::MeasureTokenLength(SM.getSpellingLoc(EndLoc), - SM, LangOpts); - EndLoc = EndLoc.getLocWithOffset(Length); - } - - CXSourceRange Result = { { (void *)&SM, (void *)&LangOpts }, - R.getBegin().getRawEncoding(), - EndLoc.getRawEncoding() }; - return Result; -} - -//===----------------------------------------------------------------------===// -// Cursor visitor. -//===----------------------------------------------------------------------===// - -static SourceRange getRawCursorExtent(CXCursor C); -static SourceRange getFullCursorExtent(CXCursor C, SourceManager &SrcMgr); - - -RangeComparisonResult CursorVisitor::CompareRegionOfInterest(SourceRange R) { - return RangeCompare(AU->getSourceManager(), R, RegionOfInterest); -} - -/// \brief Visit the given cursor and, if requested by the visitor, -/// its children. -/// -/// \param Cursor the cursor to visit. -/// -/// \param CheckedRegionOfInterest if true, then the caller already checked -/// that this cursor is within the region of interest. -/// -/// \returns true if the visitation should be aborted, false if it -/// should continue. -bool CursorVisitor::Visit(CXCursor Cursor, bool CheckedRegionOfInterest) { - if (clang_isInvalid(Cursor.kind)) - return false; - - if (clang_isDeclaration(Cursor.kind)) { - Decl *D = getCursorDecl(Cursor); - if (!D) { - assert(0 && "Invalid declaration cursor"); - return true; // abort. - } - - // Ignore implicit declarations, unless it's an objc method because - // currently we should report implicit methods for properties when indexing. - if (D->isImplicit() && !isa<ObjCMethodDecl>(D)) - return false; - } - - // If we have a range of interest, and this cursor doesn't intersect with it, - // we're done. - if (RegionOfInterest.isValid() && !CheckedRegionOfInterest) { - SourceRange Range = getRawCursorExtent(Cursor); - if (Range.isInvalid() || CompareRegionOfInterest(Range)) - return false; - } - - switch (Visitor(Cursor, Parent, ClientData)) { - case CXChildVisit_Break: - return true; - - case CXChildVisit_Continue: - return false; - - case CXChildVisit_Recurse: { - bool ret = VisitChildren(Cursor); - if (PostChildrenVisitor) - if (PostChildrenVisitor(Cursor, ClientData)) - return true; - return ret; - } - } - - llvm_unreachable("Invalid CXChildVisitResult!"); -} - -static bool visitPreprocessedEntitiesInRange(SourceRange R, - PreprocessingRecord &PPRec, - CursorVisitor &Visitor) { - SourceManager &SM = Visitor.getASTUnit()->getSourceManager(); - FileID FID; - - if (!Visitor.shouldVisitIncludedEntities()) { - // If the begin/end of the range lie in the same FileID, do the optimization - // where we skip preprocessed entities that do not come from the same FileID. - FID = SM.getFileID(SM.getFileLoc(R.getBegin())); - if (FID != SM.getFileID(SM.getFileLoc(R.getEnd()))) - FID = FileID(); - } - - std::pair<PreprocessingRecord::iterator, PreprocessingRecord::iterator> - Entities = PPRec.getPreprocessedEntitiesInRange(R); - return Visitor.visitPreprocessedEntities(Entities.first, Entities.second, - PPRec, FID); -} - -void CursorVisitor::visitFileRegion() { - if (RegionOfInterest.isInvalid()) - return; - - ASTUnit *Unit = static_cast<ASTUnit *>(TU->TUData); - SourceManager &SM = Unit->getSourceManager(); - - std::pair<FileID, unsigned> - Begin = SM.getDecomposedLoc(SM.getFileLoc(RegionOfInterest.getBegin())), - End = SM.getDecomposedLoc(SM.getFileLoc(RegionOfInterest.getEnd())); - - if (End.first != Begin.first) { - // If the end does not reside in the same file, try to recover by - // picking the end of the file of begin location. - End.first = Begin.first; - End.second = SM.getFileIDSize(Begin.first); - } - - assert(Begin.first == End.first); - if (Begin.second > End.second) - return; - - FileID File = Begin.first; - unsigned Offset = Begin.second; - unsigned Length = End.second - Begin.second; - - if (!VisitDeclsOnly && !VisitPreprocessorLast) - if (visitPreprocessedEntitiesInRegion()) - return; // visitation break. - - visitDeclsFromFileRegion(File, Offset, Length); - - if (!VisitDeclsOnly && VisitPreprocessorLast) - visitPreprocessedEntitiesInRegion(); -} - -static bool isInLexicalContext(Decl *D, DeclContext *DC) { - if (!DC) - return false; - - for (DeclContext *DeclDC = D->getLexicalDeclContext(); - DeclDC; DeclDC = DeclDC->getLexicalParent()) { - if (DeclDC == DC) - return true; - } - return false; -} - -void CursorVisitor::visitDeclsFromFileRegion(FileID File, - unsigned Offset, unsigned Length) { - ASTUnit *Unit = static_cast<ASTUnit *>(TU->TUData); - SourceManager &SM = Unit->getSourceManager(); - SourceRange Range = RegionOfInterest; - - SmallVector<Decl *, 16> Decls; - Unit->findFileRegionDecls(File, Offset, Length, Decls); - - // If we didn't find any file level decls for the file, try looking at the - // file that it was included from. - while (Decls.empty() || Decls.front()->isTopLevelDeclInObjCContainer()) { - bool Invalid = false; - const SrcMgr::SLocEntry &SLEntry = SM.getSLocEntry(File, &Invalid); - if (Invalid) - return; - - SourceLocation Outer; - if (SLEntry.isFile()) - Outer = SLEntry.getFile().getIncludeLoc(); - else - Outer = SLEntry.getExpansion().getExpansionLocStart(); - if (Outer.isInvalid()) - return; - - llvm::tie(File, Offset) = SM.getDecomposedExpansionLoc(Outer); - Length = 0; - Unit->findFileRegionDecls(File, Offset, Length, Decls); - } - - assert(!Decls.empty()); - - bool VisitedAtLeastOnce = false; - DeclContext *CurDC = 0; - SmallVector<Decl *, 16>::iterator DIt = Decls.begin(); - for (SmallVector<Decl *, 16>::iterator DE = Decls.end(); DIt != DE; ++DIt) { - Decl *D = *DIt; - if (D->getSourceRange().isInvalid()) - continue; - - if (isInLexicalContext(D, CurDC)) - continue; - - CurDC = dyn_cast<DeclContext>(D); - - if (TagDecl *TD = dyn_cast<TagDecl>(D)) - if (!TD->isFreeStanding()) - continue; - - RangeComparisonResult CompRes = RangeCompare(SM, D->getSourceRange(),Range); - if (CompRes == RangeBefore) - continue; - if (CompRes == RangeAfter) - break; - - assert(CompRes == RangeOverlap); - VisitedAtLeastOnce = true; - - if (isa<ObjCContainerDecl>(D)) { - FileDI_current = &DIt; - FileDE_current = DE; - } else { - FileDI_current = 0; - } - - if (Visit(MakeCXCursor(D, TU, Range), /*CheckedRegionOfInterest=*/true)) - break; - } - - if (VisitedAtLeastOnce) - return; - - // No Decls overlapped with the range. Move up the lexical context until there - // is a context that contains the range or we reach the translation unit - // level. - DeclContext *DC = DIt == Decls.begin() ? (*DIt)->getLexicalDeclContext() - : (*(DIt-1))->getLexicalDeclContext(); - - while (DC && !DC->isTranslationUnit()) { - Decl *D = cast<Decl>(DC); - SourceRange CurDeclRange = D->getSourceRange(); - if (CurDeclRange.isInvalid()) - break; - - if (RangeCompare(SM, CurDeclRange, Range) == RangeOverlap) { - Visit(MakeCXCursor(D, TU, Range), /*CheckedRegionOfInterest=*/true); - break; - } - - DC = D->getLexicalDeclContext(); - } -} - -bool CursorVisitor::visitPreprocessedEntitiesInRegion() { - if (!AU->getPreprocessor().getPreprocessingRecord()) - return false; - - PreprocessingRecord &PPRec - = *AU->getPreprocessor().getPreprocessingRecord(); - SourceManager &SM = AU->getSourceManager(); - - if (RegionOfInterest.isValid()) { - SourceRange MappedRange = AU->mapRangeToPreamble(RegionOfInterest); - SourceLocation B = MappedRange.getBegin(); - SourceLocation E = MappedRange.getEnd(); - - if (AU->isInPreambleFileID(B)) { - if (SM.isLoadedSourceLocation(E)) - return visitPreprocessedEntitiesInRange(SourceRange(B, E), - PPRec, *this); - - // Beginning of range lies in the preamble but it also extends beyond - // it into the main file. Split the range into 2 parts, one covering - // the preamble and another covering the main file. This allows subsequent - // calls to visitPreprocessedEntitiesInRange to accept a source range that - // lies in the same FileID, allowing it to skip preprocessed entities that - // do not come from the same FileID. - bool breaked = - visitPreprocessedEntitiesInRange( - SourceRange(B, AU->getEndOfPreambleFileID()), - PPRec, *this); - if (breaked) return true; - return visitPreprocessedEntitiesInRange( - SourceRange(AU->getStartOfMainFileID(), E), - PPRec, *this); - } - - return visitPreprocessedEntitiesInRange(SourceRange(B, E), PPRec, *this); - } - - bool OnlyLocalDecls - = !AU->isMainFileAST() && AU->getOnlyLocalDecls(); - - if (OnlyLocalDecls) - return visitPreprocessedEntities(PPRec.local_begin(), PPRec.local_end(), - PPRec); - - return visitPreprocessedEntities(PPRec.begin(), PPRec.end(), PPRec); -} - -template<typename InputIterator> -bool CursorVisitor::visitPreprocessedEntities(InputIterator First, - InputIterator Last, - PreprocessingRecord &PPRec, - FileID FID) { - for (; First != Last; ++First) { - if (!FID.isInvalid() && !PPRec.isEntityInFileID(First, FID)) - continue; - - PreprocessedEntity *PPE = *First; - if (MacroExpansion *ME = dyn_cast<MacroExpansion>(PPE)) { - if (Visit(MakeMacroExpansionCursor(ME, TU))) - return true; - - continue; - } - - if (MacroDefinition *MD = dyn_cast<MacroDefinition>(PPE)) { - if (Visit(MakeMacroDefinitionCursor(MD, TU))) - return true; - - continue; - } - - if (InclusionDirective *ID = dyn_cast<InclusionDirective>(PPE)) { - if (Visit(MakeInclusionDirectiveCursor(ID, TU))) - return true; - - continue; - } - } - - return false; -} - -/// \brief Visit the children of the given cursor. -/// -/// \returns true if the visitation should be aborted, false if it -/// should continue. -bool CursorVisitor::VisitChildren(CXCursor Cursor) { - if (clang_isReference(Cursor.kind) && - Cursor.kind != CXCursor_CXXBaseSpecifier) { - // By definition, references have no children. - return false; - } - - // Set the Parent field to Cursor, then back to its old value once we're - // done. - SetParentRAII SetParent(Parent, StmtParent, Cursor); - - if (clang_isDeclaration(Cursor.kind)) { - Decl *D = getCursorDecl(Cursor); - if (!D) - return false; - - return VisitAttributes(D) || Visit(D); - } - - if (clang_isStatement(Cursor.kind)) { - if (Stmt *S = getCursorStmt(Cursor)) - return Visit(S); - - return false; - } - - if (clang_isExpression(Cursor.kind)) { - if (Expr *E = getCursorExpr(Cursor)) - return Visit(E); - - return false; - } - - if (clang_isTranslationUnit(Cursor.kind)) { - CXTranslationUnit tu = getCursorTU(Cursor); - ASTUnit *CXXUnit = static_cast<ASTUnit*>(tu->TUData); - - int VisitOrder[2] = { VisitPreprocessorLast, !VisitPreprocessorLast }; - for (unsigned I = 0; I != 2; ++I) { - if (VisitOrder[I]) { - if (!CXXUnit->isMainFileAST() && CXXUnit->getOnlyLocalDecls() && - RegionOfInterest.isInvalid()) { - for (ASTUnit::top_level_iterator TL = CXXUnit->top_level_begin(), - TLEnd = CXXUnit->top_level_end(); - TL != TLEnd; ++TL) { - if (Visit(MakeCXCursor(*TL, tu, RegionOfInterest), true)) - return true; - } - } else if (VisitDeclContext( - CXXUnit->getASTContext().getTranslationUnitDecl())) - return true; - continue; - } - - // Walk the preprocessing record. - if (CXXUnit->getPreprocessor().getPreprocessingRecord()) - visitPreprocessedEntitiesInRegion(); - } - - return false; - } - - if (Cursor.kind == CXCursor_CXXBaseSpecifier) { - if (CXXBaseSpecifier *Base = getCursorCXXBaseSpecifier(Cursor)) { - if (TypeSourceInfo *BaseTSInfo = Base->getTypeSourceInfo()) { - return Visit(BaseTSInfo->getTypeLoc()); - } - } - } - - if (Cursor.kind == CXCursor_IBOutletCollectionAttr) { - IBOutletCollectionAttr *A = - cast<IBOutletCollectionAttr>(cxcursor::getCursorAttr(Cursor)); - if (const ObjCInterfaceType *InterT = A->getInterface()->getAs<ObjCInterfaceType>()) - return Visit(cxcursor::MakeCursorObjCClassRef(InterT->getInterface(), - A->getInterfaceLoc(), TU)); - } - - // Nothing to visit at the moment. - return false; -} - -bool CursorVisitor::VisitBlockDecl(BlockDecl *B) { - if (TypeSourceInfo *TSInfo = B->getSignatureAsWritten()) - if (Visit(TSInfo->getTypeLoc())) - return true; - - if (Stmt *Body = B->getBody()) - return Visit(MakeCXCursor(Body, StmtParent, TU, RegionOfInterest)); - - return false; -} - -llvm::Optional<bool> CursorVisitor::shouldVisitCursor(CXCursor Cursor) { - if (RegionOfInterest.isValid()) { - SourceRange Range = getFullCursorExtent(Cursor, AU->getSourceManager()); - if (Range.isInvalid()) - return llvm::Optional<bool>(); - - switch (CompareRegionOfInterest(Range)) { - case RangeBefore: - // This declaration comes before the region of interest; skip it. - return llvm::Optional<bool>(); - - case RangeAfter: - // This declaration comes after the region of interest; we're done. - return false; - - case RangeOverlap: - // This declaration overlaps the region of interest; visit it. - break; - } - } - return true; -} - -bool CursorVisitor::VisitDeclContext(DeclContext *DC) { - DeclContext::decl_iterator I = DC->decls_begin(), E = DC->decls_end(); - - // FIXME: Eventually remove. This part of a hack to support proper - // iteration over all Decls contained lexically within an ObjC container. - SaveAndRestore<DeclContext::decl_iterator*> DI_saved(DI_current, &I); - SaveAndRestore<DeclContext::decl_iterator> DE_saved(DE_current, E); - - for ( ; I != E; ++I) { - Decl *D = *I; - if (D->getLexicalDeclContext() != DC) - continue; - CXCursor Cursor = MakeCXCursor(D, TU, RegionOfInterest); - - // Ignore synthesized ivars here, otherwise if we have something like: - // @synthesize prop = _prop; - // and '_prop' is not declared, we will encounter a '_prop' ivar before - // encountering the 'prop' synthesize declaration and we will think that - // we passed the region-of-interest. - if (ObjCIvarDecl *ivarD = dyn_cast<ObjCIvarDecl>(D)) { - if (ivarD->getSynthesize()) - continue; - } - - // FIXME: ObjCClassRef/ObjCProtocolRef for forward class/protocol - // declarations is a mismatch with the compiler semantics. - if (Cursor.kind == CXCursor_ObjCInterfaceDecl) { - ObjCInterfaceDecl *ID = cast<ObjCInterfaceDecl>(D); - if (!ID->isThisDeclarationADefinition()) - Cursor = MakeCursorObjCClassRef(ID, ID->getLocation(), TU); - - } else if (Cursor.kind == CXCursor_ObjCProtocolDecl) { - ObjCProtocolDecl *PD = cast<ObjCProtocolDecl>(D); - if (!PD->isThisDeclarationADefinition()) - Cursor = MakeCursorObjCProtocolRef(PD, PD->getLocation(), TU); - } - - const llvm::Optional<bool> &V = shouldVisitCursor(Cursor); - if (!V.hasValue()) - continue; - if (!V.getValue()) - return false; - if (Visit(Cursor, true)) - return true; - } - return false; -} - -bool CursorVisitor::VisitTranslationUnitDecl(TranslationUnitDecl *D) { - llvm_unreachable("Translation units are visited directly by Visit()"); -} - -bool CursorVisitor::VisitTypeAliasDecl(TypeAliasDecl *D) { - if (TypeSourceInfo *TSInfo = D->getTypeSourceInfo()) - return Visit(TSInfo->getTypeLoc()); - - return false; -} - -bool CursorVisitor::VisitTypedefDecl(TypedefDecl *D) { - if (TypeSourceInfo *TSInfo = D->getTypeSourceInfo()) - return Visit(TSInfo->getTypeLoc()); - - return false; -} - -bool CursorVisitor::VisitTagDecl(TagDecl *D) { - return VisitDeclContext(D); -} - -bool CursorVisitor::VisitClassTemplateSpecializationDecl( - ClassTemplateSpecializationDecl *D) { - bool ShouldVisitBody = false; - switch (D->getSpecializationKind()) { - case TSK_Undeclared: - case TSK_ImplicitInstantiation: - // Nothing to visit - return false; - - case TSK_ExplicitInstantiationDeclaration: - case TSK_ExplicitInstantiationDefinition: - break; - - case TSK_ExplicitSpecialization: - ShouldVisitBody = true; - break; - } - - // Visit the template arguments used in the specialization. - if (TypeSourceInfo *SpecType = D->getTypeAsWritten()) { - TypeLoc TL = SpecType->getTypeLoc(); - if (TemplateSpecializationTypeLoc *TSTLoc - = dyn_cast<TemplateSpecializationTypeLoc>(&TL)) { - for (unsigned I = 0, N = TSTLoc->getNumArgs(); I != N; ++I) - if (VisitTemplateArgumentLoc(TSTLoc->getArgLoc(I))) - return true; - } - } - - if (ShouldVisitBody && VisitCXXRecordDecl(D)) - return true; - - return false; -} - -bool CursorVisitor::VisitClassTemplatePartialSpecializationDecl( - ClassTemplatePartialSpecializationDecl *D) { - // FIXME: Visit the "outer" template parameter lists on the TagDecl - // before visiting these template parameters. - if (VisitTemplateParameters(D->getTemplateParameters())) - return true; - - // Visit the partial specialization arguments. - const TemplateArgumentLoc *TemplateArgs = D->getTemplateArgsAsWritten(); - for (unsigned I = 0, N = D->getNumTemplateArgsAsWritten(); I != N; ++I) - if (VisitTemplateArgumentLoc(TemplateArgs[I])) - return true; - - return VisitCXXRecordDecl(D); -} - -bool CursorVisitor::VisitTemplateTypeParmDecl(TemplateTypeParmDecl *D) { - // Visit the default argument. - if (D->hasDefaultArgument() && !D->defaultArgumentWasInherited()) - if (TypeSourceInfo *DefArg = D->getDefaultArgumentInfo()) - if (Visit(DefArg->getTypeLoc())) - return true; - - return false; -} - -bool CursorVisitor::VisitEnumConstantDecl(EnumConstantDecl *D) { - if (Expr *Init = D->getInitExpr()) - return Visit(MakeCXCursor(Init, StmtParent, TU, RegionOfInterest)); - return false; -} - -bool CursorVisitor::VisitDeclaratorDecl(DeclaratorDecl *DD) { - if (TypeSourceInfo *TSInfo = DD->getTypeSourceInfo()) - if (Visit(TSInfo->getTypeLoc())) - return true; - - // Visit the nested-name-specifier, if present. - if (NestedNameSpecifierLoc QualifierLoc = DD->getQualifierLoc()) - if (VisitNestedNameSpecifierLoc(QualifierLoc)) - return true; - - return false; -} - -/// \brief Compare two base or member initializers based on their source order. -static int CompareCXXCtorInitializers(const void* Xp, const void *Yp) { - CXXCtorInitializer const * const *X - = static_cast<CXXCtorInitializer const * const *>(Xp); - CXXCtorInitializer const * const *Y - = static_cast<CXXCtorInitializer const * const *>(Yp); - - if ((*X)->getSourceOrder() < (*Y)->getSourceOrder()) - return -1; - else if ((*X)->getSourceOrder() > (*Y)->getSourceOrder()) - return 1; - else - return 0; -} - -bool CursorVisitor::VisitFunctionDecl(FunctionDecl *ND) { - if (TypeSourceInfo *TSInfo = ND->getTypeSourceInfo()) { - // Visit the function declaration's syntactic components in the order - // written. This requires a bit of work. - TypeLoc TL = TSInfo->getTypeLoc().IgnoreParens(); - FunctionTypeLoc *FTL = dyn_cast<FunctionTypeLoc>(&TL); - - // If we have a function declared directly (without the use of a typedef), - // visit just the return type. Otherwise, just visit the function's type - // now. - if ((FTL && !isa<CXXConversionDecl>(ND) && Visit(FTL->getResultLoc())) || - (!FTL && Visit(TL))) - return true; - - // Visit the nested-name-specifier, if present. - if (NestedNameSpecifierLoc QualifierLoc = ND->getQualifierLoc()) - if (VisitNestedNameSpecifierLoc(QualifierLoc)) - return true; - - // Visit the declaration name. - if (VisitDeclarationNameInfo(ND->getNameInfo())) - return true; - - // FIXME: Visit explicitly-specified template arguments! - - // Visit the function parameters, if we have a function type. - if (FTL && VisitFunctionTypeLoc(*FTL, true)) - return true; - - // FIXME: Attributes? - } - - if (ND->doesThisDeclarationHaveABody() && !ND->isLateTemplateParsed()) { - if (CXXConstructorDecl *Constructor = dyn_cast<CXXConstructorDecl>(ND)) { - // Find the initializers that were written in the source. - SmallVector<CXXCtorInitializer *, 4> WrittenInits; - for (CXXConstructorDecl::init_iterator I = Constructor->init_begin(), - IEnd = Constructor->init_end(); - I != IEnd; ++I) { - if (!(*I)->isWritten()) - continue; - - WrittenInits.push_back(*I); - } - - // Sort the initializers in source order - llvm::array_pod_sort(WrittenInits.begin(), WrittenInits.end(), - &CompareCXXCtorInitializers); - - // Visit the initializers in source order - for (unsigned I = 0, N = WrittenInits.size(); I != N; ++I) { - CXXCtorInitializer *Init = WrittenInits[I]; - if (Init->isAnyMemberInitializer()) { - if (Visit(MakeCursorMemberRef(Init->getAnyMember(), - Init->getMemberLocation(), TU))) - return true; - } else if (TypeSourceInfo *TInfo = Init->getTypeSourceInfo()) { - if (Visit(TInfo->getTypeLoc())) - return true; - } - - // Visit the initializer value. - if (Expr *Initializer = Init->getInit()) - if (Visit(MakeCXCursor(Initializer, ND, TU, RegionOfInterest))) - return true; - } - } - - if (Visit(MakeCXCursor(ND->getBody(), StmtParent, TU, RegionOfInterest))) - return true; - } - - return false; -} - -bool CursorVisitor::VisitFieldDecl(FieldDecl *D) { - if (VisitDeclaratorDecl(D)) - return true; - - if (Expr *BitWidth = D->getBitWidth()) - return Visit(MakeCXCursor(BitWidth, StmtParent, TU, RegionOfInterest)); - - return false; -} - -bool CursorVisitor::VisitVarDecl(VarDecl *D) { - if (VisitDeclaratorDecl(D)) - return true; - - if (Expr *Init = D->getInit()) - return Visit(MakeCXCursor(Init, StmtParent, TU, RegionOfInterest)); - - return false; -} - -bool CursorVisitor::VisitNonTypeTemplateParmDecl(NonTypeTemplateParmDecl *D) { - if (VisitDeclaratorDecl(D)) - return true; - - if (D->hasDefaultArgument() && !D->defaultArgumentWasInherited()) - if (Expr *DefArg = D->getDefaultArgument()) - return Visit(MakeCXCursor(DefArg, StmtParent, TU, RegionOfInterest)); - - return false; -} - -bool CursorVisitor::VisitFunctionTemplateDecl(FunctionTemplateDecl *D) { - // FIXME: Visit the "outer" template parameter lists on the FunctionDecl - // before visiting these template parameters. - if (VisitTemplateParameters(D->getTemplateParameters())) - return true; - - return VisitFunctionDecl(D->getTemplatedDecl()); -} - -bool CursorVisitor::VisitClassTemplateDecl(ClassTemplateDecl *D) { - // FIXME: Visit the "outer" template parameter lists on the TagDecl - // before visiting these template parameters. - if (VisitTemplateParameters(D->getTemplateParameters())) - return true; - - return VisitCXXRecordDecl(D->getTemplatedDecl()); -} - -bool CursorVisitor::VisitTemplateTemplateParmDecl(TemplateTemplateParmDecl *D) { - if (VisitTemplateParameters(D->getTemplateParameters())) - return true; - - if (D->hasDefaultArgument() && !D->defaultArgumentWasInherited() && - VisitTemplateArgumentLoc(D->getDefaultArgument())) - return true; - - return false; -} - -bool CursorVisitor::VisitObjCMethodDecl(ObjCMethodDecl *ND) { - if (TypeSourceInfo *TSInfo = ND->getResultTypeSourceInfo()) - if (Visit(TSInfo->getTypeLoc())) - return true; - - for (ObjCMethodDecl::param_iterator P = ND->param_begin(), - PEnd = ND->param_end(); - P != PEnd; ++P) { - if (Visit(MakeCXCursor(*P, TU, RegionOfInterest))) - return true; - } - - if (ND->isThisDeclarationADefinition() && - Visit(MakeCXCursor(ND->getBody(), StmtParent, TU, RegionOfInterest))) - return true; - - return false; -} - -template <typename DeclIt> -static void addRangedDeclsInContainer(DeclIt *DI_current, DeclIt DE_current, - SourceManager &SM, SourceLocation EndLoc, - SmallVectorImpl<Decl *> &Decls) { - DeclIt next = *DI_current; - while (++next != DE_current) { - Decl *D_next = *next; - if (!D_next) - break; - SourceLocation L = D_next->getLocStart(); - if (!L.isValid()) - break; - if (SM.isBeforeInTranslationUnit(L, EndLoc)) { - *DI_current = next; - Decls.push_back(D_next); - continue; - } - break; - } -} - -namespace { - struct ContainerDeclsSort { - SourceManager &SM; - ContainerDeclsSort(SourceManager &sm) : SM(sm) {} - bool operator()(Decl *A, Decl *B) { - SourceLocation L_A = A->getLocStart(); - SourceLocation L_B = B->getLocStart(); - assert(L_A.isValid() && L_B.isValid()); - return SM.isBeforeInTranslationUnit(L_A, L_B); - } - }; -} - -bool CursorVisitor::VisitObjCContainerDecl(ObjCContainerDecl *D) { - // FIXME: Eventually convert back to just 'VisitDeclContext()'. Essentially - // an @implementation can lexically contain Decls that are not properly - // nested in the AST. When we identify such cases, we need to retrofit - // this nesting here. - if (!DI_current && !FileDI_current) - return VisitDeclContext(D); - - // Scan the Decls that immediately come after the container - // in the current DeclContext. If any fall within the - // container's lexical region, stash them into a vector - // for later processing. - SmallVector<Decl *, 24> DeclsInContainer; - SourceLocation EndLoc = D->getSourceRange().getEnd(); - SourceManager &SM = AU->getSourceManager(); - if (EndLoc.isValid()) { - if (DI_current) { - addRangedDeclsInContainer(DI_current, DE_current, SM, EndLoc, - DeclsInContainer); - } else { - addRangedDeclsInContainer(FileDI_current, FileDE_current, SM, EndLoc, - DeclsInContainer); - } - } - - // The common case. - if (DeclsInContainer.empty()) - return VisitDeclContext(D); - - // Get all the Decls in the DeclContext, and sort them with the - // additional ones we've collected. Then visit them. - for (DeclContext::decl_iterator I = D->decls_begin(), E = D->decls_end(); - I!=E; ++I) { - Decl *subDecl = *I; - if (!subDecl || subDecl->getLexicalDeclContext() != D || - subDecl->getLocStart().isInvalid()) - continue; - DeclsInContainer.push_back(subDecl); - } - - // Now sort the Decls so that they appear in lexical order. - std::sort(DeclsInContainer.begin(), DeclsInContainer.end(), - ContainerDeclsSort(SM)); - - // Now visit the decls. - for (SmallVectorImpl<Decl*>::iterator I = DeclsInContainer.begin(), - E = DeclsInContainer.end(); I != E; ++I) { - CXCursor Cursor = MakeCXCursor(*I, TU, RegionOfInterest); - const llvm::Optional<bool> &V = shouldVisitCursor(Cursor); - if (!V.hasValue()) - continue; - if (!V.getValue()) - return false; - if (Visit(Cursor, true)) - return true; - } - return false; -} - -bool CursorVisitor::VisitObjCCategoryDecl(ObjCCategoryDecl *ND) { - if (Visit(MakeCursorObjCClassRef(ND->getClassInterface(), ND->getLocation(), - TU))) - return true; - - ObjCCategoryDecl::protocol_loc_iterator PL = ND->protocol_loc_begin(); - for (ObjCCategoryDecl::protocol_iterator I = ND->protocol_begin(), - E = ND->protocol_end(); I != E; ++I, ++PL) - if (Visit(MakeCursorObjCProtocolRef(*I, *PL, TU))) - return true; - - return VisitObjCContainerDecl(ND); -} - -bool CursorVisitor::VisitObjCProtocolDecl(ObjCProtocolDecl *PID) { - if (!PID->isThisDeclarationADefinition()) - return Visit(MakeCursorObjCProtocolRef(PID, PID->getLocation(), TU)); - - ObjCProtocolDecl::protocol_loc_iterator PL = PID->protocol_loc_begin(); - for (ObjCProtocolDecl::protocol_iterator I = PID->protocol_begin(), - E = PID->protocol_end(); I != E; ++I, ++PL) - if (Visit(MakeCursorObjCProtocolRef(*I, *PL, TU))) - return true; - - return VisitObjCContainerDecl(PID); -} - -bool CursorVisitor::VisitObjCPropertyDecl(ObjCPropertyDecl *PD) { - if (PD->getTypeSourceInfo() && Visit(PD->getTypeSourceInfo()->getTypeLoc())) - return true; - - // FIXME: This implements a workaround with @property declarations also being - // installed in the DeclContext for the @interface. Eventually this code - // should be removed. - ObjCCategoryDecl *CDecl = dyn_cast<ObjCCategoryDecl>(PD->getDeclContext()); - if (!CDecl || !CDecl->IsClassExtension()) - return false; - - ObjCInterfaceDecl *ID = CDecl->getClassInterface(); - if (!ID) - return false; - - IdentifierInfo *PropertyId = PD->getIdentifier(); - ObjCPropertyDecl *prevDecl = - ObjCPropertyDecl::findPropertyDecl(cast<DeclContext>(ID), PropertyId); - - if (!prevDecl) - return false; - - // Visit synthesized methods since they will be skipped when visiting - // the @interface. - if (ObjCMethodDecl *MD = prevDecl->getGetterMethodDecl()) - if (MD->isPropertyAccessor() && MD->getLexicalDeclContext() == CDecl) - if (Visit(MakeCXCursor(MD, TU, RegionOfInterest))) - return true; - - if (ObjCMethodDecl *MD = prevDecl->getSetterMethodDecl()) - if (MD->isPropertyAccessor() && MD->getLexicalDeclContext() == CDecl) - if (Visit(MakeCXCursor(MD, TU, RegionOfInterest))) - return true; - - return false; -} - -bool CursorVisitor::VisitObjCInterfaceDecl(ObjCInterfaceDecl *D) { - if (!D->isThisDeclarationADefinition()) { - // Forward declaration is treated like a reference. - return Visit(MakeCursorObjCClassRef(D, D->getLocation(), TU)); - } - - // Issue callbacks for super class. - if (D->getSuperClass() && - Visit(MakeCursorObjCSuperClassRef(D->getSuperClass(), - D->getSuperClassLoc(), - TU))) - return true; - - ObjCInterfaceDecl::protocol_loc_iterator PL = D->protocol_loc_begin(); - for (ObjCInterfaceDecl::protocol_iterator I = D->protocol_begin(), - E = D->protocol_end(); I != E; ++I, ++PL) - if (Visit(MakeCursorObjCProtocolRef(*I, *PL, TU))) - return true; - - return VisitObjCContainerDecl(D); -} - -bool CursorVisitor::VisitObjCImplDecl(ObjCImplDecl *D) { - return VisitObjCContainerDecl(D); -} - -bool CursorVisitor::VisitObjCCategoryImplDecl(ObjCCategoryImplDecl *D) { - // 'ID' could be null when dealing with invalid code. - if (ObjCInterfaceDecl *ID = D->getClassInterface()) - if (Visit(MakeCursorObjCClassRef(ID, D->getLocation(), TU))) - return true; - - return VisitObjCImplDecl(D); -} - -bool CursorVisitor::VisitObjCImplementationDecl(ObjCImplementationDecl *D) { -#if 0 - // Issue callbacks for super class. - // FIXME: No source location information! - if (D->getSuperClass() && - Visit(MakeCursorObjCSuperClassRef(D->getSuperClass(), - D->getSuperClassLoc(), - TU))) - return true; -#endif - - return VisitObjCImplDecl(D); -} - -bool CursorVisitor::VisitObjCPropertyImplDecl(ObjCPropertyImplDecl *PD) { - if (ObjCIvarDecl *Ivar = PD->getPropertyIvarDecl()) - if (PD->isIvarNameSpecified()) - return Visit(MakeCursorMemberRef(Ivar, PD->getPropertyIvarDeclLoc(), TU)); - - return false; -} - -bool CursorVisitor::VisitNamespaceDecl(NamespaceDecl *D) { - return VisitDeclContext(D); -} - -bool CursorVisitor::VisitNamespaceAliasDecl(NamespaceAliasDecl *D) { - // Visit nested-name-specifier. - if (NestedNameSpecifierLoc QualifierLoc = D->getQualifierLoc()) - if (VisitNestedNameSpecifierLoc(QualifierLoc)) - return true; - - return Visit(MakeCursorNamespaceRef(D->getAliasedNamespace(), - D->getTargetNameLoc(), TU)); -} - -bool CursorVisitor::VisitUsingDecl(UsingDecl *D) { - // Visit nested-name-specifier. - if (NestedNameSpecifierLoc QualifierLoc = D->getQualifierLoc()) { - if (VisitNestedNameSpecifierLoc(QualifierLoc)) - return true; - } - - if (Visit(MakeCursorOverloadedDeclRef(D, D->getLocation(), TU))) - return true; - - return VisitDeclarationNameInfo(D->getNameInfo()); -} - -bool CursorVisitor::VisitUsingDirectiveDecl(UsingDirectiveDecl *D) { - // Visit nested-name-specifier. - if (NestedNameSpecifierLoc QualifierLoc = D->getQualifierLoc()) - if (VisitNestedNameSpecifierLoc(QualifierLoc)) - return true; - - return Visit(MakeCursorNamespaceRef(D->getNominatedNamespaceAsWritten(), - D->getIdentLocation(), TU)); -} - -bool CursorVisitor::VisitUnresolvedUsingValueDecl(UnresolvedUsingValueDecl *D) { - // Visit nested-name-specifier. - if (NestedNameSpecifierLoc QualifierLoc = D->getQualifierLoc()) { - if (VisitNestedNameSpecifierLoc(QualifierLoc)) - return true; - } - - return VisitDeclarationNameInfo(D->getNameInfo()); -} - -bool CursorVisitor::VisitUnresolvedUsingTypenameDecl( - UnresolvedUsingTypenameDecl *D) { - // Visit nested-name-specifier. - if (NestedNameSpecifierLoc QualifierLoc = D->getQualifierLoc()) - if (VisitNestedNameSpecifierLoc(QualifierLoc)) - return true; - - return false; -} - -bool CursorVisitor::VisitDeclarationNameInfo(DeclarationNameInfo Name) { - switch (Name.getName().getNameKind()) { - case clang::DeclarationName::Identifier: - case clang::DeclarationName::CXXLiteralOperatorName: - case clang::DeclarationName::CXXOperatorName: - case clang::DeclarationName::CXXUsingDirective: - return false; - - case clang::DeclarationName::CXXConstructorName: - case clang::DeclarationName::CXXDestructorName: - case clang::DeclarationName::CXXConversionFunctionName: - if (TypeSourceInfo *TSInfo = Name.getNamedTypeInfo()) - return Visit(TSInfo->getTypeLoc()); - return false; - - case clang::DeclarationName::ObjCZeroArgSelector: - case clang::DeclarationName::ObjCOneArgSelector: - case clang::DeclarationName::ObjCMultiArgSelector: - // FIXME: Per-identifier location info? - return false; - } - - llvm_unreachable("Invalid DeclarationName::Kind!"); -} - -bool CursorVisitor::VisitNestedNameSpecifier(NestedNameSpecifier *NNS, - SourceRange Range) { - // FIXME: This whole routine is a hack to work around the lack of proper - // source information in nested-name-specifiers (PR5791). Since we do have - // a beginning source location, we can visit the first component of the - // nested-name-specifier, if it's a single-token component. - if (!NNS) - return false; - - // Get the first component in the nested-name-specifier. - while (NestedNameSpecifier *Prefix = NNS->getPrefix()) - NNS = Prefix; - - switch (NNS->getKind()) { - case NestedNameSpecifier::Namespace: - return Visit(MakeCursorNamespaceRef(NNS->getAsNamespace(), Range.getBegin(), - TU)); - - case NestedNameSpecifier::NamespaceAlias: - return Visit(MakeCursorNamespaceRef(NNS->getAsNamespaceAlias(), - Range.getBegin(), TU)); - - case NestedNameSpecifier::TypeSpec: { - // If the type has a form where we know that the beginning of the source - // range matches up with a reference cursor. Visit the appropriate reference - // cursor. - const Type *T = NNS->getAsType(); - if (const TypedefType *Typedef = dyn_cast<TypedefType>(T)) - return Visit(MakeCursorTypeRef(Typedef->getDecl(), Range.getBegin(), TU)); - if (const TagType *Tag = dyn_cast<TagType>(T)) - return Visit(MakeCursorTypeRef(Tag->getDecl(), Range.getBegin(), TU)); - if (const TemplateSpecializationType *TST - = dyn_cast<TemplateSpecializationType>(T)) - return VisitTemplateName(TST->getTemplateName(), Range.getBegin()); - break; - } - - case NestedNameSpecifier::TypeSpecWithTemplate: - case NestedNameSpecifier::Global: - case NestedNameSpecifier::Identifier: - break; - } - - return false; -} - -bool -CursorVisitor::VisitNestedNameSpecifierLoc(NestedNameSpecifierLoc Qualifier) { - SmallVector<NestedNameSpecifierLoc, 4> Qualifiers; - for (; Qualifier; Qualifier = Qualifier.getPrefix()) - Qualifiers.push_back(Qualifier); - - while (!Qualifiers.empty()) { - NestedNameSpecifierLoc Q = Qualifiers.pop_back_val(); - NestedNameSpecifier *NNS = Q.getNestedNameSpecifier(); - switch (NNS->getKind()) { - case NestedNameSpecifier::Namespace: - if (Visit(MakeCursorNamespaceRef(NNS->getAsNamespace(), - Q.getLocalBeginLoc(), - TU))) - return true; - - break; - - case NestedNameSpecifier::NamespaceAlias: - if (Visit(MakeCursorNamespaceRef(NNS->getAsNamespaceAlias(), - Q.getLocalBeginLoc(), - TU))) - return true; - - break; - - case NestedNameSpecifier::TypeSpec: - case NestedNameSpecifier::TypeSpecWithTemplate: - if (Visit(Q.getTypeLoc())) - return true; - - break; - - case NestedNameSpecifier::Global: - case NestedNameSpecifier::Identifier: - break; - } - } - - return false; -} - -bool CursorVisitor::VisitTemplateParameters( - const TemplateParameterList *Params) { - if (!Params) - return false; - - for (TemplateParameterList::const_iterator P = Params->begin(), - PEnd = Params->end(); - P != PEnd; ++P) { - if (Visit(MakeCXCursor(*P, TU, RegionOfInterest))) - return true; - } - - return false; -} - -bool CursorVisitor::VisitTemplateName(TemplateName Name, SourceLocation Loc) { - switch (Name.getKind()) { - case TemplateName::Template: - return Visit(MakeCursorTemplateRef(Name.getAsTemplateDecl(), Loc, TU)); - - case TemplateName::OverloadedTemplate: - // Visit the overloaded template set. - if (Visit(MakeCursorOverloadedDeclRef(Name, Loc, TU))) - return true; - - return false; - - case TemplateName::DependentTemplate: - // FIXME: Visit nested-name-specifier. - return false; - - case TemplateName::QualifiedTemplate: - // FIXME: Visit nested-name-specifier. - return Visit(MakeCursorTemplateRef( - Name.getAsQualifiedTemplateName()->getDecl(), - Loc, TU)); - - case TemplateName::SubstTemplateTemplateParm: - return Visit(MakeCursorTemplateRef( - Name.getAsSubstTemplateTemplateParm()->getParameter(), - Loc, TU)); - - case TemplateName::SubstTemplateTemplateParmPack: - return Visit(MakeCursorTemplateRef( - Name.getAsSubstTemplateTemplateParmPack()->getParameterPack(), - Loc, TU)); - } - - llvm_unreachable("Invalid TemplateName::Kind!"); -} - -bool CursorVisitor::VisitTemplateArgumentLoc(const TemplateArgumentLoc &TAL) { - switch (TAL.getArgument().getKind()) { - case TemplateArgument::Null: - case TemplateArgument::Integral: - case TemplateArgument::Pack: - return false; - - case TemplateArgument::Type: - if (TypeSourceInfo *TSInfo = TAL.getTypeSourceInfo()) - return Visit(TSInfo->getTypeLoc()); - return false; - - case TemplateArgument::Declaration: - if (Expr *E = TAL.getSourceDeclExpression()) - return Visit(MakeCXCursor(E, StmtParent, TU, RegionOfInterest)); - return false; - - case TemplateArgument::NullPtr: - if (Expr *E = TAL.getSourceNullPtrExpression()) - return Visit(MakeCXCursor(E, StmtParent, TU, RegionOfInterest)); - return false; - - case TemplateArgument::Expression: - if (Expr *E = TAL.getSourceExpression()) - return Visit(MakeCXCursor(E, StmtParent, TU, RegionOfInterest)); - return false; - - case TemplateArgument::Template: - case TemplateArgument::TemplateExpansion: - if (VisitNestedNameSpecifierLoc(TAL.getTemplateQualifierLoc())) - return true; - - return VisitTemplateName(TAL.getArgument().getAsTemplateOrTemplatePattern(), - TAL.getTemplateNameLoc()); - } - - llvm_unreachable("Invalid TemplateArgument::Kind!"); -} - -bool CursorVisitor::VisitLinkageSpecDecl(LinkageSpecDecl *D) { - return VisitDeclContext(D); -} - -bool CursorVisitor::VisitQualifiedTypeLoc(QualifiedTypeLoc TL) { - return Visit(TL.getUnqualifiedLoc()); -} - -bool CursorVisitor::VisitBuiltinTypeLoc(BuiltinTypeLoc TL) { - ASTContext &Context = AU->getASTContext(); - - // Some builtin types (such as Objective-C's "id", "sel", and - // "Class") have associated declarations. Create cursors for those. - QualType VisitType; - switch (TL.getTypePtr()->getKind()) { - - case BuiltinType::Void: - case BuiltinType::NullPtr: - case BuiltinType::Dependent: -#define BUILTIN_TYPE(Id, SingletonId) -#define SIGNED_TYPE(Id, SingletonId) case BuiltinType::Id: -#define UNSIGNED_TYPE(Id, SingletonId) case BuiltinType::Id: -#define FLOATING_TYPE(Id, SingletonId) case BuiltinType::Id: -#define PLACEHOLDER_TYPE(Id, SingletonId) case BuiltinType::Id: -#include "clang/AST/BuiltinTypes.def" - break; - - case BuiltinType::ObjCId: - VisitType = Context.getObjCIdType(); - break; - - case BuiltinType::ObjCClass: - VisitType = Context.getObjCClassType(); - break; - - case BuiltinType::ObjCSel: - VisitType = Context.getObjCSelType(); - break; - } - - if (!VisitType.isNull()) { - if (const TypedefType *Typedef = VisitType->getAs<TypedefType>()) - return Visit(MakeCursorTypeRef(Typedef->getDecl(), TL.getBuiltinLoc(), - TU)); - } - - return false; -} - -bool CursorVisitor::VisitTypedefTypeLoc(TypedefTypeLoc TL) { - return Visit(MakeCursorTypeRef(TL.getTypedefNameDecl(), TL.getNameLoc(), TU)); -} - -bool CursorVisitor::VisitUnresolvedUsingTypeLoc(UnresolvedUsingTypeLoc TL) { - return Visit(MakeCursorTypeRef(TL.getDecl(), TL.getNameLoc(), TU)); -} - -bool CursorVisitor::VisitTagTypeLoc(TagTypeLoc TL) { - if (TL.isDefinition()) - return Visit(MakeCXCursor(TL.getDecl(), TU, RegionOfInterest)); - - return Visit(MakeCursorTypeRef(TL.getDecl(), TL.getNameLoc(), TU)); -} - -bool CursorVisitor::VisitTemplateTypeParmTypeLoc(TemplateTypeParmTypeLoc TL) { - return Visit(MakeCursorTypeRef(TL.getDecl(), TL.getNameLoc(), TU)); -} - -bool CursorVisitor::VisitObjCInterfaceTypeLoc(ObjCInterfaceTypeLoc TL) { - if (Visit(MakeCursorObjCClassRef(TL.getIFaceDecl(), TL.getNameLoc(), TU))) - return true; - - return false; -} - -bool CursorVisitor::VisitObjCObjectTypeLoc(ObjCObjectTypeLoc TL) { - if (TL.hasBaseTypeAsWritten() && Visit(TL.getBaseLoc())) - return true; - - for (unsigned I = 0, N = TL.getNumProtocols(); I != N; ++I) { - if (Visit(MakeCursorObjCProtocolRef(TL.getProtocol(I), TL.getProtocolLoc(I), - TU))) - return true; - } - - return false; -} - -bool CursorVisitor::VisitObjCObjectPointerTypeLoc(ObjCObjectPointerTypeLoc TL) { - return Visit(TL.getPointeeLoc()); -} - -bool CursorVisitor::VisitParenTypeLoc(ParenTypeLoc TL) { - return Visit(TL.getInnerLoc()); -} - -bool CursorVisitor::VisitPointerTypeLoc(PointerTypeLoc TL) { - return Visit(TL.getPointeeLoc()); -} - -bool CursorVisitor::VisitBlockPointerTypeLoc(BlockPointerTypeLoc TL) { - return Visit(TL.getPointeeLoc()); -} - -bool CursorVisitor::VisitMemberPointerTypeLoc(MemberPointerTypeLoc TL) { - return Visit(TL.getPointeeLoc()); -} - -bool CursorVisitor::VisitLValueReferenceTypeLoc(LValueReferenceTypeLoc TL) { - return Visit(TL.getPointeeLoc()); -} - -bool CursorVisitor::VisitRValueReferenceTypeLoc(RValueReferenceTypeLoc TL) { - return Visit(TL.getPointeeLoc()); -} - -bool CursorVisitor::VisitAttributedTypeLoc(AttributedTypeLoc TL) { - return Visit(TL.getModifiedLoc()); -} - -bool CursorVisitor::VisitFunctionTypeLoc(FunctionTypeLoc TL, - bool SkipResultType) { - if (!SkipResultType && Visit(TL.getResultLoc())) - return true; - - for (unsigned I = 0, N = TL.getNumArgs(); I != N; ++I) - if (Decl *D = TL.getArg(I)) - if (Visit(MakeCXCursor(D, TU, RegionOfInterest))) - return true; - - return false; -} - -bool CursorVisitor::VisitArrayTypeLoc(ArrayTypeLoc TL) { - if (Visit(TL.getElementLoc())) - return true; - - if (Expr *Size = TL.getSizeExpr()) - return Visit(MakeCXCursor(Size, StmtParent, TU, RegionOfInterest)); - - return false; -} - -bool CursorVisitor::VisitTemplateSpecializationTypeLoc( - TemplateSpecializationTypeLoc TL) { - // Visit the template name. - if (VisitTemplateName(TL.getTypePtr()->getTemplateName(), - TL.getTemplateNameLoc())) - return true; - - // Visit the template arguments. - for (unsigned I = 0, N = TL.getNumArgs(); I != N; ++I) - if (VisitTemplateArgumentLoc(TL.getArgLoc(I))) - return true; - - return false; -} - -bool CursorVisitor::VisitTypeOfExprTypeLoc(TypeOfExprTypeLoc TL) { - return Visit(MakeCXCursor(TL.getUnderlyingExpr(), StmtParent, TU)); -} - -bool CursorVisitor::VisitTypeOfTypeLoc(TypeOfTypeLoc TL) { - if (TypeSourceInfo *TSInfo = TL.getUnderlyingTInfo()) - return Visit(TSInfo->getTypeLoc()); - - return false; -} - -bool CursorVisitor::VisitUnaryTransformTypeLoc(UnaryTransformTypeLoc TL) { - if (TypeSourceInfo *TSInfo = TL.getUnderlyingTInfo()) - return Visit(TSInfo->getTypeLoc()); - - return false; -} - -bool CursorVisitor::VisitDependentNameTypeLoc(DependentNameTypeLoc TL) { - if (VisitNestedNameSpecifierLoc(TL.getQualifierLoc())) - return true; - - return false; -} - -bool CursorVisitor::VisitDependentTemplateSpecializationTypeLoc( - DependentTemplateSpecializationTypeLoc TL) { - // Visit the nested-name-specifier, if there is one. - if (TL.getQualifierLoc() && - VisitNestedNameSpecifierLoc(TL.getQualifierLoc())) - return true; - - // Visit the template arguments. - for (unsigned I = 0, N = TL.getNumArgs(); I != N; ++I) - if (VisitTemplateArgumentLoc(TL.getArgLoc(I))) - return true; - - return false; -} - -bool CursorVisitor::VisitElaboratedTypeLoc(ElaboratedTypeLoc TL) { - if (VisitNestedNameSpecifierLoc(TL.getQualifierLoc())) - return true; - - return Visit(TL.getNamedTypeLoc()); -} - -bool CursorVisitor::VisitPackExpansionTypeLoc(PackExpansionTypeLoc TL) { - return Visit(TL.getPatternLoc()); -} - -bool CursorVisitor::VisitDecltypeTypeLoc(DecltypeTypeLoc TL) { - if (Expr *E = TL.getUnderlyingExpr()) - return Visit(MakeCXCursor(E, StmtParent, TU)); - - return false; -} - -bool CursorVisitor::VisitInjectedClassNameTypeLoc(InjectedClassNameTypeLoc TL) { - return Visit(MakeCursorTypeRef(TL.getDecl(), TL.getNameLoc(), TU)); -} - -bool CursorVisitor::VisitAtomicTypeLoc(AtomicTypeLoc TL) { - return Visit(TL.getValueLoc()); -} - -#define DEFAULT_TYPELOC_IMPL(CLASS, PARENT) \ -bool CursorVisitor::Visit##CLASS##TypeLoc(CLASS##TypeLoc TL) { \ - return Visit##PARENT##Loc(TL); \ -} - -DEFAULT_TYPELOC_IMPL(Complex, Type) -DEFAULT_TYPELOC_IMPL(ConstantArray, ArrayType) -DEFAULT_TYPELOC_IMPL(IncompleteArray, ArrayType) -DEFAULT_TYPELOC_IMPL(VariableArray, ArrayType) -DEFAULT_TYPELOC_IMPL(DependentSizedArray, ArrayType) -DEFAULT_TYPELOC_IMPL(DependentSizedExtVector, Type) -DEFAULT_TYPELOC_IMPL(Vector, Type) -DEFAULT_TYPELOC_IMPL(ExtVector, VectorType) -DEFAULT_TYPELOC_IMPL(FunctionProto, FunctionType) -DEFAULT_TYPELOC_IMPL(FunctionNoProto, FunctionType) -DEFAULT_TYPELOC_IMPL(Record, TagType) -DEFAULT_TYPELOC_IMPL(Enum, TagType) -DEFAULT_TYPELOC_IMPL(SubstTemplateTypeParm, Type) -DEFAULT_TYPELOC_IMPL(SubstTemplateTypeParmPack, Type) -DEFAULT_TYPELOC_IMPL(Auto, Type) - -bool CursorVisitor::VisitCXXRecordDecl(CXXRecordDecl *D) { - // Visit the nested-name-specifier, if present. - if (NestedNameSpecifierLoc QualifierLoc = D->getQualifierLoc()) - if (VisitNestedNameSpecifierLoc(QualifierLoc)) - return true; - - if (D->isCompleteDefinition()) { - for (CXXRecordDecl::base_class_iterator I = D->bases_begin(), - E = D->bases_end(); I != E; ++I) { - if (Visit(cxcursor::MakeCursorCXXBaseSpecifier(I, TU))) - return true; - } - } - - return VisitTagDecl(D); -} - -bool CursorVisitor::VisitAttributes(Decl *D) { - for (AttrVec::const_iterator i = D->attr_begin(), e = D->attr_end(); - i != e; ++i) - if (Visit(MakeCXCursor(*i, D, TU))) - return true; - - return false; -} - -//===----------------------------------------------------------------------===// -// Data-recursive visitor methods. -//===----------------------------------------------------------------------===// - -namespace { -#define DEF_JOB(NAME, DATA, KIND)\ -class NAME : public VisitorJob {\ -public:\ - NAME(DATA *d, CXCursor parent) : VisitorJob(parent, VisitorJob::KIND, d) {} \ - static bool classof(const VisitorJob *VJ) { return VJ->getKind() == KIND; }\ - DATA *get() const { return static_cast<DATA*>(data[0]); }\ -}; - -DEF_JOB(StmtVisit, Stmt, StmtVisitKind) -DEF_JOB(MemberExprParts, MemberExpr, MemberExprPartsKind) -DEF_JOB(DeclRefExprParts, DeclRefExpr, DeclRefExprPartsKind) -DEF_JOB(OverloadExprParts, OverloadExpr, OverloadExprPartsKind) -DEF_JOB(ExplicitTemplateArgsVisit, ASTTemplateArgumentListInfo, - ExplicitTemplateArgsVisitKind) -DEF_JOB(SizeOfPackExprParts, SizeOfPackExpr, SizeOfPackExprPartsKind) -DEF_JOB(LambdaExprParts, LambdaExpr, LambdaExprPartsKind) -DEF_JOB(PostChildrenVisit, void, PostChildrenVisitKind) -#undef DEF_JOB - -class DeclVisit : public VisitorJob { -public: - DeclVisit(Decl *d, CXCursor parent, bool isFirst) : - VisitorJob(parent, VisitorJob::DeclVisitKind, - d, isFirst ? (void*) 1 : (void*) 0) {} - static bool classof(const VisitorJob *VJ) { - return VJ->getKind() == DeclVisitKind; - } - Decl *get() const { return static_cast<Decl*>(data[0]); } - bool isFirst() const { return data[1] ? true : false; } -}; -class TypeLocVisit : public VisitorJob { -public: - TypeLocVisit(TypeLoc tl, CXCursor parent) : - VisitorJob(parent, VisitorJob::TypeLocVisitKind, - tl.getType().getAsOpaquePtr(), tl.getOpaqueData()) {} - - static bool classof(const VisitorJob *VJ) { - return VJ->getKind() == TypeLocVisitKind; - } - - TypeLoc get() const { - QualType T = QualType::getFromOpaquePtr(data[0]); - return TypeLoc(T, data[1]); - } -}; - -class LabelRefVisit : public VisitorJob { -public: - LabelRefVisit(LabelDecl *LD, SourceLocation labelLoc, CXCursor parent) - : VisitorJob(parent, VisitorJob::LabelRefVisitKind, LD, - labelLoc.getPtrEncoding()) {} - - static bool classof(const VisitorJob *VJ) { - return VJ->getKind() == VisitorJob::LabelRefVisitKind; - } - LabelDecl *get() const { return static_cast<LabelDecl*>(data[0]); } - SourceLocation getLoc() const { - return SourceLocation::getFromPtrEncoding(data[1]); } -}; - -class NestedNameSpecifierLocVisit : public VisitorJob { -public: - NestedNameSpecifierLocVisit(NestedNameSpecifierLoc Qualifier, CXCursor parent) - : VisitorJob(parent, VisitorJob::NestedNameSpecifierLocVisitKind, - Qualifier.getNestedNameSpecifier(), - Qualifier.getOpaqueData()) { } - - static bool classof(const VisitorJob *VJ) { - return VJ->getKind() == VisitorJob::NestedNameSpecifierLocVisitKind; - } - - NestedNameSpecifierLoc get() const { - return NestedNameSpecifierLoc(static_cast<NestedNameSpecifier*>(data[0]), - data[1]); - } -}; - -class DeclarationNameInfoVisit : public VisitorJob { -public: - DeclarationNameInfoVisit(Stmt *S, CXCursor parent) - : VisitorJob(parent, VisitorJob::DeclarationNameInfoVisitKind, S) {} - static bool classof(const VisitorJob *VJ) { - return VJ->getKind() == VisitorJob::DeclarationNameInfoVisitKind; - } - DeclarationNameInfo get() const { - Stmt *S = static_cast<Stmt*>(data[0]); - switch (S->getStmtClass()) { - default: - llvm_unreachable("Unhandled Stmt"); - case clang::Stmt::MSDependentExistsStmtClass: - return cast<MSDependentExistsStmt>(S)->getNameInfo(); - case Stmt::CXXDependentScopeMemberExprClass: - return cast<CXXDependentScopeMemberExpr>(S)->getMemberNameInfo(); - case Stmt::DependentScopeDeclRefExprClass: - return cast<DependentScopeDeclRefExpr>(S)->getNameInfo(); - } - } -}; -class MemberRefVisit : public VisitorJob { -public: - MemberRefVisit(FieldDecl *D, SourceLocation L, CXCursor parent) - : VisitorJob(parent, VisitorJob::MemberRefVisitKind, D, - L.getPtrEncoding()) {} - static bool classof(const VisitorJob *VJ) { - return VJ->getKind() == VisitorJob::MemberRefVisitKind; - } - FieldDecl *get() const { - return static_cast<FieldDecl*>(data[0]); - } - SourceLocation getLoc() const { - return SourceLocation::getFromRawEncoding((unsigned)(uintptr_t) data[1]); - } -}; -class EnqueueVisitor : public StmtVisitor<EnqueueVisitor, void> { - VisitorWorkList &WL; - CXCursor Parent; -public: - EnqueueVisitor(VisitorWorkList &wl, CXCursor parent) - : WL(wl), Parent(parent) {} - - void VisitAddrLabelExpr(AddrLabelExpr *E); - void VisitBlockExpr(BlockExpr *B); - void VisitCompoundLiteralExpr(CompoundLiteralExpr *E); - void VisitCompoundStmt(CompoundStmt *S); - void VisitCXXDefaultArgExpr(CXXDefaultArgExpr *E) { /* Do nothing. */ } - void VisitMSDependentExistsStmt(MSDependentExistsStmt *S); - void VisitCXXDependentScopeMemberExpr(CXXDependentScopeMemberExpr *E); - void VisitCXXNewExpr(CXXNewExpr *E); - void VisitCXXScalarValueInitExpr(CXXScalarValueInitExpr *E); - void VisitCXXOperatorCallExpr(CXXOperatorCallExpr *E); - void VisitCXXPseudoDestructorExpr(CXXPseudoDestructorExpr *E); - void VisitCXXTemporaryObjectExpr(CXXTemporaryObjectExpr *E); - void VisitCXXTypeidExpr(CXXTypeidExpr *E); - void VisitCXXUnresolvedConstructExpr(CXXUnresolvedConstructExpr *E); - void VisitCXXUuidofExpr(CXXUuidofExpr *E); - void VisitCXXCatchStmt(CXXCatchStmt *S); - void VisitDeclRefExpr(DeclRefExpr *D); - void VisitDeclStmt(DeclStmt *S); - void VisitDependentScopeDeclRefExpr(DependentScopeDeclRefExpr *E); - void VisitDesignatedInitExpr(DesignatedInitExpr *E); - void VisitExplicitCastExpr(ExplicitCastExpr *E); - void VisitForStmt(ForStmt *FS); - void VisitGotoStmt(GotoStmt *GS); - void VisitIfStmt(IfStmt *If); - void VisitInitListExpr(InitListExpr *IE); - void VisitMemberExpr(MemberExpr *M); - void VisitOffsetOfExpr(OffsetOfExpr *E); - void VisitObjCEncodeExpr(ObjCEncodeExpr *E); - void VisitObjCMessageExpr(ObjCMessageExpr *M); - void VisitOverloadExpr(OverloadExpr *E); - void VisitUnaryExprOrTypeTraitExpr(UnaryExprOrTypeTraitExpr *E); - void VisitStmt(Stmt *S); - void VisitSwitchStmt(SwitchStmt *S); - void VisitWhileStmt(WhileStmt *W); - void VisitUnaryTypeTraitExpr(UnaryTypeTraitExpr *E); - void VisitBinaryTypeTraitExpr(BinaryTypeTraitExpr *E); - void VisitTypeTraitExpr(TypeTraitExpr *E); - void VisitArrayTypeTraitExpr(ArrayTypeTraitExpr *E); - void VisitExpressionTraitExpr(ExpressionTraitExpr *E); - void VisitUnresolvedMemberExpr(UnresolvedMemberExpr *U); - void VisitVAArgExpr(VAArgExpr *E); - void VisitSizeOfPackExpr(SizeOfPackExpr *E); - void VisitPseudoObjectExpr(PseudoObjectExpr *E); - void VisitOpaqueValueExpr(OpaqueValueExpr *E); - void VisitLambdaExpr(LambdaExpr *E); - -private: - void AddDeclarationNameInfo(Stmt *S); - void AddNestedNameSpecifierLoc(NestedNameSpecifierLoc Qualifier); - void AddExplicitTemplateArgs(const ASTTemplateArgumentListInfo *A); - void AddMemberRef(FieldDecl *D, SourceLocation L); - void AddStmt(Stmt *S); - void AddDecl(Decl *D, bool isFirst = true); - void AddTypeLoc(TypeSourceInfo *TI); - void EnqueueChildren(Stmt *S); -}; -} // end anonyous namespace - -void EnqueueVisitor::AddDeclarationNameInfo(Stmt *S) { - // 'S' should always be non-null, since it comes from the - // statement we are visiting. - WL.push_back(DeclarationNameInfoVisit(S, Parent)); -} - -void -EnqueueVisitor::AddNestedNameSpecifierLoc(NestedNameSpecifierLoc Qualifier) { - if (Qualifier) - WL.push_back(NestedNameSpecifierLocVisit(Qualifier, Parent)); -} - -void EnqueueVisitor::AddStmt(Stmt *S) { - if (S) - WL.push_back(StmtVisit(S, Parent)); -} -void EnqueueVisitor::AddDecl(Decl *D, bool isFirst) { - if (D) - WL.push_back(DeclVisit(D, Parent, isFirst)); -} -void EnqueueVisitor:: - AddExplicitTemplateArgs(const ASTTemplateArgumentListInfo *A) { - if (A) - WL.push_back(ExplicitTemplateArgsVisit( - const_cast<ASTTemplateArgumentListInfo*>(A), Parent)); -} -void EnqueueVisitor::AddMemberRef(FieldDecl *D, SourceLocation L) { - if (D) - WL.push_back(MemberRefVisit(D, L, Parent)); -} -void EnqueueVisitor::AddTypeLoc(TypeSourceInfo *TI) { - if (TI) - WL.push_back(TypeLocVisit(TI->getTypeLoc(), Parent)); - } -void EnqueueVisitor::EnqueueChildren(Stmt *S) { - unsigned size = WL.size(); - for (Stmt::child_range Child = S->children(); Child; ++Child) { - AddStmt(*Child); - } - if (size == WL.size()) - return; - // Now reverse the entries we just added. This will match the DFS - // ordering performed by the worklist. - VisitorWorkList::iterator I = WL.begin() + size, E = WL.end(); - std::reverse(I, E); -} -void EnqueueVisitor::VisitAddrLabelExpr(AddrLabelExpr *E) { - WL.push_back(LabelRefVisit(E->getLabel(), E->getLabelLoc(), Parent)); -} -void EnqueueVisitor::VisitBlockExpr(BlockExpr *B) { - AddDecl(B->getBlockDecl()); -} -void EnqueueVisitor::VisitCompoundLiteralExpr(CompoundLiteralExpr *E) { - EnqueueChildren(E); - AddTypeLoc(E->getTypeSourceInfo()); -} -void EnqueueVisitor::VisitCompoundStmt(CompoundStmt *S) { - for (CompoundStmt::reverse_body_iterator I = S->body_rbegin(), - E = S->body_rend(); I != E; ++I) { - AddStmt(*I); - } -} -void EnqueueVisitor:: -VisitMSDependentExistsStmt(MSDependentExistsStmt *S) { - AddStmt(S->getSubStmt()); - AddDeclarationNameInfo(S); - if (NestedNameSpecifierLoc QualifierLoc = S->getQualifierLoc()) - AddNestedNameSpecifierLoc(QualifierLoc); -} - -void EnqueueVisitor:: -VisitCXXDependentScopeMemberExpr(CXXDependentScopeMemberExpr *E) { - AddExplicitTemplateArgs(E->getOptionalExplicitTemplateArgs()); - AddDeclarationNameInfo(E); - if (NestedNameSpecifierLoc QualifierLoc = E->getQualifierLoc()) - AddNestedNameSpecifierLoc(QualifierLoc); - if (!E->isImplicitAccess()) - AddStmt(E->getBase()); -} -void EnqueueVisitor::VisitCXXNewExpr(CXXNewExpr *E) { - // Enqueue the initializer , if any. - AddStmt(E->getInitializer()); - // Enqueue the array size, if any. - AddStmt(E->getArraySize()); - // Enqueue the allocated type. - AddTypeLoc(E->getAllocatedTypeSourceInfo()); - // Enqueue the placement arguments. - for (unsigned I = E->getNumPlacementArgs(); I > 0; --I) - AddStmt(E->getPlacementArg(I-1)); -} -void EnqueueVisitor::VisitCXXOperatorCallExpr(CXXOperatorCallExpr *CE) { - for (unsigned I = CE->getNumArgs(); I > 1 /* Yes, this is 1 */; --I) - AddStmt(CE->getArg(I-1)); - AddStmt(CE->getCallee()); - AddStmt(CE->getArg(0)); -} -void EnqueueVisitor::VisitCXXPseudoDestructorExpr(CXXPseudoDestructorExpr *E) { - // Visit the name of the type being destroyed. - AddTypeLoc(E->getDestroyedTypeInfo()); - // Visit the scope type that looks disturbingly like the nested-name-specifier - // but isn't. - AddTypeLoc(E->getScopeTypeInfo()); - // Visit the nested-name-specifier. - if (NestedNameSpecifierLoc QualifierLoc = E->getQualifierLoc()) - AddNestedNameSpecifierLoc(QualifierLoc); - // Visit base expression. - AddStmt(E->getBase()); -} -void EnqueueVisitor::VisitCXXScalarValueInitExpr(CXXScalarValueInitExpr *E) { - AddTypeLoc(E->getTypeSourceInfo()); -} -void EnqueueVisitor::VisitCXXTemporaryObjectExpr(CXXTemporaryObjectExpr *E) { - EnqueueChildren(E); - AddTypeLoc(E->getTypeSourceInfo()); -} -void EnqueueVisitor::VisitCXXTypeidExpr(CXXTypeidExpr *E) { - EnqueueChildren(E); - if (E->isTypeOperand()) - AddTypeLoc(E->getTypeOperandSourceInfo()); -} - -void EnqueueVisitor::VisitCXXUnresolvedConstructExpr(CXXUnresolvedConstructExpr - *E) { - EnqueueChildren(E); - AddTypeLoc(E->getTypeSourceInfo()); -} -void EnqueueVisitor::VisitCXXUuidofExpr(CXXUuidofExpr *E) { - EnqueueChildren(E); - if (E->isTypeOperand()) - AddTypeLoc(E->getTypeOperandSourceInfo()); -} - -void EnqueueVisitor::VisitCXXCatchStmt(CXXCatchStmt *S) { - EnqueueChildren(S); - AddDecl(S->getExceptionDecl()); -} - -void EnqueueVisitor::VisitDeclRefExpr(DeclRefExpr *DR) { - if (DR->hasExplicitTemplateArgs()) { - AddExplicitTemplateArgs(&DR->getExplicitTemplateArgs()); - } - WL.push_back(DeclRefExprParts(DR, Parent)); -} -void EnqueueVisitor::VisitDependentScopeDeclRefExpr(DependentScopeDeclRefExpr *E) { - AddExplicitTemplateArgs(E->getOptionalExplicitTemplateArgs()); - AddDeclarationNameInfo(E); - AddNestedNameSpecifierLoc(E->getQualifierLoc()); -} -void EnqueueVisitor::VisitDeclStmt(DeclStmt *S) { - unsigned size = WL.size(); - bool isFirst = true; - for (DeclStmt::decl_iterator D = S->decl_begin(), DEnd = S->decl_end(); - D != DEnd; ++D) { - AddDecl(*D, isFirst); - isFirst = false; - } - if (size == WL.size()) - return; - // Now reverse the entries we just added. This will match the DFS - // ordering performed by the worklist. - VisitorWorkList::iterator I = WL.begin() + size, E = WL.end(); - std::reverse(I, E); -} -void EnqueueVisitor::VisitDesignatedInitExpr(DesignatedInitExpr *E) { - AddStmt(E->getInit()); - typedef DesignatedInitExpr::Designator Designator; - for (DesignatedInitExpr::reverse_designators_iterator - D = E->designators_rbegin(), DEnd = E->designators_rend(); - D != DEnd; ++D) { - if (D->isFieldDesignator()) { - if (FieldDecl *Field = D->getField()) - AddMemberRef(Field, D->getFieldLoc()); - continue; - } - if (D->isArrayDesignator()) { - AddStmt(E->getArrayIndex(*D)); - continue; - } - assert(D->isArrayRangeDesignator() && "Unknown designator kind"); - AddStmt(E->getArrayRangeEnd(*D)); - AddStmt(E->getArrayRangeStart(*D)); - } -} -void EnqueueVisitor::VisitExplicitCastExpr(ExplicitCastExpr *E) { - EnqueueChildren(E); - AddTypeLoc(E->getTypeInfoAsWritten()); -} -void EnqueueVisitor::VisitForStmt(ForStmt *FS) { - AddStmt(FS->getBody()); - AddStmt(FS->getInc()); - AddStmt(FS->getCond()); - AddDecl(FS->getConditionVariable()); - AddStmt(FS->getInit()); -} -void EnqueueVisitor::VisitGotoStmt(GotoStmt *GS) { - WL.push_back(LabelRefVisit(GS->getLabel(), GS->getLabelLoc(), Parent)); -} -void EnqueueVisitor::VisitIfStmt(IfStmt *If) { - AddStmt(If->getElse()); - AddStmt(If->getThen()); - AddStmt(If->getCond()); - AddDecl(If->getConditionVariable()); -} -void EnqueueVisitor::VisitInitListExpr(InitListExpr *IE) { - // We care about the syntactic form of the initializer list, only. - if (InitListExpr *Syntactic = IE->getSyntacticForm()) - IE = Syntactic; - EnqueueChildren(IE); -} -void EnqueueVisitor::VisitMemberExpr(MemberExpr *M) { - WL.push_back(MemberExprParts(M, Parent)); - - // If the base of the member access expression is an implicit 'this', don't - // visit it. - // FIXME: If we ever want to show these implicit accesses, this will be - // unfortunate. However, clang_getCursor() relies on this behavior. - if (!M->isImplicitAccess()) - AddStmt(M->getBase()); -} -void EnqueueVisitor::VisitObjCEncodeExpr(ObjCEncodeExpr *E) { - AddTypeLoc(E->getEncodedTypeSourceInfo()); -} -void EnqueueVisitor::VisitObjCMessageExpr(ObjCMessageExpr *M) { - EnqueueChildren(M); - AddTypeLoc(M->getClassReceiverTypeInfo()); -} -void EnqueueVisitor::VisitOffsetOfExpr(OffsetOfExpr *E) { - // Visit the components of the offsetof expression. - for (unsigned N = E->getNumComponents(), I = N; I > 0; --I) { - typedef OffsetOfExpr::OffsetOfNode OffsetOfNode; - const OffsetOfNode &Node = E->getComponent(I-1); - switch (Node.getKind()) { - case OffsetOfNode::Array: - AddStmt(E->getIndexExpr(Node.getArrayExprIndex())); - break; - case OffsetOfNode::Field: - AddMemberRef(Node.getField(), Node.getSourceRange().getEnd()); - break; - case OffsetOfNode::Identifier: - case OffsetOfNode::Base: - continue; - } - } - // Visit the type into which we're computing the offset. - AddTypeLoc(E->getTypeSourceInfo()); -} -void EnqueueVisitor::VisitOverloadExpr(OverloadExpr *E) { - AddExplicitTemplateArgs(E->getOptionalExplicitTemplateArgs()); - WL.push_back(OverloadExprParts(E, Parent)); -} -void EnqueueVisitor::VisitUnaryExprOrTypeTraitExpr( - UnaryExprOrTypeTraitExpr *E) { - EnqueueChildren(E); - if (E->isArgumentType()) - AddTypeLoc(E->getArgumentTypeInfo()); -} -void EnqueueVisitor::VisitStmt(Stmt *S) { - EnqueueChildren(S); -} -void EnqueueVisitor::VisitSwitchStmt(SwitchStmt *S) { - AddStmt(S->getBody()); - AddStmt(S->getCond()); - AddDecl(S->getConditionVariable()); -} - -void EnqueueVisitor::VisitWhileStmt(WhileStmt *W) { - AddStmt(W->getBody()); - AddStmt(W->getCond()); - AddDecl(W->getConditionVariable()); -} - -void EnqueueVisitor::VisitUnaryTypeTraitExpr(UnaryTypeTraitExpr *E) { - AddTypeLoc(E->getQueriedTypeSourceInfo()); -} - -void EnqueueVisitor::VisitBinaryTypeTraitExpr(BinaryTypeTraitExpr *E) { - AddTypeLoc(E->getRhsTypeSourceInfo()); - AddTypeLoc(E->getLhsTypeSourceInfo()); -} - -void EnqueueVisitor::VisitTypeTraitExpr(TypeTraitExpr *E) { - for (unsigned I = E->getNumArgs(); I > 0; --I) - AddTypeLoc(E->getArg(I-1)); -} - -void EnqueueVisitor::VisitArrayTypeTraitExpr(ArrayTypeTraitExpr *E) { - AddTypeLoc(E->getQueriedTypeSourceInfo()); -} - -void EnqueueVisitor::VisitExpressionTraitExpr(ExpressionTraitExpr *E) { - EnqueueChildren(E); -} - -void EnqueueVisitor::VisitUnresolvedMemberExpr(UnresolvedMemberExpr *U) { - VisitOverloadExpr(U); - if (!U->isImplicitAccess()) - AddStmt(U->getBase()); -} -void EnqueueVisitor::VisitVAArgExpr(VAArgExpr *E) { - AddStmt(E->getSubExpr()); - AddTypeLoc(E->getWrittenTypeInfo()); -} -void EnqueueVisitor::VisitSizeOfPackExpr(SizeOfPackExpr *E) { - WL.push_back(SizeOfPackExprParts(E, Parent)); -} -void EnqueueVisitor::VisitOpaqueValueExpr(OpaqueValueExpr *E) { - // If the opaque value has a source expression, just transparently - // visit that. This is useful for (e.g.) pseudo-object expressions. - if (Expr *SourceExpr = E->getSourceExpr()) - return Visit(SourceExpr); -} -void EnqueueVisitor::VisitLambdaExpr(LambdaExpr *E) { - AddStmt(E->getBody()); - WL.push_back(LambdaExprParts(E, Parent)); -} -void EnqueueVisitor::VisitPseudoObjectExpr(PseudoObjectExpr *E) { - // Treat the expression like its syntactic form. - Visit(E->getSyntacticForm()); -} - -void CursorVisitor::EnqueueWorkList(VisitorWorkList &WL, Stmt *S) { - EnqueueVisitor(WL, MakeCXCursor(S, StmtParent, TU,RegionOfInterest)).Visit(S); -} - -bool CursorVisitor::IsInRegionOfInterest(CXCursor C) { - if (RegionOfInterest.isValid()) { - SourceRange Range = getRawCursorExtent(C); - if (Range.isInvalid() || CompareRegionOfInterest(Range)) - return false; - } - return true; -} - -bool CursorVisitor::RunVisitorWorkList(VisitorWorkList &WL) { - while (!WL.empty()) { - // Dequeue the worklist item. - VisitorJob LI = WL.back(); - WL.pop_back(); - - // Set the Parent field, then back to its old value once we're done. - SetParentRAII SetParent(Parent, StmtParent, LI.getParent()); - - switch (LI.getKind()) { - case VisitorJob::DeclVisitKind: { - Decl *D = cast<DeclVisit>(&LI)->get(); - if (!D) - continue; - - // For now, perform default visitation for Decls. - if (Visit(MakeCXCursor(D, TU, RegionOfInterest, - cast<DeclVisit>(&LI)->isFirst()))) - return true; - - continue; - } - case VisitorJob::ExplicitTemplateArgsVisitKind: { - const ASTTemplateArgumentListInfo *ArgList = - cast<ExplicitTemplateArgsVisit>(&LI)->get(); - for (const TemplateArgumentLoc *Arg = ArgList->getTemplateArgs(), - *ArgEnd = Arg + ArgList->NumTemplateArgs; - Arg != ArgEnd; ++Arg) { - if (VisitTemplateArgumentLoc(*Arg)) - return true; - } - continue; - } - case VisitorJob::TypeLocVisitKind: { - // Perform default visitation for TypeLocs. - if (Visit(cast<TypeLocVisit>(&LI)->get())) - return true; - continue; - } - case VisitorJob::LabelRefVisitKind: { - LabelDecl *LS = cast<LabelRefVisit>(&LI)->get(); - if (LabelStmt *stmt = LS->getStmt()) { - if (Visit(MakeCursorLabelRef(stmt, cast<LabelRefVisit>(&LI)->getLoc(), - TU))) { - return true; - } - } - continue; - } - - case VisitorJob::NestedNameSpecifierLocVisitKind: { - NestedNameSpecifierLocVisit *V = cast<NestedNameSpecifierLocVisit>(&LI); - if (VisitNestedNameSpecifierLoc(V->get())) - return true; - continue; - } - - case VisitorJob::DeclarationNameInfoVisitKind: { - if (VisitDeclarationNameInfo(cast<DeclarationNameInfoVisit>(&LI) - ->get())) - return true; - continue; - } - case VisitorJob::MemberRefVisitKind: { - MemberRefVisit *V = cast<MemberRefVisit>(&LI); - if (Visit(MakeCursorMemberRef(V->get(), V->getLoc(), TU))) - return true; - continue; - } - case VisitorJob::StmtVisitKind: { - Stmt *S = cast<StmtVisit>(&LI)->get(); - if (!S) - continue; - - // Update the current cursor. - CXCursor Cursor = MakeCXCursor(S, StmtParent, TU, RegionOfInterest); - if (!IsInRegionOfInterest(Cursor)) - continue; - switch (Visitor(Cursor, Parent, ClientData)) { - case CXChildVisit_Break: return true; - case CXChildVisit_Continue: break; - case CXChildVisit_Recurse: - if (PostChildrenVisitor) - WL.push_back(PostChildrenVisit(0, Cursor)); - EnqueueWorkList(WL, S); - break; - } - continue; - } - case VisitorJob::MemberExprPartsKind: { - // Handle the other pieces in the MemberExpr besides the base. - MemberExpr *M = cast<MemberExprParts>(&LI)->get(); - - // Visit the nested-name-specifier - if (NestedNameSpecifierLoc QualifierLoc = M->getQualifierLoc()) - if (VisitNestedNameSpecifierLoc(QualifierLoc)) - return true; - - // Visit the declaration name. - if (VisitDeclarationNameInfo(M->getMemberNameInfo())) - return true; - - // Visit the explicitly-specified template arguments, if any. - if (M->hasExplicitTemplateArgs()) { - for (const TemplateArgumentLoc *Arg = M->getTemplateArgs(), - *ArgEnd = Arg + M->getNumTemplateArgs(); - Arg != ArgEnd; ++Arg) { - if (VisitTemplateArgumentLoc(*Arg)) - return true; - } - } - continue; - } - case VisitorJob::DeclRefExprPartsKind: { - DeclRefExpr *DR = cast<DeclRefExprParts>(&LI)->get(); - // Visit nested-name-specifier, if present. - if (NestedNameSpecifierLoc QualifierLoc = DR->getQualifierLoc()) - if (VisitNestedNameSpecifierLoc(QualifierLoc)) - return true; - // Visit declaration name. - if (VisitDeclarationNameInfo(DR->getNameInfo())) - return true; - continue; - } - case VisitorJob::OverloadExprPartsKind: { - OverloadExpr *O = cast<OverloadExprParts>(&LI)->get(); - // Visit the nested-name-specifier. - if (NestedNameSpecifierLoc QualifierLoc = O->getQualifierLoc()) - if (VisitNestedNameSpecifierLoc(QualifierLoc)) - return true; - // Visit the declaration name. - if (VisitDeclarationNameInfo(O->getNameInfo())) - return true; - // Visit the overloaded declaration reference. - if (Visit(MakeCursorOverloadedDeclRef(O, TU))) - return true; - continue; - } - case VisitorJob::SizeOfPackExprPartsKind: { - SizeOfPackExpr *E = cast<SizeOfPackExprParts>(&LI)->get(); - NamedDecl *Pack = E->getPack(); - if (isa<TemplateTypeParmDecl>(Pack)) { - if (Visit(MakeCursorTypeRef(cast<TemplateTypeParmDecl>(Pack), - E->getPackLoc(), TU))) - return true; - - continue; - } - - if (isa<TemplateTemplateParmDecl>(Pack)) { - if (Visit(MakeCursorTemplateRef(cast<TemplateTemplateParmDecl>(Pack), - E->getPackLoc(), TU))) - return true; - - continue; - } - - // Non-type template parameter packs and function parameter packs are - // treated like DeclRefExpr cursors. - continue; - } - - case VisitorJob::LambdaExprPartsKind: { - // Visit captures. - LambdaExpr *E = cast<LambdaExprParts>(&LI)->get(); - for (LambdaExpr::capture_iterator C = E->explicit_capture_begin(), - CEnd = E->explicit_capture_end(); - C != CEnd; ++C) { - if (C->capturesThis()) - continue; - - if (Visit(MakeCursorVariableRef(C->getCapturedVar(), - C->getLocation(), - TU))) - return true; - } - - // Visit parameters and return type, if present. - if (E->hasExplicitParameters() || E->hasExplicitResultType()) { - TypeLoc TL = E->getCallOperator()->getTypeSourceInfo()->getTypeLoc(); - if (E->hasExplicitParameters() && E->hasExplicitResultType()) { - // Visit the whole type. - if (Visit(TL)) - return true; - } else if (isa<FunctionProtoTypeLoc>(TL)) { - FunctionProtoTypeLoc Proto = cast<FunctionProtoTypeLoc>(TL); - if (E->hasExplicitParameters()) { - // Visit parameters. - for (unsigned I = 0, N = Proto.getNumArgs(); I != N; ++I) - if (Visit(MakeCXCursor(Proto.getArg(I), TU))) - return true; - } else { - // Visit result type. - if (Visit(Proto.getResultLoc())) - return true; - } - } - } - break; - } - - case VisitorJob::PostChildrenVisitKind: - if (PostChildrenVisitor(Parent, ClientData)) - return true; - break; - } - } - return false; -} - -bool CursorVisitor::Visit(Stmt *S) { - VisitorWorkList *WL = 0; - if (!WorkListFreeList.empty()) { - WL = WorkListFreeList.back(); - WL->clear(); - WorkListFreeList.pop_back(); - } - else { - WL = new VisitorWorkList(); - WorkListCache.push_back(WL); - } - EnqueueWorkList(*WL, S); - bool result = RunVisitorWorkList(*WL); - WorkListFreeList.push_back(WL); - return result; -} - -namespace { -typedef llvm::SmallVector<SourceRange, 4> RefNamePieces; -RefNamePieces buildPieces(unsigned NameFlags, bool IsMemberRefExpr, - const DeclarationNameInfo &NI, - const SourceRange &QLoc, - const ASTTemplateArgumentListInfo *TemplateArgs = 0){ - const bool WantQualifier = NameFlags & CXNameRange_WantQualifier; - const bool WantTemplateArgs = NameFlags & CXNameRange_WantTemplateArgs; - const bool WantSinglePiece = NameFlags & CXNameRange_WantSinglePiece; - - const DeclarationName::NameKind Kind = NI.getName().getNameKind(); - - RefNamePieces Pieces; - - if (WantQualifier && QLoc.isValid()) - Pieces.push_back(QLoc); - - if (Kind != DeclarationName::CXXOperatorName || IsMemberRefExpr) - Pieces.push_back(NI.getLoc()); - - if (WantTemplateArgs && TemplateArgs) - Pieces.push_back(SourceRange(TemplateArgs->LAngleLoc, - TemplateArgs->RAngleLoc)); - - if (Kind == DeclarationName::CXXOperatorName) { - Pieces.push_back(SourceLocation::getFromRawEncoding( - NI.getInfo().CXXOperatorName.BeginOpNameLoc)); - Pieces.push_back(SourceLocation::getFromRawEncoding( - NI.getInfo().CXXOperatorName.EndOpNameLoc)); - } - - if (WantSinglePiece) { - SourceRange R(Pieces.front().getBegin(), Pieces.back().getEnd()); - Pieces.clear(); - Pieces.push_back(R); - } - - return Pieces; -} -} - -//===----------------------------------------------------------------------===// -// Misc. API hooks. -//===----------------------------------------------------------------------===// - -static llvm::sys::Mutex EnableMultithreadingMutex; -static bool EnabledMultithreading; - -static void fatal_error_handler(void *user_data, const std::string& reason) { - // Write the result out to stderr avoiding errs() because raw_ostreams can - // call report_fatal_error. - fprintf(stderr, "LIBCLANG FATAL ERROR: %s\n", reason.c_str()); - ::abort(); -} - -extern "C" { -CXIndex clang_createIndex(int excludeDeclarationsFromPCH, - int displayDiagnostics) { - // Disable pretty stack trace functionality, which will otherwise be a very - // poor citizen of the world and set up all sorts of signal handlers. - llvm::DisablePrettyStackTrace = true; - - // We use crash recovery to make some of our APIs more reliable, implicitly - // enable it. - llvm::CrashRecoveryContext::Enable(); - - // Enable support for multithreading in LLVM. - { - llvm::sys::ScopedLock L(EnableMultithreadingMutex); - if (!EnabledMultithreading) { - llvm::install_fatal_error_handler(fatal_error_handler, 0); - llvm::llvm_start_multithreaded(); - EnabledMultithreading = true; - } - } - - CIndexer *CIdxr = new CIndexer(); - if (excludeDeclarationsFromPCH) - CIdxr->setOnlyLocalDecls(); - if (displayDiagnostics) - CIdxr->setDisplayDiagnostics(); - - if (getenv("LIBCLANG_BGPRIO_INDEX")) - CIdxr->setCXGlobalOptFlags(CIdxr->getCXGlobalOptFlags() | - CXGlobalOpt_ThreadBackgroundPriorityForIndexing); - if (getenv("LIBCLANG_BGPRIO_EDIT")) - CIdxr->setCXGlobalOptFlags(CIdxr->getCXGlobalOptFlags() | - CXGlobalOpt_ThreadBackgroundPriorityForEditing); - - return CIdxr; -} - -void clang_disposeIndex(CXIndex CIdx) { - if (CIdx) - delete static_cast<CIndexer *>(CIdx); -} - -void clang_CXIndex_setGlobalOptions(CXIndex CIdx, unsigned options) { - if (CIdx) - static_cast<CIndexer *>(CIdx)->setCXGlobalOptFlags(options); -} - -unsigned clang_CXIndex_getGlobalOptions(CXIndex CIdx) { - if (CIdx) - return static_cast<CIndexer *>(CIdx)->getCXGlobalOptFlags(); - return 0; -} - -void clang_toggleCrashRecovery(unsigned isEnabled) { - if (isEnabled) - llvm::CrashRecoveryContext::Enable(); - else - llvm::CrashRecoveryContext::Disable(); -} - -CXTranslationUnit clang_createTranslationUnit(CXIndex CIdx, - const char *ast_filename) { - if (!CIdx) - return 0; - - CIndexer *CXXIdx = static_cast<CIndexer *>(CIdx); - FileSystemOptions FileSystemOpts; - - IntrusiveRefCntPtr<DiagnosticsEngine> Diags; - ASTUnit *TU = ASTUnit::LoadFromASTFile(ast_filename, Diags, FileSystemOpts, - CXXIdx->getOnlyLocalDecls(), - 0, 0, - /*CaptureDiagnostics=*/true, - /*AllowPCHWithCompilerErrors=*/true, - /*UserFilesAreVolatile=*/true); - return MakeCXTranslationUnit(CXXIdx, TU); -} - -unsigned clang_defaultEditingTranslationUnitOptions() { - return CXTranslationUnit_PrecompiledPreamble | - CXTranslationUnit_CacheCompletionResults; -} - -CXTranslationUnit -clang_createTranslationUnitFromSourceFile(CXIndex CIdx, - const char *source_filename, - int num_command_line_args, - const char * const *command_line_args, - unsigned num_unsaved_files, - struct CXUnsavedFile *unsaved_files) { - unsigned Options = CXTranslationUnit_DetailedPreprocessingRecord; - return clang_parseTranslationUnit(CIdx, source_filename, - command_line_args, num_command_line_args, - unsaved_files, num_unsaved_files, - Options); -} - -struct ParseTranslationUnitInfo { - CXIndex CIdx; - const char *source_filename; - const char *const *command_line_args; - int num_command_line_args; - struct CXUnsavedFile *unsaved_files; - unsigned num_unsaved_files; - unsigned options; - CXTranslationUnit result; -}; -static void clang_parseTranslationUnit_Impl(void *UserData) { - ParseTranslationUnitInfo *PTUI = - static_cast<ParseTranslationUnitInfo*>(UserData); - CXIndex CIdx = PTUI->CIdx; - const char *source_filename = PTUI->source_filename; - const char * const *command_line_args = PTUI->command_line_args; - int num_command_line_args = PTUI->num_command_line_args; - struct CXUnsavedFile *unsaved_files = PTUI->unsaved_files; - unsigned num_unsaved_files = PTUI->num_unsaved_files; - unsigned options = PTUI->options; - PTUI->result = 0; - - if (!CIdx) - return; - - CIndexer *CXXIdx = static_cast<CIndexer *>(CIdx); - - if (CXXIdx->isOptEnabled(CXGlobalOpt_ThreadBackgroundPriorityForIndexing)) - setThreadBackgroundPriority(); - - bool PrecompilePreamble = options & CXTranslationUnit_PrecompiledPreamble; - // FIXME: Add a flag for modules. - TranslationUnitKind TUKind - = (options & CXTranslationUnit_Incomplete)? TU_Prefix : TU_Complete; - bool CacheCodeCompetionResults - = options & CXTranslationUnit_CacheCompletionResults; - bool IncludeBriefCommentsInCodeCompletion - = options & CXTranslationUnit_IncludeBriefCommentsInCodeCompletion; - bool SkipFunctionBodies = options & CXTranslationUnit_SkipFunctionBodies; - bool ForSerialization = options & CXTranslationUnit_ForSerialization; - - // Configure the diagnostics. - IntrusiveRefCntPtr<DiagnosticsEngine> - Diags(CompilerInstance::createDiagnostics(new DiagnosticOptions, - num_command_line_args, - command_line_args)); - - // Recover resources if we crash before exiting this function. - llvm::CrashRecoveryContextCleanupRegistrar<DiagnosticsEngine, - llvm::CrashRecoveryContextReleaseRefCleanup<DiagnosticsEngine> > - DiagCleanup(Diags.getPtr()); - - OwningPtr<std::vector<ASTUnit::RemappedFile> > - RemappedFiles(new std::vector<ASTUnit::RemappedFile>()); - - // Recover resources if we crash before exiting this function. - llvm::CrashRecoveryContextCleanupRegistrar< - std::vector<ASTUnit::RemappedFile> > RemappedCleanup(RemappedFiles.get()); - - for (unsigned I = 0; I != num_unsaved_files; ++I) { - StringRef Data(unsaved_files[I].Contents, unsaved_files[I].Length); - const llvm::MemoryBuffer *Buffer - = llvm::MemoryBuffer::getMemBufferCopy(Data, unsaved_files[I].Filename); - RemappedFiles->push_back(std::make_pair(unsaved_files[I].Filename, - Buffer)); - } - - OwningPtr<std::vector<const char *> > - Args(new std::vector<const char*>()); - - // Recover resources if we crash before exiting this method. - llvm::CrashRecoveryContextCleanupRegistrar<std::vector<const char*> > - ArgsCleanup(Args.get()); - - // Since the Clang C library is primarily used by batch tools dealing with - // (often very broken) source code, where spell-checking can have a - // significant negative impact on performance (particularly when - // precompiled headers are involved), we disable it by default. - // Only do this if we haven't found a spell-checking-related argument. - bool FoundSpellCheckingArgument = false; - for (int I = 0; I != num_command_line_args; ++I) { - if (strcmp(command_line_args[I], "-fno-spell-checking") == 0 || - strcmp(command_line_args[I], "-fspell-checking") == 0) { - FoundSpellCheckingArgument = true; - break; - } - } - if (!FoundSpellCheckingArgument) - Args->push_back("-fno-spell-checking"); - - Args->insert(Args->end(), command_line_args, - command_line_args + num_command_line_args); - - // The 'source_filename' argument is optional. If the caller does not - // specify it then it is assumed that the source file is specified - // in the actual argument list. - // Put the source file after command_line_args otherwise if '-x' flag is - // present it will be unused. - if (source_filename) - Args->push_back(source_filename); - - // Do we need the detailed preprocessing record? - if (options & CXTranslationUnit_DetailedPreprocessingRecord) { - Args->push_back("-Xclang"); - Args->push_back("-detailed-preprocessing-record"); - } - - unsigned NumErrors = Diags->getClient()->getNumErrors(); - OwningPtr<ASTUnit> ErrUnit; - OwningPtr<ASTUnit> Unit( - ASTUnit::LoadFromCommandLine(Args->size() ? &(*Args)[0] : 0 - /* vector::data() not portable */, - Args->size() ? (&(*Args)[0] + Args->size()) :0, - Diags, - CXXIdx->getClangResourcesPath(), - CXXIdx->getOnlyLocalDecls(), - /*CaptureDiagnostics=*/true, - RemappedFiles->size() ? &(*RemappedFiles)[0]:0, - RemappedFiles->size(), - /*RemappedFilesKeepOriginalName=*/true, - PrecompilePreamble, - TUKind, - CacheCodeCompetionResults, - IncludeBriefCommentsInCodeCompletion, - /*AllowPCHWithCompilerErrors=*/true, - SkipFunctionBodies, - /*UserFilesAreVolatile=*/true, - ForSerialization, - &ErrUnit)); - - if (NumErrors != Diags->getClient()->getNumErrors()) { - // Make sure to check that 'Unit' is non-NULL. - if (CXXIdx->getDisplayDiagnostics()) - printDiagsToStderr(Unit ? Unit.get() : ErrUnit.get()); - } - - PTUI->result = MakeCXTranslationUnit(CXXIdx, Unit.take()); -} -CXTranslationUnit clang_parseTranslationUnit(CXIndex CIdx, - const char *source_filename, - const char * const *command_line_args, - int num_command_line_args, - struct CXUnsavedFile *unsaved_files, - unsigned num_unsaved_files, - unsigned options) { - ParseTranslationUnitInfo PTUI = { CIdx, source_filename, command_line_args, - num_command_line_args, unsaved_files, - num_unsaved_files, options, 0 }; - llvm::CrashRecoveryContext CRC; - - if (!RunSafely(CRC, clang_parseTranslationUnit_Impl, &PTUI)) { - fprintf(stderr, "libclang: crash detected during parsing: {\n"); - fprintf(stderr, " 'source_filename' : '%s'\n", source_filename); - fprintf(stderr, " 'command_line_args' : ["); - for (int i = 0; i != num_command_line_args; ++i) { - if (i) - fprintf(stderr, ", "); - fprintf(stderr, "'%s'", command_line_args[i]); - } - fprintf(stderr, "],\n"); - fprintf(stderr, " 'unsaved_files' : ["); - for (unsigned i = 0; i != num_unsaved_files; ++i) { - if (i) - fprintf(stderr, ", "); - fprintf(stderr, "('%s', '...', %ld)", unsaved_files[i].Filename, - unsaved_files[i].Length); - } - fprintf(stderr, "],\n"); - fprintf(stderr, " 'options' : %d,\n", options); - fprintf(stderr, "}\n"); - - return 0; - } else if (getenv("LIBCLANG_RESOURCE_USAGE")) { - PrintLibclangResourceUsage(PTUI.result); - } - - return PTUI.result; -} - -unsigned clang_defaultSaveOptions(CXTranslationUnit TU) { - return CXSaveTranslationUnit_None; -} - -namespace { - -struct SaveTranslationUnitInfo { - CXTranslationUnit TU; - const char *FileName; - unsigned options; - CXSaveError result; -}; - -} - -static void clang_saveTranslationUnit_Impl(void *UserData) { - SaveTranslationUnitInfo *STUI = - static_cast<SaveTranslationUnitInfo*>(UserData); - - CIndexer *CXXIdx = (CIndexer*)STUI->TU->CIdx; - if (CXXIdx->isOptEnabled(CXGlobalOpt_ThreadBackgroundPriorityForIndexing)) - setThreadBackgroundPriority(); - - bool hadError = static_cast<ASTUnit *>(STUI->TU->TUData)->Save(STUI->FileName); - STUI->result = hadError ? CXSaveError_Unknown : CXSaveError_None; -} - -int clang_saveTranslationUnit(CXTranslationUnit TU, const char *FileName, - unsigned options) { - if (!TU) - return CXSaveError_InvalidTU; - - ASTUnit *CXXUnit = static_cast<ASTUnit *>(TU->TUData); - ASTUnit::ConcurrencyCheck Check(*CXXUnit); - if (!CXXUnit->hasSema()) - return CXSaveError_InvalidTU; - - SaveTranslationUnitInfo STUI = { TU, FileName, options, CXSaveError_None }; - - if (!CXXUnit->getDiagnostics().hasUnrecoverableErrorOccurred() || - getenv("LIBCLANG_NOTHREADS")) { - clang_saveTranslationUnit_Impl(&STUI); - - if (getenv("LIBCLANG_RESOURCE_USAGE")) - PrintLibclangResourceUsage(TU); - - return STUI.result; - } - - // We have an AST that has invalid nodes due to compiler errors. - // Use a crash recovery thread for protection. - - llvm::CrashRecoveryContext CRC; - - if (!RunSafely(CRC, clang_saveTranslationUnit_Impl, &STUI)) { - fprintf(stderr, "libclang: crash detected during AST saving: {\n"); - fprintf(stderr, " 'filename' : '%s'\n", FileName); - fprintf(stderr, " 'options' : %d,\n", options); - fprintf(stderr, "}\n"); - - return CXSaveError_Unknown; - - } else if (getenv("LIBCLANG_RESOURCE_USAGE")) { - PrintLibclangResourceUsage(TU); - } - - return STUI.result; -} - -void clang_disposeTranslationUnit(CXTranslationUnit CTUnit) { - if (CTUnit) { - // If the translation unit has been marked as unsafe to free, just discard - // it. - if (static_cast<ASTUnit *>(CTUnit->TUData)->isUnsafeToFree()) - return; - - delete static_cast<ASTUnit *>(CTUnit->TUData); - disposeCXStringPool(CTUnit->StringPool); - delete static_cast<CXDiagnosticSetImpl *>(CTUnit->Diagnostics); - disposeOverridenCXCursorsPool(CTUnit->OverridenCursorsPool); - delete CTUnit; - } -} - -unsigned clang_defaultReparseOptions(CXTranslationUnit TU) { - return CXReparse_None; -} - -struct ReparseTranslationUnitInfo { - CXTranslationUnit TU; - unsigned num_unsaved_files; - struct CXUnsavedFile *unsaved_files; - unsigned options; - int result; -}; - -static void clang_reparseTranslationUnit_Impl(void *UserData) { - ReparseTranslationUnitInfo *RTUI = - static_cast<ReparseTranslationUnitInfo*>(UserData); - CXTranslationUnit TU = RTUI->TU; - - // Reset the associated diagnostics. - delete static_cast<CXDiagnosticSetImpl*>(TU->Diagnostics); - TU->Diagnostics = 0; - - unsigned num_unsaved_files = RTUI->num_unsaved_files; - struct CXUnsavedFile *unsaved_files = RTUI->unsaved_files; - unsigned options = RTUI->options; - (void) options; - RTUI->result = 1; - - if (!TU) - return; - - CIndexer *CXXIdx = (CIndexer*)TU->CIdx; - if (CXXIdx->isOptEnabled(CXGlobalOpt_ThreadBackgroundPriorityForEditing)) - setThreadBackgroundPriority(); - - ASTUnit *CXXUnit = static_cast<ASTUnit *>(TU->TUData); - ASTUnit::ConcurrencyCheck Check(*CXXUnit); - - OwningPtr<std::vector<ASTUnit::RemappedFile> > - RemappedFiles(new std::vector<ASTUnit::RemappedFile>()); - - // Recover resources if we crash before exiting this function. - llvm::CrashRecoveryContextCleanupRegistrar< - std::vector<ASTUnit::RemappedFile> > RemappedCleanup(RemappedFiles.get()); - - for (unsigned I = 0; I != num_unsaved_files; ++I) { - StringRef Data(unsaved_files[I].Contents, unsaved_files[I].Length); - const llvm::MemoryBuffer *Buffer - = llvm::MemoryBuffer::getMemBufferCopy(Data, unsaved_files[I].Filename); - RemappedFiles->push_back(std::make_pair(unsaved_files[I].Filename, - Buffer)); - } - - if (!CXXUnit->Reparse(RemappedFiles->size() ? &(*RemappedFiles)[0] : 0, - RemappedFiles->size())) - RTUI->result = 0; -} - -int clang_reparseTranslationUnit(CXTranslationUnit TU, - unsigned num_unsaved_files, - struct CXUnsavedFile *unsaved_files, - unsigned options) { - ReparseTranslationUnitInfo RTUI = { TU, num_unsaved_files, unsaved_files, - options, 0 }; - - if (getenv("LIBCLANG_NOTHREADS")) { - clang_reparseTranslationUnit_Impl(&RTUI); - return RTUI.result; - } - - llvm::CrashRecoveryContext CRC; - - if (!RunSafely(CRC, clang_reparseTranslationUnit_Impl, &RTUI)) { - fprintf(stderr, "libclang: crash detected during reparsing\n"); - static_cast<ASTUnit *>(TU->TUData)->setUnsafeToFree(true); - return 1; - } else if (getenv("LIBCLANG_RESOURCE_USAGE")) - PrintLibclangResourceUsage(TU); - - return RTUI.result; -} - - -CXString clang_getTranslationUnitSpelling(CXTranslationUnit CTUnit) { - if (!CTUnit) - return createCXString(""); - - ASTUnit *CXXUnit = static_cast<ASTUnit *>(CTUnit->TUData); - return createCXString(CXXUnit->getOriginalSourceFileName(), true); -} - -CXCursor clang_getTranslationUnitCursor(CXTranslationUnit TU) { - ASTUnit *CXXUnit = static_cast<ASTUnit*>(TU->TUData); - return MakeCXCursor(CXXUnit->getASTContext().getTranslationUnitDecl(), TU); -} - -} // end: extern "C" - -//===----------------------------------------------------------------------===// -// CXFile Operations. -//===----------------------------------------------------------------------===// - -extern "C" { -CXString clang_getFileName(CXFile SFile) { - if (!SFile) - return createCXString((const char*)NULL); - - FileEntry *FEnt = static_cast<FileEntry *>(SFile); - return createCXString(FEnt->getName()); -} - -time_t clang_getFileTime(CXFile SFile) { - if (!SFile) - return 0; - - FileEntry *FEnt = static_cast<FileEntry *>(SFile); - return FEnt->getModificationTime(); -} - -CXFile clang_getFile(CXTranslationUnit tu, const char *file_name) { - if (!tu) - return 0; - - ASTUnit *CXXUnit = static_cast<ASTUnit *>(tu->TUData); - - FileManager &FMgr = CXXUnit->getFileManager(); - return const_cast<FileEntry *>(FMgr.getFile(file_name)); -} - -unsigned clang_isFileMultipleIncludeGuarded(CXTranslationUnit tu, CXFile file) { - if (!tu || !file) - return 0; - - ASTUnit *CXXUnit = static_cast<ASTUnit *>(tu->TUData); - FileEntry *FEnt = static_cast<FileEntry *>(file); - return CXXUnit->getPreprocessor().getHeaderSearchInfo() - .isFileMultipleIncludeGuarded(FEnt); -} - -} // end: extern "C" - -//===----------------------------------------------------------------------===// -// CXCursor Operations. -//===----------------------------------------------------------------------===// - -static Decl *getDeclFromExpr(Stmt *E) { - if (ImplicitCastExpr *CE = dyn_cast<ImplicitCastExpr>(E)) - return getDeclFromExpr(CE->getSubExpr()); - - if (DeclRefExpr *RefExpr = dyn_cast<DeclRefExpr>(E)) - return RefExpr->getDecl(); - if (MemberExpr *ME = dyn_cast<MemberExpr>(E)) - return ME->getMemberDecl(); - if (ObjCIvarRefExpr *RE = dyn_cast<ObjCIvarRefExpr>(E)) - return RE->getDecl(); - if (ObjCPropertyRefExpr *PRE = dyn_cast<ObjCPropertyRefExpr>(E)) { - if (PRE->isExplicitProperty()) - return PRE->getExplicitProperty(); - // It could be messaging both getter and setter as in: - // ++myobj.myprop; - // in which case prefer to associate the setter since it is less obvious - // from inspecting the source that the setter is going to get called. - if (PRE->isMessagingSetter()) - return PRE->getImplicitPropertySetter(); - return PRE->getImplicitPropertyGetter(); - } - if (PseudoObjectExpr *POE = dyn_cast<PseudoObjectExpr>(E)) - return getDeclFromExpr(POE->getSyntacticForm()); - if (OpaqueValueExpr *OVE = dyn_cast<OpaqueValueExpr>(E)) - if (Expr *Src = OVE->getSourceExpr()) - return getDeclFromExpr(Src); - - if (CallExpr *CE = dyn_cast<CallExpr>(E)) - return getDeclFromExpr(CE->getCallee()); - if (CXXConstructExpr *CE = dyn_cast<CXXConstructExpr>(E)) - if (!CE->isElidable()) - return CE->getConstructor(); - if (ObjCMessageExpr *OME = dyn_cast<ObjCMessageExpr>(E)) - return OME->getMethodDecl(); - - if (ObjCProtocolExpr *PE = dyn_cast<ObjCProtocolExpr>(E)) - return PE->getProtocol(); - if (SubstNonTypeTemplateParmPackExpr *NTTP - = dyn_cast<SubstNonTypeTemplateParmPackExpr>(E)) - return NTTP->getParameterPack(); - if (SizeOfPackExpr *SizeOfPack = dyn_cast<SizeOfPackExpr>(E)) - if (isa<NonTypeTemplateParmDecl>(SizeOfPack->getPack()) || - isa<ParmVarDecl>(SizeOfPack->getPack())) - return SizeOfPack->getPack(); - - return 0; -} - -static SourceLocation getLocationFromExpr(Expr *E) { - if (ImplicitCastExpr *CE = dyn_cast<ImplicitCastExpr>(E)) - return getLocationFromExpr(CE->getSubExpr()); - - if (ObjCMessageExpr *Msg = dyn_cast<ObjCMessageExpr>(E)) - return /*FIXME:*/Msg->getLeftLoc(); - if (DeclRefExpr *DRE = dyn_cast<DeclRefExpr>(E)) - return DRE->getLocation(); - if (MemberExpr *Member = dyn_cast<MemberExpr>(E)) - return Member->getMemberLoc(); - if (ObjCIvarRefExpr *Ivar = dyn_cast<ObjCIvarRefExpr>(E)) - return Ivar->getLocation(); - if (SizeOfPackExpr *SizeOfPack = dyn_cast<SizeOfPackExpr>(E)) - return SizeOfPack->getPackLoc(); - if (ObjCPropertyRefExpr *PropRef = dyn_cast<ObjCPropertyRefExpr>(E)) - return PropRef->getLocation(); - - return E->getLocStart(); -} - -extern "C" { - -unsigned clang_visitChildren(CXCursor parent, - CXCursorVisitor visitor, - CXClientData client_data) { - CursorVisitor CursorVis(getCursorTU(parent), visitor, client_data, - /*VisitPreprocessorLast=*/false); - return CursorVis.VisitChildren(parent); -} - -#ifndef __has_feature -#define __has_feature(x) 0 -#endif -#if __has_feature(blocks) -typedef enum CXChildVisitResult - (^CXCursorVisitorBlock)(CXCursor cursor, CXCursor parent); - -static enum CXChildVisitResult visitWithBlock(CXCursor cursor, CXCursor parent, - CXClientData client_data) { - CXCursorVisitorBlock block = (CXCursorVisitorBlock)client_data; - return block(cursor, parent); -} -#else -// If we are compiled with a compiler that doesn't have native blocks support, -// define and call the block manually, so the -typedef struct _CXChildVisitResult -{ - void *isa; - int flags; - int reserved; - enum CXChildVisitResult(*invoke)(struct _CXChildVisitResult*, CXCursor, - CXCursor); -} *CXCursorVisitorBlock; - -static enum CXChildVisitResult visitWithBlock(CXCursor cursor, CXCursor parent, - CXClientData client_data) { - CXCursorVisitorBlock block = (CXCursorVisitorBlock)client_data; - return block->invoke(block, cursor, parent); -} -#endif - - -unsigned clang_visitChildrenWithBlock(CXCursor parent, - CXCursorVisitorBlock block) { - return clang_visitChildren(parent, visitWithBlock, block); -} - -static CXString getDeclSpelling(Decl *D) { - if (!D) - return createCXString(""); - - NamedDecl *ND = dyn_cast<NamedDecl>(D); - if (!ND) { - if (ObjCPropertyImplDecl *PropImpl =dyn_cast<ObjCPropertyImplDecl>(D)) - if (ObjCPropertyDecl *Property = PropImpl->getPropertyDecl()) - return createCXString(Property->getIdentifier()->getName()); - - if (ImportDecl *ImportD = dyn_cast<ImportDecl>(D)) - if (Module *Mod = ImportD->getImportedModule()) - return createCXString(Mod->getFullModuleName()); - - return createCXString(""); - } - - if (ObjCMethodDecl *OMD = dyn_cast<ObjCMethodDecl>(ND)) - return createCXString(OMD->getSelector().getAsString()); - - if (ObjCCategoryImplDecl *CIMP = dyn_cast<ObjCCategoryImplDecl>(ND)) - // No, this isn't the same as the code below. getIdentifier() is non-virtual - // and returns different names. NamedDecl returns the class name and - // ObjCCategoryImplDecl returns the category name. - return createCXString(CIMP->getIdentifier()->getNameStart()); - - if (isa<UsingDirectiveDecl>(D)) - return createCXString(""); - - SmallString<1024> S; - llvm::raw_svector_ostream os(S); - ND->printName(os); - - return createCXString(os.str()); -} - -CXString clang_getCursorSpelling(CXCursor C) { - if (clang_isTranslationUnit(C.kind)) - return clang_getTranslationUnitSpelling( - static_cast<CXTranslationUnit>(C.data[2])); - - if (clang_isReference(C.kind)) { - switch (C.kind) { - case CXCursor_ObjCSuperClassRef: { - ObjCInterfaceDecl *Super = getCursorObjCSuperClassRef(C).first; - return createCXString(Super->getIdentifier()->getNameStart()); - } - case CXCursor_ObjCClassRef: { - ObjCInterfaceDecl *Class = getCursorObjCClassRef(C).first; - return createCXString(Class->getIdentifier()->getNameStart()); - } - case CXCursor_ObjCProtocolRef: { - ObjCProtocolDecl *OID = getCursorObjCProtocolRef(C).first; - assert(OID && "getCursorSpelling(): Missing protocol decl"); - return createCXString(OID->getIdentifier()->getNameStart()); - } - case CXCursor_CXXBaseSpecifier: { - CXXBaseSpecifier *B = getCursorCXXBaseSpecifier(C); - return createCXString(B->getType().getAsString()); - } - case CXCursor_TypeRef: { - TypeDecl *Type = getCursorTypeRef(C).first; - assert(Type && "Missing type decl"); - - return createCXString(getCursorContext(C).getTypeDeclType(Type). - getAsString()); - } - case CXCursor_TemplateRef: { - TemplateDecl *Template = getCursorTemplateRef(C).first; - assert(Template && "Missing template decl"); - - return createCXString(Template->getNameAsString()); - } - - case CXCursor_NamespaceRef: { - NamedDecl *NS = getCursorNamespaceRef(C).first; - assert(NS && "Missing namespace decl"); - - return createCXString(NS->getNameAsString()); - } - - case CXCursor_MemberRef: { - FieldDecl *Field = getCursorMemberRef(C).first; - assert(Field && "Missing member decl"); - - return createCXString(Field->getNameAsString()); - } - - case CXCursor_LabelRef: { - LabelStmt *Label = getCursorLabelRef(C).first; - assert(Label && "Missing label"); - - return createCXString(Label->getName()); - } - - case CXCursor_OverloadedDeclRef: { - OverloadedDeclRefStorage Storage = getCursorOverloadedDeclRef(C).first; - if (Decl *D = Storage.dyn_cast<Decl *>()) { - if (NamedDecl *ND = dyn_cast<NamedDecl>(D)) - return createCXString(ND->getNameAsString()); - return createCXString(""); - } - if (OverloadExpr *E = Storage.dyn_cast<OverloadExpr *>()) - return createCXString(E->getName().getAsString()); - OverloadedTemplateStorage *Ovl - = Storage.get<OverloadedTemplateStorage*>(); - if (Ovl->size() == 0) - return createCXString(""); - return createCXString((*Ovl->begin())->getNameAsString()); - } - - case CXCursor_VariableRef: { - VarDecl *Var = getCursorVariableRef(C).first; - assert(Var && "Missing variable decl"); - - return createCXString(Var->getNameAsString()); - } - - default: - return createCXString("<not implemented>"); - } - } - - if (clang_isExpression(C.kind)) { - Decl *D = getDeclFromExpr(getCursorExpr(C)); - if (D) - return getDeclSpelling(D); - return createCXString(""); - } - - if (clang_isStatement(C.kind)) { - Stmt *S = getCursorStmt(C); - if (LabelStmt *Label = dyn_cast_or_null<LabelStmt>(S)) - return createCXString(Label->getName()); - - return createCXString(""); - } - - if (C.kind == CXCursor_MacroExpansion) - return createCXString(getCursorMacroExpansion(C)->getName() - ->getNameStart()); - - if (C.kind == CXCursor_MacroDefinition) - return createCXString(getCursorMacroDefinition(C)->getName() - ->getNameStart()); - - if (C.kind == CXCursor_InclusionDirective) - return createCXString(getCursorInclusionDirective(C)->getFileName()); - - if (clang_isDeclaration(C.kind)) - return getDeclSpelling(getCursorDecl(C)); - - if (C.kind == CXCursor_AnnotateAttr) { - AnnotateAttr *AA = cast<AnnotateAttr>(cxcursor::getCursorAttr(C)); - return createCXString(AA->getAnnotation()); - } - - if (C.kind == CXCursor_AsmLabelAttr) { - AsmLabelAttr *AA = cast<AsmLabelAttr>(cxcursor::getCursorAttr(C)); - return createCXString(AA->getLabel()); - } - - return createCXString(""); -} - -CXSourceRange clang_Cursor_getSpellingNameRange(CXCursor C, - unsigned pieceIndex, - unsigned options) { - if (clang_Cursor_isNull(C)) - return clang_getNullRange(); - - ASTContext &Ctx = getCursorContext(C); - - if (clang_isStatement(C.kind)) { - Stmt *S = getCursorStmt(C); - if (LabelStmt *Label = dyn_cast_or_null<LabelStmt>(S)) { - if (pieceIndex > 0) - return clang_getNullRange(); - return cxloc::translateSourceRange(Ctx, Label->getIdentLoc()); - } - - return clang_getNullRange(); - } - - if (C.kind == CXCursor_ObjCMessageExpr) { - if (ObjCMessageExpr * - ME = dyn_cast_or_null<ObjCMessageExpr>(getCursorExpr(C))) { - if (pieceIndex >= ME->getNumSelectorLocs()) - return clang_getNullRange(); - return cxloc::translateSourceRange(Ctx, ME->getSelectorLoc(pieceIndex)); - } - } - - if (C.kind == CXCursor_ObjCInstanceMethodDecl || - C.kind == CXCursor_ObjCClassMethodDecl) { - if (ObjCMethodDecl * - MD = dyn_cast_or_null<ObjCMethodDecl>(getCursorDecl(C))) { - if (pieceIndex >= MD->getNumSelectorLocs()) - return clang_getNullRange(); - return cxloc::translateSourceRange(Ctx, MD->getSelectorLoc(pieceIndex)); - } - } - - if (C.kind == CXCursor_ObjCCategoryDecl || - C.kind == CXCursor_ObjCCategoryImplDecl) { - if (pieceIndex > 0) - return clang_getNullRange(); - if (ObjCCategoryDecl * - CD = dyn_cast_or_null<ObjCCategoryDecl>(getCursorDecl(C))) - return cxloc::translateSourceRange(Ctx, CD->getCategoryNameLoc()); - if (ObjCCategoryImplDecl * - CID = dyn_cast_or_null<ObjCCategoryImplDecl>(getCursorDecl(C))) - return cxloc::translateSourceRange(Ctx, CID->getCategoryNameLoc()); - } - - if (C.kind == CXCursor_ModuleImportDecl) { - if (pieceIndex > 0) - return clang_getNullRange(); - if (ImportDecl *ImportD = dyn_cast_or_null<ImportDecl>(getCursorDecl(C))) { - ArrayRef<SourceLocation> Locs = ImportD->getIdentifierLocs(); - if (!Locs.empty()) - return cxloc::translateSourceRange(Ctx, - SourceRange(Locs.front(), Locs.back())); - } - return clang_getNullRange(); - } - - // FIXME: A CXCursor_InclusionDirective should give the location of the - // filename, but we don't keep track of this. - - // FIXME: A CXCursor_AnnotateAttr should give the location of the annotation - // but we don't keep track of this. - - // FIXME: A CXCursor_AsmLabelAttr should give the location of the label - // but we don't keep track of this. - - // Default handling, give the location of the cursor. - - if (pieceIndex > 0) - return clang_getNullRange(); - - CXSourceLocation CXLoc = clang_getCursorLocation(C); - SourceLocation Loc = cxloc::translateSourceLocation(CXLoc); - return cxloc::translateSourceRange(Ctx, Loc); -} - -CXString clang_getCursorDisplayName(CXCursor C) { - if (!clang_isDeclaration(C.kind)) - return clang_getCursorSpelling(C); - - Decl *D = getCursorDecl(C); - if (!D) - return createCXString(""); - - PrintingPolicy Policy = getCursorContext(C).getPrintingPolicy(); - if (FunctionTemplateDecl *FunTmpl = dyn_cast<FunctionTemplateDecl>(D)) - D = FunTmpl->getTemplatedDecl(); - - if (FunctionDecl *Function = dyn_cast<FunctionDecl>(D)) { - SmallString<64> Str; - llvm::raw_svector_ostream OS(Str); - OS << *Function; - if (Function->getPrimaryTemplate()) - OS << "<>"; - OS << "("; - for (unsigned I = 0, N = Function->getNumParams(); I != N; ++I) { - if (I) - OS << ", "; - OS << Function->getParamDecl(I)->getType().getAsString(Policy); - } - - if (Function->isVariadic()) { - if (Function->getNumParams()) - OS << ", "; - OS << "..."; - } - OS << ")"; - return createCXString(OS.str()); - } - - if (ClassTemplateDecl *ClassTemplate = dyn_cast<ClassTemplateDecl>(D)) { - SmallString<64> Str; - llvm::raw_svector_ostream OS(Str); - OS << *ClassTemplate; - OS << "<"; - TemplateParameterList *Params = ClassTemplate->getTemplateParameters(); - for (unsigned I = 0, N = Params->size(); I != N; ++I) { - if (I) - OS << ", "; - - NamedDecl *Param = Params->getParam(I); - if (Param->getIdentifier()) { - OS << Param->getIdentifier()->getName(); - continue; - } - - // There is no parameter name, which makes this tricky. Try to come up - // with something useful that isn't too long. - if (TemplateTypeParmDecl *TTP = dyn_cast<TemplateTypeParmDecl>(Param)) - OS << (TTP->wasDeclaredWithTypename()? "typename" : "class"); - else if (NonTypeTemplateParmDecl *NTTP - = dyn_cast<NonTypeTemplateParmDecl>(Param)) - OS << NTTP->getType().getAsString(Policy); - else - OS << "template<...> class"; - } - - OS << ">"; - return createCXString(OS.str()); - } - - if (ClassTemplateSpecializationDecl *ClassSpec - = dyn_cast<ClassTemplateSpecializationDecl>(D)) { - // If the type was explicitly written, use that. - if (TypeSourceInfo *TSInfo = ClassSpec->getTypeAsWritten()) - return createCXString(TSInfo->getType().getAsString(Policy)); - - SmallString<64> Str; - llvm::raw_svector_ostream OS(Str); - OS << *ClassSpec; - OS << TemplateSpecializationType::PrintTemplateArgumentList( - ClassSpec->getTemplateArgs().data(), - ClassSpec->getTemplateArgs().size(), - Policy); - return createCXString(OS.str()); - } - - return clang_getCursorSpelling(C); -} - -CXString clang_getCursorKindSpelling(enum CXCursorKind Kind) { - switch (Kind) { - case CXCursor_FunctionDecl: - return createCXString("FunctionDecl"); - case CXCursor_TypedefDecl: - return createCXString("TypedefDecl"); - case CXCursor_EnumDecl: - return createCXString("EnumDecl"); - case CXCursor_EnumConstantDecl: - return createCXString("EnumConstantDecl"); - case CXCursor_StructDecl: - return createCXString("StructDecl"); - case CXCursor_UnionDecl: - return createCXString("UnionDecl"); - case CXCursor_ClassDecl: - return createCXString("ClassDecl"); - case CXCursor_FieldDecl: - return createCXString("FieldDecl"); - case CXCursor_VarDecl: - return createCXString("VarDecl"); - case CXCursor_ParmDecl: - return createCXString("ParmDecl"); - case CXCursor_ObjCInterfaceDecl: - return createCXString("ObjCInterfaceDecl"); - case CXCursor_ObjCCategoryDecl: - return createCXString("ObjCCategoryDecl"); - case CXCursor_ObjCProtocolDecl: - return createCXString("ObjCProtocolDecl"); - case CXCursor_ObjCPropertyDecl: - return createCXString("ObjCPropertyDecl"); - case CXCursor_ObjCIvarDecl: - return createCXString("ObjCIvarDecl"); - case CXCursor_ObjCInstanceMethodDecl: - return createCXString("ObjCInstanceMethodDecl"); - case CXCursor_ObjCClassMethodDecl: - return createCXString("ObjCClassMethodDecl"); - case CXCursor_ObjCImplementationDecl: - return createCXString("ObjCImplementationDecl"); - case CXCursor_ObjCCategoryImplDecl: - return createCXString("ObjCCategoryImplDecl"); - case CXCursor_CXXMethod: - return createCXString("CXXMethod"); - case CXCursor_UnexposedDecl: - return createCXString("UnexposedDecl"); - case CXCursor_ObjCSuperClassRef: - return createCXString("ObjCSuperClassRef"); - case CXCursor_ObjCProtocolRef: - return createCXString("ObjCProtocolRef"); - case CXCursor_ObjCClassRef: - return createCXString("ObjCClassRef"); - case CXCursor_TypeRef: - return createCXString("TypeRef"); - case CXCursor_TemplateRef: - return createCXString("TemplateRef"); - case CXCursor_NamespaceRef: - return createCXString("NamespaceRef"); - case CXCursor_MemberRef: - return createCXString("MemberRef"); - case CXCursor_LabelRef: - return createCXString("LabelRef"); - case CXCursor_OverloadedDeclRef: - return createCXString("OverloadedDeclRef"); - case CXCursor_VariableRef: - return createCXString("VariableRef"); - case CXCursor_IntegerLiteral: - return createCXString("IntegerLiteral"); - case CXCursor_FloatingLiteral: - return createCXString("FloatingLiteral"); - case CXCursor_ImaginaryLiteral: - return createCXString("ImaginaryLiteral"); - case CXCursor_StringLiteral: - return createCXString("StringLiteral"); - case CXCursor_CharacterLiteral: - return createCXString("CharacterLiteral"); - case CXCursor_ParenExpr: - return createCXString("ParenExpr"); - case CXCursor_UnaryOperator: - return createCXString("UnaryOperator"); - case CXCursor_ArraySubscriptExpr: - return createCXString("ArraySubscriptExpr"); - case CXCursor_BinaryOperator: - return createCXString("BinaryOperator"); - case CXCursor_CompoundAssignOperator: - return createCXString("CompoundAssignOperator"); - case CXCursor_ConditionalOperator: - return createCXString("ConditionalOperator"); - case CXCursor_CStyleCastExpr: - return createCXString("CStyleCastExpr"); - case CXCursor_CompoundLiteralExpr: - return createCXString("CompoundLiteralExpr"); - case CXCursor_InitListExpr: - return createCXString("InitListExpr"); - case CXCursor_AddrLabelExpr: - return createCXString("AddrLabelExpr"); - case CXCursor_StmtExpr: - return createCXString("StmtExpr"); - case CXCursor_GenericSelectionExpr: - return createCXString("GenericSelectionExpr"); - case CXCursor_GNUNullExpr: - return createCXString("GNUNullExpr"); - case CXCursor_CXXStaticCastExpr: - return createCXString("CXXStaticCastExpr"); - case CXCursor_CXXDynamicCastExpr: - return createCXString("CXXDynamicCastExpr"); - case CXCursor_CXXReinterpretCastExpr: - return createCXString("CXXReinterpretCastExpr"); - case CXCursor_CXXConstCastExpr: - return createCXString("CXXConstCastExpr"); - case CXCursor_CXXFunctionalCastExpr: - return createCXString("CXXFunctionalCastExpr"); - case CXCursor_CXXTypeidExpr: - return createCXString("CXXTypeidExpr"); - case CXCursor_CXXBoolLiteralExpr: - return createCXString("CXXBoolLiteralExpr"); - case CXCursor_CXXNullPtrLiteralExpr: - return createCXString("CXXNullPtrLiteralExpr"); - case CXCursor_CXXThisExpr: - return createCXString("CXXThisExpr"); - case CXCursor_CXXThrowExpr: - return createCXString("CXXThrowExpr"); - case CXCursor_CXXNewExpr: - return createCXString("CXXNewExpr"); - case CXCursor_CXXDeleteExpr: - return createCXString("CXXDeleteExpr"); - case CXCursor_UnaryExpr: - return createCXString("UnaryExpr"); - case CXCursor_ObjCStringLiteral: - return createCXString("ObjCStringLiteral"); - case CXCursor_ObjCBoolLiteralExpr: - return createCXString("ObjCBoolLiteralExpr"); - case CXCursor_ObjCEncodeExpr: - return createCXString("ObjCEncodeExpr"); - case CXCursor_ObjCSelectorExpr: - return createCXString("ObjCSelectorExpr"); - case CXCursor_ObjCProtocolExpr: - return createCXString("ObjCProtocolExpr"); - case CXCursor_ObjCBridgedCastExpr: - return createCXString("ObjCBridgedCastExpr"); - case CXCursor_BlockExpr: - return createCXString("BlockExpr"); - case CXCursor_PackExpansionExpr: - return createCXString("PackExpansionExpr"); - case CXCursor_SizeOfPackExpr: - return createCXString("SizeOfPackExpr"); - case CXCursor_LambdaExpr: - return createCXString("LambdaExpr"); - case CXCursor_UnexposedExpr: - return createCXString("UnexposedExpr"); - case CXCursor_DeclRefExpr: - return createCXString("DeclRefExpr"); - case CXCursor_MemberRefExpr: - return createCXString("MemberRefExpr"); - case CXCursor_CallExpr: - return createCXString("CallExpr"); - case CXCursor_ObjCMessageExpr: - return createCXString("ObjCMessageExpr"); - case CXCursor_UnexposedStmt: - return createCXString("UnexposedStmt"); - case CXCursor_DeclStmt: - return createCXString("DeclStmt"); - case CXCursor_LabelStmt: - return createCXString("LabelStmt"); - case CXCursor_CompoundStmt: - return createCXString("CompoundStmt"); - case CXCursor_CaseStmt: - return createCXString("CaseStmt"); - case CXCursor_DefaultStmt: - return createCXString("DefaultStmt"); - case CXCursor_IfStmt: - return createCXString("IfStmt"); - case CXCursor_SwitchStmt: - return createCXString("SwitchStmt"); - case CXCursor_WhileStmt: - return createCXString("WhileStmt"); - case CXCursor_DoStmt: - return createCXString("DoStmt"); - case CXCursor_ForStmt: - return createCXString("ForStmt"); - case CXCursor_GotoStmt: - return createCXString("GotoStmt"); - case CXCursor_IndirectGotoStmt: - return createCXString("IndirectGotoStmt"); - case CXCursor_ContinueStmt: - return createCXString("ContinueStmt"); - case CXCursor_BreakStmt: - return createCXString("BreakStmt"); - case CXCursor_ReturnStmt: - return createCXString("ReturnStmt"); - case CXCursor_GCCAsmStmt: - return createCXString("GCCAsmStmt"); - case CXCursor_MSAsmStmt: - return createCXString("MSAsmStmt"); - case CXCursor_ObjCAtTryStmt: - return createCXString("ObjCAtTryStmt"); - case CXCursor_ObjCAtCatchStmt: - return createCXString("ObjCAtCatchStmt"); - case CXCursor_ObjCAtFinallyStmt: - return createCXString("ObjCAtFinallyStmt"); - case CXCursor_ObjCAtThrowStmt: - return createCXString("ObjCAtThrowStmt"); - case CXCursor_ObjCAtSynchronizedStmt: - return createCXString("ObjCAtSynchronizedStmt"); - case CXCursor_ObjCAutoreleasePoolStmt: - return createCXString("ObjCAutoreleasePoolStmt"); - case CXCursor_ObjCForCollectionStmt: - return createCXString("ObjCForCollectionStmt"); - case CXCursor_CXXCatchStmt: - return createCXString("CXXCatchStmt"); - case CXCursor_CXXTryStmt: - return createCXString("CXXTryStmt"); - case CXCursor_CXXForRangeStmt: - return createCXString("CXXForRangeStmt"); - case CXCursor_SEHTryStmt: - return createCXString("SEHTryStmt"); - case CXCursor_SEHExceptStmt: - return createCXString("SEHExceptStmt"); - case CXCursor_SEHFinallyStmt: - return createCXString("SEHFinallyStmt"); - case CXCursor_NullStmt: - return createCXString("NullStmt"); - case CXCursor_InvalidFile: - return createCXString("InvalidFile"); - case CXCursor_InvalidCode: - return createCXString("InvalidCode"); - case CXCursor_NoDeclFound: - return createCXString("NoDeclFound"); - case CXCursor_NotImplemented: - return createCXString("NotImplemented"); - case CXCursor_TranslationUnit: - return createCXString("TranslationUnit"); - case CXCursor_UnexposedAttr: - return createCXString("UnexposedAttr"); - case CXCursor_IBActionAttr: - return createCXString("attribute(ibaction)"); - case CXCursor_IBOutletAttr: - return createCXString("attribute(iboutlet)"); - case CXCursor_IBOutletCollectionAttr: - return createCXString("attribute(iboutletcollection)"); - case CXCursor_CXXFinalAttr: - return createCXString("attribute(final)"); - case CXCursor_CXXOverrideAttr: - return createCXString("attribute(override)"); - case CXCursor_AnnotateAttr: - return createCXString("attribute(annotate)"); - case CXCursor_AsmLabelAttr: - return createCXString("asm label"); - case CXCursor_PreprocessingDirective: - return createCXString("preprocessing directive"); - case CXCursor_MacroDefinition: - return createCXString("macro definition"); - case CXCursor_MacroExpansion: - return createCXString("macro expansion"); - case CXCursor_InclusionDirective: - return createCXString("inclusion directive"); - case CXCursor_Namespace: - return createCXString("Namespace"); - case CXCursor_LinkageSpec: - return createCXString("LinkageSpec"); - case CXCursor_CXXBaseSpecifier: - return createCXString("C++ base class specifier"); - case CXCursor_Constructor: - return createCXString("CXXConstructor"); - case CXCursor_Destructor: - return createCXString("CXXDestructor"); - case CXCursor_ConversionFunction: - return createCXString("CXXConversion"); - case CXCursor_TemplateTypeParameter: - return createCXString("TemplateTypeParameter"); - case CXCursor_NonTypeTemplateParameter: - return createCXString("NonTypeTemplateParameter"); - case CXCursor_TemplateTemplateParameter: - return createCXString("TemplateTemplateParameter"); - case CXCursor_FunctionTemplate: - return createCXString("FunctionTemplate"); - case CXCursor_ClassTemplate: - return createCXString("ClassTemplate"); - case CXCursor_ClassTemplatePartialSpecialization: - return createCXString("ClassTemplatePartialSpecialization"); - case CXCursor_NamespaceAlias: - return createCXString("NamespaceAlias"); - case CXCursor_UsingDirective: - return createCXString("UsingDirective"); - case CXCursor_UsingDeclaration: - return createCXString("UsingDeclaration"); - case CXCursor_TypeAliasDecl: - return createCXString("TypeAliasDecl"); - case CXCursor_ObjCSynthesizeDecl: - return createCXString("ObjCSynthesizeDecl"); - case CXCursor_ObjCDynamicDecl: - return createCXString("ObjCDynamicDecl"); - case CXCursor_CXXAccessSpecifier: - return createCXString("CXXAccessSpecifier"); - case CXCursor_ModuleImportDecl: - return createCXString("ModuleImport"); - } - - llvm_unreachable("Unhandled CXCursorKind"); -} - -struct GetCursorData { - SourceLocation TokenBeginLoc; - bool PointsAtMacroArgExpansion; - bool VisitedObjCPropertyImplDecl; - SourceLocation VisitedDeclaratorDeclStartLoc; - CXCursor &BestCursor; - - GetCursorData(SourceManager &SM, - SourceLocation tokenBegin, CXCursor &outputCursor) - : TokenBeginLoc(tokenBegin), BestCursor(outputCursor) { - PointsAtMacroArgExpansion = SM.isMacroArgExpansion(tokenBegin); - VisitedObjCPropertyImplDecl = false; - } -}; - -static enum CXChildVisitResult GetCursorVisitor(CXCursor cursor, - CXCursor parent, - CXClientData client_data) { - GetCursorData *Data = static_cast<GetCursorData *>(client_data); - CXCursor *BestCursor = &Data->BestCursor; - - // If we point inside a macro argument we should provide info of what the - // token is so use the actual cursor, don't replace it with a macro expansion - // cursor. - if (cursor.kind == CXCursor_MacroExpansion && Data->PointsAtMacroArgExpansion) - return CXChildVisit_Recurse; - - if (clang_isDeclaration(cursor.kind)) { - // Avoid having the implicit methods override the property decls. - if (ObjCMethodDecl *MD - = dyn_cast_or_null<ObjCMethodDecl>(getCursorDecl(cursor))) { - if (MD->isImplicit()) - return CXChildVisit_Break; - - } else if (ObjCInterfaceDecl *ID - = dyn_cast_or_null<ObjCInterfaceDecl>(getCursorDecl(cursor))) { - // Check that when we have multiple @class references in the same line, - // that later ones do not override the previous ones. - // If we have: - // @class Foo, Bar; - // source ranges for both start at '@', so 'Bar' will end up overriding - // 'Foo' even though the cursor location was at 'Foo'. - if (BestCursor->kind == CXCursor_ObjCInterfaceDecl || - BestCursor->kind == CXCursor_ObjCClassRef) - if (ObjCInterfaceDecl *PrevID - = dyn_cast_or_null<ObjCInterfaceDecl>(getCursorDecl(*BestCursor))){ - if (PrevID != ID && - !PrevID->isThisDeclarationADefinition() && - !ID->isThisDeclarationADefinition()) - return CXChildVisit_Break; - } - - } else if (DeclaratorDecl *DD - = dyn_cast_or_null<DeclaratorDecl>(getCursorDecl(cursor))) { - SourceLocation StartLoc = DD->getSourceRange().getBegin(); - // Check that when we have multiple declarators in the same line, - // that later ones do not override the previous ones. - // If we have: - // int Foo, Bar; - // source ranges for both start at 'int', so 'Bar' will end up overriding - // 'Foo' even though the cursor location was at 'Foo'. - if (Data->VisitedDeclaratorDeclStartLoc == StartLoc) - return CXChildVisit_Break; - Data->VisitedDeclaratorDeclStartLoc = StartLoc; - - } else if (ObjCPropertyImplDecl *PropImp - = dyn_cast_or_null<ObjCPropertyImplDecl>(getCursorDecl(cursor))) { - (void)PropImp; - // Check that when we have multiple @synthesize in the same line, - // that later ones do not override the previous ones. - // If we have: - // @synthesize Foo, Bar; - // source ranges for both start at '@', so 'Bar' will end up overriding - // 'Foo' even though the cursor location was at 'Foo'. - if (Data->VisitedObjCPropertyImplDecl) - return CXChildVisit_Break; - Data->VisitedObjCPropertyImplDecl = true; - } - } - - if (clang_isExpression(cursor.kind) && - clang_isDeclaration(BestCursor->kind)) { - if (Decl *D = getCursorDecl(*BestCursor)) { - // Avoid having the cursor of an expression replace the declaration cursor - // when the expression source range overlaps the declaration range. - // This can happen for C++ constructor expressions whose range generally - // include the variable declaration, e.g.: - // MyCXXClass foo; // Make sure pointing at 'foo' returns a VarDecl cursor. - if (D->getLocation().isValid() && Data->TokenBeginLoc.isValid() && - D->getLocation() == Data->TokenBeginLoc) - return CXChildVisit_Break; - } - } - - // If our current best cursor is the construction of a temporary object, - // don't replace that cursor with a type reference, because we want - // clang_getCursor() to point at the constructor. - if (clang_isExpression(BestCursor->kind) && - isa<CXXTemporaryObjectExpr>(getCursorExpr(*BestCursor)) && - cursor.kind == CXCursor_TypeRef) { - // Keep the cursor pointing at CXXTemporaryObjectExpr but also mark it - // as having the actual point on the type reference. - *BestCursor = getTypeRefedCallExprCursor(*BestCursor); - return CXChildVisit_Recurse; - } - - *BestCursor = cursor; - return CXChildVisit_Recurse; -} - -CXCursor clang_getCursor(CXTranslationUnit TU, CXSourceLocation Loc) { - if (!TU) - return clang_getNullCursor(); - - ASTUnit *CXXUnit = static_cast<ASTUnit *>(TU->TUData); - ASTUnit::ConcurrencyCheck Check(*CXXUnit); - - SourceLocation SLoc = cxloc::translateSourceLocation(Loc); - CXCursor Result = cxcursor::getCursor(TU, SLoc); - - bool Logging = getenv("LIBCLANG_LOGGING"); - if (Logging) { - CXFile SearchFile; - unsigned SearchLine, SearchColumn; - CXFile ResultFile; - unsigned ResultLine, ResultColumn; - CXString SearchFileName, ResultFileName, KindSpelling, USR; - const char *IsDef = clang_isCursorDefinition(Result)? " (Definition)" : ""; - CXSourceLocation ResultLoc = clang_getCursorLocation(Result); - - clang_getExpansionLocation(Loc, &SearchFile, &SearchLine, &SearchColumn, 0); - clang_getExpansionLocation(ResultLoc, &ResultFile, &ResultLine, - &ResultColumn, 0); - SearchFileName = clang_getFileName(SearchFile); - ResultFileName = clang_getFileName(ResultFile); - KindSpelling = clang_getCursorKindSpelling(Result.kind); - USR = clang_getCursorUSR(Result); - fprintf(stderr, "clang_getCursor(%s:%d:%d) = %s(%s:%d:%d):%s%s\n", - clang_getCString(SearchFileName), SearchLine, SearchColumn, - clang_getCString(KindSpelling), - clang_getCString(ResultFileName), ResultLine, ResultColumn, - clang_getCString(USR), IsDef); - clang_disposeString(SearchFileName); - clang_disposeString(ResultFileName); - clang_disposeString(KindSpelling); - clang_disposeString(USR); - - CXCursor Definition = clang_getCursorDefinition(Result); - if (!clang_equalCursors(Definition, clang_getNullCursor())) { - CXSourceLocation DefinitionLoc = clang_getCursorLocation(Definition); - CXString DefinitionKindSpelling - = clang_getCursorKindSpelling(Definition.kind); - CXFile DefinitionFile; - unsigned DefinitionLine, DefinitionColumn; - clang_getExpansionLocation(DefinitionLoc, &DefinitionFile, - &DefinitionLine, &DefinitionColumn, 0); - CXString DefinitionFileName = clang_getFileName(DefinitionFile); - fprintf(stderr, " -> %s(%s:%d:%d)\n", - clang_getCString(DefinitionKindSpelling), - clang_getCString(DefinitionFileName), - DefinitionLine, DefinitionColumn); - clang_disposeString(DefinitionFileName); - clang_disposeString(DefinitionKindSpelling); - } - } - - return Result; -} - -CXCursor clang_getNullCursor(void) { - return MakeCXCursorInvalid(CXCursor_InvalidFile); -} - -unsigned clang_equalCursors(CXCursor X, CXCursor Y) { - return X == Y; -} - -unsigned clang_hashCursor(CXCursor C) { - unsigned Index = 0; - if (clang_isExpression(C.kind) || clang_isStatement(C.kind)) - Index = 1; - - return llvm::DenseMapInfo<std::pair<unsigned, void*> >::getHashValue( - std::make_pair(C.kind, C.data[Index])); -} - -unsigned clang_isInvalid(enum CXCursorKind K) { - return K >= CXCursor_FirstInvalid && K <= CXCursor_LastInvalid; -} - -unsigned clang_isDeclaration(enum CXCursorKind K) { - return (K >= CXCursor_FirstDecl && K <= CXCursor_LastDecl) || - (K >= CXCursor_FirstExtraDecl && K <= CXCursor_LastExtraDecl); -} - -unsigned clang_isReference(enum CXCursorKind K) { - return K >= CXCursor_FirstRef && K <= CXCursor_LastRef; -} - -unsigned clang_isExpression(enum CXCursorKind K) { - return K >= CXCursor_FirstExpr && K <= CXCursor_LastExpr; -} - -unsigned clang_isStatement(enum CXCursorKind K) { - return K >= CXCursor_FirstStmt && K <= CXCursor_LastStmt; -} - -unsigned clang_isAttribute(enum CXCursorKind K) { - return K >= CXCursor_FirstAttr && K <= CXCursor_LastAttr; -} - -unsigned clang_isTranslationUnit(enum CXCursorKind K) { - return K == CXCursor_TranslationUnit; -} - -unsigned clang_isPreprocessing(enum CXCursorKind K) { - return K >= CXCursor_FirstPreprocessing && K <= CXCursor_LastPreprocessing; -} - -unsigned clang_isUnexposed(enum CXCursorKind K) { - switch (K) { - case CXCursor_UnexposedDecl: - case CXCursor_UnexposedExpr: - case CXCursor_UnexposedStmt: - case CXCursor_UnexposedAttr: - return true; - default: - return false; - } -} - -CXCursorKind clang_getCursorKind(CXCursor C) { - return C.kind; -} - -CXSourceLocation clang_getCursorLocation(CXCursor C) { - if (clang_isReference(C.kind)) { - switch (C.kind) { - case CXCursor_ObjCSuperClassRef: { - std::pair<ObjCInterfaceDecl *, SourceLocation> P - = getCursorObjCSuperClassRef(C); - return cxloc::translateSourceLocation(P.first->getASTContext(), P.second); - } - - case CXCursor_ObjCProtocolRef: { - std::pair<ObjCProtocolDecl *, SourceLocation> P - = getCursorObjCProtocolRef(C); - return cxloc::translateSourceLocation(P.first->getASTContext(), P.second); - } - - case CXCursor_ObjCClassRef: { - std::pair<ObjCInterfaceDecl *, SourceLocation> P - = getCursorObjCClassRef(C); - return cxloc::translateSourceLocation(P.first->getASTContext(), P.second); - } - - case CXCursor_TypeRef: { - std::pair<TypeDecl *, SourceLocation> P = getCursorTypeRef(C); - return cxloc::translateSourceLocation(P.first->getASTContext(), P.second); - } - - case CXCursor_TemplateRef: { - std::pair<TemplateDecl *, SourceLocation> P = getCursorTemplateRef(C); - return cxloc::translateSourceLocation(P.first->getASTContext(), P.second); - } - - case CXCursor_NamespaceRef: { - std::pair<NamedDecl *, SourceLocation> P = getCursorNamespaceRef(C); - return cxloc::translateSourceLocation(P.first->getASTContext(), P.second); - } - - case CXCursor_MemberRef: { - std::pair<FieldDecl *, SourceLocation> P = getCursorMemberRef(C); - return cxloc::translateSourceLocation(P.first->getASTContext(), P.second); - } - - case CXCursor_VariableRef: { - std::pair<VarDecl *, SourceLocation> P = getCursorVariableRef(C); - return cxloc::translateSourceLocation(P.first->getASTContext(), P.second); - } - - case CXCursor_CXXBaseSpecifier: { - CXXBaseSpecifier *BaseSpec = getCursorCXXBaseSpecifier(C); - if (!BaseSpec) - return clang_getNullLocation(); - - if (TypeSourceInfo *TSInfo = BaseSpec->getTypeSourceInfo()) - return cxloc::translateSourceLocation(getCursorContext(C), - TSInfo->getTypeLoc().getBeginLoc()); - - return cxloc::translateSourceLocation(getCursorContext(C), - BaseSpec->getLocStart()); - } - - case CXCursor_LabelRef: { - std::pair<LabelStmt *, SourceLocation> P = getCursorLabelRef(C); - return cxloc::translateSourceLocation(getCursorContext(C), P.second); - } - - case CXCursor_OverloadedDeclRef: - return cxloc::translateSourceLocation(getCursorContext(C), - getCursorOverloadedDeclRef(C).second); - - default: - // FIXME: Need a way to enumerate all non-reference cases. - llvm_unreachable("Missed a reference kind"); - } - } - - if (clang_isExpression(C.kind)) - return cxloc::translateSourceLocation(getCursorContext(C), - getLocationFromExpr(getCursorExpr(C))); - - if (clang_isStatement(C.kind)) - return cxloc::translateSourceLocation(getCursorContext(C), - getCursorStmt(C)->getLocStart()); - - if (C.kind == CXCursor_PreprocessingDirective) { - SourceLocation L = cxcursor::getCursorPreprocessingDirective(C).getBegin(); - return cxloc::translateSourceLocation(getCursorContext(C), L); - } - - if (C.kind == CXCursor_MacroExpansion) { - SourceLocation L - = cxcursor::getCursorMacroExpansion(C)->getSourceRange().getBegin(); - return cxloc::translateSourceLocation(getCursorContext(C), L); - } - - if (C.kind == CXCursor_MacroDefinition) { - SourceLocation L = cxcursor::getCursorMacroDefinition(C)->getLocation(); - return cxloc::translateSourceLocation(getCursorContext(C), L); - } - - if (C.kind == CXCursor_InclusionDirective) { - SourceLocation L - = cxcursor::getCursorInclusionDirective(C)->getSourceRange().getBegin(); - return cxloc::translateSourceLocation(getCursorContext(C), L); - } - - if (!clang_isDeclaration(C.kind)) - return clang_getNullLocation(); - - Decl *D = getCursorDecl(C); - if (!D) - return clang_getNullLocation(); - - SourceLocation Loc = D->getLocation(); - // FIXME: Multiple variables declared in a single declaration - // currently lack the information needed to correctly determine their - // ranges when accounting for the type-specifier. We use context - // stored in the CXCursor to determine if the VarDecl is in a DeclGroup, - // and if so, whether it is the first decl. - if (VarDecl *VD = dyn_cast<VarDecl>(D)) { - if (!cxcursor::isFirstInDeclGroup(C)) - Loc = VD->getLocation(); - } - - // For ObjC methods, give the start location of the method name. - if (ObjCMethodDecl *MD = dyn_cast<ObjCMethodDecl>(D)) - Loc = MD->getSelectorStartLoc(); - - return cxloc::translateSourceLocation(getCursorContext(C), Loc); -} - -} // end extern "C" - -CXCursor cxcursor::getCursor(CXTranslationUnit TU, SourceLocation SLoc) { - assert(TU); - - // Guard against an invalid SourceLocation, or we may assert in one - // of the following calls. - if (SLoc.isInvalid()) - return clang_getNullCursor(); - - ASTUnit *CXXUnit = static_cast<ASTUnit *>(TU->TUData); - - // Translate the given source location to make it point at the beginning of - // the token under the cursor. - SLoc = Lexer::GetBeginningOfToken(SLoc, CXXUnit->getSourceManager(), - CXXUnit->getASTContext().getLangOpts()); - - CXCursor Result = MakeCXCursorInvalid(CXCursor_NoDeclFound); - if (SLoc.isValid()) { - GetCursorData ResultData(CXXUnit->getSourceManager(), SLoc, Result); - CursorVisitor CursorVis(TU, GetCursorVisitor, &ResultData, - /*VisitPreprocessorLast=*/true, - /*VisitIncludedEntities=*/false, - SourceLocation(SLoc)); - CursorVis.visitFileRegion(); - } - - return Result; -} - -static SourceRange getRawCursorExtent(CXCursor C) { - if (clang_isReference(C.kind)) { - switch (C.kind) { - case CXCursor_ObjCSuperClassRef: - return getCursorObjCSuperClassRef(C).second; - - case CXCursor_ObjCProtocolRef: - return getCursorObjCProtocolRef(C).second; - - case CXCursor_ObjCClassRef: - return getCursorObjCClassRef(C).second; - - case CXCursor_TypeRef: - return getCursorTypeRef(C).second; - - case CXCursor_TemplateRef: - return getCursorTemplateRef(C).second; - - case CXCursor_NamespaceRef: - return getCursorNamespaceRef(C).second; - - case CXCursor_MemberRef: - return getCursorMemberRef(C).second; - - case CXCursor_CXXBaseSpecifier: - return getCursorCXXBaseSpecifier(C)->getSourceRange(); - - case CXCursor_LabelRef: - return getCursorLabelRef(C).second; - - case CXCursor_OverloadedDeclRef: - return getCursorOverloadedDeclRef(C).second; - - case CXCursor_VariableRef: - return getCursorVariableRef(C).second; - - default: - // FIXME: Need a way to enumerate all non-reference cases. - llvm_unreachable("Missed a reference kind"); - } - } - - if (clang_isExpression(C.kind)) - return getCursorExpr(C)->getSourceRange(); - - if (clang_isStatement(C.kind)) - return getCursorStmt(C)->getSourceRange(); - - if (clang_isAttribute(C.kind)) - return getCursorAttr(C)->getRange(); - - if (C.kind == CXCursor_PreprocessingDirective) - return cxcursor::getCursorPreprocessingDirective(C); - - if (C.kind == CXCursor_MacroExpansion) { - ASTUnit *TU = getCursorASTUnit(C); - SourceRange Range = cxcursor::getCursorMacroExpansion(C)->getSourceRange(); - return TU->mapRangeFromPreamble(Range); - } - - if (C.kind == CXCursor_MacroDefinition) { - ASTUnit *TU = getCursorASTUnit(C); - SourceRange Range = cxcursor::getCursorMacroDefinition(C)->getSourceRange(); - return TU->mapRangeFromPreamble(Range); - } - - if (C.kind == CXCursor_InclusionDirective) { - ASTUnit *TU = getCursorASTUnit(C); - SourceRange Range = cxcursor::getCursorInclusionDirective(C)->getSourceRange(); - return TU->mapRangeFromPreamble(Range); - } - - if (C.kind == CXCursor_TranslationUnit) { - ASTUnit *TU = getCursorASTUnit(C); - FileID MainID = TU->getSourceManager().getMainFileID(); - SourceLocation Start = TU->getSourceManager().getLocForStartOfFile(MainID); - SourceLocation End = TU->getSourceManager().getLocForEndOfFile(MainID); - return SourceRange(Start, End); - } - - if (clang_isDeclaration(C.kind)) { - Decl *D = cxcursor::getCursorDecl(C); - if (!D) - return SourceRange(); - - SourceRange R = D->getSourceRange(); - // FIXME: Multiple variables declared in a single declaration - // currently lack the information needed to correctly determine their - // ranges when accounting for the type-specifier. We use context - // stored in the CXCursor to determine if the VarDecl is in a DeclGroup, - // and if so, whether it is the first decl. - if (VarDecl *VD = dyn_cast<VarDecl>(D)) { - if (!cxcursor::isFirstInDeclGroup(C)) - R.setBegin(VD->getLocation()); - } - return R; - } - return SourceRange(); -} - -/// \brief Retrieves the "raw" cursor extent, which is then extended to include -/// the decl-specifier-seq for declarations. -static SourceRange getFullCursorExtent(CXCursor C, SourceManager &SrcMgr) { - if (clang_isDeclaration(C.kind)) { - Decl *D = cxcursor::getCursorDecl(C); - if (!D) - return SourceRange(); - - SourceRange R = D->getSourceRange(); - - // Adjust the start of the location for declarations preceded by - // declaration specifiers. - SourceLocation StartLoc; - if (const DeclaratorDecl *DD = dyn_cast<DeclaratorDecl>(D)) { - if (TypeSourceInfo *TI = DD->getTypeSourceInfo()) - StartLoc = TI->getTypeLoc().getLocStart(); - } else if (TypedefDecl *Typedef = dyn_cast<TypedefDecl>(D)) { - if (TypeSourceInfo *TI = Typedef->getTypeSourceInfo()) - StartLoc = TI->getTypeLoc().getLocStart(); - } - - if (StartLoc.isValid() && R.getBegin().isValid() && - SrcMgr.isBeforeInTranslationUnit(StartLoc, R.getBegin())) - R.setBegin(StartLoc); - - // FIXME: Multiple variables declared in a single declaration - // currently lack the information needed to correctly determine their - // ranges when accounting for the type-specifier. We use context - // stored in the CXCursor to determine if the VarDecl is in a DeclGroup, - // and if so, whether it is the first decl. - if (VarDecl *VD = dyn_cast<VarDecl>(D)) { - if (!cxcursor::isFirstInDeclGroup(C)) - R.setBegin(VD->getLocation()); - } - - return R; - } - - return getRawCursorExtent(C); -} - -extern "C" { - -CXSourceRange clang_getCursorExtent(CXCursor C) { - SourceRange R = getRawCursorExtent(C); - if (R.isInvalid()) - return clang_getNullRange(); - - return cxloc::translateSourceRange(getCursorContext(C), R); -} - -CXCursor clang_getCursorReferenced(CXCursor C) { - if (clang_isInvalid(C.kind)) - return clang_getNullCursor(); - - CXTranslationUnit tu = getCursorTU(C); - if (clang_isDeclaration(C.kind)) { - Decl *D = getCursorDecl(C); - if (!D) - return clang_getNullCursor(); - if (UsingDecl *Using = dyn_cast<UsingDecl>(D)) - return MakeCursorOverloadedDeclRef(Using, D->getLocation(), tu); - if (ObjCPropertyImplDecl *PropImpl =dyn_cast<ObjCPropertyImplDecl>(D)) - if (ObjCPropertyDecl *Property = PropImpl->getPropertyDecl()) - return MakeCXCursor(Property, tu); - - return C; - } - - if (clang_isExpression(C.kind)) { - Expr *E = getCursorExpr(C); - Decl *D = getDeclFromExpr(E); - if (D) { - CXCursor declCursor = MakeCXCursor(D, tu); - declCursor = getSelectorIdentifierCursor(getSelectorIdentifierIndex(C), - declCursor); - return declCursor; - } - - if (OverloadExpr *Ovl = dyn_cast_or_null<OverloadExpr>(E)) - return MakeCursorOverloadedDeclRef(Ovl, tu); - - return clang_getNullCursor(); - } - - if (clang_isStatement(C.kind)) { - Stmt *S = getCursorStmt(C); - if (GotoStmt *Goto = dyn_cast_or_null<GotoStmt>(S)) - if (LabelDecl *label = Goto->getLabel()) - if (LabelStmt *labelS = label->getStmt()) - return MakeCXCursor(labelS, getCursorDecl(C), tu); - - return clang_getNullCursor(); - } - - if (C.kind == CXCursor_MacroExpansion) { - if (MacroDefinition *Def = getCursorMacroExpansion(C)->getDefinition()) - return MakeMacroDefinitionCursor(Def, tu); - } - - if (!clang_isReference(C.kind)) - return clang_getNullCursor(); - - switch (C.kind) { - case CXCursor_ObjCSuperClassRef: - return MakeCXCursor(getCursorObjCSuperClassRef(C).first, tu); - - case CXCursor_ObjCProtocolRef: { - ObjCProtocolDecl *Prot = getCursorObjCProtocolRef(C).first; - if (ObjCProtocolDecl *Def = Prot->getDefinition()) - return MakeCXCursor(Def, tu); - - return MakeCXCursor(Prot, tu); - } - - case CXCursor_ObjCClassRef: { - ObjCInterfaceDecl *Class = getCursorObjCClassRef(C).first; - if (ObjCInterfaceDecl *Def = Class->getDefinition()) - return MakeCXCursor(Def, tu); - - return MakeCXCursor(Class, tu); - } - - case CXCursor_TypeRef: - return MakeCXCursor(getCursorTypeRef(C).first, tu ); - - case CXCursor_TemplateRef: - return MakeCXCursor(getCursorTemplateRef(C).first, tu ); - - case CXCursor_NamespaceRef: - return MakeCXCursor(getCursorNamespaceRef(C).first, tu ); - - case CXCursor_MemberRef: - return MakeCXCursor(getCursorMemberRef(C).first, tu ); - - case CXCursor_CXXBaseSpecifier: { - CXXBaseSpecifier *B = cxcursor::getCursorCXXBaseSpecifier(C); - return clang_getTypeDeclaration(cxtype::MakeCXType(B->getType(), - tu )); - } - - case CXCursor_LabelRef: - // FIXME: We end up faking the "parent" declaration here because we - // don't want to make CXCursor larger. - return MakeCXCursor(getCursorLabelRef(C).first, - static_cast<ASTUnit*>(tu->TUData)->getASTContext() - .getTranslationUnitDecl(), - tu); - - case CXCursor_OverloadedDeclRef: - return C; - - case CXCursor_VariableRef: - return MakeCXCursor(getCursorVariableRef(C).first, tu); - - default: - // We would prefer to enumerate all non-reference cursor kinds here. - llvm_unreachable("Unhandled reference cursor kind"); - } -} - -CXCursor clang_getCursorDefinition(CXCursor C) { - if (clang_isInvalid(C.kind)) - return clang_getNullCursor(); - - CXTranslationUnit TU = getCursorTU(C); - - bool WasReference = false; - if (clang_isReference(C.kind) || clang_isExpression(C.kind)) { - C = clang_getCursorReferenced(C); - WasReference = true; - } - - if (C.kind == CXCursor_MacroExpansion) - return clang_getCursorReferenced(C); - - if (!clang_isDeclaration(C.kind)) - return clang_getNullCursor(); - - Decl *D = getCursorDecl(C); - if (!D) - return clang_getNullCursor(); - - switch (D->getKind()) { - // Declaration kinds that don't really separate the notions of - // declaration and definition. - case Decl::Namespace: - case Decl::Typedef: - case Decl::TypeAlias: - case Decl::TypeAliasTemplate: - case Decl::TemplateTypeParm: - case Decl::EnumConstant: - case Decl::Field: - case Decl::IndirectField: - case Decl::ObjCIvar: - case Decl::ObjCAtDefsField: - case Decl::ImplicitParam: - case Decl::ParmVar: - case Decl::NonTypeTemplateParm: - case Decl::TemplateTemplateParm: - case Decl::ObjCCategoryImpl: - case Decl::ObjCImplementation: - case Decl::AccessSpec: - case Decl::LinkageSpec: - case Decl::ObjCPropertyImpl: - case Decl::FileScopeAsm: - case Decl::StaticAssert: - case Decl::Block: - case Decl::Label: // FIXME: Is this right?? - case Decl::ClassScopeFunctionSpecialization: - case Decl::Import: - return C; - - // Declaration kinds that don't make any sense here, but are - // nonetheless harmless. - case Decl::TranslationUnit: - break; - - // Declaration kinds for which the definition is not resolvable. - case Decl::UnresolvedUsingTypename: - case Decl::UnresolvedUsingValue: - break; - - case Decl::UsingDirective: - return MakeCXCursor(cast<UsingDirectiveDecl>(D)->getNominatedNamespace(), - TU); - - case Decl::NamespaceAlias: - return MakeCXCursor(cast<NamespaceAliasDecl>(D)->getNamespace(), TU); - - case Decl::Enum: - case Decl::Record: - case Decl::CXXRecord: - case Decl::ClassTemplateSpecialization: - case Decl::ClassTemplatePartialSpecialization: - if (TagDecl *Def = cast<TagDecl>(D)->getDefinition()) - return MakeCXCursor(Def, TU); - return clang_getNullCursor(); - - case Decl::Function: - case Decl::CXXMethod: - case Decl::CXXConstructor: - case Decl::CXXDestructor: - case Decl::CXXConversion: { - const FunctionDecl *Def = 0; - if (cast<FunctionDecl>(D)->getBody(Def)) - return MakeCXCursor(const_cast<FunctionDecl *>(Def), TU); - return clang_getNullCursor(); - } - - case Decl::Var: { - // Ask the variable if it has a definition. - if (VarDecl *Def = cast<VarDecl>(D)->getDefinition()) - return MakeCXCursor(Def, TU); - return clang_getNullCursor(); - } - - case Decl::FunctionTemplate: { - const FunctionDecl *Def = 0; - if (cast<FunctionTemplateDecl>(D)->getTemplatedDecl()->getBody(Def)) - return MakeCXCursor(Def->getDescribedFunctionTemplate(), TU); - return clang_getNullCursor(); - } - - case Decl::ClassTemplate: { - if (RecordDecl *Def = cast<ClassTemplateDecl>(D)->getTemplatedDecl() - ->getDefinition()) - return MakeCXCursor(cast<CXXRecordDecl>(Def)->getDescribedClassTemplate(), - TU); - return clang_getNullCursor(); - } - - case Decl::Using: - return MakeCursorOverloadedDeclRef(cast<UsingDecl>(D), - D->getLocation(), TU); - - case Decl::UsingShadow: - return clang_getCursorDefinition( - MakeCXCursor(cast<UsingShadowDecl>(D)->getTargetDecl(), - TU)); - - case Decl::ObjCMethod: { - ObjCMethodDecl *Method = cast<ObjCMethodDecl>(D); - if (Method->isThisDeclarationADefinition()) - return C; - - // Dig out the method definition in the associated - // @implementation, if we have it. - // FIXME: The ASTs should make finding the definition easier. - if (ObjCInterfaceDecl *Class - = dyn_cast<ObjCInterfaceDecl>(Method->getDeclContext())) - if (ObjCImplementationDecl *ClassImpl = Class->getImplementation()) - if (ObjCMethodDecl *Def = ClassImpl->getMethod(Method->getSelector(), - Method->isInstanceMethod())) - if (Def->isThisDeclarationADefinition()) - return MakeCXCursor(Def, TU); - - return clang_getNullCursor(); - } - - case Decl::ObjCCategory: - if (ObjCCategoryImplDecl *Impl - = cast<ObjCCategoryDecl>(D)->getImplementation()) - return MakeCXCursor(Impl, TU); - return clang_getNullCursor(); - - case Decl::ObjCProtocol: - if (ObjCProtocolDecl *Def = cast<ObjCProtocolDecl>(D)->getDefinition()) - return MakeCXCursor(Def, TU); - return clang_getNullCursor(); - - case Decl::ObjCInterface: { - // There are two notions of a "definition" for an Objective-C - // class: the interface and its implementation. When we resolved a - // reference to an Objective-C class, produce the @interface as - // the definition; when we were provided with the interface, - // produce the @implementation as the definition. - ObjCInterfaceDecl *IFace = cast<ObjCInterfaceDecl>(D); - if (WasReference) { - if (ObjCInterfaceDecl *Def = IFace->getDefinition()) - return MakeCXCursor(Def, TU); - } else if (ObjCImplementationDecl *Impl = IFace->getImplementation()) - return MakeCXCursor(Impl, TU); - return clang_getNullCursor(); - } - - case Decl::ObjCProperty: - // FIXME: We don't really know where to find the - // ObjCPropertyImplDecls that implement this property. - return clang_getNullCursor(); - - case Decl::ObjCCompatibleAlias: - if (ObjCInterfaceDecl *Class - = cast<ObjCCompatibleAliasDecl>(D)->getClassInterface()) - if (ObjCInterfaceDecl *Def = Class->getDefinition()) - return MakeCXCursor(Def, TU); - - return clang_getNullCursor(); - - case Decl::Friend: - if (NamedDecl *Friend = cast<FriendDecl>(D)->getFriendDecl()) - return clang_getCursorDefinition(MakeCXCursor(Friend, TU)); - return clang_getNullCursor(); - - case Decl::FriendTemplate: - if (NamedDecl *Friend = cast<FriendTemplateDecl>(D)->getFriendDecl()) - return clang_getCursorDefinition(MakeCXCursor(Friend, TU)); - return clang_getNullCursor(); - } - - return clang_getNullCursor(); -} - -unsigned clang_isCursorDefinition(CXCursor C) { - if (!clang_isDeclaration(C.kind)) - return 0; - - return clang_getCursorDefinition(C) == C; -} - -CXCursor clang_getCanonicalCursor(CXCursor C) { - if (!clang_isDeclaration(C.kind)) - return C; - - if (Decl *D = getCursorDecl(C)) { - if (ObjCCategoryImplDecl *CatImplD = dyn_cast<ObjCCategoryImplDecl>(D)) - if (ObjCCategoryDecl *CatD = CatImplD->getCategoryDecl()) - return MakeCXCursor(CatD, getCursorTU(C)); - - if (ObjCImplDecl *ImplD = dyn_cast<ObjCImplDecl>(D)) - if (ObjCInterfaceDecl *IFD = ImplD->getClassInterface()) - return MakeCXCursor(IFD, getCursorTU(C)); - - return MakeCXCursor(D->getCanonicalDecl(), getCursorTU(C)); - } - - return C; -} - -int clang_Cursor_getObjCSelectorIndex(CXCursor cursor) { - return cxcursor::getSelectorIdentifierIndexAndLoc(cursor).first; -} - -unsigned clang_getNumOverloadedDecls(CXCursor C) { - if (C.kind != CXCursor_OverloadedDeclRef) - return 0; - - OverloadedDeclRefStorage Storage = getCursorOverloadedDeclRef(C).first; - if (OverloadExpr *E = Storage.dyn_cast<OverloadExpr *>()) - return E->getNumDecls(); - - if (OverloadedTemplateStorage *S - = Storage.dyn_cast<OverloadedTemplateStorage*>()) - return S->size(); - - Decl *D = Storage.get<Decl*>(); - if (UsingDecl *Using = dyn_cast<UsingDecl>(D)) - return Using->shadow_size(); - - return 0; -} - -CXCursor clang_getOverloadedDecl(CXCursor cursor, unsigned index) { - if (cursor.kind != CXCursor_OverloadedDeclRef) - return clang_getNullCursor(); - - if (index >= clang_getNumOverloadedDecls(cursor)) - return clang_getNullCursor(); - - CXTranslationUnit TU = getCursorTU(cursor); - OverloadedDeclRefStorage Storage = getCursorOverloadedDeclRef(cursor).first; - if (OverloadExpr *E = Storage.dyn_cast<OverloadExpr *>()) - return MakeCXCursor(E->decls_begin()[index], TU); - - if (OverloadedTemplateStorage *S - = Storage.dyn_cast<OverloadedTemplateStorage*>()) - return MakeCXCursor(S->begin()[index], TU); - - Decl *D = Storage.get<Decl*>(); - if (UsingDecl *Using = dyn_cast<UsingDecl>(D)) { - // FIXME: This is, unfortunately, linear time. - UsingDecl::shadow_iterator Pos = Using->shadow_begin(); - std::advance(Pos, index); - return MakeCXCursor(cast<UsingShadowDecl>(*Pos)->getTargetDecl(), TU); - } - - return clang_getNullCursor(); -} - -void clang_getDefinitionSpellingAndExtent(CXCursor C, - const char **startBuf, - const char **endBuf, - unsigned *startLine, - unsigned *startColumn, - unsigned *endLine, - unsigned *endColumn) { - assert(getCursorDecl(C) && "CXCursor has null decl"); - NamedDecl *ND = static_cast<NamedDecl *>(getCursorDecl(C)); - FunctionDecl *FD = dyn_cast<FunctionDecl>(ND); - CompoundStmt *Body = dyn_cast<CompoundStmt>(FD->getBody()); - - SourceManager &SM = FD->getASTContext().getSourceManager(); - *startBuf = SM.getCharacterData(Body->getLBracLoc()); - *endBuf = SM.getCharacterData(Body->getRBracLoc()); - *startLine = SM.getSpellingLineNumber(Body->getLBracLoc()); - *startColumn = SM.getSpellingColumnNumber(Body->getLBracLoc()); - *endLine = SM.getSpellingLineNumber(Body->getRBracLoc()); - *endColumn = SM.getSpellingColumnNumber(Body->getRBracLoc()); -} - - -CXSourceRange clang_getCursorReferenceNameRange(CXCursor C, unsigned NameFlags, - unsigned PieceIndex) { - RefNamePieces Pieces; - - switch (C.kind) { - case CXCursor_MemberRefExpr: - if (MemberExpr *E = dyn_cast<MemberExpr>(getCursorExpr(C))) - Pieces = buildPieces(NameFlags, true, E->getMemberNameInfo(), - E->getQualifierLoc().getSourceRange()); - break; - - case CXCursor_DeclRefExpr: - if (DeclRefExpr *E = dyn_cast<DeclRefExpr>(getCursorExpr(C))) - Pieces = buildPieces(NameFlags, false, E->getNameInfo(), - E->getQualifierLoc().getSourceRange(), - E->getOptionalExplicitTemplateArgs()); - break; - - case CXCursor_CallExpr: - if (CXXOperatorCallExpr *OCE = - dyn_cast<CXXOperatorCallExpr>(getCursorExpr(C))) { - Expr *Callee = OCE->getCallee(); - if (ImplicitCastExpr *ICE = dyn_cast<ImplicitCastExpr>(Callee)) - Callee = ICE->getSubExpr(); - - if (DeclRefExpr *DRE = dyn_cast<DeclRefExpr>(Callee)) - Pieces = buildPieces(NameFlags, false, DRE->getNameInfo(), - DRE->getQualifierLoc().getSourceRange()); - } - break; - - default: - break; - } - - if (Pieces.empty()) { - if (PieceIndex == 0) - return clang_getCursorExtent(C); - } else if (PieceIndex < Pieces.size()) { - SourceRange R = Pieces[PieceIndex]; - if (R.isValid()) - return cxloc::translateSourceRange(getCursorContext(C), R); - } - - return clang_getNullRange(); -} - -void clang_enableStackTraces(void) { - llvm::sys::PrintStackTraceOnErrorSignal(); -} - -void clang_executeOnThread(void (*fn)(void*), void *user_data, - unsigned stack_size) { - llvm::llvm_execute_on_thread(fn, user_data, stack_size); -} - -} // end: extern "C" - -//===----------------------------------------------------------------------===// -// Token-based Operations. -//===----------------------------------------------------------------------===// - -/* CXToken layout: - * int_data[0]: a CXTokenKind - * int_data[1]: starting token location - * int_data[2]: token length - * int_data[3]: reserved - * ptr_data: for identifiers and keywords, an IdentifierInfo*. - * otherwise unused. - */ -extern "C" { - -CXTokenKind clang_getTokenKind(CXToken CXTok) { - return static_cast<CXTokenKind>(CXTok.int_data[0]); -} - -CXString clang_getTokenSpelling(CXTranslationUnit TU, CXToken CXTok) { - switch (clang_getTokenKind(CXTok)) { - case CXToken_Identifier: - case CXToken_Keyword: - // We know we have an IdentifierInfo*, so use that. - return createCXString(static_cast<IdentifierInfo *>(CXTok.ptr_data) - ->getNameStart()); - - case CXToken_Literal: { - // We have stashed the starting pointer in the ptr_data field. Use it. - const char *Text = static_cast<const char *>(CXTok.ptr_data); - return createCXString(StringRef(Text, CXTok.int_data[2])); - } - - case CXToken_Punctuation: - case CXToken_Comment: - break; - } - - // We have to find the starting buffer pointer the hard way, by - // deconstructing the source location. - ASTUnit *CXXUnit = static_cast<ASTUnit *>(TU->TUData); - if (!CXXUnit) - return createCXString(""); - - SourceLocation Loc = SourceLocation::getFromRawEncoding(CXTok.int_data[1]); - std::pair<FileID, unsigned> LocInfo - = CXXUnit->getSourceManager().getDecomposedSpellingLoc(Loc); - bool Invalid = false; - StringRef Buffer - = CXXUnit->getSourceManager().getBufferData(LocInfo.first, &Invalid); - if (Invalid) - return createCXString(""); - - return createCXString(Buffer.substr(LocInfo.second, CXTok.int_data[2])); -} - -CXSourceLocation clang_getTokenLocation(CXTranslationUnit TU, CXToken CXTok) { - ASTUnit *CXXUnit = static_cast<ASTUnit *>(TU->TUData); - if (!CXXUnit) - return clang_getNullLocation(); - - return cxloc::translateSourceLocation(CXXUnit->getASTContext(), - SourceLocation::getFromRawEncoding(CXTok.int_data[1])); -} - -CXSourceRange clang_getTokenExtent(CXTranslationUnit TU, CXToken CXTok) { - ASTUnit *CXXUnit = static_cast<ASTUnit *>(TU->TUData); - if (!CXXUnit) - return clang_getNullRange(); - - return cxloc::translateSourceRange(CXXUnit->getASTContext(), - SourceLocation::getFromRawEncoding(CXTok.int_data[1])); -} - -static void getTokens(ASTUnit *CXXUnit, SourceRange Range, - SmallVectorImpl<CXToken> &CXTokens) { - SourceManager &SourceMgr = CXXUnit->getSourceManager(); - std::pair<FileID, unsigned> BeginLocInfo - = SourceMgr.getDecomposedLoc(Range.getBegin()); - std::pair<FileID, unsigned> EndLocInfo - = SourceMgr.getDecomposedLoc(Range.getEnd()); - - // Cannot tokenize across files. - if (BeginLocInfo.first != EndLocInfo.first) - return; - - // Create a lexer - bool Invalid = false; - StringRef Buffer - = SourceMgr.getBufferData(BeginLocInfo.first, &Invalid); - if (Invalid) - return; - - Lexer Lex(SourceMgr.getLocForStartOfFile(BeginLocInfo.first), - CXXUnit->getASTContext().getLangOpts(), - Buffer.begin(), Buffer.data() + BeginLocInfo.second, Buffer.end()); - Lex.SetCommentRetentionState(true); - - // Lex tokens until we hit the end of the range. - const char *EffectiveBufferEnd = Buffer.data() + EndLocInfo.second; - Token Tok; - bool previousWasAt = false; - do { - // Lex the next token - Lex.LexFromRawLexer(Tok); - if (Tok.is(tok::eof)) - break; - - // Initialize the CXToken. - CXToken CXTok; - - // - Common fields - CXTok.int_data[1] = Tok.getLocation().getRawEncoding(); - CXTok.int_data[2] = Tok.getLength(); - CXTok.int_data[3] = 0; - - // - Kind-specific fields - if (Tok.isLiteral()) { - CXTok.int_data[0] = CXToken_Literal; - CXTok.ptr_data = (void *)Tok.getLiteralData(); - } else if (Tok.is(tok::raw_identifier)) { - // Lookup the identifier to determine whether we have a keyword. - IdentifierInfo *II - = CXXUnit->getPreprocessor().LookUpIdentifierInfo(Tok); - - if ((II->getObjCKeywordID() != tok::objc_not_keyword) && previousWasAt) { - CXTok.int_data[0] = CXToken_Keyword; - } - else { - CXTok.int_data[0] = Tok.is(tok::identifier) - ? CXToken_Identifier - : CXToken_Keyword; - } - CXTok.ptr_data = II; - } else if (Tok.is(tok::comment)) { - CXTok.int_data[0] = CXToken_Comment; - CXTok.ptr_data = 0; - } else { - CXTok.int_data[0] = CXToken_Punctuation; - CXTok.ptr_data = 0; - } - CXTokens.push_back(CXTok); - previousWasAt = Tok.is(tok::at); - } while (Lex.getBufferLocation() <= EffectiveBufferEnd); -} - -void clang_tokenize(CXTranslationUnit TU, CXSourceRange Range, - CXToken **Tokens, unsigned *NumTokens) { - if (Tokens) - *Tokens = 0; - if (NumTokens) - *NumTokens = 0; - - ASTUnit *CXXUnit = static_cast<ASTUnit *>(TU->TUData); - if (!CXXUnit || !Tokens || !NumTokens) - return; - - ASTUnit::ConcurrencyCheck Check(*CXXUnit); - - SourceRange R = cxloc::translateCXSourceRange(Range); - if (R.isInvalid()) - return; - - SmallVector<CXToken, 32> CXTokens; - getTokens(CXXUnit, R, CXTokens); - - if (CXTokens.empty()) - return; - - *Tokens = (CXToken *)malloc(sizeof(CXToken) * CXTokens.size()); - memmove(*Tokens, CXTokens.data(), sizeof(CXToken) * CXTokens.size()); - *NumTokens = CXTokens.size(); -} - -void clang_disposeTokens(CXTranslationUnit TU, - CXToken *Tokens, unsigned NumTokens) { - free(Tokens); -} - -} // end: extern "C" - -//===----------------------------------------------------------------------===// -// Token annotation APIs. -//===----------------------------------------------------------------------===// - -typedef llvm::DenseMap<unsigned, CXCursor> AnnotateTokensData; -static enum CXChildVisitResult AnnotateTokensVisitor(CXCursor cursor, - CXCursor parent, - CXClientData client_data); -static bool AnnotateTokensPostChildrenVisitor(CXCursor cursor, - CXClientData client_data); - -namespace { -class AnnotateTokensWorker { - AnnotateTokensData &Annotated; - CXToken *Tokens; - CXCursor *Cursors; - unsigned NumTokens; - unsigned TokIdx; - unsigned PreprocessingTokIdx; - CursorVisitor AnnotateVis; - SourceManager &SrcMgr; - bool HasContextSensitiveKeywords; - - struct PostChildrenInfo { - CXCursor Cursor; - SourceRange CursorRange; - unsigned BeforeChildrenTokenIdx; - }; - llvm::SmallVector<PostChildrenInfo, 8> PostChildrenInfos; - - bool MoreTokens() const { return TokIdx < NumTokens; } - unsigned NextToken() const { return TokIdx; } - void AdvanceToken() { ++TokIdx; } - SourceLocation GetTokenLoc(unsigned tokI) { - return SourceLocation::getFromRawEncoding(Tokens[tokI].int_data[1]); - } - bool isFunctionMacroToken(unsigned tokI) const { - return Tokens[tokI].int_data[3] != 0; - } - SourceLocation getFunctionMacroTokenLoc(unsigned tokI) const { - return SourceLocation::getFromRawEncoding(Tokens[tokI].int_data[3]); - } - - void annotateAndAdvanceTokens(CXCursor, RangeComparisonResult, SourceRange); - void annotateAndAdvanceFunctionMacroTokens(CXCursor, RangeComparisonResult, - SourceRange); - -public: - AnnotateTokensWorker(AnnotateTokensData &annotated, - CXToken *tokens, CXCursor *cursors, unsigned numTokens, - CXTranslationUnit tu, SourceRange RegionOfInterest) - : Annotated(annotated), Tokens(tokens), Cursors(cursors), - NumTokens(numTokens), TokIdx(0), PreprocessingTokIdx(0), - AnnotateVis(tu, - AnnotateTokensVisitor, this, - /*VisitPreprocessorLast=*/true, - /*VisitIncludedEntities=*/false, - RegionOfInterest, - /*VisitDeclsOnly=*/false, - AnnotateTokensPostChildrenVisitor), - SrcMgr(static_cast<ASTUnit*>(tu->TUData)->getSourceManager()), - HasContextSensitiveKeywords(false) { } - - void VisitChildren(CXCursor C) { AnnotateVis.VisitChildren(C); } - enum CXChildVisitResult Visit(CXCursor cursor, CXCursor parent); - bool postVisitChildren(CXCursor cursor); - void AnnotateTokens(); - - /// \brief Determine whether the annotator saw any cursors that have - /// context-sensitive keywords. - bool hasContextSensitiveKeywords() const { - return HasContextSensitiveKeywords; - } - - ~AnnotateTokensWorker() { - assert(PostChildrenInfos.empty()); - } -}; -} - -void AnnotateTokensWorker::AnnotateTokens() { - // Walk the AST within the region of interest, annotating tokens - // along the way. - AnnotateVis.visitFileRegion(); - - for (unsigned I = 0 ; I < TokIdx ; ++I) { - AnnotateTokensData::iterator Pos = Annotated.find(Tokens[I].int_data[1]); - if (Pos != Annotated.end() && !clang_isPreprocessing(Cursors[I].kind)) - Cursors[I] = Pos->second; - } - - // Finish up annotating any tokens left. - if (!MoreTokens()) - return; - - const CXCursor &C = clang_getNullCursor(); - for (unsigned I = TokIdx ; I < NumTokens ; ++I) { - if (I < PreprocessingTokIdx && clang_isPreprocessing(Cursors[I].kind)) - continue; - - AnnotateTokensData::iterator Pos = Annotated.find(Tokens[I].int_data[1]); - Cursors[I] = (Pos == Annotated.end()) ? C : Pos->second; - } -} - -/// \brief It annotates and advances tokens with a cursor until the comparison -//// between the cursor location and the source range is the same as -/// \arg compResult. -/// -/// Pass RangeBefore to annotate tokens with a cursor until a range is reached. -/// Pass RangeOverlap to annotate tokens inside a range. -void AnnotateTokensWorker::annotateAndAdvanceTokens(CXCursor updateC, - RangeComparisonResult compResult, - SourceRange range) { - while (MoreTokens()) { - const unsigned I = NextToken(); - if (isFunctionMacroToken(I)) - return annotateAndAdvanceFunctionMacroTokens(updateC, compResult, range); - - SourceLocation TokLoc = GetTokenLoc(I); - if (LocationCompare(SrcMgr, TokLoc, range) == compResult) { - Cursors[I] = updateC; - AdvanceToken(); - continue; - } - break; - } -} - -/// \brief Special annotation handling for macro argument tokens. -void AnnotateTokensWorker::annotateAndAdvanceFunctionMacroTokens( - CXCursor updateC, - RangeComparisonResult compResult, - SourceRange range) { - assert(MoreTokens()); - assert(isFunctionMacroToken(NextToken()) && - "Should be called only for macro arg tokens"); - - // This works differently than annotateAndAdvanceTokens; because expanded - // macro arguments can have arbitrary translation-unit source order, we do not - // advance the token index one by one until a token fails the range test. - // We only advance once past all of the macro arg tokens if all of them - // pass the range test. If one of them fails we keep the token index pointing - // at the start of the macro arg tokens so that the failing token will be - // annotated by a subsequent annotation try. - - bool atLeastOneCompFail = false; - - unsigned I = NextToken(); - for (; I < NumTokens && isFunctionMacroToken(I); ++I) { - SourceLocation TokLoc = getFunctionMacroTokenLoc(I); - if (TokLoc.isFileID()) - continue; // not macro arg token, it's parens or comma. - if (LocationCompare(SrcMgr, TokLoc, range) == compResult) { - if (clang_isInvalid(clang_getCursorKind(Cursors[I]))) - Cursors[I] = updateC; - } else - atLeastOneCompFail = true; - } - - if (!atLeastOneCompFail) - TokIdx = I; // All of the tokens were handled, advance beyond all of them. -} - -enum CXChildVisitResult -AnnotateTokensWorker::Visit(CXCursor cursor, CXCursor parent) { - CXSourceLocation Loc = clang_getCursorLocation(cursor); - SourceRange cursorRange = getRawCursorExtent(cursor); - if (cursorRange.isInvalid()) - return CXChildVisit_Recurse; - - if (!HasContextSensitiveKeywords) { - // Objective-C properties can have context-sensitive keywords. - if (cursor.kind == CXCursor_ObjCPropertyDecl) { - if (ObjCPropertyDecl *Property - = dyn_cast_or_null<ObjCPropertyDecl>(getCursorDecl(cursor))) - HasContextSensitiveKeywords = Property->getPropertyAttributesAsWritten() != 0; - } - // Objective-C methods can have context-sensitive keywords. - else if (cursor.kind == CXCursor_ObjCInstanceMethodDecl || - cursor.kind == CXCursor_ObjCClassMethodDecl) { - if (ObjCMethodDecl *Method - = dyn_cast_or_null<ObjCMethodDecl>(getCursorDecl(cursor))) { - if (Method->getObjCDeclQualifier()) - HasContextSensitiveKeywords = true; - else { - for (ObjCMethodDecl::param_iterator P = Method->param_begin(), - PEnd = Method->param_end(); - P != PEnd; ++P) { - if ((*P)->getObjCDeclQualifier()) { - HasContextSensitiveKeywords = true; - break; - } - } - } - } - } - // C++ methods can have context-sensitive keywords. - else if (cursor.kind == CXCursor_CXXMethod) { - if (CXXMethodDecl *Method - = dyn_cast_or_null<CXXMethodDecl>(getCursorDecl(cursor))) { - if (Method->hasAttr<FinalAttr>() || Method->hasAttr<OverrideAttr>()) - HasContextSensitiveKeywords = true; - } - } - // C++ classes can have context-sensitive keywords. - else if (cursor.kind == CXCursor_StructDecl || - cursor.kind == CXCursor_ClassDecl || - cursor.kind == CXCursor_ClassTemplate || - cursor.kind == CXCursor_ClassTemplatePartialSpecialization) { - if (Decl *D = getCursorDecl(cursor)) - if (D->hasAttr<FinalAttr>()) - HasContextSensitiveKeywords = true; - } - } - - if (clang_isPreprocessing(cursor.kind)) { - // Items in the preprocessing record are kept separate from items in - // declarations, so we keep a separate token index. - unsigned SavedTokIdx = TokIdx; - TokIdx = PreprocessingTokIdx; - - // Skip tokens up until we catch up to the beginning of the preprocessing - // entry. - while (MoreTokens()) { - const unsigned I = NextToken(); - SourceLocation TokLoc = GetTokenLoc(I); - switch (LocationCompare(SrcMgr, TokLoc, cursorRange)) { - case RangeBefore: - AdvanceToken(); - continue; - case RangeAfter: - case RangeOverlap: - break; - } - break; - } - - // Look at all of the tokens within this range. - while (MoreTokens()) { - const unsigned I = NextToken(); - SourceLocation TokLoc = GetTokenLoc(I); - switch (LocationCompare(SrcMgr, TokLoc, cursorRange)) { - case RangeBefore: - llvm_unreachable("Infeasible"); - case RangeAfter: - break; - case RangeOverlap: - Cursors[I] = cursor; - AdvanceToken(); - // For macro expansions, just note where the beginning of the macro - // expansion occurs. - if (cursor.kind == CXCursor_MacroExpansion) - break; - continue; - } - break; - } - - // Save the preprocessing token index; restore the non-preprocessing - // token index. - PreprocessingTokIdx = TokIdx; - TokIdx = SavedTokIdx; - return CXChildVisit_Recurse; - } - - if (cursorRange.isInvalid()) - return CXChildVisit_Continue; - - SourceLocation L = SourceLocation::getFromRawEncoding(Loc.int_data); - - // Adjust the annotated range based specific declarations. - const enum CXCursorKind cursorK = clang_getCursorKind(cursor); - if (clang_isDeclaration(cursorK)) { - Decl *D = cxcursor::getCursorDecl(cursor); - - SourceLocation StartLoc; - if (const DeclaratorDecl *DD = dyn_cast_or_null<DeclaratorDecl>(D)) { - if (TypeSourceInfo *TI = DD->getTypeSourceInfo()) - StartLoc = TI->getTypeLoc().getLocStart(); - } else if (TypedefDecl *Typedef = dyn_cast_or_null<TypedefDecl>(D)) { - if (TypeSourceInfo *TI = Typedef->getTypeSourceInfo()) - StartLoc = TI->getTypeLoc().getLocStart(); - } - - if (StartLoc.isValid() && L.isValid() && - SrcMgr.isBeforeInTranslationUnit(StartLoc, L)) - cursorRange.setBegin(StartLoc); - } - - // If the location of the cursor occurs within a macro instantiation, record - // the spelling location of the cursor in our annotation map. We can then - // paper over the token labelings during a post-processing step to try and - // get cursor mappings for tokens that are the *arguments* of a macro - // instantiation. - if (L.isMacroID()) { - unsigned rawEncoding = SrcMgr.getSpellingLoc(L).getRawEncoding(); - // Only invalidate the old annotation if it isn't part of a preprocessing - // directive. Here we assume that the default construction of CXCursor - // results in CXCursor.kind being an initialized value (i.e., 0). If - // this isn't the case, we can fix by doing lookup + insertion. - - CXCursor &oldC = Annotated[rawEncoding]; - if (!clang_isPreprocessing(oldC.kind)) - oldC = cursor; - } - - const enum CXCursorKind K = clang_getCursorKind(parent); - const CXCursor updateC = - (clang_isInvalid(K) || K == CXCursor_TranslationUnit) - ? clang_getNullCursor() : parent; - - annotateAndAdvanceTokens(updateC, RangeBefore, cursorRange); - - // Avoid having the cursor of an expression "overwrite" the annotation of the - // variable declaration that it belongs to. - // This can happen for C++ constructor expressions whose range generally - // include the variable declaration, e.g.: - // MyCXXClass foo; // Make sure we don't annotate 'foo' as a CallExpr cursor. - if (clang_isExpression(cursorK)) { - Expr *E = getCursorExpr(cursor); - if (Decl *D = getCursorParentDecl(cursor)) { - const unsigned I = NextToken(); - if (E->getLocStart().isValid() && D->getLocation().isValid() && - E->getLocStart() == D->getLocation() && - E->getLocStart() == GetTokenLoc(I)) { - Cursors[I] = updateC; - AdvanceToken(); - } - } - } - - // Before recursing into the children keep some state that we are going - // to use in the AnnotateTokensWorker::postVisitChildren callback to do some - // extra work after the child nodes are visited. - // Note that we don't call VisitChildren here to avoid traversing statements - // code-recursively which can blow the stack. - - PostChildrenInfo Info; - Info.Cursor = cursor; - Info.CursorRange = cursorRange; - Info.BeforeChildrenTokenIdx = NextToken(); - PostChildrenInfos.push_back(Info); - - return CXChildVisit_Recurse; -} - -bool AnnotateTokensWorker::postVisitChildren(CXCursor cursor) { - if (PostChildrenInfos.empty()) - return false; - const PostChildrenInfo &Info = PostChildrenInfos.back(); - if (!clang_equalCursors(Info.Cursor, cursor)) - return false; - - const unsigned BeforeChildren = Info.BeforeChildrenTokenIdx; - const unsigned AfterChildren = NextToken(); - SourceRange cursorRange = Info.CursorRange; - - // Scan the tokens that are at the end of the cursor, but are not captured - // but the child cursors. - annotateAndAdvanceTokens(cursor, RangeOverlap, cursorRange); - - // Scan the tokens that are at the beginning of the cursor, but are not - // capture by the child cursors. - for (unsigned I = BeforeChildren; I != AfterChildren; ++I) { - if (!clang_isInvalid(clang_getCursorKind(Cursors[I]))) - break; - - Cursors[I] = cursor; - } - - PostChildrenInfos.pop_back(); - return false; -} - -static enum CXChildVisitResult AnnotateTokensVisitor(CXCursor cursor, - CXCursor parent, - CXClientData client_data) { - return static_cast<AnnotateTokensWorker*>(client_data)->Visit(cursor, parent); -} - -static bool AnnotateTokensPostChildrenVisitor(CXCursor cursor, - CXClientData client_data) { - return static_cast<AnnotateTokensWorker*>(client_data)-> - postVisitChildren(cursor); -} - -namespace { - -/// \brief Uses the macro expansions in the preprocessing record to find -/// and mark tokens that are macro arguments. This info is used by the -/// AnnotateTokensWorker. -class MarkMacroArgTokensVisitor { - SourceManager &SM; - CXToken *Tokens; - unsigned NumTokens; - unsigned CurIdx; - -public: - MarkMacroArgTokensVisitor(SourceManager &SM, - CXToken *tokens, unsigned numTokens) - : SM(SM), Tokens(tokens), NumTokens(numTokens), CurIdx(0) { } - - CXChildVisitResult visit(CXCursor cursor, CXCursor parent) { - if (cursor.kind != CXCursor_MacroExpansion) - return CXChildVisit_Continue; - - SourceRange macroRange = getCursorMacroExpansion(cursor)->getSourceRange(); - if (macroRange.getBegin() == macroRange.getEnd()) - return CXChildVisit_Continue; // it's not a function macro. - - for (; CurIdx < NumTokens; ++CurIdx) { - if (!SM.isBeforeInTranslationUnit(getTokenLoc(CurIdx), - macroRange.getBegin())) - break; - } - - if (CurIdx == NumTokens) - return CXChildVisit_Break; - - for (; CurIdx < NumTokens; ++CurIdx) { - SourceLocation tokLoc = getTokenLoc(CurIdx); - if (!SM.isBeforeInTranslationUnit(tokLoc, macroRange.getEnd())) - break; - - setFunctionMacroTokenLoc(CurIdx, SM.getMacroArgExpandedLocation(tokLoc)); - } - - if (CurIdx == NumTokens) - return CXChildVisit_Break; - - return CXChildVisit_Continue; - } - -private: - SourceLocation getTokenLoc(unsigned tokI) { - return SourceLocation::getFromRawEncoding(Tokens[tokI].int_data[1]); - } - - void setFunctionMacroTokenLoc(unsigned tokI, SourceLocation loc) { - // The third field is reserved and currently not used. Use it here - // to mark macro arg expanded tokens with their expanded locations. - Tokens[tokI].int_data[3] = loc.getRawEncoding(); - } -}; - -} // end anonymous namespace - -static CXChildVisitResult -MarkMacroArgTokensVisitorDelegate(CXCursor cursor, CXCursor parent, - CXClientData client_data) { - return static_cast<MarkMacroArgTokensVisitor*>(client_data)->visit(cursor, - parent); -} - -namespace { - struct clang_annotateTokens_Data { - CXTranslationUnit TU; - ASTUnit *CXXUnit; - CXToken *Tokens; - unsigned NumTokens; - CXCursor *Cursors; - }; -} - -static void annotatePreprocessorTokens(CXTranslationUnit TU, - SourceRange RegionOfInterest, - AnnotateTokensData &Annotated) { - ASTUnit *CXXUnit = static_cast<ASTUnit *>(TU->TUData); - - SourceManager &SourceMgr = CXXUnit->getSourceManager(); - std::pair<FileID, unsigned> BeginLocInfo - = SourceMgr.getDecomposedLoc(RegionOfInterest.getBegin()); - std::pair<FileID, unsigned> EndLocInfo - = SourceMgr.getDecomposedLoc(RegionOfInterest.getEnd()); - - if (BeginLocInfo.first != EndLocInfo.first) - return; - - StringRef Buffer; - bool Invalid = false; - Buffer = SourceMgr.getBufferData(BeginLocInfo.first, &Invalid); - if (Buffer.empty() || Invalid) - return; - - Lexer Lex(SourceMgr.getLocForStartOfFile(BeginLocInfo.first), - CXXUnit->getASTContext().getLangOpts(), - Buffer.begin(), Buffer.data() + BeginLocInfo.second, - Buffer.end()); - Lex.SetCommentRetentionState(true); - - // Lex tokens in raw mode until we hit the end of the range, to avoid - // entering #includes or expanding macros. - while (true) { - Token Tok; - Lex.LexFromRawLexer(Tok); - - reprocess: - if (Tok.is(tok::hash) && Tok.isAtStartOfLine()) { - // We have found a preprocessing directive. Gobble it up so that we - // don't see it while preprocessing these tokens later, but keep track - // of all of the token locations inside this preprocessing directive so - // that we can annotate them appropriately. - // - // FIXME: Some simple tests here could identify macro definitions and - // #undefs, to provide specific cursor kinds for those. - SmallVector<SourceLocation, 32> Locations; - do { - Locations.push_back(Tok.getLocation()); - Lex.LexFromRawLexer(Tok); - } while (!Tok.isAtStartOfLine() && !Tok.is(tok::eof)); - - using namespace cxcursor; - CXCursor Cursor - = MakePreprocessingDirectiveCursor(SourceRange(Locations.front(), - Locations.back()), - TU); - for (unsigned I = 0, N = Locations.size(); I != N; ++I) { - Annotated[Locations[I].getRawEncoding()] = Cursor; - } - - if (Tok.isAtStartOfLine()) - goto reprocess; - - continue; - } - - if (Tok.is(tok::eof)) - break; - } -} - -// This gets run a separate thread to avoid stack blowout. -static void clang_annotateTokensImpl(void *UserData) { - CXTranslationUnit TU = ((clang_annotateTokens_Data*)UserData)->TU; - ASTUnit *CXXUnit = ((clang_annotateTokens_Data*)UserData)->CXXUnit; - CXToken *Tokens = ((clang_annotateTokens_Data*)UserData)->Tokens; - const unsigned NumTokens = ((clang_annotateTokens_Data*)UserData)->NumTokens; - CXCursor *Cursors = ((clang_annotateTokens_Data*)UserData)->Cursors; - - CIndexer *CXXIdx = (CIndexer*)TU->CIdx; - if (CXXIdx->isOptEnabled(CXGlobalOpt_ThreadBackgroundPriorityForEditing)) - setThreadBackgroundPriority(); - - // Determine the region of interest, which contains all of the tokens. - SourceRange RegionOfInterest; - RegionOfInterest.setBegin( - cxloc::translateSourceLocation(clang_getTokenLocation(TU, Tokens[0]))); - RegionOfInterest.setEnd( - cxloc::translateSourceLocation(clang_getTokenLocation(TU, - Tokens[NumTokens-1]))); - - // A mapping from the source locations found when re-lexing or traversing the - // region of interest to the corresponding cursors. - AnnotateTokensData Annotated; - - // Relex the tokens within the source range to look for preprocessing - // directives. - annotatePreprocessorTokens(TU, RegionOfInterest, Annotated); - - if (CXXUnit->getPreprocessor().getPreprocessingRecord()) { - // Search and mark tokens that are macro argument expansions. - MarkMacroArgTokensVisitor Visitor(CXXUnit->getSourceManager(), - Tokens, NumTokens); - CursorVisitor MacroArgMarker(TU, - MarkMacroArgTokensVisitorDelegate, &Visitor, - /*VisitPreprocessorLast=*/true, - /*VisitIncludedEntities=*/false, - RegionOfInterest); - MacroArgMarker.visitPreprocessedEntitiesInRegion(); - } - - // Annotate all of the source locations in the region of interest that map to - // a specific cursor. - AnnotateTokensWorker W(Annotated, Tokens, Cursors, NumTokens, - TU, RegionOfInterest); - - // FIXME: We use a ridiculous stack size here because the data-recursion - // algorithm uses a large stack frame than the non-data recursive version, - // and AnnotationTokensWorker currently transforms the data-recursion - // algorithm back into a traditional recursion by explicitly calling - // VisitChildren(). We will need to remove this explicit recursive call. - W.AnnotateTokens(); - - // If we ran into any entities that involve context-sensitive keywords, - // take another pass through the tokens to mark them as such. - if (W.hasContextSensitiveKeywords()) { - for (unsigned I = 0; I != NumTokens; ++I) { - if (clang_getTokenKind(Tokens[I]) != CXToken_Identifier) - continue; - - if (Cursors[I].kind == CXCursor_ObjCPropertyDecl) { - IdentifierInfo *II = static_cast<IdentifierInfo *>(Tokens[I].ptr_data); - if (ObjCPropertyDecl *Property - = dyn_cast_or_null<ObjCPropertyDecl>(getCursorDecl(Cursors[I]))) { - if (Property->getPropertyAttributesAsWritten() != 0 && - llvm::StringSwitch<bool>(II->getName()) - .Case("readonly", true) - .Case("assign", true) - .Case("unsafe_unretained", true) - .Case("readwrite", true) - .Case("retain", true) - .Case("copy", true) - .Case("nonatomic", true) - .Case("atomic", true) - .Case("getter", true) - .Case("setter", true) - .Case("strong", true) - .Case("weak", true) - .Default(false)) - Tokens[I].int_data[0] = CXToken_Keyword; - } - continue; - } - - if (Cursors[I].kind == CXCursor_ObjCInstanceMethodDecl || - Cursors[I].kind == CXCursor_ObjCClassMethodDecl) { - IdentifierInfo *II = static_cast<IdentifierInfo *>(Tokens[I].ptr_data); - if (llvm::StringSwitch<bool>(II->getName()) - .Case("in", true) - .Case("out", true) - .Case("inout", true) - .Case("oneway", true) - .Case("bycopy", true) - .Case("byref", true) - .Default(false)) - Tokens[I].int_data[0] = CXToken_Keyword; - continue; - } - - if (Cursors[I].kind == CXCursor_CXXFinalAttr || - Cursors[I].kind == CXCursor_CXXOverrideAttr) { - Tokens[I].int_data[0] = CXToken_Keyword; - continue; - } - } - } -} - -extern "C" { - -void clang_annotateTokens(CXTranslationUnit TU, - CXToken *Tokens, unsigned NumTokens, - CXCursor *Cursors) { - - if (NumTokens == 0 || !Tokens || !Cursors) - return; - - // Any token we don't specifically annotate will have a NULL cursor. - CXCursor C = clang_getNullCursor(); - for (unsigned I = 0; I != NumTokens; ++I) - Cursors[I] = C; - - ASTUnit *CXXUnit = static_cast<ASTUnit *>(TU->TUData); - if (!CXXUnit) - return; - - ASTUnit::ConcurrencyCheck Check(*CXXUnit); - - clang_annotateTokens_Data data = { TU, CXXUnit, Tokens, NumTokens, Cursors }; - llvm::CrashRecoveryContext CRC; - if (!RunSafely(CRC, clang_annotateTokensImpl, &data, - GetSafetyThreadStackSize() * 2)) { - fprintf(stderr, "libclang: crash detected while annotating tokens\n"); - } -} - -} // end: extern "C" - -//===----------------------------------------------------------------------===// -// Operations for querying linkage of a cursor. -//===----------------------------------------------------------------------===// - -extern "C" { -CXLinkageKind clang_getCursorLinkage(CXCursor cursor) { - if (!clang_isDeclaration(cursor.kind)) - return CXLinkage_Invalid; - - Decl *D = cxcursor::getCursorDecl(cursor); - if (NamedDecl *ND = dyn_cast_or_null<NamedDecl>(D)) - switch (ND->getLinkage()) { - case NoLinkage: return CXLinkage_NoLinkage; - case InternalLinkage: return CXLinkage_Internal; - case UniqueExternalLinkage: return CXLinkage_UniqueExternal; - case ExternalLinkage: return CXLinkage_External; - }; - - return CXLinkage_Invalid; -} -} // end: extern "C" - -//===----------------------------------------------------------------------===// -// Operations for querying language of a cursor. -//===----------------------------------------------------------------------===// - -static CXLanguageKind getDeclLanguage(const Decl *D) { - if (!D) - return CXLanguage_C; - - switch (D->getKind()) { - default: - break; - case Decl::ImplicitParam: - case Decl::ObjCAtDefsField: - case Decl::ObjCCategory: - case Decl::ObjCCategoryImpl: - case Decl::ObjCCompatibleAlias: - case Decl::ObjCImplementation: - case Decl::ObjCInterface: - case Decl::ObjCIvar: - case Decl::ObjCMethod: - case Decl::ObjCProperty: - case Decl::ObjCPropertyImpl: - case Decl::ObjCProtocol: - return CXLanguage_ObjC; - case Decl::CXXConstructor: - case Decl::CXXConversion: - case Decl::CXXDestructor: - case Decl::CXXMethod: - case Decl::CXXRecord: - case Decl::ClassTemplate: - case Decl::ClassTemplatePartialSpecialization: - case Decl::ClassTemplateSpecialization: - case Decl::Friend: - case Decl::FriendTemplate: - case Decl::FunctionTemplate: - case Decl::LinkageSpec: - case Decl::Namespace: - case Decl::NamespaceAlias: - case Decl::NonTypeTemplateParm: - case Decl::StaticAssert: - case Decl::TemplateTemplateParm: - case Decl::TemplateTypeParm: - case Decl::UnresolvedUsingTypename: - case Decl::UnresolvedUsingValue: - case Decl::Using: - case Decl::UsingDirective: - case Decl::UsingShadow: - return CXLanguage_CPlusPlus; - } - - return CXLanguage_C; -} - -extern "C" { - -enum CXAvailabilityKind clang_getCursorAvailability(CXCursor cursor) { - if (clang_isDeclaration(cursor.kind)) - if (Decl *D = cxcursor::getCursorDecl(cursor)) { - if (isa<FunctionDecl>(D) && cast<FunctionDecl>(D)->isDeleted()) - return CXAvailability_Available; - - switch (D->getAvailability()) { - case AR_Available: - case AR_NotYetIntroduced: - return CXAvailability_Available; - - case AR_Deprecated: - return CXAvailability_Deprecated; - - case AR_Unavailable: - return CXAvailability_NotAvailable; - } - } - - return CXAvailability_Available; -} - -static CXVersion convertVersion(VersionTuple In) { - CXVersion Out = { -1, -1, -1 }; - if (In.empty()) - return Out; - - Out.Major = In.getMajor(); - - if (llvm::Optional<unsigned> Minor = In.getMinor()) - Out.Minor = *Minor; - else - return Out; - - if (llvm::Optional<unsigned> Subminor = In.getSubminor()) - Out.Subminor = *Subminor; - - return Out; -} - -int clang_getCursorPlatformAvailability(CXCursor cursor, - int *always_deprecated, - CXString *deprecated_message, - int *always_unavailable, - CXString *unavailable_message, - CXPlatformAvailability *availability, - int availability_size) { - if (always_deprecated) - *always_deprecated = 0; - if (deprecated_message) - *deprecated_message = cxstring::createCXString("", /*DupString=*/false); - if (always_unavailable) - *always_unavailable = 0; - if (unavailable_message) - *unavailable_message = cxstring::createCXString("", /*DupString=*/false); - - if (!clang_isDeclaration(cursor.kind)) - return 0; - - Decl *D = cxcursor::getCursorDecl(cursor); - if (!D) - return 0; - - int N = 0; - for (Decl::attr_iterator A = D->attr_begin(), AEnd = D->attr_end(); A != AEnd; - ++A) { - if (DeprecatedAttr *Deprecated = dyn_cast<DeprecatedAttr>(*A)) { - if (always_deprecated) - *always_deprecated = 1; - if (deprecated_message) - *deprecated_message = cxstring::createCXString(Deprecated->getMessage()); - continue; - } - - if (UnavailableAttr *Unavailable = dyn_cast<UnavailableAttr>(*A)) { - if (always_unavailable) - *always_unavailable = 1; - if (unavailable_message) { - *unavailable_message - = cxstring::createCXString(Unavailable->getMessage()); - } - continue; - } - - if (AvailabilityAttr *Avail = dyn_cast<AvailabilityAttr>(*A)) { - if (N < availability_size) { - availability[N].Platform - = cxstring::createCXString(Avail->getPlatform()->getName()); - availability[N].Introduced = convertVersion(Avail->getIntroduced()); - availability[N].Deprecated = convertVersion(Avail->getDeprecated()); - availability[N].Obsoleted = convertVersion(Avail->getObsoleted()); - availability[N].Unavailable = Avail->getUnavailable(); - availability[N].Message = cxstring::createCXString(Avail->getMessage()); - } - ++N; - } - } - - return N; -} - -void clang_disposeCXPlatformAvailability(CXPlatformAvailability *availability) { - clang_disposeString(availability->Platform); - clang_disposeString(availability->Message); -} - -CXLanguageKind clang_getCursorLanguage(CXCursor cursor) { - if (clang_isDeclaration(cursor.kind)) - return getDeclLanguage(cxcursor::getCursorDecl(cursor)); - - return CXLanguage_Invalid; -} - - /// \brief If the given cursor is the "templated" declaration - /// descibing a class or function template, return the class or - /// function template. -static Decl *maybeGetTemplateCursor(Decl *D) { - if (!D) - return 0; - - if (FunctionDecl *FD = dyn_cast<FunctionDecl>(D)) - if (FunctionTemplateDecl *FunTmpl = FD->getDescribedFunctionTemplate()) - return FunTmpl; - - if (CXXRecordDecl *RD = dyn_cast<CXXRecordDecl>(D)) - if (ClassTemplateDecl *ClassTmpl = RD->getDescribedClassTemplate()) - return ClassTmpl; - - return D; -} - -CXCursor clang_getCursorSemanticParent(CXCursor cursor) { - if (clang_isDeclaration(cursor.kind)) { - if (Decl *D = getCursorDecl(cursor)) { - DeclContext *DC = D->getDeclContext(); - if (!DC) - return clang_getNullCursor(); - - return MakeCXCursor(maybeGetTemplateCursor(cast<Decl>(DC)), - getCursorTU(cursor)); - } - } - - if (clang_isStatement(cursor.kind) || clang_isExpression(cursor.kind)) { - if (Decl *D = getCursorDecl(cursor)) - return MakeCXCursor(D, getCursorTU(cursor)); - } - - return clang_getNullCursor(); -} - -CXCursor clang_getCursorLexicalParent(CXCursor cursor) { - if (clang_isDeclaration(cursor.kind)) { - if (Decl *D = getCursorDecl(cursor)) { - DeclContext *DC = D->getLexicalDeclContext(); - if (!DC) - return clang_getNullCursor(); - - return MakeCXCursor(maybeGetTemplateCursor(cast<Decl>(DC)), - getCursorTU(cursor)); - } - } - - // FIXME: Note that we can't easily compute the lexical context of a - // statement or expression, so we return nothing. - return clang_getNullCursor(); -} - -CXFile clang_getIncludedFile(CXCursor cursor) { - if (cursor.kind != CXCursor_InclusionDirective) - return 0; - - InclusionDirective *ID = getCursorInclusionDirective(cursor); - return (void *)ID->getFile(); -} - -CXSourceRange clang_Cursor_getCommentRange(CXCursor C) { - if (!clang_isDeclaration(C.kind)) - return clang_getNullRange(); - - const Decl *D = getCursorDecl(C); - ASTContext &Context = getCursorContext(C); - const RawComment *RC = Context.getRawCommentForAnyRedecl(D); - if (!RC) - return clang_getNullRange(); - - return cxloc::translateSourceRange(Context, RC->getSourceRange()); -} - -CXString clang_Cursor_getRawCommentText(CXCursor C) { - if (!clang_isDeclaration(C.kind)) - return createCXString((const char *) NULL); - - const Decl *D = getCursorDecl(C); - ASTContext &Context = getCursorContext(C); - const RawComment *RC = Context.getRawCommentForAnyRedecl(D); - StringRef RawText = RC ? RC->getRawText(Context.getSourceManager()) : - StringRef(); - - // Don't duplicate the string because RawText points directly into source - // code. - return createCXString(RawText, false); -} - -CXString clang_Cursor_getBriefCommentText(CXCursor C) { - if (!clang_isDeclaration(C.kind)) - return createCXString((const char *) NULL); - - const Decl *D = getCursorDecl(C); - const ASTContext &Context = getCursorContext(C); - const RawComment *RC = Context.getRawCommentForAnyRedecl(D); - - if (RC) { - StringRef BriefText = RC->getBriefText(Context); - - // Don't duplicate the string because RawComment ensures that this memory - // will not go away. - return createCXString(BriefText, false); - } - - return createCXString((const char *) NULL); -} - -CXComment clang_Cursor_getParsedComment(CXCursor C) { - if (!clang_isDeclaration(C.kind)) - return cxcomment::createCXComment(NULL, NULL); - - const Decl *D = getCursorDecl(C); - const ASTContext &Context = getCursorContext(C); - const comments::FullComment *FC = Context.getCommentForDecl(D, /*PP=*/ NULL); - - return cxcomment::createCXComment(FC, getCursorTU(C)); -} - -CXModule clang_Cursor_getModule(CXCursor C) { - if (C.kind == CXCursor_ModuleImportDecl) { - if (ImportDecl *ImportD = dyn_cast_or_null<ImportDecl>(getCursorDecl(C))) - return ImportD->getImportedModule(); - } - - return 0; -} - -CXModule clang_Module_getParent(CXModule CXMod) { - if (!CXMod) - return 0; - Module *Mod = static_cast<Module*>(CXMod); - return Mod->Parent; -} - -CXString clang_Module_getName(CXModule CXMod) { - if (!CXMod) - return createCXString(""); - Module *Mod = static_cast<Module*>(CXMod); - return createCXString(Mod->Name); -} - -CXString clang_Module_getFullName(CXModule CXMod) { - if (!CXMod) - return createCXString(""); - Module *Mod = static_cast<Module*>(CXMod); - return createCXString(Mod->getFullModuleName()); -} - -unsigned clang_Module_getNumTopLevelHeaders(CXModule CXMod) { - if (!CXMod) - return 0; - Module *Mod = static_cast<Module*>(CXMod); - return Mod->TopHeaders.size(); -} - -CXFile clang_Module_getTopLevelHeader(CXModule CXMod, unsigned Index) { - if (!CXMod) - return 0; - Module *Mod = static_cast<Module*>(CXMod); - - if (Index < Mod->TopHeaders.size()) - return const_cast<FileEntry *>(Mod->TopHeaders[Index]); - - return 0; -} - -} // end: extern "C" - -//===----------------------------------------------------------------------===// -// C++ AST instrospection. -//===----------------------------------------------------------------------===// - -extern "C" { -unsigned clang_CXXMethod_isStatic(CXCursor C) { - if (!clang_isDeclaration(C.kind)) - return 0; - - CXXMethodDecl *Method = 0; - Decl *D = cxcursor::getCursorDecl(C); - if (FunctionTemplateDecl *FunTmpl = dyn_cast_or_null<FunctionTemplateDecl>(D)) - Method = dyn_cast<CXXMethodDecl>(FunTmpl->getTemplatedDecl()); - else - Method = dyn_cast_or_null<CXXMethodDecl>(D); - return (Method && Method->isStatic()) ? 1 : 0; -} - -unsigned clang_CXXMethod_isVirtual(CXCursor C) { - if (!clang_isDeclaration(C.kind)) - return 0; - - CXXMethodDecl *Method = 0; - Decl *D = cxcursor::getCursorDecl(C); - if (FunctionTemplateDecl *FunTmpl = dyn_cast_or_null<FunctionTemplateDecl>(D)) - Method = dyn_cast<CXXMethodDecl>(FunTmpl->getTemplatedDecl()); - else - Method = dyn_cast_or_null<CXXMethodDecl>(D); - return (Method && Method->isVirtual()) ? 1 : 0; -} -} // end: extern "C" - -//===----------------------------------------------------------------------===// -// Attribute introspection. -//===----------------------------------------------------------------------===// - -extern "C" { -CXType clang_getIBOutletCollectionType(CXCursor C) { - if (C.kind != CXCursor_IBOutletCollectionAttr) - return cxtype::MakeCXType(QualType(), cxcursor::getCursorTU(C)); - - IBOutletCollectionAttr *A = - cast<IBOutletCollectionAttr>(cxcursor::getCursorAttr(C)); - - return cxtype::MakeCXType(A->getInterface(), cxcursor::getCursorTU(C)); -} -} // end: extern "C" - -//===----------------------------------------------------------------------===// -// Inspecting memory usage. -//===----------------------------------------------------------------------===// - -typedef std::vector<CXTUResourceUsageEntry> MemUsageEntries; - -static inline void createCXTUResourceUsageEntry(MemUsageEntries &entries, - enum CXTUResourceUsageKind k, - unsigned long amount) { - CXTUResourceUsageEntry entry = { k, amount }; - entries.push_back(entry); -} - -extern "C" { - -const char *clang_getTUResourceUsageName(CXTUResourceUsageKind kind) { - const char *str = ""; - switch (kind) { - case CXTUResourceUsage_AST: - str = "ASTContext: expressions, declarations, and types"; - break; - case CXTUResourceUsage_Identifiers: - str = "ASTContext: identifiers"; - break; - case CXTUResourceUsage_Selectors: - str = "ASTContext: selectors"; - break; - case CXTUResourceUsage_GlobalCompletionResults: - str = "Code completion: cached global results"; - break; - case CXTUResourceUsage_SourceManagerContentCache: - str = "SourceManager: content cache allocator"; - break; - case CXTUResourceUsage_AST_SideTables: - str = "ASTContext: side tables"; - break; - case CXTUResourceUsage_SourceManager_Membuffer_Malloc: - str = "SourceManager: malloc'ed memory buffers"; - break; - case CXTUResourceUsage_SourceManager_Membuffer_MMap: - str = "SourceManager: mmap'ed memory buffers"; - break; - case CXTUResourceUsage_ExternalASTSource_Membuffer_Malloc: - str = "ExternalASTSource: malloc'ed memory buffers"; - break; - case CXTUResourceUsage_ExternalASTSource_Membuffer_MMap: - str = "ExternalASTSource: mmap'ed memory buffers"; - break; - case CXTUResourceUsage_Preprocessor: - str = "Preprocessor: malloc'ed memory"; - break; - case CXTUResourceUsage_PreprocessingRecord: - str = "Preprocessor: PreprocessingRecord"; - break; - case CXTUResourceUsage_SourceManager_DataStructures: - str = "SourceManager: data structures and tables"; - break; - case CXTUResourceUsage_Preprocessor_HeaderSearch: - str = "Preprocessor: header search tables"; - break; - } - return str; -} - -CXTUResourceUsage clang_getCXTUResourceUsage(CXTranslationUnit TU) { - if (!TU) { - CXTUResourceUsage usage = { (void*) 0, 0, 0 }; - return usage; - } - - ASTUnit *astUnit = static_cast<ASTUnit*>(TU->TUData); - OwningPtr<MemUsageEntries> entries(new MemUsageEntries()); - ASTContext &astContext = astUnit->getASTContext(); - - // How much memory is used by AST nodes and types? - createCXTUResourceUsageEntry(*entries, CXTUResourceUsage_AST, - (unsigned long) astContext.getASTAllocatedMemory()); - - // How much memory is used by identifiers? - createCXTUResourceUsageEntry(*entries, CXTUResourceUsage_Identifiers, - (unsigned long) astContext.Idents.getAllocator().getTotalMemory()); - - // How much memory is used for selectors? - createCXTUResourceUsageEntry(*entries, CXTUResourceUsage_Selectors, - (unsigned long) astContext.Selectors.getTotalMemory()); - - // How much memory is used by ASTContext's side tables? - createCXTUResourceUsageEntry(*entries, CXTUResourceUsage_AST_SideTables, - (unsigned long) astContext.getSideTableAllocatedMemory()); - - // How much memory is used for caching global code completion results? - unsigned long completionBytes = 0; - if (GlobalCodeCompletionAllocator *completionAllocator = - astUnit->getCachedCompletionAllocator().getPtr()) { - completionBytes = completionAllocator->getTotalMemory(); - } - createCXTUResourceUsageEntry(*entries, - CXTUResourceUsage_GlobalCompletionResults, - completionBytes); - - // How much memory is being used by SourceManager's content cache? - createCXTUResourceUsageEntry(*entries, - CXTUResourceUsage_SourceManagerContentCache, - (unsigned long) astContext.getSourceManager().getContentCacheSize()); - - // How much memory is being used by the MemoryBuffer's in SourceManager? - const SourceManager::MemoryBufferSizes &srcBufs = - astUnit->getSourceManager().getMemoryBufferSizes(); - - createCXTUResourceUsageEntry(*entries, - CXTUResourceUsage_SourceManager_Membuffer_Malloc, - (unsigned long) srcBufs.malloc_bytes); - createCXTUResourceUsageEntry(*entries, - CXTUResourceUsage_SourceManager_Membuffer_MMap, - (unsigned long) srcBufs.mmap_bytes); - createCXTUResourceUsageEntry(*entries, - CXTUResourceUsage_SourceManager_DataStructures, - (unsigned long) astContext.getSourceManager() - .getDataStructureSizes()); - - // How much memory is being used by the ExternalASTSource? - if (ExternalASTSource *esrc = astContext.getExternalSource()) { - const ExternalASTSource::MemoryBufferSizes &sizes = - esrc->getMemoryBufferSizes(); - - createCXTUResourceUsageEntry(*entries, - CXTUResourceUsage_ExternalASTSource_Membuffer_Malloc, - (unsigned long) sizes.malloc_bytes); - createCXTUResourceUsageEntry(*entries, - CXTUResourceUsage_ExternalASTSource_Membuffer_MMap, - (unsigned long) sizes.mmap_bytes); - } - - // How much memory is being used by the Preprocessor? - Preprocessor &pp = astUnit->getPreprocessor(); - createCXTUResourceUsageEntry(*entries, - CXTUResourceUsage_Preprocessor, - pp.getTotalMemory()); - - if (PreprocessingRecord *pRec = pp.getPreprocessingRecord()) { - createCXTUResourceUsageEntry(*entries, - CXTUResourceUsage_PreprocessingRecord, - pRec->getTotalMemory()); - } - - createCXTUResourceUsageEntry(*entries, - CXTUResourceUsage_Preprocessor_HeaderSearch, - pp.getHeaderSearchInfo().getTotalMemory()); - - CXTUResourceUsage usage = { (void*) entries.get(), - (unsigned) entries->size(), - entries->size() ? &(*entries)[0] : 0 }; - entries.take(); - return usage; -} - -void clang_disposeCXTUResourceUsage(CXTUResourceUsage usage) { - if (usage.data) - delete (MemUsageEntries*) usage.data; -} - -} // end extern "C" - -void clang::PrintLibclangResourceUsage(CXTranslationUnit TU) { - CXTUResourceUsage Usage = clang_getCXTUResourceUsage(TU); - for (unsigned I = 0; I != Usage.numEntries; ++I) - fprintf(stderr, " %s: %lu\n", - clang_getTUResourceUsageName(Usage.entries[I].kind), - Usage.entries[I].amount); - - clang_disposeCXTUResourceUsage(Usage); -} - -//===----------------------------------------------------------------------===// -// Misc. utility functions. -//===----------------------------------------------------------------------===// - -/// Default to using an 8 MB stack size on "safety" threads. -static unsigned SafetyStackThreadSize = 8 << 20; - -namespace clang { - -bool RunSafely(llvm::CrashRecoveryContext &CRC, - void (*Fn)(void*), void *UserData, - unsigned Size) { - if (!Size) - Size = GetSafetyThreadStackSize(); - if (Size) - return CRC.RunSafelyOnThread(Fn, UserData, Size); - return CRC.RunSafely(Fn, UserData); -} - -unsigned GetSafetyThreadStackSize() { - return SafetyStackThreadSize; -} - -void SetSafetyThreadStackSize(unsigned Value) { - SafetyStackThreadSize = Value; -} - -} - -void clang::setThreadBackgroundPriority() { - if (getenv("LIBCLANG_BGPRIO_DISABLE")) - return; - - // FIXME: Move to llvm/Support and make it cross-platform. -#ifdef __APPLE__ - setpriority(PRIO_DARWIN_THREAD, 0, PRIO_DARWIN_BG); -#endif -} - -void cxindex::printDiagsToStderr(ASTUnit *Unit) { - if (!Unit) - return; - - for (ASTUnit::stored_diag_iterator D = Unit->stored_diag_begin(), - DEnd = Unit->stored_diag_end(); - D != DEnd; ++D) { - CXStoredDiagnostic Diag(*D, Unit->getASTContext().getLangOpts()); - CXString Msg = clang_formatDiagnostic(&Diag, - clang_defaultDiagnosticDisplayOptions()); - fprintf(stderr, "%s\n", clang_getCString(Msg)); - clang_disposeString(Msg); - } -#ifdef LLVM_ON_WIN32 - // On Windows, force a flush, since there may be multiple copies of - // stderr and stdout in the file system, all with different buffers - // but writing to the same device. - fflush(stderr); -#endif -} - -extern "C" { - -CXString clang_getClangVersion() { - return createCXString(getClangFullVersion()); -} - -} // end: extern "C" - +//===- CIndex.cpp - Clang-C Source Indexing Library -----------------------===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+//
+// This file implements the main API hooks in the Clang-C Source Indexing
+// library.
+//
+//===----------------------------------------------------------------------===//
+
+#include "CIndexer.h"
+#include "CIndexDiagnostic.h"
+#include "CXComment.h"
+#include "CXCursor.h"
+#include "CXSourceLocation.h"
+#include "CXString.h"
+#include "CXTranslationUnit.h"
+#include "CXType.h"
+#include "CursorVisitor.h"
+#include "clang/AST/StmtVisitor.h"
+#include "clang/Basic/Diagnostic.h"
+#include "clang/Basic/Version.h"
+#include "clang/Frontend/ASTUnit.h"
+#include "clang/Frontend/CompilerInstance.h"
+#include "clang/Frontend/FrontendDiagnostic.h"
+#include "clang/Lex/HeaderSearch.h"
+#include "clang/Lex/Lexer.h"
+#include "clang/Lex/PreprocessingRecord.h"
+#include "clang/Lex/Preprocessor.h"
+#include "llvm/ADT/Optional.h"
+#include "llvm/ADT/STLExtras.h"
+#include "llvm/ADT/StringSwitch.h"
+#include "llvm/Support/Compiler.h"
+#include "llvm/Support/CrashRecoveryContext.h"
+#include "llvm/Support/MemoryBuffer.h"
+#include "llvm/Support/Mutex.h"
+#include "llvm/Support/PrettyStackTrace.h"
+#include "llvm/Support/Program.h"
+#include "llvm/Support/SaveAndRestore.h"
+#include "llvm/Support/Signals.h"
+#include "llvm/Support/Threading.h"
+#include "llvm/Support/Timer.h"
+#include "llvm/Support/raw_ostream.h"
+
+using namespace clang;
+using namespace clang::cxcursor;
+using namespace clang::cxstring;
+using namespace clang::cxtu;
+using namespace clang::cxindex;
+
+CXTranslationUnit cxtu::MakeCXTranslationUnit(CIndexer *CIdx, ASTUnit *TU) {
+ if (!TU)
+ return 0;
+ CXTranslationUnit D = new CXTranslationUnitImpl();
+ D->CIdx = CIdx;
+ D->TUData = TU;
+ D->StringPool = createCXStringPool();
+ D->Diagnostics = 0;
+ D->OverridenCursorsPool = createOverridenCXCursorsPool();
+ return D;
+}
+
+cxtu::CXTUOwner::~CXTUOwner() {
+ if (TU)
+ clang_disposeTranslationUnit(TU);
+}
+
+/// \brief Compare two source ranges to determine their relative position in
+/// the translation unit.
+static RangeComparisonResult RangeCompare(SourceManager &SM,
+ SourceRange R1,
+ SourceRange R2) {
+ assert(R1.isValid() && "First range is invalid?");
+ assert(R2.isValid() && "Second range is invalid?");
+ if (R1.getEnd() != R2.getBegin() &&
+ SM.isBeforeInTranslationUnit(R1.getEnd(), R2.getBegin()))
+ return RangeBefore;
+ if (R2.getEnd() != R1.getBegin() &&
+ SM.isBeforeInTranslationUnit(R2.getEnd(), R1.getBegin()))
+ return RangeAfter;
+ return RangeOverlap;
+}
+
+/// \brief Determine if a source location falls within, before, or after a
+/// a given source range.
+static RangeComparisonResult LocationCompare(SourceManager &SM,
+ SourceLocation L, SourceRange R) {
+ assert(R.isValid() && "First range is invalid?");
+ assert(L.isValid() && "Second range is invalid?");
+ if (L == R.getBegin() || L == R.getEnd())
+ return RangeOverlap;
+ if (SM.isBeforeInTranslationUnit(L, R.getBegin()))
+ return RangeBefore;
+ if (SM.isBeforeInTranslationUnit(R.getEnd(), L))
+ return RangeAfter;
+ return RangeOverlap;
+}
+
+/// \brief Translate a Clang source range into a CIndex source range.
+///
+/// Clang internally represents ranges where the end location points to the
+/// start of the token at the end. However, for external clients it is more
+/// useful to have a CXSourceRange be a proper half-open interval. This routine
+/// does the appropriate translation.
+CXSourceRange cxloc::translateSourceRange(const SourceManager &SM,
+ const LangOptions &LangOpts,
+ const CharSourceRange &R) {
+ // We want the last character in this location, so we will adjust the
+ // location accordingly.
+ SourceLocation EndLoc = R.getEnd();
+ if (EndLoc.isValid() && EndLoc.isMacroID() && !SM.isMacroArgExpansion(EndLoc))
+ EndLoc = SM.getExpansionRange(EndLoc).second;
+ if (R.isTokenRange() && !EndLoc.isInvalid()) {
+ unsigned Length = Lexer::MeasureTokenLength(SM.getSpellingLoc(EndLoc),
+ SM, LangOpts);
+ EndLoc = EndLoc.getLocWithOffset(Length);
+ }
+
+ CXSourceRange Result = { { (void *)&SM, (void *)&LangOpts },
+ R.getBegin().getRawEncoding(),
+ EndLoc.getRawEncoding() };
+ return Result;
+}
+
+//===----------------------------------------------------------------------===//
+// Cursor visitor.
+//===----------------------------------------------------------------------===//
+
+static SourceRange getRawCursorExtent(CXCursor C);
+static SourceRange getFullCursorExtent(CXCursor C, SourceManager &SrcMgr);
+
+
+RangeComparisonResult CursorVisitor::CompareRegionOfInterest(SourceRange R) {
+ return RangeCompare(AU->getSourceManager(), R, RegionOfInterest);
+}
+
+/// \brief Visit the given cursor and, if requested by the visitor,
+/// its children.
+///
+/// \param Cursor the cursor to visit.
+///
+/// \param CheckedRegionOfInterest if true, then the caller already checked
+/// that this cursor is within the region of interest.
+///
+/// \returns true if the visitation should be aborted, false if it
+/// should continue.
+bool CursorVisitor::Visit(CXCursor Cursor, bool CheckedRegionOfInterest) {
+ if (clang_isInvalid(Cursor.kind))
+ return false;
+
+ if (clang_isDeclaration(Cursor.kind)) {
+ Decl *D = getCursorDecl(Cursor);
+ if (!D) {
+ assert(0 && "Invalid declaration cursor");
+ return true; // abort.
+ }
+
+ // Ignore implicit declarations, unless it's an objc method because
+ // currently we should report implicit methods for properties when indexing.
+ if (D->isImplicit() && !isa<ObjCMethodDecl>(D))
+ return false;
+ }
+
+ // If we have a range of interest, and this cursor doesn't intersect with it,
+ // we're done.
+ if (RegionOfInterest.isValid() && !CheckedRegionOfInterest) {
+ SourceRange Range = getRawCursorExtent(Cursor);
+ if (Range.isInvalid() || CompareRegionOfInterest(Range))
+ return false;
+ }
+
+ switch (Visitor(Cursor, Parent, ClientData)) {
+ case CXChildVisit_Break:
+ return true;
+
+ case CXChildVisit_Continue:
+ return false;
+
+ case CXChildVisit_Recurse: {
+ bool ret = VisitChildren(Cursor);
+ if (PostChildrenVisitor)
+ if (PostChildrenVisitor(Cursor, ClientData))
+ return true;
+ return ret;
+ }
+ }
+
+ llvm_unreachable("Invalid CXChildVisitResult!");
+}
+
+static bool visitPreprocessedEntitiesInRange(SourceRange R,
+ PreprocessingRecord &PPRec,
+ CursorVisitor &Visitor) {
+ SourceManager &SM = Visitor.getASTUnit()->getSourceManager();
+ FileID FID;
+
+ if (!Visitor.shouldVisitIncludedEntities()) {
+ // If the begin/end of the range lie in the same FileID, do the optimization
+ // where we skip preprocessed entities that do not come from the same FileID.
+ FID = SM.getFileID(SM.getFileLoc(R.getBegin()));
+ if (FID != SM.getFileID(SM.getFileLoc(R.getEnd())))
+ FID = FileID();
+ }
+
+ std::pair<PreprocessingRecord::iterator, PreprocessingRecord::iterator>
+ Entities = PPRec.getPreprocessedEntitiesInRange(R);
+ return Visitor.visitPreprocessedEntities(Entities.first, Entities.second,
+ PPRec, FID);
+}
+
+void CursorVisitor::visitFileRegion() {
+ if (RegionOfInterest.isInvalid())
+ return;
+
+ ASTUnit *Unit = static_cast<ASTUnit *>(TU->TUData);
+ SourceManager &SM = Unit->getSourceManager();
+
+ std::pair<FileID, unsigned>
+ Begin = SM.getDecomposedLoc(SM.getFileLoc(RegionOfInterest.getBegin())),
+ End = SM.getDecomposedLoc(SM.getFileLoc(RegionOfInterest.getEnd()));
+
+ if (End.first != Begin.first) {
+ // If the end does not reside in the same file, try to recover by
+ // picking the end of the file of begin location.
+ End.first = Begin.first;
+ End.second = SM.getFileIDSize(Begin.first);
+ }
+
+ assert(Begin.first == End.first);
+ if (Begin.second > End.second)
+ return;
+
+ FileID File = Begin.first;
+ unsigned Offset = Begin.second;
+ unsigned Length = End.second - Begin.second;
+
+ if (!VisitDeclsOnly && !VisitPreprocessorLast)
+ if (visitPreprocessedEntitiesInRegion())
+ return; // visitation break.
+
+ visitDeclsFromFileRegion(File, Offset, Length);
+
+ if (!VisitDeclsOnly && VisitPreprocessorLast)
+ visitPreprocessedEntitiesInRegion();
+}
+
+static bool isInLexicalContext(Decl *D, DeclContext *DC) {
+ if (!DC)
+ return false;
+
+ for (DeclContext *DeclDC = D->getLexicalDeclContext();
+ DeclDC; DeclDC = DeclDC->getLexicalParent()) {
+ if (DeclDC == DC)
+ return true;
+ }
+ return false;
+}
+
+void CursorVisitor::visitDeclsFromFileRegion(FileID File,
+ unsigned Offset, unsigned Length) {
+ ASTUnit *Unit = static_cast<ASTUnit *>(TU->TUData);
+ SourceManager &SM = Unit->getSourceManager();
+ SourceRange Range = RegionOfInterest;
+
+ SmallVector<Decl *, 16> Decls;
+ Unit->findFileRegionDecls(File, Offset, Length, Decls);
+
+ // If we didn't find any file level decls for the file, try looking at the
+ // file that it was included from.
+ while (Decls.empty() || Decls.front()->isTopLevelDeclInObjCContainer()) {
+ bool Invalid = false;
+ const SrcMgr::SLocEntry &SLEntry = SM.getSLocEntry(File, &Invalid);
+ if (Invalid)
+ return;
+
+ SourceLocation Outer;
+ if (SLEntry.isFile())
+ Outer = SLEntry.getFile().getIncludeLoc();
+ else
+ Outer = SLEntry.getExpansion().getExpansionLocStart();
+ if (Outer.isInvalid())
+ return;
+
+ llvm::tie(File, Offset) = SM.getDecomposedExpansionLoc(Outer);
+ Length = 0;
+ Unit->findFileRegionDecls(File, Offset, Length, Decls);
+ }
+
+ assert(!Decls.empty());
+
+ bool VisitedAtLeastOnce = false;
+ DeclContext *CurDC = 0;
+ SmallVector<Decl *, 16>::iterator DIt = Decls.begin();
+ for (SmallVector<Decl *, 16>::iterator DE = Decls.end(); DIt != DE; ++DIt) {
+ Decl *D = *DIt;
+ if (D->getSourceRange().isInvalid())
+ continue;
+
+ if (isInLexicalContext(D, CurDC))
+ continue;
+
+ CurDC = dyn_cast<DeclContext>(D);
+
+ if (TagDecl *TD = dyn_cast<TagDecl>(D))
+ if (!TD->isFreeStanding())
+ continue;
+
+ RangeComparisonResult CompRes = RangeCompare(SM, D->getSourceRange(),Range);
+ if (CompRes == RangeBefore)
+ continue;
+ if (CompRes == RangeAfter)
+ break;
+
+ assert(CompRes == RangeOverlap);
+ VisitedAtLeastOnce = true;
+
+ if (isa<ObjCContainerDecl>(D)) {
+ FileDI_current = &DIt;
+ FileDE_current = DE;
+ } else {
+ FileDI_current = 0;
+ }
+
+ if (Visit(MakeCXCursor(D, TU, Range), /*CheckedRegionOfInterest=*/true))
+ break;
+ }
+
+ if (VisitedAtLeastOnce)
+ return;
+
+ // No Decls overlapped with the range. Move up the lexical context until there
+ // is a context that contains the range or we reach the translation unit
+ // level.
+ DeclContext *DC = DIt == Decls.begin() ? (*DIt)->getLexicalDeclContext()
+ : (*(DIt-1))->getLexicalDeclContext();
+
+ while (DC && !DC->isTranslationUnit()) {
+ Decl *D = cast<Decl>(DC);
+ SourceRange CurDeclRange = D->getSourceRange();
+ if (CurDeclRange.isInvalid())
+ break;
+
+ if (RangeCompare(SM, CurDeclRange, Range) == RangeOverlap) {
+ Visit(MakeCXCursor(D, TU, Range), /*CheckedRegionOfInterest=*/true);
+ break;
+ }
+
+ DC = D->getLexicalDeclContext();
+ }
+}
+
+bool CursorVisitor::visitPreprocessedEntitiesInRegion() {
+ if (!AU->getPreprocessor().getPreprocessingRecord())
+ return false;
+
+ PreprocessingRecord &PPRec
+ = *AU->getPreprocessor().getPreprocessingRecord();
+ SourceManager &SM = AU->getSourceManager();
+
+ if (RegionOfInterest.isValid()) {
+ SourceRange MappedRange = AU->mapRangeToPreamble(RegionOfInterest);
+ SourceLocation B = MappedRange.getBegin();
+ SourceLocation E = MappedRange.getEnd();
+
+ if (AU->isInPreambleFileID(B)) {
+ if (SM.isLoadedSourceLocation(E))
+ return visitPreprocessedEntitiesInRange(SourceRange(B, E),
+ PPRec, *this);
+
+ // Beginning of range lies in the preamble but it also extends beyond
+ // it into the main file. Split the range into 2 parts, one covering
+ // the preamble and another covering the main file. This allows subsequent
+ // calls to visitPreprocessedEntitiesInRange to accept a source range that
+ // lies in the same FileID, allowing it to skip preprocessed entities that
+ // do not come from the same FileID.
+ bool breaked =
+ visitPreprocessedEntitiesInRange(
+ SourceRange(B, AU->getEndOfPreambleFileID()),
+ PPRec, *this);
+ if (breaked) return true;
+ return visitPreprocessedEntitiesInRange(
+ SourceRange(AU->getStartOfMainFileID(), E),
+ PPRec, *this);
+ }
+
+ return visitPreprocessedEntitiesInRange(SourceRange(B, E), PPRec, *this);
+ }
+
+ bool OnlyLocalDecls
+ = !AU->isMainFileAST() && AU->getOnlyLocalDecls();
+
+ if (OnlyLocalDecls)
+ return visitPreprocessedEntities(PPRec.local_begin(), PPRec.local_end(),
+ PPRec);
+
+ return visitPreprocessedEntities(PPRec.begin(), PPRec.end(), PPRec);
+}
+
+template<typename InputIterator>
+bool CursorVisitor::visitPreprocessedEntities(InputIterator First,
+ InputIterator Last,
+ PreprocessingRecord &PPRec,
+ FileID FID) {
+ for (; First != Last; ++First) {
+ if (!FID.isInvalid() && !PPRec.isEntityInFileID(First, FID))
+ continue;
+
+ PreprocessedEntity *PPE = *First;
+ if (MacroExpansion *ME = dyn_cast<MacroExpansion>(PPE)) {
+ if (Visit(MakeMacroExpansionCursor(ME, TU)))
+ return true;
+
+ continue;
+ }
+
+ if (MacroDefinition *MD = dyn_cast<MacroDefinition>(PPE)) {
+ if (Visit(MakeMacroDefinitionCursor(MD, TU)))
+ return true;
+
+ continue;
+ }
+
+ if (InclusionDirective *ID = dyn_cast<InclusionDirective>(PPE)) {
+ if (Visit(MakeInclusionDirectiveCursor(ID, TU)))
+ return true;
+
+ continue;
+ }
+ }
+
+ return false;
+}
+
+/// \brief Visit the children of the given cursor.
+///
+/// \returns true if the visitation should be aborted, false if it
+/// should continue.
+bool CursorVisitor::VisitChildren(CXCursor Cursor) {
+ if (clang_isReference(Cursor.kind) &&
+ Cursor.kind != CXCursor_CXXBaseSpecifier) {
+ // By definition, references have no children.
+ return false;
+ }
+
+ // Set the Parent field to Cursor, then back to its old value once we're
+ // done.
+ SetParentRAII SetParent(Parent, StmtParent, Cursor);
+
+ if (clang_isDeclaration(Cursor.kind)) {
+ Decl *D = getCursorDecl(Cursor);
+ if (!D)
+ return false;
+
+ return VisitAttributes(D) || Visit(D);
+ }
+
+ if (clang_isStatement(Cursor.kind)) {
+ if (Stmt *S = getCursorStmt(Cursor))
+ return Visit(S);
+
+ return false;
+ }
+
+ if (clang_isExpression(Cursor.kind)) {
+ if (Expr *E = getCursorExpr(Cursor))
+ return Visit(E);
+
+ return false;
+ }
+
+ if (clang_isTranslationUnit(Cursor.kind)) {
+ CXTranslationUnit tu = getCursorTU(Cursor);
+ ASTUnit *CXXUnit = static_cast<ASTUnit*>(tu->TUData);
+
+ int VisitOrder[2] = { VisitPreprocessorLast, !VisitPreprocessorLast };
+ for (unsigned I = 0; I != 2; ++I) {
+ if (VisitOrder[I]) {
+ if (!CXXUnit->isMainFileAST() && CXXUnit->getOnlyLocalDecls() &&
+ RegionOfInterest.isInvalid()) {
+ for (ASTUnit::top_level_iterator TL = CXXUnit->top_level_begin(),
+ TLEnd = CXXUnit->top_level_end();
+ TL != TLEnd; ++TL) {
+ if (Visit(MakeCXCursor(*TL, tu, RegionOfInterest), true))
+ return true;
+ }
+ } else if (VisitDeclContext(
+ CXXUnit->getASTContext().getTranslationUnitDecl()))
+ return true;
+ continue;
+ }
+
+ // Walk the preprocessing record.
+ if (CXXUnit->getPreprocessor().getPreprocessingRecord())
+ visitPreprocessedEntitiesInRegion();
+ }
+
+ return false;
+ }
+
+ if (Cursor.kind == CXCursor_CXXBaseSpecifier) {
+ if (CXXBaseSpecifier *Base = getCursorCXXBaseSpecifier(Cursor)) {
+ if (TypeSourceInfo *BaseTSInfo = Base->getTypeSourceInfo()) {
+ return Visit(BaseTSInfo->getTypeLoc());
+ }
+ }
+ }
+
+ if (Cursor.kind == CXCursor_IBOutletCollectionAttr) {
+ IBOutletCollectionAttr *A =
+ cast<IBOutletCollectionAttr>(cxcursor::getCursorAttr(Cursor));
+ if (const ObjCInterfaceType *InterT = A->getInterface()->getAs<ObjCInterfaceType>())
+ return Visit(cxcursor::MakeCursorObjCClassRef(InterT->getInterface(),
+ A->getInterfaceLoc(), TU));
+ }
+
+ // Nothing to visit at the moment.
+ return false;
+}
+
+bool CursorVisitor::VisitBlockDecl(BlockDecl *B) {
+ if (TypeSourceInfo *TSInfo = B->getSignatureAsWritten())
+ if (Visit(TSInfo->getTypeLoc()))
+ return true;
+
+ if (Stmt *Body = B->getBody())
+ return Visit(MakeCXCursor(Body, StmtParent, TU, RegionOfInterest));
+
+ return false;
+}
+
+llvm::Optional<bool> CursorVisitor::shouldVisitCursor(CXCursor Cursor) {
+ if (RegionOfInterest.isValid()) {
+ SourceRange Range = getFullCursorExtent(Cursor, AU->getSourceManager());
+ if (Range.isInvalid())
+ return llvm::Optional<bool>();
+
+ switch (CompareRegionOfInterest(Range)) {
+ case RangeBefore:
+ // This declaration comes before the region of interest; skip it.
+ return llvm::Optional<bool>();
+
+ case RangeAfter:
+ // This declaration comes after the region of interest; we're done.
+ return false;
+
+ case RangeOverlap:
+ // This declaration overlaps the region of interest; visit it.
+ break;
+ }
+ }
+ return true;
+}
+
+bool CursorVisitor::VisitDeclContext(DeclContext *DC) {
+ DeclContext::decl_iterator I = DC->decls_begin(), E = DC->decls_end();
+
+ // FIXME: Eventually remove. This part of a hack to support proper
+ // iteration over all Decls contained lexically within an ObjC container.
+ SaveAndRestore<DeclContext::decl_iterator*> DI_saved(DI_current, &I);
+ SaveAndRestore<DeclContext::decl_iterator> DE_saved(DE_current, E);
+
+ for ( ; I != E; ++I) {
+ Decl *D = *I;
+ if (D->getLexicalDeclContext() != DC)
+ continue;
+ CXCursor Cursor = MakeCXCursor(D, TU, RegionOfInterest);
+
+ // Ignore synthesized ivars here, otherwise if we have something like:
+ // @synthesize prop = _prop;
+ // and '_prop' is not declared, we will encounter a '_prop' ivar before
+ // encountering the 'prop' synthesize declaration and we will think that
+ // we passed the region-of-interest.
+ if (ObjCIvarDecl *ivarD = dyn_cast<ObjCIvarDecl>(D)) {
+ if (ivarD->getSynthesize())
+ continue;
+ }
+
+ // FIXME: ObjCClassRef/ObjCProtocolRef for forward class/protocol
+ // declarations is a mismatch with the compiler semantics.
+ if (Cursor.kind == CXCursor_ObjCInterfaceDecl) {
+ ObjCInterfaceDecl *ID = cast<ObjCInterfaceDecl>(D);
+ if (!ID->isThisDeclarationADefinition())
+ Cursor = MakeCursorObjCClassRef(ID, ID->getLocation(), TU);
+
+ } else if (Cursor.kind == CXCursor_ObjCProtocolDecl) {
+ ObjCProtocolDecl *PD = cast<ObjCProtocolDecl>(D);
+ if (!PD->isThisDeclarationADefinition())
+ Cursor = MakeCursorObjCProtocolRef(PD, PD->getLocation(), TU);
+ }
+
+ const llvm::Optional<bool> &V = shouldVisitCursor(Cursor);
+ if (!V.hasValue())
+ continue;
+ if (!V.getValue())
+ return false;
+ if (Visit(Cursor, true))
+ return true;
+ }
+ return false;
+}
+
+bool CursorVisitor::VisitTranslationUnitDecl(TranslationUnitDecl *D) {
+ llvm_unreachable("Translation units are visited directly by Visit()");
+}
+
+bool CursorVisitor::VisitTypeAliasDecl(TypeAliasDecl *D) {
+ if (TypeSourceInfo *TSInfo = D->getTypeSourceInfo())
+ return Visit(TSInfo->getTypeLoc());
+
+ return false;
+}
+
+bool CursorVisitor::VisitTypedefDecl(TypedefDecl *D) {
+ if (TypeSourceInfo *TSInfo = D->getTypeSourceInfo())
+ return Visit(TSInfo->getTypeLoc());
+
+ return false;
+}
+
+bool CursorVisitor::VisitTagDecl(TagDecl *D) {
+ return VisitDeclContext(D);
+}
+
+bool CursorVisitor::VisitClassTemplateSpecializationDecl(
+ ClassTemplateSpecializationDecl *D) {
+ bool ShouldVisitBody = false;
+ switch (D->getSpecializationKind()) {
+ case TSK_Undeclared:
+ case TSK_ImplicitInstantiation:
+ // Nothing to visit
+ return false;
+
+ case TSK_ExplicitInstantiationDeclaration:
+ case TSK_ExplicitInstantiationDefinition:
+ break;
+
+ case TSK_ExplicitSpecialization:
+ ShouldVisitBody = true;
+ break;
+ }
+
+ // Visit the template arguments used in the specialization.
+ if (TypeSourceInfo *SpecType = D->getTypeAsWritten()) {
+ TypeLoc TL = SpecType->getTypeLoc();
+ if (TemplateSpecializationTypeLoc *TSTLoc
+ = dyn_cast<TemplateSpecializationTypeLoc>(&TL)) {
+ for (unsigned I = 0, N = TSTLoc->getNumArgs(); I != N; ++I)
+ if (VisitTemplateArgumentLoc(TSTLoc->getArgLoc(I)))
+ return true;
+ }
+ }
+
+ if (ShouldVisitBody && VisitCXXRecordDecl(D))
+ return true;
+
+ return false;
+}
+
+bool CursorVisitor::VisitClassTemplatePartialSpecializationDecl(
+ ClassTemplatePartialSpecializationDecl *D) {
+ // FIXME: Visit the "outer" template parameter lists on the TagDecl
+ // before visiting these template parameters.
+ if (VisitTemplateParameters(D->getTemplateParameters()))
+ return true;
+
+ // Visit the partial specialization arguments.
+ const TemplateArgumentLoc *TemplateArgs = D->getTemplateArgsAsWritten();
+ for (unsigned I = 0, N = D->getNumTemplateArgsAsWritten(); I != N; ++I)
+ if (VisitTemplateArgumentLoc(TemplateArgs[I]))
+ return true;
+
+ return VisitCXXRecordDecl(D);
+}
+
+bool CursorVisitor::VisitTemplateTypeParmDecl(TemplateTypeParmDecl *D) {
+ // Visit the default argument.
+ if (D->hasDefaultArgument() && !D->defaultArgumentWasInherited())
+ if (TypeSourceInfo *DefArg = D->getDefaultArgumentInfo())
+ if (Visit(DefArg->getTypeLoc()))
+ return true;
+
+ return false;
+}
+
+bool CursorVisitor::VisitEnumConstantDecl(EnumConstantDecl *D) {
+ if (Expr *Init = D->getInitExpr())
+ return Visit(MakeCXCursor(Init, StmtParent, TU, RegionOfInterest));
+ return false;
+}
+
+bool CursorVisitor::VisitDeclaratorDecl(DeclaratorDecl *DD) {
+ if (TypeSourceInfo *TSInfo = DD->getTypeSourceInfo())
+ if (Visit(TSInfo->getTypeLoc()))
+ return true;
+
+ // Visit the nested-name-specifier, if present.
+ if (NestedNameSpecifierLoc QualifierLoc = DD->getQualifierLoc())
+ if (VisitNestedNameSpecifierLoc(QualifierLoc))
+ return true;
+
+ return false;
+}
+
+/// \brief Compare two base or member initializers based on their source order.
+static int CompareCXXCtorInitializers(const void* Xp, const void *Yp) {
+ CXXCtorInitializer const * const *X
+ = static_cast<CXXCtorInitializer const * const *>(Xp);
+ CXXCtorInitializer const * const *Y
+ = static_cast<CXXCtorInitializer const * const *>(Yp);
+
+ if ((*X)->getSourceOrder() < (*Y)->getSourceOrder())
+ return -1;
+ else if ((*X)->getSourceOrder() > (*Y)->getSourceOrder())
+ return 1;
+ else
+ return 0;
+}
+
+bool CursorVisitor::VisitFunctionDecl(FunctionDecl *ND) {
+ if (TypeSourceInfo *TSInfo = ND->getTypeSourceInfo()) {
+ // Visit the function declaration's syntactic components in the order
+ // written. This requires a bit of work.
+ TypeLoc TL = TSInfo->getTypeLoc().IgnoreParens();
+ FunctionTypeLoc *FTL = dyn_cast<FunctionTypeLoc>(&TL);
+
+ // If we have a function declared directly (without the use of a typedef),
+ // visit just the return type. Otherwise, just visit the function's type
+ // now.
+ if ((FTL && !isa<CXXConversionDecl>(ND) && Visit(FTL->getResultLoc())) ||
+ (!FTL && Visit(TL)))
+ return true;
+
+ // Visit the nested-name-specifier, if present.
+ if (NestedNameSpecifierLoc QualifierLoc = ND->getQualifierLoc())
+ if (VisitNestedNameSpecifierLoc(QualifierLoc))
+ return true;
+
+ // Visit the declaration name.
+ if (VisitDeclarationNameInfo(ND->getNameInfo()))
+ return true;
+
+ // FIXME: Visit explicitly-specified template arguments!
+
+ // Visit the function parameters, if we have a function type.
+ if (FTL && VisitFunctionTypeLoc(*FTL, true))
+ return true;
+
+ // FIXME: Attributes?
+ }
+
+ if (ND->doesThisDeclarationHaveABody() && !ND->isLateTemplateParsed()) {
+ if (CXXConstructorDecl *Constructor = dyn_cast<CXXConstructorDecl>(ND)) {
+ // Find the initializers that were written in the source.
+ SmallVector<CXXCtorInitializer *, 4> WrittenInits;
+ for (CXXConstructorDecl::init_iterator I = Constructor->init_begin(),
+ IEnd = Constructor->init_end();
+ I != IEnd; ++I) {
+ if (!(*I)->isWritten())
+ continue;
+
+ WrittenInits.push_back(*I);
+ }
+
+ // Sort the initializers in source order
+ llvm::array_pod_sort(WrittenInits.begin(), WrittenInits.end(),
+ &CompareCXXCtorInitializers);
+
+ // Visit the initializers in source order
+ for (unsigned I = 0, N = WrittenInits.size(); I != N; ++I) {
+ CXXCtorInitializer *Init = WrittenInits[I];
+ if (Init->isAnyMemberInitializer()) {
+ if (Visit(MakeCursorMemberRef(Init->getAnyMember(),
+ Init->getMemberLocation(), TU)))
+ return true;
+ } else if (TypeSourceInfo *TInfo = Init->getTypeSourceInfo()) {
+ if (Visit(TInfo->getTypeLoc()))
+ return true;
+ }
+
+ // Visit the initializer value.
+ if (Expr *Initializer = Init->getInit())
+ if (Visit(MakeCXCursor(Initializer, ND, TU, RegionOfInterest)))
+ return true;
+ }
+ }
+
+ if (Visit(MakeCXCursor(ND->getBody(), StmtParent, TU, RegionOfInterest)))
+ return true;
+ }
+
+ return false;
+}
+
+bool CursorVisitor::VisitFieldDecl(FieldDecl *D) {
+ if (VisitDeclaratorDecl(D))
+ return true;
+
+ if (Expr *BitWidth = D->getBitWidth())
+ return Visit(MakeCXCursor(BitWidth, StmtParent, TU, RegionOfInterest));
+
+ return false;
+}
+
+bool CursorVisitor::VisitVarDecl(VarDecl *D) {
+ if (VisitDeclaratorDecl(D))
+ return true;
+
+ if (Expr *Init = D->getInit())
+ return Visit(MakeCXCursor(Init, StmtParent, TU, RegionOfInterest));
+
+ return false;
+}
+
+bool CursorVisitor::VisitNonTypeTemplateParmDecl(NonTypeTemplateParmDecl *D) {
+ if (VisitDeclaratorDecl(D))
+ return true;
+
+ if (D->hasDefaultArgument() && !D->defaultArgumentWasInherited())
+ if (Expr *DefArg = D->getDefaultArgument())
+ return Visit(MakeCXCursor(DefArg, StmtParent, TU, RegionOfInterest));
+
+ return false;
+}
+
+bool CursorVisitor::VisitFunctionTemplateDecl(FunctionTemplateDecl *D) {
+ // FIXME: Visit the "outer" template parameter lists on the FunctionDecl
+ // before visiting these template parameters.
+ if (VisitTemplateParameters(D->getTemplateParameters()))
+ return true;
+
+ return VisitFunctionDecl(D->getTemplatedDecl());
+}
+
+bool CursorVisitor::VisitClassTemplateDecl(ClassTemplateDecl *D) {
+ // FIXME: Visit the "outer" template parameter lists on the TagDecl
+ // before visiting these template parameters.
+ if (VisitTemplateParameters(D->getTemplateParameters()))
+ return true;
+
+ return VisitCXXRecordDecl(D->getTemplatedDecl());
+}
+
+bool CursorVisitor::VisitTemplateTemplateParmDecl(TemplateTemplateParmDecl *D) {
+ if (VisitTemplateParameters(D->getTemplateParameters()))
+ return true;
+
+ if (D->hasDefaultArgument() && !D->defaultArgumentWasInherited() &&
+ VisitTemplateArgumentLoc(D->getDefaultArgument()))
+ return true;
+
+ return false;
+}
+
+bool CursorVisitor::VisitObjCMethodDecl(ObjCMethodDecl *ND) {
+ if (TypeSourceInfo *TSInfo = ND->getResultTypeSourceInfo())
+ if (Visit(TSInfo->getTypeLoc()))
+ return true;
+
+ for (ObjCMethodDecl::param_iterator P = ND->param_begin(),
+ PEnd = ND->param_end();
+ P != PEnd; ++P) {
+ if (Visit(MakeCXCursor(*P, TU, RegionOfInterest)))
+ return true;
+ }
+
+ if (ND->isThisDeclarationADefinition() &&
+ Visit(MakeCXCursor(ND->getBody(), StmtParent, TU, RegionOfInterest)))
+ return true;
+
+ return false;
+}
+
+template <typename DeclIt>
+static void addRangedDeclsInContainer(DeclIt *DI_current, DeclIt DE_current,
+ SourceManager &SM, SourceLocation EndLoc,
+ SmallVectorImpl<Decl *> &Decls) {
+ DeclIt next = *DI_current;
+ while (++next != DE_current) {
+ Decl *D_next = *next;
+ if (!D_next)
+ break;
+ SourceLocation L = D_next->getLocStart();
+ if (!L.isValid())
+ break;
+ if (SM.isBeforeInTranslationUnit(L, EndLoc)) {
+ *DI_current = next;
+ Decls.push_back(D_next);
+ continue;
+ }
+ break;
+ }
+}
+
+namespace {
+ struct ContainerDeclsSort {
+ SourceManager &SM;
+ ContainerDeclsSort(SourceManager &sm) : SM(sm) {}
+ bool operator()(Decl *A, Decl *B) {
+ SourceLocation L_A = A->getLocStart();
+ SourceLocation L_B = B->getLocStart();
+ assert(L_A.isValid() && L_B.isValid());
+ return SM.isBeforeInTranslationUnit(L_A, L_B);
+ }
+ };
+}
+
+bool CursorVisitor::VisitObjCContainerDecl(ObjCContainerDecl *D) {
+ // FIXME: Eventually convert back to just 'VisitDeclContext()'. Essentially
+ // an @implementation can lexically contain Decls that are not properly
+ // nested in the AST. When we identify such cases, we need to retrofit
+ // this nesting here.
+ if (!DI_current && !FileDI_current)
+ return VisitDeclContext(D);
+
+ // Scan the Decls that immediately come after the container
+ // in the current DeclContext. If any fall within the
+ // container's lexical region, stash them into a vector
+ // for later processing.
+ SmallVector<Decl *, 24> DeclsInContainer;
+ SourceLocation EndLoc = D->getSourceRange().getEnd();
+ SourceManager &SM = AU->getSourceManager();
+ if (EndLoc.isValid()) {
+ if (DI_current) {
+ addRangedDeclsInContainer(DI_current, DE_current, SM, EndLoc,
+ DeclsInContainer);
+ } else {
+ addRangedDeclsInContainer(FileDI_current, FileDE_current, SM, EndLoc,
+ DeclsInContainer);
+ }
+ }
+
+ // The common case.
+ if (DeclsInContainer.empty())
+ return VisitDeclContext(D);
+
+ // Get all the Decls in the DeclContext, and sort them with the
+ // additional ones we've collected. Then visit them.
+ for (DeclContext::decl_iterator I = D->decls_begin(), E = D->decls_end();
+ I!=E; ++I) {
+ Decl *subDecl = *I;
+ if (!subDecl || subDecl->getLexicalDeclContext() != D ||
+ subDecl->getLocStart().isInvalid())
+ continue;
+ DeclsInContainer.push_back(subDecl);
+ }
+
+ // Now sort the Decls so that they appear in lexical order.
+ std::sort(DeclsInContainer.begin(), DeclsInContainer.end(),
+ ContainerDeclsSort(SM));
+
+ // Now visit the decls.
+ for (SmallVectorImpl<Decl*>::iterator I = DeclsInContainer.begin(),
+ E = DeclsInContainer.end(); I != E; ++I) {
+ CXCursor Cursor = MakeCXCursor(*I, TU, RegionOfInterest);
+ const llvm::Optional<bool> &V = shouldVisitCursor(Cursor);
+ if (!V.hasValue())
+ continue;
+ if (!V.getValue())
+ return false;
+ if (Visit(Cursor, true))
+ return true;
+ }
+ return false;
+}
+
+bool CursorVisitor::VisitObjCCategoryDecl(ObjCCategoryDecl *ND) {
+ if (Visit(MakeCursorObjCClassRef(ND->getClassInterface(), ND->getLocation(),
+ TU)))
+ return true;
+
+ ObjCCategoryDecl::protocol_loc_iterator PL = ND->protocol_loc_begin();
+ for (ObjCCategoryDecl::protocol_iterator I = ND->protocol_begin(),
+ E = ND->protocol_end(); I != E; ++I, ++PL)
+ if (Visit(MakeCursorObjCProtocolRef(*I, *PL, TU)))
+ return true;
+
+ return VisitObjCContainerDecl(ND);
+}
+
+bool CursorVisitor::VisitObjCProtocolDecl(ObjCProtocolDecl *PID) {
+ if (!PID->isThisDeclarationADefinition())
+ return Visit(MakeCursorObjCProtocolRef(PID, PID->getLocation(), TU));
+
+ ObjCProtocolDecl::protocol_loc_iterator PL = PID->protocol_loc_begin();
+ for (ObjCProtocolDecl::protocol_iterator I = PID->protocol_begin(),
+ E = PID->protocol_end(); I != E; ++I, ++PL)
+ if (Visit(MakeCursorObjCProtocolRef(*I, *PL, TU)))
+ return true;
+
+ return VisitObjCContainerDecl(PID);
+}
+
+bool CursorVisitor::VisitObjCPropertyDecl(ObjCPropertyDecl *PD) {
+ if (PD->getTypeSourceInfo() && Visit(PD->getTypeSourceInfo()->getTypeLoc()))
+ return true;
+
+ // FIXME: This implements a workaround with @property declarations also being
+ // installed in the DeclContext for the @interface. Eventually this code
+ // should be removed.
+ ObjCCategoryDecl *CDecl = dyn_cast<ObjCCategoryDecl>(PD->getDeclContext());
+ if (!CDecl || !CDecl->IsClassExtension())
+ return false;
+
+ ObjCInterfaceDecl *ID = CDecl->getClassInterface();
+ if (!ID)
+ return false;
+
+ IdentifierInfo *PropertyId = PD->getIdentifier();
+ ObjCPropertyDecl *prevDecl =
+ ObjCPropertyDecl::findPropertyDecl(cast<DeclContext>(ID), PropertyId);
+
+ if (!prevDecl)
+ return false;
+
+ // Visit synthesized methods since they will be skipped when visiting
+ // the @interface.
+ if (ObjCMethodDecl *MD = prevDecl->getGetterMethodDecl())
+ if (MD->isPropertyAccessor() && MD->getLexicalDeclContext() == CDecl)
+ if (Visit(MakeCXCursor(MD, TU, RegionOfInterest)))
+ return true;
+
+ if (ObjCMethodDecl *MD = prevDecl->getSetterMethodDecl())
+ if (MD->isPropertyAccessor() && MD->getLexicalDeclContext() == CDecl)
+ if (Visit(MakeCXCursor(MD, TU, RegionOfInterest)))
+ return true;
+
+ return false;
+}
+
+bool CursorVisitor::VisitObjCInterfaceDecl(ObjCInterfaceDecl *D) {
+ if (!D->isThisDeclarationADefinition()) {
+ // Forward declaration is treated like a reference.
+ return Visit(MakeCursorObjCClassRef(D, D->getLocation(), TU));
+ }
+
+ // Issue callbacks for super class.
+ if (D->getSuperClass() &&
+ Visit(MakeCursorObjCSuperClassRef(D->getSuperClass(),
+ D->getSuperClassLoc(),
+ TU)))
+ return true;
+
+ ObjCInterfaceDecl::protocol_loc_iterator PL = D->protocol_loc_begin();
+ for (ObjCInterfaceDecl::protocol_iterator I = D->protocol_begin(),
+ E = D->protocol_end(); I != E; ++I, ++PL)
+ if (Visit(MakeCursorObjCProtocolRef(*I, *PL, TU)))
+ return true;
+
+ return VisitObjCContainerDecl(D);
+}
+
+bool CursorVisitor::VisitObjCImplDecl(ObjCImplDecl *D) {
+ return VisitObjCContainerDecl(D);
+}
+
+bool CursorVisitor::VisitObjCCategoryImplDecl(ObjCCategoryImplDecl *D) {
+ // 'ID' could be null when dealing with invalid code.
+ if (ObjCInterfaceDecl *ID = D->getClassInterface())
+ if (Visit(MakeCursorObjCClassRef(ID, D->getLocation(), TU)))
+ return true;
+
+ return VisitObjCImplDecl(D);
+}
+
+bool CursorVisitor::VisitObjCImplementationDecl(ObjCImplementationDecl *D) {
+#if 0
+ // Issue callbacks for super class.
+ // FIXME: No source location information!
+ if (D->getSuperClass() &&
+ Visit(MakeCursorObjCSuperClassRef(D->getSuperClass(),
+ D->getSuperClassLoc(),
+ TU)))
+ return true;
+#endif
+
+ return VisitObjCImplDecl(D);
+}
+
+bool CursorVisitor::VisitObjCPropertyImplDecl(ObjCPropertyImplDecl *PD) {
+ if (ObjCIvarDecl *Ivar = PD->getPropertyIvarDecl())
+ if (PD->isIvarNameSpecified())
+ return Visit(MakeCursorMemberRef(Ivar, PD->getPropertyIvarDeclLoc(), TU));
+
+ return false;
+}
+
+bool CursorVisitor::VisitNamespaceDecl(NamespaceDecl *D) {
+ return VisitDeclContext(D);
+}
+
+bool CursorVisitor::VisitNamespaceAliasDecl(NamespaceAliasDecl *D) {
+ // Visit nested-name-specifier.
+ if (NestedNameSpecifierLoc QualifierLoc = D->getQualifierLoc())
+ if (VisitNestedNameSpecifierLoc(QualifierLoc))
+ return true;
+
+ return Visit(MakeCursorNamespaceRef(D->getAliasedNamespace(),
+ D->getTargetNameLoc(), TU));
+}
+
+bool CursorVisitor::VisitUsingDecl(UsingDecl *D) {
+ // Visit nested-name-specifier.
+ if (NestedNameSpecifierLoc QualifierLoc = D->getQualifierLoc()) {
+ if (VisitNestedNameSpecifierLoc(QualifierLoc))
+ return true;
+ }
+
+ if (Visit(MakeCursorOverloadedDeclRef(D, D->getLocation(), TU)))
+ return true;
+
+ return VisitDeclarationNameInfo(D->getNameInfo());
+}
+
+bool CursorVisitor::VisitUsingDirectiveDecl(UsingDirectiveDecl *D) {
+ // Visit nested-name-specifier.
+ if (NestedNameSpecifierLoc QualifierLoc = D->getQualifierLoc())
+ if (VisitNestedNameSpecifierLoc(QualifierLoc))
+ return true;
+
+ return Visit(MakeCursorNamespaceRef(D->getNominatedNamespaceAsWritten(),
+ D->getIdentLocation(), TU));
+}
+
+bool CursorVisitor::VisitUnresolvedUsingValueDecl(UnresolvedUsingValueDecl *D) {
+ // Visit nested-name-specifier.
+ if (NestedNameSpecifierLoc QualifierLoc = D->getQualifierLoc()) {
+ if (VisitNestedNameSpecifierLoc(QualifierLoc))
+ return true;
+ }
+
+ return VisitDeclarationNameInfo(D->getNameInfo());
+}
+
+bool CursorVisitor::VisitUnresolvedUsingTypenameDecl(
+ UnresolvedUsingTypenameDecl *D) {
+ // Visit nested-name-specifier.
+ if (NestedNameSpecifierLoc QualifierLoc = D->getQualifierLoc())
+ if (VisitNestedNameSpecifierLoc(QualifierLoc))
+ return true;
+
+ return false;
+}
+
+bool CursorVisitor::VisitDeclarationNameInfo(DeclarationNameInfo Name) {
+ switch (Name.getName().getNameKind()) {
+ case clang::DeclarationName::Identifier:
+ case clang::DeclarationName::CXXLiteralOperatorName:
+ case clang::DeclarationName::CXXOperatorName:
+ case clang::DeclarationName::CXXUsingDirective:
+ return false;
+
+ case clang::DeclarationName::CXXConstructorName:
+ case clang::DeclarationName::CXXDestructorName:
+ case clang::DeclarationName::CXXConversionFunctionName:
+ if (TypeSourceInfo *TSInfo = Name.getNamedTypeInfo())
+ return Visit(TSInfo->getTypeLoc());
+ return false;
+
+ case clang::DeclarationName::ObjCZeroArgSelector:
+ case clang::DeclarationName::ObjCOneArgSelector:
+ case clang::DeclarationName::ObjCMultiArgSelector:
+ // FIXME: Per-identifier location info?
+ return false;
+ }
+
+ llvm_unreachable("Invalid DeclarationName::Kind!");
+}
+
+bool CursorVisitor::VisitNestedNameSpecifier(NestedNameSpecifier *NNS,
+ SourceRange Range) {
+ // FIXME: This whole routine is a hack to work around the lack of proper
+ // source information in nested-name-specifiers (PR5791). Since we do have
+ // a beginning source location, we can visit the first component of the
+ // nested-name-specifier, if it's a single-token component.
+ if (!NNS)
+ return false;
+
+ // Get the first component in the nested-name-specifier.
+ while (NestedNameSpecifier *Prefix = NNS->getPrefix())
+ NNS = Prefix;
+
+ switch (NNS->getKind()) {
+ case NestedNameSpecifier::Namespace:
+ return Visit(MakeCursorNamespaceRef(NNS->getAsNamespace(), Range.getBegin(),
+ TU));
+
+ case NestedNameSpecifier::NamespaceAlias:
+ return Visit(MakeCursorNamespaceRef(NNS->getAsNamespaceAlias(),
+ Range.getBegin(), TU));
+
+ case NestedNameSpecifier::TypeSpec: {
+ // If the type has a form where we know that the beginning of the source
+ // range matches up with a reference cursor. Visit the appropriate reference
+ // cursor.
+ const Type *T = NNS->getAsType();
+ if (const TypedefType *Typedef = dyn_cast<TypedefType>(T))
+ return Visit(MakeCursorTypeRef(Typedef->getDecl(), Range.getBegin(), TU));
+ if (const TagType *Tag = dyn_cast<TagType>(T))
+ return Visit(MakeCursorTypeRef(Tag->getDecl(), Range.getBegin(), TU));
+ if (const TemplateSpecializationType *TST
+ = dyn_cast<TemplateSpecializationType>(T))
+ return VisitTemplateName(TST->getTemplateName(), Range.getBegin());
+ break;
+ }
+
+ case NestedNameSpecifier::TypeSpecWithTemplate:
+ case NestedNameSpecifier::Global:
+ case NestedNameSpecifier::Identifier:
+ break;
+ }
+
+ return false;
+}
+
+bool
+CursorVisitor::VisitNestedNameSpecifierLoc(NestedNameSpecifierLoc Qualifier) {
+ SmallVector<NestedNameSpecifierLoc, 4> Qualifiers;
+ for (; Qualifier; Qualifier = Qualifier.getPrefix())
+ Qualifiers.push_back(Qualifier);
+
+ while (!Qualifiers.empty()) {
+ NestedNameSpecifierLoc Q = Qualifiers.pop_back_val();
+ NestedNameSpecifier *NNS = Q.getNestedNameSpecifier();
+ switch (NNS->getKind()) {
+ case NestedNameSpecifier::Namespace:
+ if (Visit(MakeCursorNamespaceRef(NNS->getAsNamespace(),
+ Q.getLocalBeginLoc(),
+ TU)))
+ return true;
+
+ break;
+
+ case NestedNameSpecifier::NamespaceAlias:
+ if (Visit(MakeCursorNamespaceRef(NNS->getAsNamespaceAlias(),
+ Q.getLocalBeginLoc(),
+ TU)))
+ return true;
+
+ break;
+
+ case NestedNameSpecifier::TypeSpec:
+ case NestedNameSpecifier::TypeSpecWithTemplate:
+ if (Visit(Q.getTypeLoc()))
+ return true;
+
+ break;
+
+ case NestedNameSpecifier::Global:
+ case NestedNameSpecifier::Identifier:
+ break;
+ }
+ }
+
+ return false;
+}
+
+bool CursorVisitor::VisitTemplateParameters(
+ const TemplateParameterList *Params) {
+ if (!Params)
+ return false;
+
+ for (TemplateParameterList::const_iterator P = Params->begin(),
+ PEnd = Params->end();
+ P != PEnd; ++P) {
+ if (Visit(MakeCXCursor(*P, TU, RegionOfInterest)))
+ return true;
+ }
+
+ return false;
+}
+
+bool CursorVisitor::VisitTemplateName(TemplateName Name, SourceLocation Loc) {
+ switch (Name.getKind()) {
+ case TemplateName::Template:
+ return Visit(MakeCursorTemplateRef(Name.getAsTemplateDecl(), Loc, TU));
+
+ case TemplateName::OverloadedTemplate:
+ // Visit the overloaded template set.
+ if (Visit(MakeCursorOverloadedDeclRef(Name, Loc, TU)))
+ return true;
+
+ return false;
+
+ case TemplateName::DependentTemplate:
+ // FIXME: Visit nested-name-specifier.
+ return false;
+
+ case TemplateName::QualifiedTemplate:
+ // FIXME: Visit nested-name-specifier.
+ return Visit(MakeCursorTemplateRef(
+ Name.getAsQualifiedTemplateName()->getDecl(),
+ Loc, TU));
+
+ case TemplateName::SubstTemplateTemplateParm:
+ return Visit(MakeCursorTemplateRef(
+ Name.getAsSubstTemplateTemplateParm()->getParameter(),
+ Loc, TU));
+
+ case TemplateName::SubstTemplateTemplateParmPack:
+ return Visit(MakeCursorTemplateRef(
+ Name.getAsSubstTemplateTemplateParmPack()->getParameterPack(),
+ Loc, TU));
+ }
+
+ llvm_unreachable("Invalid TemplateName::Kind!");
+}
+
+bool CursorVisitor::VisitTemplateArgumentLoc(const TemplateArgumentLoc &TAL) {
+ switch (TAL.getArgument().getKind()) {
+ case TemplateArgument::Null:
+ case TemplateArgument::Integral:
+ case TemplateArgument::Pack:
+ return false;
+
+ case TemplateArgument::Type:
+ if (TypeSourceInfo *TSInfo = TAL.getTypeSourceInfo())
+ return Visit(TSInfo->getTypeLoc());
+ return false;
+
+ case TemplateArgument::Declaration:
+ if (Expr *E = TAL.getSourceDeclExpression())
+ return Visit(MakeCXCursor(E, StmtParent, TU, RegionOfInterest));
+ return false;
+
+ case TemplateArgument::NullPtr:
+ if (Expr *E = TAL.getSourceNullPtrExpression())
+ return Visit(MakeCXCursor(E, StmtParent, TU, RegionOfInterest));
+ return false;
+
+ case TemplateArgument::Expression:
+ if (Expr *E = TAL.getSourceExpression())
+ return Visit(MakeCXCursor(E, StmtParent, TU, RegionOfInterest));
+ return false;
+
+ case TemplateArgument::Template:
+ case TemplateArgument::TemplateExpansion:
+ if (VisitNestedNameSpecifierLoc(TAL.getTemplateQualifierLoc()))
+ return true;
+
+ return VisitTemplateName(TAL.getArgument().getAsTemplateOrTemplatePattern(),
+ TAL.getTemplateNameLoc());
+ }
+
+ llvm_unreachable("Invalid TemplateArgument::Kind!");
+}
+
+bool CursorVisitor::VisitLinkageSpecDecl(LinkageSpecDecl *D) {
+ return VisitDeclContext(D);
+}
+
+bool CursorVisitor::VisitQualifiedTypeLoc(QualifiedTypeLoc TL) {
+ return Visit(TL.getUnqualifiedLoc());
+}
+
+bool CursorVisitor::VisitBuiltinTypeLoc(BuiltinTypeLoc TL) {
+ ASTContext &Context = AU->getASTContext();
+
+ // Some builtin types (such as Objective-C's "id", "sel", and
+ // "Class") have associated declarations. Create cursors for those.
+ QualType VisitType;
+ switch (TL.getTypePtr()->getKind()) {
+
+ case BuiltinType::Void:
+ case BuiltinType::NullPtr:
+ case BuiltinType::Dependent:
+ case BuiltinType::OCLImage1d:
+ case BuiltinType::OCLImage1dArray:
+ case BuiltinType::OCLImage1dBuffer:
+ case BuiltinType::OCLImage2d:
+ case BuiltinType::OCLImage2dArray:
+ case BuiltinType::OCLImage3d:
+#define BUILTIN_TYPE(Id, SingletonId)
+#define SIGNED_TYPE(Id, SingletonId) case BuiltinType::Id:
+#define UNSIGNED_TYPE(Id, SingletonId) case BuiltinType::Id:
+#define FLOATING_TYPE(Id, SingletonId) case BuiltinType::Id:
+#define PLACEHOLDER_TYPE(Id, SingletonId) case BuiltinType::Id:
+#include "clang/AST/BuiltinTypes.def"
+ break;
+
+ case BuiltinType::ObjCId:
+ VisitType = Context.getObjCIdType();
+ break;
+
+ case BuiltinType::ObjCClass:
+ VisitType = Context.getObjCClassType();
+ break;
+
+ case BuiltinType::ObjCSel:
+ VisitType = Context.getObjCSelType();
+ break;
+ }
+
+ if (!VisitType.isNull()) {
+ if (const TypedefType *Typedef = VisitType->getAs<TypedefType>())
+ return Visit(MakeCursorTypeRef(Typedef->getDecl(), TL.getBuiltinLoc(),
+ TU));
+ }
+
+ return false;
+}
+
+bool CursorVisitor::VisitTypedefTypeLoc(TypedefTypeLoc TL) {
+ return Visit(MakeCursorTypeRef(TL.getTypedefNameDecl(), TL.getNameLoc(), TU));
+}
+
+bool CursorVisitor::VisitUnresolvedUsingTypeLoc(UnresolvedUsingTypeLoc TL) {
+ return Visit(MakeCursorTypeRef(TL.getDecl(), TL.getNameLoc(), TU));
+}
+
+bool CursorVisitor::VisitTagTypeLoc(TagTypeLoc TL) {
+ if (TL.isDefinition())
+ return Visit(MakeCXCursor(TL.getDecl(), TU, RegionOfInterest));
+
+ return Visit(MakeCursorTypeRef(TL.getDecl(), TL.getNameLoc(), TU));
+}
+
+bool CursorVisitor::VisitTemplateTypeParmTypeLoc(TemplateTypeParmTypeLoc TL) {
+ return Visit(MakeCursorTypeRef(TL.getDecl(), TL.getNameLoc(), TU));
+}
+
+bool CursorVisitor::VisitObjCInterfaceTypeLoc(ObjCInterfaceTypeLoc TL) {
+ if (Visit(MakeCursorObjCClassRef(TL.getIFaceDecl(), TL.getNameLoc(), TU)))
+ return true;
+
+ return false;
+}
+
+bool CursorVisitor::VisitObjCObjectTypeLoc(ObjCObjectTypeLoc TL) {
+ if (TL.hasBaseTypeAsWritten() && Visit(TL.getBaseLoc()))
+ return true;
+
+ for (unsigned I = 0, N = TL.getNumProtocols(); I != N; ++I) {
+ if (Visit(MakeCursorObjCProtocolRef(TL.getProtocol(I), TL.getProtocolLoc(I),
+ TU)))
+ return true;
+ }
+
+ return false;
+}
+
+bool CursorVisitor::VisitObjCObjectPointerTypeLoc(ObjCObjectPointerTypeLoc TL) {
+ return Visit(TL.getPointeeLoc());
+}
+
+bool CursorVisitor::VisitParenTypeLoc(ParenTypeLoc TL) {
+ return Visit(TL.getInnerLoc());
+}
+
+bool CursorVisitor::VisitPointerTypeLoc(PointerTypeLoc TL) {
+ return Visit(TL.getPointeeLoc());
+}
+
+bool CursorVisitor::VisitBlockPointerTypeLoc(BlockPointerTypeLoc TL) {
+ return Visit(TL.getPointeeLoc());
+}
+
+bool CursorVisitor::VisitMemberPointerTypeLoc(MemberPointerTypeLoc TL) {
+ return Visit(TL.getPointeeLoc());
+}
+
+bool CursorVisitor::VisitLValueReferenceTypeLoc(LValueReferenceTypeLoc TL) {
+ return Visit(TL.getPointeeLoc());
+}
+
+bool CursorVisitor::VisitRValueReferenceTypeLoc(RValueReferenceTypeLoc TL) {
+ return Visit(TL.getPointeeLoc());
+}
+
+bool CursorVisitor::VisitAttributedTypeLoc(AttributedTypeLoc TL) {
+ return Visit(TL.getModifiedLoc());
+}
+
+bool CursorVisitor::VisitFunctionTypeLoc(FunctionTypeLoc TL,
+ bool SkipResultType) {
+ if (!SkipResultType && Visit(TL.getResultLoc()))
+ return true;
+
+ for (unsigned I = 0, N = TL.getNumArgs(); I != N; ++I)
+ if (Decl *D = TL.getArg(I))
+ if (Visit(MakeCXCursor(D, TU, RegionOfInterest)))
+ return true;
+
+ return false;
+}
+
+bool CursorVisitor::VisitArrayTypeLoc(ArrayTypeLoc TL) {
+ if (Visit(TL.getElementLoc()))
+ return true;
+
+ if (Expr *Size = TL.getSizeExpr())
+ return Visit(MakeCXCursor(Size, StmtParent, TU, RegionOfInterest));
+
+ return false;
+}
+
+bool CursorVisitor::VisitTemplateSpecializationTypeLoc(
+ TemplateSpecializationTypeLoc TL) {
+ // Visit the template name.
+ if (VisitTemplateName(TL.getTypePtr()->getTemplateName(),
+ TL.getTemplateNameLoc()))
+ return true;
+
+ // Visit the template arguments.
+ for (unsigned I = 0, N = TL.getNumArgs(); I != N; ++I)
+ if (VisitTemplateArgumentLoc(TL.getArgLoc(I)))
+ return true;
+
+ return false;
+}
+
+bool CursorVisitor::VisitTypeOfExprTypeLoc(TypeOfExprTypeLoc TL) {
+ return Visit(MakeCXCursor(TL.getUnderlyingExpr(), StmtParent, TU));
+}
+
+bool CursorVisitor::VisitTypeOfTypeLoc(TypeOfTypeLoc TL) {
+ if (TypeSourceInfo *TSInfo = TL.getUnderlyingTInfo())
+ return Visit(TSInfo->getTypeLoc());
+
+ return false;
+}
+
+bool CursorVisitor::VisitUnaryTransformTypeLoc(UnaryTransformTypeLoc TL) {
+ if (TypeSourceInfo *TSInfo = TL.getUnderlyingTInfo())
+ return Visit(TSInfo->getTypeLoc());
+
+ return false;
+}
+
+bool CursorVisitor::VisitDependentNameTypeLoc(DependentNameTypeLoc TL) {
+ if (VisitNestedNameSpecifierLoc(TL.getQualifierLoc()))
+ return true;
+
+ return false;
+}
+
+bool CursorVisitor::VisitDependentTemplateSpecializationTypeLoc(
+ DependentTemplateSpecializationTypeLoc TL) {
+ // Visit the nested-name-specifier, if there is one.
+ if (TL.getQualifierLoc() &&
+ VisitNestedNameSpecifierLoc(TL.getQualifierLoc()))
+ return true;
+
+ // Visit the template arguments.
+ for (unsigned I = 0, N = TL.getNumArgs(); I != N; ++I)
+ if (VisitTemplateArgumentLoc(TL.getArgLoc(I)))
+ return true;
+
+ return false;
+}
+
+bool CursorVisitor::VisitElaboratedTypeLoc(ElaboratedTypeLoc TL) {
+ if (VisitNestedNameSpecifierLoc(TL.getQualifierLoc()))
+ return true;
+
+ return Visit(TL.getNamedTypeLoc());
+}
+
+bool CursorVisitor::VisitPackExpansionTypeLoc(PackExpansionTypeLoc TL) {
+ return Visit(TL.getPatternLoc());
+}
+
+bool CursorVisitor::VisitDecltypeTypeLoc(DecltypeTypeLoc TL) {
+ if (Expr *E = TL.getUnderlyingExpr())
+ return Visit(MakeCXCursor(E, StmtParent, TU));
+
+ return false;
+}
+
+bool CursorVisitor::VisitInjectedClassNameTypeLoc(InjectedClassNameTypeLoc TL) {
+ return Visit(MakeCursorTypeRef(TL.getDecl(), TL.getNameLoc(), TU));
+}
+
+bool CursorVisitor::VisitAtomicTypeLoc(AtomicTypeLoc TL) {
+ return Visit(TL.getValueLoc());
+}
+
+#define DEFAULT_TYPELOC_IMPL(CLASS, PARENT) \
+bool CursorVisitor::Visit##CLASS##TypeLoc(CLASS##TypeLoc TL) { \
+ return Visit##PARENT##Loc(TL); \
+}
+
+DEFAULT_TYPELOC_IMPL(Complex, Type)
+DEFAULT_TYPELOC_IMPL(ConstantArray, ArrayType)
+DEFAULT_TYPELOC_IMPL(IncompleteArray, ArrayType)
+DEFAULT_TYPELOC_IMPL(VariableArray, ArrayType)
+DEFAULT_TYPELOC_IMPL(DependentSizedArray, ArrayType)
+DEFAULT_TYPELOC_IMPL(DependentSizedExtVector, Type)
+DEFAULT_TYPELOC_IMPL(Vector, Type)
+DEFAULT_TYPELOC_IMPL(ExtVector, VectorType)
+DEFAULT_TYPELOC_IMPL(FunctionProto, FunctionType)
+DEFAULT_TYPELOC_IMPL(FunctionNoProto, FunctionType)
+DEFAULT_TYPELOC_IMPL(Record, TagType)
+DEFAULT_TYPELOC_IMPL(Enum, TagType)
+DEFAULT_TYPELOC_IMPL(SubstTemplateTypeParm, Type)
+DEFAULT_TYPELOC_IMPL(SubstTemplateTypeParmPack, Type)
+DEFAULT_TYPELOC_IMPL(Auto, Type)
+
+bool CursorVisitor::VisitCXXRecordDecl(CXXRecordDecl *D) {
+ // Visit the nested-name-specifier, if present.
+ if (NestedNameSpecifierLoc QualifierLoc = D->getQualifierLoc())
+ if (VisitNestedNameSpecifierLoc(QualifierLoc))
+ return true;
+
+ if (D->isCompleteDefinition()) {
+ for (CXXRecordDecl::base_class_iterator I = D->bases_begin(),
+ E = D->bases_end(); I != E; ++I) {
+ if (Visit(cxcursor::MakeCursorCXXBaseSpecifier(I, TU)))
+ return true;
+ }
+ }
+
+ return VisitTagDecl(D);
+}
+
+bool CursorVisitor::VisitAttributes(Decl *D) {
+ for (AttrVec::const_iterator i = D->attr_begin(), e = D->attr_end();
+ i != e; ++i)
+ if (Visit(MakeCXCursor(*i, D, TU)))
+ return true;
+
+ return false;
+}
+
+//===----------------------------------------------------------------------===//
+// Data-recursive visitor methods.
+//===----------------------------------------------------------------------===//
+
+namespace {
+#define DEF_JOB(NAME, DATA, KIND)\
+class NAME : public VisitorJob {\
+public:\
+ NAME(DATA *d, CXCursor parent) : VisitorJob(parent, VisitorJob::KIND, d) {} \
+ static bool classof(const VisitorJob *VJ) { return VJ->getKind() == KIND; }\
+ DATA *get() const { return static_cast<DATA*>(data[0]); }\
+};
+
+DEF_JOB(StmtVisit, Stmt, StmtVisitKind)
+DEF_JOB(MemberExprParts, MemberExpr, MemberExprPartsKind)
+DEF_JOB(DeclRefExprParts, DeclRefExpr, DeclRefExprPartsKind)
+DEF_JOB(OverloadExprParts, OverloadExpr, OverloadExprPartsKind)
+DEF_JOB(ExplicitTemplateArgsVisit, ASTTemplateArgumentListInfo,
+ ExplicitTemplateArgsVisitKind)
+DEF_JOB(SizeOfPackExprParts, SizeOfPackExpr, SizeOfPackExprPartsKind)
+DEF_JOB(LambdaExprParts, LambdaExpr, LambdaExprPartsKind)
+DEF_JOB(PostChildrenVisit, void, PostChildrenVisitKind)
+#undef DEF_JOB
+
+class DeclVisit : public VisitorJob {
+public:
+ DeclVisit(Decl *d, CXCursor parent, bool isFirst) :
+ VisitorJob(parent, VisitorJob::DeclVisitKind,
+ d, isFirst ? (void*) 1 : (void*) 0) {}
+ static bool classof(const VisitorJob *VJ) {
+ return VJ->getKind() == DeclVisitKind;
+ }
+ Decl *get() const { return static_cast<Decl*>(data[0]); }
+ bool isFirst() const { return data[1] ? true : false; }
+};
+class TypeLocVisit : public VisitorJob {
+public:
+ TypeLocVisit(TypeLoc tl, CXCursor parent) :
+ VisitorJob(parent, VisitorJob::TypeLocVisitKind,
+ tl.getType().getAsOpaquePtr(), tl.getOpaqueData()) {}
+
+ static bool classof(const VisitorJob *VJ) {
+ return VJ->getKind() == TypeLocVisitKind;
+ }
+
+ TypeLoc get() const {
+ QualType T = QualType::getFromOpaquePtr(data[0]);
+ return TypeLoc(T, data[1]);
+ }
+};
+
+class LabelRefVisit : public VisitorJob {
+public:
+ LabelRefVisit(LabelDecl *LD, SourceLocation labelLoc, CXCursor parent)
+ : VisitorJob(parent, VisitorJob::LabelRefVisitKind, LD,
+ labelLoc.getPtrEncoding()) {}
+
+ static bool classof(const VisitorJob *VJ) {
+ return VJ->getKind() == VisitorJob::LabelRefVisitKind;
+ }
+ LabelDecl *get() const { return static_cast<LabelDecl*>(data[0]); }
+ SourceLocation getLoc() const {
+ return SourceLocation::getFromPtrEncoding(data[1]); }
+};
+
+class NestedNameSpecifierLocVisit : public VisitorJob {
+public:
+ NestedNameSpecifierLocVisit(NestedNameSpecifierLoc Qualifier, CXCursor parent)
+ : VisitorJob(parent, VisitorJob::NestedNameSpecifierLocVisitKind,
+ Qualifier.getNestedNameSpecifier(),
+ Qualifier.getOpaqueData()) { }
+
+ static bool classof(const VisitorJob *VJ) {
+ return VJ->getKind() == VisitorJob::NestedNameSpecifierLocVisitKind;
+ }
+
+ NestedNameSpecifierLoc get() const {
+ return NestedNameSpecifierLoc(static_cast<NestedNameSpecifier*>(data[0]),
+ data[1]);
+ }
+};
+
+class DeclarationNameInfoVisit : public VisitorJob {
+public:
+ DeclarationNameInfoVisit(Stmt *S, CXCursor parent)
+ : VisitorJob(parent, VisitorJob::DeclarationNameInfoVisitKind, S) {}
+ static bool classof(const VisitorJob *VJ) {
+ return VJ->getKind() == VisitorJob::DeclarationNameInfoVisitKind;
+ }
+ DeclarationNameInfo get() const {
+ Stmt *S = static_cast<Stmt*>(data[0]);
+ switch (S->getStmtClass()) {
+ default:
+ llvm_unreachable("Unhandled Stmt");
+ case clang::Stmt::MSDependentExistsStmtClass:
+ return cast<MSDependentExistsStmt>(S)->getNameInfo();
+ case Stmt::CXXDependentScopeMemberExprClass:
+ return cast<CXXDependentScopeMemberExpr>(S)->getMemberNameInfo();
+ case Stmt::DependentScopeDeclRefExprClass:
+ return cast<DependentScopeDeclRefExpr>(S)->getNameInfo();
+ }
+ }
+};
+class MemberRefVisit : public VisitorJob {
+public:
+ MemberRefVisit(FieldDecl *D, SourceLocation L, CXCursor parent)
+ : VisitorJob(parent, VisitorJob::MemberRefVisitKind, D,
+ L.getPtrEncoding()) {}
+ static bool classof(const VisitorJob *VJ) {
+ return VJ->getKind() == VisitorJob::MemberRefVisitKind;
+ }
+ FieldDecl *get() const {
+ return static_cast<FieldDecl*>(data[0]);
+ }
+ SourceLocation getLoc() const {
+ return SourceLocation::getFromRawEncoding((unsigned)(uintptr_t) data[1]);
+ }
+};
+class EnqueueVisitor : public StmtVisitor<EnqueueVisitor, void> {
+ VisitorWorkList &WL;
+ CXCursor Parent;
+public:
+ EnqueueVisitor(VisitorWorkList &wl, CXCursor parent)
+ : WL(wl), Parent(parent) {}
+
+ void VisitAddrLabelExpr(AddrLabelExpr *E);
+ void VisitBlockExpr(BlockExpr *B);
+ void VisitCompoundLiteralExpr(CompoundLiteralExpr *E);
+ void VisitCompoundStmt(CompoundStmt *S);
+ void VisitCXXDefaultArgExpr(CXXDefaultArgExpr *E) { /* Do nothing. */ }
+ void VisitMSDependentExistsStmt(MSDependentExistsStmt *S);
+ void VisitCXXDependentScopeMemberExpr(CXXDependentScopeMemberExpr *E);
+ void VisitCXXNewExpr(CXXNewExpr *E);
+ void VisitCXXScalarValueInitExpr(CXXScalarValueInitExpr *E);
+ void VisitCXXOperatorCallExpr(CXXOperatorCallExpr *E);
+ void VisitCXXPseudoDestructorExpr(CXXPseudoDestructorExpr *E);
+ void VisitCXXTemporaryObjectExpr(CXXTemporaryObjectExpr *E);
+ void VisitCXXTypeidExpr(CXXTypeidExpr *E);
+ void VisitCXXUnresolvedConstructExpr(CXXUnresolvedConstructExpr *E);
+ void VisitCXXUuidofExpr(CXXUuidofExpr *E);
+ void VisitCXXCatchStmt(CXXCatchStmt *S);
+ void VisitDeclRefExpr(DeclRefExpr *D);
+ void VisitDeclStmt(DeclStmt *S);
+ void VisitDependentScopeDeclRefExpr(DependentScopeDeclRefExpr *E);
+ void VisitDesignatedInitExpr(DesignatedInitExpr *E);
+ void VisitExplicitCastExpr(ExplicitCastExpr *E);
+ void VisitForStmt(ForStmt *FS);
+ void VisitGotoStmt(GotoStmt *GS);
+ void VisitIfStmt(IfStmt *If);
+ void VisitInitListExpr(InitListExpr *IE);
+ void VisitMemberExpr(MemberExpr *M);
+ void VisitOffsetOfExpr(OffsetOfExpr *E);
+ void VisitObjCEncodeExpr(ObjCEncodeExpr *E);
+ void VisitObjCMessageExpr(ObjCMessageExpr *M);
+ void VisitOverloadExpr(OverloadExpr *E);
+ void VisitUnaryExprOrTypeTraitExpr(UnaryExprOrTypeTraitExpr *E);
+ void VisitStmt(Stmt *S);
+ void VisitSwitchStmt(SwitchStmt *S);
+ void VisitWhileStmt(WhileStmt *W);
+ void VisitUnaryTypeTraitExpr(UnaryTypeTraitExpr *E);
+ void VisitBinaryTypeTraitExpr(BinaryTypeTraitExpr *E);
+ void VisitTypeTraitExpr(TypeTraitExpr *E);
+ void VisitArrayTypeTraitExpr(ArrayTypeTraitExpr *E);
+ void VisitExpressionTraitExpr(ExpressionTraitExpr *E);
+ void VisitUnresolvedMemberExpr(UnresolvedMemberExpr *U);
+ void VisitVAArgExpr(VAArgExpr *E);
+ void VisitSizeOfPackExpr(SizeOfPackExpr *E);
+ void VisitPseudoObjectExpr(PseudoObjectExpr *E);
+ void VisitOpaqueValueExpr(OpaqueValueExpr *E);
+ void VisitLambdaExpr(LambdaExpr *E);
+
+private:
+ void AddDeclarationNameInfo(Stmt *S);
+ void AddNestedNameSpecifierLoc(NestedNameSpecifierLoc Qualifier);
+ void AddExplicitTemplateArgs(const ASTTemplateArgumentListInfo *A);
+ void AddMemberRef(FieldDecl *D, SourceLocation L);
+ void AddStmt(Stmt *S);
+ void AddDecl(Decl *D, bool isFirst = true);
+ void AddTypeLoc(TypeSourceInfo *TI);
+ void EnqueueChildren(Stmt *S);
+};
+} // end anonyous namespace
+
+void EnqueueVisitor::AddDeclarationNameInfo(Stmt *S) {
+ // 'S' should always be non-null, since it comes from the
+ // statement we are visiting.
+ WL.push_back(DeclarationNameInfoVisit(S, Parent));
+}
+
+void
+EnqueueVisitor::AddNestedNameSpecifierLoc(NestedNameSpecifierLoc Qualifier) {
+ if (Qualifier)
+ WL.push_back(NestedNameSpecifierLocVisit(Qualifier, Parent));
+}
+
+void EnqueueVisitor::AddStmt(Stmt *S) {
+ if (S)
+ WL.push_back(StmtVisit(S, Parent));
+}
+void EnqueueVisitor::AddDecl(Decl *D, bool isFirst) {
+ if (D)
+ WL.push_back(DeclVisit(D, Parent, isFirst));
+}
+void EnqueueVisitor::
+ AddExplicitTemplateArgs(const ASTTemplateArgumentListInfo *A) {
+ if (A)
+ WL.push_back(ExplicitTemplateArgsVisit(
+ const_cast<ASTTemplateArgumentListInfo*>(A), Parent));
+}
+void EnqueueVisitor::AddMemberRef(FieldDecl *D, SourceLocation L) {
+ if (D)
+ WL.push_back(MemberRefVisit(D, L, Parent));
+}
+void EnqueueVisitor::AddTypeLoc(TypeSourceInfo *TI) {
+ if (TI)
+ WL.push_back(TypeLocVisit(TI->getTypeLoc(), Parent));
+ }
+void EnqueueVisitor::EnqueueChildren(Stmt *S) {
+ unsigned size = WL.size();
+ for (Stmt::child_range Child = S->children(); Child; ++Child) {
+ AddStmt(*Child);
+ }
+ if (size == WL.size())
+ return;
+ // Now reverse the entries we just added. This will match the DFS
+ // ordering performed by the worklist.
+ VisitorWorkList::iterator I = WL.begin() + size, E = WL.end();
+ std::reverse(I, E);
+}
+void EnqueueVisitor::VisitAddrLabelExpr(AddrLabelExpr *E) {
+ WL.push_back(LabelRefVisit(E->getLabel(), E->getLabelLoc(), Parent));
+}
+void EnqueueVisitor::VisitBlockExpr(BlockExpr *B) {
+ AddDecl(B->getBlockDecl());
+}
+void EnqueueVisitor::VisitCompoundLiteralExpr(CompoundLiteralExpr *E) {
+ EnqueueChildren(E);
+ AddTypeLoc(E->getTypeSourceInfo());
+}
+void EnqueueVisitor::VisitCompoundStmt(CompoundStmt *S) {
+ for (CompoundStmt::reverse_body_iterator I = S->body_rbegin(),
+ E = S->body_rend(); I != E; ++I) {
+ AddStmt(*I);
+ }
+}
+void EnqueueVisitor::
+VisitMSDependentExistsStmt(MSDependentExistsStmt *S) {
+ AddStmt(S->getSubStmt());
+ AddDeclarationNameInfo(S);
+ if (NestedNameSpecifierLoc QualifierLoc = S->getQualifierLoc())
+ AddNestedNameSpecifierLoc(QualifierLoc);
+}
+
+void EnqueueVisitor::
+VisitCXXDependentScopeMemberExpr(CXXDependentScopeMemberExpr *E) {
+ AddExplicitTemplateArgs(E->getOptionalExplicitTemplateArgs());
+ AddDeclarationNameInfo(E);
+ if (NestedNameSpecifierLoc QualifierLoc = E->getQualifierLoc())
+ AddNestedNameSpecifierLoc(QualifierLoc);
+ if (!E->isImplicitAccess())
+ AddStmt(E->getBase());
+}
+void EnqueueVisitor::VisitCXXNewExpr(CXXNewExpr *E) {
+ // Enqueue the initializer , if any.
+ AddStmt(E->getInitializer());
+ // Enqueue the array size, if any.
+ AddStmt(E->getArraySize());
+ // Enqueue the allocated type.
+ AddTypeLoc(E->getAllocatedTypeSourceInfo());
+ // Enqueue the placement arguments.
+ for (unsigned I = E->getNumPlacementArgs(); I > 0; --I)
+ AddStmt(E->getPlacementArg(I-1));
+}
+void EnqueueVisitor::VisitCXXOperatorCallExpr(CXXOperatorCallExpr *CE) {
+ for (unsigned I = CE->getNumArgs(); I > 1 /* Yes, this is 1 */; --I)
+ AddStmt(CE->getArg(I-1));
+ AddStmt(CE->getCallee());
+ AddStmt(CE->getArg(0));
+}
+void EnqueueVisitor::VisitCXXPseudoDestructorExpr(CXXPseudoDestructorExpr *E) {
+ // Visit the name of the type being destroyed.
+ AddTypeLoc(E->getDestroyedTypeInfo());
+ // Visit the scope type that looks disturbingly like the nested-name-specifier
+ // but isn't.
+ AddTypeLoc(E->getScopeTypeInfo());
+ // Visit the nested-name-specifier.
+ if (NestedNameSpecifierLoc QualifierLoc = E->getQualifierLoc())
+ AddNestedNameSpecifierLoc(QualifierLoc);
+ // Visit base expression.
+ AddStmt(E->getBase());
+}
+void EnqueueVisitor::VisitCXXScalarValueInitExpr(CXXScalarValueInitExpr *E) {
+ AddTypeLoc(E->getTypeSourceInfo());
+}
+void EnqueueVisitor::VisitCXXTemporaryObjectExpr(CXXTemporaryObjectExpr *E) {
+ EnqueueChildren(E);
+ AddTypeLoc(E->getTypeSourceInfo());
+}
+void EnqueueVisitor::VisitCXXTypeidExpr(CXXTypeidExpr *E) {
+ EnqueueChildren(E);
+ if (E->isTypeOperand())
+ AddTypeLoc(E->getTypeOperandSourceInfo());
+}
+
+void EnqueueVisitor::VisitCXXUnresolvedConstructExpr(CXXUnresolvedConstructExpr
+ *E) {
+ EnqueueChildren(E);
+ AddTypeLoc(E->getTypeSourceInfo());
+}
+void EnqueueVisitor::VisitCXXUuidofExpr(CXXUuidofExpr *E) {
+ EnqueueChildren(E);
+ if (E->isTypeOperand())
+ AddTypeLoc(E->getTypeOperandSourceInfo());
+}
+
+void EnqueueVisitor::VisitCXXCatchStmt(CXXCatchStmt *S) {
+ EnqueueChildren(S);
+ AddDecl(S->getExceptionDecl());
+}
+
+void EnqueueVisitor::VisitDeclRefExpr(DeclRefExpr *DR) {
+ if (DR->hasExplicitTemplateArgs()) {
+ AddExplicitTemplateArgs(&DR->getExplicitTemplateArgs());
+ }
+ WL.push_back(DeclRefExprParts(DR, Parent));
+}
+void EnqueueVisitor::VisitDependentScopeDeclRefExpr(DependentScopeDeclRefExpr *E) {
+ AddExplicitTemplateArgs(E->getOptionalExplicitTemplateArgs());
+ AddDeclarationNameInfo(E);
+ AddNestedNameSpecifierLoc(E->getQualifierLoc());
+}
+void EnqueueVisitor::VisitDeclStmt(DeclStmt *S) {
+ unsigned size = WL.size();
+ bool isFirst = true;
+ for (DeclStmt::decl_iterator D = S->decl_begin(), DEnd = S->decl_end();
+ D != DEnd; ++D) {
+ AddDecl(*D, isFirst);
+ isFirst = false;
+ }
+ if (size == WL.size())
+ return;
+ // Now reverse the entries we just added. This will match the DFS
+ // ordering performed by the worklist.
+ VisitorWorkList::iterator I = WL.begin() + size, E = WL.end();
+ std::reverse(I, E);
+}
+void EnqueueVisitor::VisitDesignatedInitExpr(DesignatedInitExpr *E) {
+ AddStmt(E->getInit());
+ typedef DesignatedInitExpr::Designator Designator;
+ for (DesignatedInitExpr::reverse_designators_iterator
+ D = E->designators_rbegin(), DEnd = E->designators_rend();
+ D != DEnd; ++D) {
+ if (D->isFieldDesignator()) {
+ if (FieldDecl *Field = D->getField())
+ AddMemberRef(Field, D->getFieldLoc());
+ continue;
+ }
+ if (D->isArrayDesignator()) {
+ AddStmt(E->getArrayIndex(*D));
+ continue;
+ }
+ assert(D->isArrayRangeDesignator() && "Unknown designator kind");
+ AddStmt(E->getArrayRangeEnd(*D));
+ AddStmt(E->getArrayRangeStart(*D));
+ }
+}
+void EnqueueVisitor::VisitExplicitCastExpr(ExplicitCastExpr *E) {
+ EnqueueChildren(E);
+ AddTypeLoc(E->getTypeInfoAsWritten());
+}
+void EnqueueVisitor::VisitForStmt(ForStmt *FS) {
+ AddStmt(FS->getBody());
+ AddStmt(FS->getInc());
+ AddStmt(FS->getCond());
+ AddDecl(FS->getConditionVariable());
+ AddStmt(FS->getInit());
+}
+void EnqueueVisitor::VisitGotoStmt(GotoStmt *GS) {
+ WL.push_back(LabelRefVisit(GS->getLabel(), GS->getLabelLoc(), Parent));
+}
+void EnqueueVisitor::VisitIfStmt(IfStmt *If) {
+ AddStmt(If->getElse());
+ AddStmt(If->getThen());
+ AddStmt(If->getCond());
+ AddDecl(If->getConditionVariable());
+}
+void EnqueueVisitor::VisitInitListExpr(InitListExpr *IE) {
+ // We care about the syntactic form of the initializer list, only.
+ if (InitListExpr *Syntactic = IE->getSyntacticForm())
+ IE = Syntactic;
+ EnqueueChildren(IE);
+}
+void EnqueueVisitor::VisitMemberExpr(MemberExpr *M) {
+ WL.push_back(MemberExprParts(M, Parent));
+
+ // If the base of the member access expression is an implicit 'this', don't
+ // visit it.
+ // FIXME: If we ever want to show these implicit accesses, this will be
+ // unfortunate. However, clang_getCursor() relies on this behavior.
+ if (!M->isImplicitAccess())
+ AddStmt(M->getBase());
+}
+void EnqueueVisitor::VisitObjCEncodeExpr(ObjCEncodeExpr *E) {
+ AddTypeLoc(E->getEncodedTypeSourceInfo());
+}
+void EnqueueVisitor::VisitObjCMessageExpr(ObjCMessageExpr *M) {
+ EnqueueChildren(M);
+ AddTypeLoc(M->getClassReceiverTypeInfo());
+}
+void EnqueueVisitor::VisitOffsetOfExpr(OffsetOfExpr *E) {
+ // Visit the components of the offsetof expression.
+ for (unsigned N = E->getNumComponents(), I = N; I > 0; --I) {
+ typedef OffsetOfExpr::OffsetOfNode OffsetOfNode;
+ const OffsetOfNode &Node = E->getComponent(I-1);
+ switch (Node.getKind()) {
+ case OffsetOfNode::Array:
+ AddStmt(E->getIndexExpr(Node.getArrayExprIndex()));
+ break;
+ case OffsetOfNode::Field:
+ AddMemberRef(Node.getField(), Node.getSourceRange().getEnd());
+ break;
+ case OffsetOfNode::Identifier:
+ case OffsetOfNode::Base:
+ continue;
+ }
+ }
+ // Visit the type into which we're computing the offset.
+ AddTypeLoc(E->getTypeSourceInfo());
+}
+void EnqueueVisitor::VisitOverloadExpr(OverloadExpr *E) {
+ AddExplicitTemplateArgs(E->getOptionalExplicitTemplateArgs());
+ WL.push_back(OverloadExprParts(E, Parent));
+}
+void EnqueueVisitor::VisitUnaryExprOrTypeTraitExpr(
+ UnaryExprOrTypeTraitExpr *E) {
+ EnqueueChildren(E);
+ if (E->isArgumentType())
+ AddTypeLoc(E->getArgumentTypeInfo());
+}
+void EnqueueVisitor::VisitStmt(Stmt *S) {
+ EnqueueChildren(S);
+}
+void EnqueueVisitor::VisitSwitchStmt(SwitchStmt *S) {
+ AddStmt(S->getBody());
+ AddStmt(S->getCond());
+ AddDecl(S->getConditionVariable());
+}
+
+void EnqueueVisitor::VisitWhileStmt(WhileStmt *W) {
+ AddStmt(W->getBody());
+ AddStmt(W->getCond());
+ AddDecl(W->getConditionVariable());
+}
+
+void EnqueueVisitor::VisitUnaryTypeTraitExpr(UnaryTypeTraitExpr *E) {
+ AddTypeLoc(E->getQueriedTypeSourceInfo());
+}
+
+void EnqueueVisitor::VisitBinaryTypeTraitExpr(BinaryTypeTraitExpr *E) {
+ AddTypeLoc(E->getRhsTypeSourceInfo());
+ AddTypeLoc(E->getLhsTypeSourceInfo());
+}
+
+void EnqueueVisitor::VisitTypeTraitExpr(TypeTraitExpr *E) {
+ for (unsigned I = E->getNumArgs(); I > 0; --I)
+ AddTypeLoc(E->getArg(I-1));
+}
+
+void EnqueueVisitor::VisitArrayTypeTraitExpr(ArrayTypeTraitExpr *E) {
+ AddTypeLoc(E->getQueriedTypeSourceInfo());
+}
+
+void EnqueueVisitor::VisitExpressionTraitExpr(ExpressionTraitExpr *E) {
+ EnqueueChildren(E);
+}
+
+void EnqueueVisitor::VisitUnresolvedMemberExpr(UnresolvedMemberExpr *U) {
+ VisitOverloadExpr(U);
+ if (!U->isImplicitAccess())
+ AddStmt(U->getBase());
+}
+void EnqueueVisitor::VisitVAArgExpr(VAArgExpr *E) {
+ AddStmt(E->getSubExpr());
+ AddTypeLoc(E->getWrittenTypeInfo());
+}
+void EnqueueVisitor::VisitSizeOfPackExpr(SizeOfPackExpr *E) {
+ WL.push_back(SizeOfPackExprParts(E, Parent));
+}
+void EnqueueVisitor::VisitOpaqueValueExpr(OpaqueValueExpr *E) {
+ // If the opaque value has a source expression, just transparently
+ // visit that. This is useful for (e.g.) pseudo-object expressions.
+ if (Expr *SourceExpr = E->getSourceExpr())
+ return Visit(SourceExpr);
+}
+void EnqueueVisitor::VisitLambdaExpr(LambdaExpr *E) {
+ AddStmt(E->getBody());
+ WL.push_back(LambdaExprParts(E, Parent));
+}
+void EnqueueVisitor::VisitPseudoObjectExpr(PseudoObjectExpr *E) {
+ // Treat the expression like its syntactic form.
+ Visit(E->getSyntacticForm());
+}
+
+void CursorVisitor::EnqueueWorkList(VisitorWorkList &WL, Stmt *S) {
+ EnqueueVisitor(WL, MakeCXCursor(S, StmtParent, TU,RegionOfInterest)).Visit(S);
+}
+
+bool CursorVisitor::IsInRegionOfInterest(CXCursor C) {
+ if (RegionOfInterest.isValid()) {
+ SourceRange Range = getRawCursorExtent(C);
+ if (Range.isInvalid() || CompareRegionOfInterest(Range))
+ return false;
+ }
+ return true;
+}
+
+bool CursorVisitor::RunVisitorWorkList(VisitorWorkList &WL) {
+ while (!WL.empty()) {
+ // Dequeue the worklist item.
+ VisitorJob LI = WL.back();
+ WL.pop_back();
+
+ // Set the Parent field, then back to its old value once we're done.
+ SetParentRAII SetParent(Parent, StmtParent, LI.getParent());
+
+ switch (LI.getKind()) {
+ case VisitorJob::DeclVisitKind: {
+ Decl *D = cast<DeclVisit>(&LI)->get();
+ if (!D)
+ continue;
+
+ // For now, perform default visitation for Decls.
+ if (Visit(MakeCXCursor(D, TU, RegionOfInterest,
+ cast<DeclVisit>(&LI)->isFirst())))
+ return true;
+
+ continue;
+ }
+ case VisitorJob::ExplicitTemplateArgsVisitKind: {
+ const ASTTemplateArgumentListInfo *ArgList =
+ cast<ExplicitTemplateArgsVisit>(&LI)->get();
+ for (const TemplateArgumentLoc *Arg = ArgList->getTemplateArgs(),
+ *ArgEnd = Arg + ArgList->NumTemplateArgs;
+ Arg != ArgEnd; ++Arg) {
+ if (VisitTemplateArgumentLoc(*Arg))
+ return true;
+ }
+ continue;
+ }
+ case VisitorJob::TypeLocVisitKind: {
+ // Perform default visitation for TypeLocs.
+ if (Visit(cast<TypeLocVisit>(&LI)->get()))
+ return true;
+ continue;
+ }
+ case VisitorJob::LabelRefVisitKind: {
+ LabelDecl *LS = cast<LabelRefVisit>(&LI)->get();
+ if (LabelStmt *stmt = LS->getStmt()) {
+ if (Visit(MakeCursorLabelRef(stmt, cast<LabelRefVisit>(&LI)->getLoc(),
+ TU))) {
+ return true;
+ }
+ }
+ continue;
+ }
+
+ case VisitorJob::NestedNameSpecifierLocVisitKind: {
+ NestedNameSpecifierLocVisit *V = cast<NestedNameSpecifierLocVisit>(&LI);
+ if (VisitNestedNameSpecifierLoc(V->get()))
+ return true;
+ continue;
+ }
+
+ case VisitorJob::DeclarationNameInfoVisitKind: {
+ if (VisitDeclarationNameInfo(cast<DeclarationNameInfoVisit>(&LI)
+ ->get()))
+ return true;
+ continue;
+ }
+ case VisitorJob::MemberRefVisitKind: {
+ MemberRefVisit *V = cast<MemberRefVisit>(&LI);
+ if (Visit(MakeCursorMemberRef(V->get(), V->getLoc(), TU)))
+ return true;
+ continue;
+ }
+ case VisitorJob::StmtVisitKind: {
+ Stmt *S = cast<StmtVisit>(&LI)->get();
+ if (!S)
+ continue;
+
+ // Update the current cursor.
+ CXCursor Cursor = MakeCXCursor(S, StmtParent, TU, RegionOfInterest);
+ if (!IsInRegionOfInterest(Cursor))
+ continue;
+ switch (Visitor(Cursor, Parent, ClientData)) {
+ case CXChildVisit_Break: return true;
+ case CXChildVisit_Continue: break;
+ case CXChildVisit_Recurse:
+ if (PostChildrenVisitor)
+ WL.push_back(PostChildrenVisit(0, Cursor));
+ EnqueueWorkList(WL, S);
+ break;
+ }
+ continue;
+ }
+ case VisitorJob::MemberExprPartsKind: {
+ // Handle the other pieces in the MemberExpr besides the base.
+ MemberExpr *M = cast<MemberExprParts>(&LI)->get();
+
+ // Visit the nested-name-specifier
+ if (NestedNameSpecifierLoc QualifierLoc = M->getQualifierLoc())
+ if (VisitNestedNameSpecifierLoc(QualifierLoc))
+ return true;
+
+ // Visit the declaration name.
+ if (VisitDeclarationNameInfo(M->getMemberNameInfo()))
+ return true;
+
+ // Visit the explicitly-specified template arguments, if any.
+ if (M->hasExplicitTemplateArgs()) {
+ for (const TemplateArgumentLoc *Arg = M->getTemplateArgs(),
+ *ArgEnd = Arg + M->getNumTemplateArgs();
+ Arg != ArgEnd; ++Arg) {
+ if (VisitTemplateArgumentLoc(*Arg))
+ return true;
+ }
+ }
+ continue;
+ }
+ case VisitorJob::DeclRefExprPartsKind: {
+ DeclRefExpr *DR = cast<DeclRefExprParts>(&LI)->get();
+ // Visit nested-name-specifier, if present.
+ if (NestedNameSpecifierLoc QualifierLoc = DR->getQualifierLoc())
+ if (VisitNestedNameSpecifierLoc(QualifierLoc))
+ return true;
+ // Visit declaration name.
+ if (VisitDeclarationNameInfo(DR->getNameInfo()))
+ return true;
+ continue;
+ }
+ case VisitorJob::OverloadExprPartsKind: {
+ OverloadExpr *O = cast<OverloadExprParts>(&LI)->get();
+ // Visit the nested-name-specifier.
+ if (NestedNameSpecifierLoc QualifierLoc = O->getQualifierLoc())
+ if (VisitNestedNameSpecifierLoc(QualifierLoc))
+ return true;
+ // Visit the declaration name.
+ if (VisitDeclarationNameInfo(O->getNameInfo()))
+ return true;
+ // Visit the overloaded declaration reference.
+ if (Visit(MakeCursorOverloadedDeclRef(O, TU)))
+ return true;
+ continue;
+ }
+ case VisitorJob::SizeOfPackExprPartsKind: {
+ SizeOfPackExpr *E = cast<SizeOfPackExprParts>(&LI)->get();
+ NamedDecl *Pack = E->getPack();
+ if (isa<TemplateTypeParmDecl>(Pack)) {
+ if (Visit(MakeCursorTypeRef(cast<TemplateTypeParmDecl>(Pack),
+ E->getPackLoc(), TU)))
+ return true;
+
+ continue;
+ }
+
+ if (isa<TemplateTemplateParmDecl>(Pack)) {
+ if (Visit(MakeCursorTemplateRef(cast<TemplateTemplateParmDecl>(Pack),
+ E->getPackLoc(), TU)))
+ return true;
+
+ continue;
+ }
+
+ // Non-type template parameter packs and function parameter packs are
+ // treated like DeclRefExpr cursors.
+ continue;
+ }
+
+ case VisitorJob::LambdaExprPartsKind: {
+ // Visit captures.
+ LambdaExpr *E = cast<LambdaExprParts>(&LI)->get();
+ for (LambdaExpr::capture_iterator C = E->explicit_capture_begin(),
+ CEnd = E->explicit_capture_end();
+ C != CEnd; ++C) {
+ if (C->capturesThis())
+ continue;
+
+ if (Visit(MakeCursorVariableRef(C->getCapturedVar(),
+ C->getLocation(),
+ TU)))
+ return true;
+ }
+
+ // Visit parameters and return type, if present.
+ if (E->hasExplicitParameters() || E->hasExplicitResultType()) {
+ TypeLoc TL = E->getCallOperator()->getTypeSourceInfo()->getTypeLoc();
+ if (E->hasExplicitParameters() && E->hasExplicitResultType()) {
+ // Visit the whole type.
+ if (Visit(TL))
+ return true;
+ } else if (isa<FunctionProtoTypeLoc>(TL)) {
+ FunctionProtoTypeLoc Proto = cast<FunctionProtoTypeLoc>(TL);
+ if (E->hasExplicitParameters()) {
+ // Visit parameters.
+ for (unsigned I = 0, N = Proto.getNumArgs(); I != N; ++I)
+ if (Visit(MakeCXCursor(Proto.getArg(I), TU)))
+ return true;
+ } else {
+ // Visit result type.
+ if (Visit(Proto.getResultLoc()))
+ return true;
+ }
+ }
+ }
+ break;
+ }
+
+ case VisitorJob::PostChildrenVisitKind:
+ if (PostChildrenVisitor(Parent, ClientData))
+ return true;
+ break;
+ }
+ }
+ return false;
+}
+
+bool CursorVisitor::Visit(Stmt *S) {
+ VisitorWorkList *WL = 0;
+ if (!WorkListFreeList.empty()) {
+ WL = WorkListFreeList.back();
+ WL->clear();
+ WorkListFreeList.pop_back();
+ }
+ else {
+ WL = new VisitorWorkList();
+ WorkListCache.push_back(WL);
+ }
+ EnqueueWorkList(*WL, S);
+ bool result = RunVisitorWorkList(*WL);
+ WorkListFreeList.push_back(WL);
+ return result;
+}
+
+namespace {
+typedef llvm::SmallVector<SourceRange, 4> RefNamePieces;
+RefNamePieces buildPieces(unsigned NameFlags, bool IsMemberRefExpr,
+ const DeclarationNameInfo &NI,
+ const SourceRange &QLoc,
+ const ASTTemplateArgumentListInfo *TemplateArgs = 0){
+ const bool WantQualifier = NameFlags & CXNameRange_WantQualifier;
+ const bool WantTemplateArgs = NameFlags & CXNameRange_WantTemplateArgs;
+ const bool WantSinglePiece = NameFlags & CXNameRange_WantSinglePiece;
+
+ const DeclarationName::NameKind Kind = NI.getName().getNameKind();
+
+ RefNamePieces Pieces;
+
+ if (WantQualifier && QLoc.isValid())
+ Pieces.push_back(QLoc);
+
+ if (Kind != DeclarationName::CXXOperatorName || IsMemberRefExpr)
+ Pieces.push_back(NI.getLoc());
+
+ if (WantTemplateArgs && TemplateArgs)
+ Pieces.push_back(SourceRange(TemplateArgs->LAngleLoc,
+ TemplateArgs->RAngleLoc));
+
+ if (Kind == DeclarationName::CXXOperatorName) {
+ Pieces.push_back(SourceLocation::getFromRawEncoding(
+ NI.getInfo().CXXOperatorName.BeginOpNameLoc));
+ Pieces.push_back(SourceLocation::getFromRawEncoding(
+ NI.getInfo().CXXOperatorName.EndOpNameLoc));
+ }
+
+ if (WantSinglePiece) {
+ SourceRange R(Pieces.front().getBegin(), Pieces.back().getEnd());
+ Pieces.clear();
+ Pieces.push_back(R);
+ }
+
+ return Pieces;
+}
+}
+
+//===----------------------------------------------------------------------===//
+// Misc. API hooks.
+//===----------------------------------------------------------------------===//
+
+static llvm::sys::Mutex EnableMultithreadingMutex;
+static bool EnabledMultithreading;
+
+static void fatal_error_handler(void *user_data, const std::string& reason) {
+ // Write the result out to stderr avoiding errs() because raw_ostreams can
+ // call report_fatal_error.
+ fprintf(stderr, "LIBCLANG FATAL ERROR: %s\n", reason.c_str());
+ ::abort();
+}
+
+extern "C" {
+CXIndex clang_createIndex(int excludeDeclarationsFromPCH,
+ int displayDiagnostics) {
+ // Disable pretty stack trace functionality, which will otherwise be a very
+ // poor citizen of the world and set up all sorts of signal handlers.
+ llvm::DisablePrettyStackTrace = true;
+
+ // We use crash recovery to make some of our APIs more reliable, implicitly
+ // enable it.
+ llvm::CrashRecoveryContext::Enable();
+
+ // Enable support for multithreading in LLVM.
+ {
+ llvm::sys::ScopedLock L(EnableMultithreadingMutex);
+ if (!EnabledMultithreading) {
+ llvm::install_fatal_error_handler(fatal_error_handler, 0);
+ llvm::llvm_start_multithreaded();
+ EnabledMultithreading = true;
+ }
+ }
+
+ CIndexer *CIdxr = new CIndexer();
+ if (excludeDeclarationsFromPCH)
+ CIdxr->setOnlyLocalDecls();
+ if (displayDiagnostics)
+ CIdxr->setDisplayDiagnostics();
+
+ if (getenv("LIBCLANG_BGPRIO_INDEX"))
+ CIdxr->setCXGlobalOptFlags(CIdxr->getCXGlobalOptFlags() |
+ CXGlobalOpt_ThreadBackgroundPriorityForIndexing);
+ if (getenv("LIBCLANG_BGPRIO_EDIT"))
+ CIdxr->setCXGlobalOptFlags(CIdxr->getCXGlobalOptFlags() |
+ CXGlobalOpt_ThreadBackgroundPriorityForEditing);
+
+ return CIdxr;
+}
+
+void clang_disposeIndex(CXIndex CIdx) {
+ if (CIdx)
+ delete static_cast<CIndexer *>(CIdx);
+}
+
+void clang_CXIndex_setGlobalOptions(CXIndex CIdx, unsigned options) {
+ if (CIdx)
+ static_cast<CIndexer *>(CIdx)->setCXGlobalOptFlags(options);
+}
+
+unsigned clang_CXIndex_getGlobalOptions(CXIndex CIdx) {
+ if (CIdx)
+ return static_cast<CIndexer *>(CIdx)->getCXGlobalOptFlags();
+ return 0;
+}
+
+void clang_toggleCrashRecovery(unsigned isEnabled) {
+ if (isEnabled)
+ llvm::CrashRecoveryContext::Enable();
+ else
+ llvm::CrashRecoveryContext::Disable();
+}
+
+CXTranslationUnit clang_createTranslationUnit(CXIndex CIdx,
+ const char *ast_filename) {
+ if (!CIdx)
+ return 0;
+
+ CIndexer *CXXIdx = static_cast<CIndexer *>(CIdx);
+ FileSystemOptions FileSystemOpts;
+
+ IntrusiveRefCntPtr<DiagnosticsEngine> Diags;
+ ASTUnit *TU = ASTUnit::LoadFromASTFile(ast_filename, Diags, FileSystemOpts,
+ CXXIdx->getOnlyLocalDecls(),
+ 0, 0,
+ /*CaptureDiagnostics=*/true,
+ /*AllowPCHWithCompilerErrors=*/true,
+ /*UserFilesAreVolatile=*/true);
+ return MakeCXTranslationUnit(CXXIdx, TU);
+}
+
+unsigned clang_defaultEditingTranslationUnitOptions() {
+ return CXTranslationUnit_PrecompiledPreamble |
+ CXTranslationUnit_CacheCompletionResults;
+}
+
+CXTranslationUnit
+clang_createTranslationUnitFromSourceFile(CXIndex CIdx,
+ const char *source_filename,
+ int num_command_line_args,
+ const char * const *command_line_args,
+ unsigned num_unsaved_files,
+ struct CXUnsavedFile *unsaved_files) {
+ unsigned Options = CXTranslationUnit_DetailedPreprocessingRecord;
+ return clang_parseTranslationUnit(CIdx, source_filename,
+ command_line_args, num_command_line_args,
+ unsaved_files, num_unsaved_files,
+ Options);
+}
+
+struct ParseTranslationUnitInfo {
+ CXIndex CIdx;
+ const char *source_filename;
+ const char *const *command_line_args;
+ int num_command_line_args;
+ struct CXUnsavedFile *unsaved_files;
+ unsigned num_unsaved_files;
+ unsigned options;
+ CXTranslationUnit result;
+};
+static void clang_parseTranslationUnit_Impl(void *UserData) {
+ ParseTranslationUnitInfo *PTUI =
+ static_cast<ParseTranslationUnitInfo*>(UserData);
+ CXIndex CIdx = PTUI->CIdx;
+ const char *source_filename = PTUI->source_filename;
+ const char * const *command_line_args = PTUI->command_line_args;
+ int num_command_line_args = PTUI->num_command_line_args;
+ struct CXUnsavedFile *unsaved_files = PTUI->unsaved_files;
+ unsigned num_unsaved_files = PTUI->num_unsaved_files;
+ unsigned options = PTUI->options;
+ PTUI->result = 0;
+
+ if (!CIdx)
+ return;
+
+ CIndexer *CXXIdx = static_cast<CIndexer *>(CIdx);
+
+ if (CXXIdx->isOptEnabled(CXGlobalOpt_ThreadBackgroundPriorityForIndexing))
+ setThreadBackgroundPriority();
+
+ bool PrecompilePreamble = options & CXTranslationUnit_PrecompiledPreamble;
+ // FIXME: Add a flag for modules.
+ TranslationUnitKind TUKind
+ = (options & CXTranslationUnit_Incomplete)? TU_Prefix : TU_Complete;
+ bool CacheCodeCompetionResults
+ = options & CXTranslationUnit_CacheCompletionResults;
+ bool IncludeBriefCommentsInCodeCompletion
+ = options & CXTranslationUnit_IncludeBriefCommentsInCodeCompletion;
+ bool SkipFunctionBodies = options & CXTranslationUnit_SkipFunctionBodies;
+ bool ForSerialization = options & CXTranslationUnit_ForSerialization;
+
+ // Configure the diagnostics.
+ IntrusiveRefCntPtr<DiagnosticsEngine>
+ Diags(CompilerInstance::createDiagnostics(new DiagnosticOptions,
+ num_command_line_args,
+ command_line_args));
+
+ // Recover resources if we crash before exiting this function.
+ llvm::CrashRecoveryContextCleanupRegistrar<DiagnosticsEngine,
+ llvm::CrashRecoveryContextReleaseRefCleanup<DiagnosticsEngine> >
+ DiagCleanup(Diags.getPtr());
+
+ OwningPtr<std::vector<ASTUnit::RemappedFile> >
+ RemappedFiles(new std::vector<ASTUnit::RemappedFile>());
+
+ // Recover resources if we crash before exiting this function.
+ llvm::CrashRecoveryContextCleanupRegistrar<
+ std::vector<ASTUnit::RemappedFile> > RemappedCleanup(RemappedFiles.get());
+
+ for (unsigned I = 0; I != num_unsaved_files; ++I) {
+ StringRef Data(unsaved_files[I].Contents, unsaved_files[I].Length);
+ const llvm::MemoryBuffer *Buffer
+ = llvm::MemoryBuffer::getMemBufferCopy(Data, unsaved_files[I].Filename);
+ RemappedFiles->push_back(std::make_pair(unsaved_files[I].Filename,
+ Buffer));
+ }
+
+ OwningPtr<std::vector<const char *> >
+ Args(new std::vector<const char*>());
+
+ // Recover resources if we crash before exiting this method.
+ llvm::CrashRecoveryContextCleanupRegistrar<std::vector<const char*> >
+ ArgsCleanup(Args.get());
+
+ // Since the Clang C library is primarily used by batch tools dealing with
+ // (often very broken) source code, where spell-checking can have a
+ // significant negative impact on performance (particularly when
+ // precompiled headers are involved), we disable it by default.
+ // Only do this if we haven't found a spell-checking-related argument.
+ bool FoundSpellCheckingArgument = false;
+ for (int I = 0; I != num_command_line_args; ++I) {
+ if (strcmp(command_line_args[I], "-fno-spell-checking") == 0 ||
+ strcmp(command_line_args[I], "-fspell-checking") == 0) {
+ FoundSpellCheckingArgument = true;
+ break;
+ }
+ }
+ if (!FoundSpellCheckingArgument)
+ Args->push_back("-fno-spell-checking");
+
+ Args->insert(Args->end(), command_line_args,
+ command_line_args + num_command_line_args);
+
+ // The 'source_filename' argument is optional. If the caller does not
+ // specify it then it is assumed that the source file is specified
+ // in the actual argument list.
+ // Put the source file after command_line_args otherwise if '-x' flag is
+ // present it will be unused.
+ if (source_filename)
+ Args->push_back(source_filename);
+
+ // Do we need the detailed preprocessing record?
+ if (options & CXTranslationUnit_DetailedPreprocessingRecord) {
+ Args->push_back("-Xclang");
+ Args->push_back("-detailed-preprocessing-record");
+ }
+
+ unsigned NumErrors = Diags->getClient()->getNumErrors();
+ OwningPtr<ASTUnit> ErrUnit;
+ OwningPtr<ASTUnit> Unit(
+ ASTUnit::LoadFromCommandLine(Args->size() ? &(*Args)[0] : 0
+ /* vector::data() not portable */,
+ Args->size() ? (&(*Args)[0] + Args->size()) :0,
+ Diags,
+ CXXIdx->getClangResourcesPath(),
+ CXXIdx->getOnlyLocalDecls(),
+ /*CaptureDiagnostics=*/true,
+ RemappedFiles->size() ? &(*RemappedFiles)[0]:0,
+ RemappedFiles->size(),
+ /*RemappedFilesKeepOriginalName=*/true,
+ PrecompilePreamble,
+ TUKind,
+ CacheCodeCompetionResults,
+ IncludeBriefCommentsInCodeCompletion,
+ /*AllowPCHWithCompilerErrors=*/true,
+ SkipFunctionBodies,
+ /*UserFilesAreVolatile=*/true,
+ ForSerialization,
+ &ErrUnit));
+
+ if (NumErrors != Diags->getClient()->getNumErrors()) {
+ // Make sure to check that 'Unit' is non-NULL.
+ if (CXXIdx->getDisplayDiagnostics())
+ printDiagsToStderr(Unit ? Unit.get() : ErrUnit.get());
+ }
+
+ PTUI->result = MakeCXTranslationUnit(CXXIdx, Unit.take());
+}
+CXTranslationUnit clang_parseTranslationUnit(CXIndex CIdx,
+ const char *source_filename,
+ const char * const *command_line_args,
+ int num_command_line_args,
+ struct CXUnsavedFile *unsaved_files,
+ unsigned num_unsaved_files,
+ unsigned options) {
+ ParseTranslationUnitInfo PTUI = { CIdx, source_filename, command_line_args,
+ num_command_line_args, unsaved_files,
+ num_unsaved_files, options, 0 };
+ llvm::CrashRecoveryContext CRC;
+
+ if (!RunSafely(CRC, clang_parseTranslationUnit_Impl, &PTUI)) {
+ fprintf(stderr, "libclang: crash detected during parsing: {\n");
+ fprintf(stderr, " 'source_filename' : '%s'\n", source_filename);
+ fprintf(stderr, " 'command_line_args' : [");
+ for (int i = 0; i != num_command_line_args; ++i) {
+ if (i)
+ fprintf(stderr, ", ");
+ fprintf(stderr, "'%s'", command_line_args[i]);
+ }
+ fprintf(stderr, "],\n");
+ fprintf(stderr, " 'unsaved_files' : [");
+ for (unsigned i = 0; i != num_unsaved_files; ++i) {
+ if (i)
+ fprintf(stderr, ", ");
+ fprintf(stderr, "('%s', '...', %ld)", unsaved_files[i].Filename,
+ unsaved_files[i].Length);
+ }
+ fprintf(stderr, "],\n");
+ fprintf(stderr, " 'options' : %d,\n", options);
+ fprintf(stderr, "}\n");
+
+ return 0;
+ } else if (getenv("LIBCLANG_RESOURCE_USAGE")) {
+ PrintLibclangResourceUsage(PTUI.result);
+ }
+
+ return PTUI.result;
+}
+
+unsigned clang_defaultSaveOptions(CXTranslationUnit TU) {
+ return CXSaveTranslationUnit_None;
+}
+
+namespace {
+
+struct SaveTranslationUnitInfo {
+ CXTranslationUnit TU;
+ const char *FileName;
+ unsigned options;
+ CXSaveError result;
+};
+
+}
+
+static void clang_saveTranslationUnit_Impl(void *UserData) {
+ SaveTranslationUnitInfo *STUI =
+ static_cast<SaveTranslationUnitInfo*>(UserData);
+
+ CIndexer *CXXIdx = (CIndexer*)STUI->TU->CIdx;
+ if (CXXIdx->isOptEnabled(CXGlobalOpt_ThreadBackgroundPriorityForIndexing))
+ setThreadBackgroundPriority();
+
+ bool hadError = static_cast<ASTUnit *>(STUI->TU->TUData)->Save(STUI->FileName);
+ STUI->result = hadError ? CXSaveError_Unknown : CXSaveError_None;
+}
+
+int clang_saveTranslationUnit(CXTranslationUnit TU, const char *FileName,
+ unsigned options) {
+ if (!TU)
+ return CXSaveError_InvalidTU;
+
+ ASTUnit *CXXUnit = static_cast<ASTUnit *>(TU->TUData);
+ ASTUnit::ConcurrencyCheck Check(*CXXUnit);
+ if (!CXXUnit->hasSema())
+ return CXSaveError_InvalidTU;
+
+ SaveTranslationUnitInfo STUI = { TU, FileName, options, CXSaveError_None };
+
+ if (!CXXUnit->getDiagnostics().hasUnrecoverableErrorOccurred() ||
+ getenv("LIBCLANG_NOTHREADS")) {
+ clang_saveTranslationUnit_Impl(&STUI);
+
+ if (getenv("LIBCLANG_RESOURCE_USAGE"))
+ PrintLibclangResourceUsage(TU);
+
+ return STUI.result;
+ }
+
+ // We have an AST that has invalid nodes due to compiler errors.
+ // Use a crash recovery thread for protection.
+
+ llvm::CrashRecoveryContext CRC;
+
+ if (!RunSafely(CRC, clang_saveTranslationUnit_Impl, &STUI)) {
+ fprintf(stderr, "libclang: crash detected during AST saving: {\n");
+ fprintf(stderr, " 'filename' : '%s'\n", FileName);
+ fprintf(stderr, " 'options' : %d,\n", options);
+ fprintf(stderr, "}\n");
+
+ return CXSaveError_Unknown;
+
+ } else if (getenv("LIBCLANG_RESOURCE_USAGE")) {
+ PrintLibclangResourceUsage(TU);
+ }
+
+ return STUI.result;
+}
+
+void clang_disposeTranslationUnit(CXTranslationUnit CTUnit) {
+ if (CTUnit) {
+ // If the translation unit has been marked as unsafe to free, just discard
+ // it.
+ if (static_cast<ASTUnit *>(CTUnit->TUData)->isUnsafeToFree())
+ return;
+
+ delete static_cast<ASTUnit *>(CTUnit->TUData);
+ disposeCXStringPool(CTUnit->StringPool);
+ delete static_cast<CXDiagnosticSetImpl *>(CTUnit->Diagnostics);
+ disposeOverridenCXCursorsPool(CTUnit->OverridenCursorsPool);
+ delete CTUnit;
+ }
+}
+
+unsigned clang_defaultReparseOptions(CXTranslationUnit TU) {
+ return CXReparse_None;
+}
+
+struct ReparseTranslationUnitInfo {
+ CXTranslationUnit TU;
+ unsigned num_unsaved_files;
+ struct CXUnsavedFile *unsaved_files;
+ unsigned options;
+ int result;
+};
+
+static void clang_reparseTranslationUnit_Impl(void *UserData) {
+ ReparseTranslationUnitInfo *RTUI =
+ static_cast<ReparseTranslationUnitInfo*>(UserData);
+ CXTranslationUnit TU = RTUI->TU;
+
+ // Reset the associated diagnostics.
+ delete static_cast<CXDiagnosticSetImpl*>(TU->Diagnostics);
+ TU->Diagnostics = 0;
+
+ unsigned num_unsaved_files = RTUI->num_unsaved_files;
+ struct CXUnsavedFile *unsaved_files = RTUI->unsaved_files;
+ unsigned options = RTUI->options;
+ (void) options;
+ RTUI->result = 1;
+
+ if (!TU)
+ return;
+
+ CIndexer *CXXIdx = (CIndexer*)TU->CIdx;
+ if (CXXIdx->isOptEnabled(CXGlobalOpt_ThreadBackgroundPriorityForEditing))
+ setThreadBackgroundPriority();
+
+ ASTUnit *CXXUnit = static_cast<ASTUnit *>(TU->TUData);
+ ASTUnit::ConcurrencyCheck Check(*CXXUnit);
+
+ OwningPtr<std::vector<ASTUnit::RemappedFile> >
+ RemappedFiles(new std::vector<ASTUnit::RemappedFile>());
+
+ // Recover resources if we crash before exiting this function.
+ llvm::CrashRecoveryContextCleanupRegistrar<
+ std::vector<ASTUnit::RemappedFile> > RemappedCleanup(RemappedFiles.get());
+
+ for (unsigned I = 0; I != num_unsaved_files; ++I) {
+ StringRef Data(unsaved_files[I].Contents, unsaved_files[I].Length);
+ const llvm::MemoryBuffer *Buffer
+ = llvm::MemoryBuffer::getMemBufferCopy(Data, unsaved_files[I].Filename);
+ RemappedFiles->push_back(std::make_pair(unsaved_files[I].Filename,
+ Buffer));
+ }
+
+ if (!CXXUnit->Reparse(RemappedFiles->size() ? &(*RemappedFiles)[0] : 0,
+ RemappedFiles->size()))
+ RTUI->result = 0;
+}
+
+int clang_reparseTranslationUnit(CXTranslationUnit TU,
+ unsigned num_unsaved_files,
+ struct CXUnsavedFile *unsaved_files,
+ unsigned options) {
+ ReparseTranslationUnitInfo RTUI = { TU, num_unsaved_files, unsaved_files,
+ options, 0 };
+
+ if (getenv("LIBCLANG_NOTHREADS")) {
+ clang_reparseTranslationUnit_Impl(&RTUI);
+ return RTUI.result;
+ }
+
+ llvm::CrashRecoveryContext CRC;
+
+ if (!RunSafely(CRC, clang_reparseTranslationUnit_Impl, &RTUI)) {
+ fprintf(stderr, "libclang: crash detected during reparsing\n");
+ static_cast<ASTUnit *>(TU->TUData)->setUnsafeToFree(true);
+ return 1;
+ } else if (getenv("LIBCLANG_RESOURCE_USAGE"))
+ PrintLibclangResourceUsage(TU);
+
+ return RTUI.result;
+}
+
+
+CXString clang_getTranslationUnitSpelling(CXTranslationUnit CTUnit) {
+ if (!CTUnit)
+ return createCXString("");
+
+ ASTUnit *CXXUnit = static_cast<ASTUnit *>(CTUnit->TUData);
+ return createCXString(CXXUnit->getOriginalSourceFileName(), true);
+}
+
+CXCursor clang_getTranslationUnitCursor(CXTranslationUnit TU) {
+ ASTUnit *CXXUnit = static_cast<ASTUnit*>(TU->TUData);
+ return MakeCXCursor(CXXUnit->getASTContext().getTranslationUnitDecl(), TU);
+}
+
+} // end: extern "C"
+
+//===----------------------------------------------------------------------===//
+// CXFile Operations.
+//===----------------------------------------------------------------------===//
+
+extern "C" {
+CXString clang_getFileName(CXFile SFile) {
+ if (!SFile)
+ return createCXString((const char*)NULL);
+
+ FileEntry *FEnt = static_cast<FileEntry *>(SFile);
+ return createCXString(FEnt->getName());
+}
+
+time_t clang_getFileTime(CXFile SFile) {
+ if (!SFile)
+ return 0;
+
+ FileEntry *FEnt = static_cast<FileEntry *>(SFile);
+ return FEnt->getModificationTime();
+}
+
+CXFile clang_getFile(CXTranslationUnit tu, const char *file_name) {
+ if (!tu)
+ return 0;
+
+ ASTUnit *CXXUnit = static_cast<ASTUnit *>(tu->TUData);
+
+ FileManager &FMgr = CXXUnit->getFileManager();
+ return const_cast<FileEntry *>(FMgr.getFile(file_name));
+}
+
+unsigned clang_isFileMultipleIncludeGuarded(CXTranslationUnit tu, CXFile file) {
+ if (!tu || !file)
+ return 0;
+
+ ASTUnit *CXXUnit = static_cast<ASTUnit *>(tu->TUData);
+ FileEntry *FEnt = static_cast<FileEntry *>(file);
+ return CXXUnit->getPreprocessor().getHeaderSearchInfo()
+ .isFileMultipleIncludeGuarded(FEnt);
+}
+
+} // end: extern "C"
+
+//===----------------------------------------------------------------------===//
+// CXCursor Operations.
+//===----------------------------------------------------------------------===//
+
+static Decl *getDeclFromExpr(Stmt *E) {
+ if (ImplicitCastExpr *CE = dyn_cast<ImplicitCastExpr>(E))
+ return getDeclFromExpr(CE->getSubExpr());
+
+ if (DeclRefExpr *RefExpr = dyn_cast<DeclRefExpr>(E))
+ return RefExpr->getDecl();
+ if (MemberExpr *ME = dyn_cast<MemberExpr>(E))
+ return ME->getMemberDecl();
+ if (ObjCIvarRefExpr *RE = dyn_cast<ObjCIvarRefExpr>(E))
+ return RE->getDecl();
+ if (ObjCPropertyRefExpr *PRE = dyn_cast<ObjCPropertyRefExpr>(E)) {
+ if (PRE->isExplicitProperty())
+ return PRE->getExplicitProperty();
+ // It could be messaging both getter and setter as in:
+ // ++myobj.myprop;
+ // in which case prefer to associate the setter since it is less obvious
+ // from inspecting the source that the setter is going to get called.
+ if (PRE->isMessagingSetter())
+ return PRE->getImplicitPropertySetter();
+ return PRE->getImplicitPropertyGetter();
+ }
+ if (PseudoObjectExpr *POE = dyn_cast<PseudoObjectExpr>(E))
+ return getDeclFromExpr(POE->getSyntacticForm());
+ if (OpaqueValueExpr *OVE = dyn_cast<OpaqueValueExpr>(E))
+ if (Expr *Src = OVE->getSourceExpr())
+ return getDeclFromExpr(Src);
+
+ if (CallExpr *CE = dyn_cast<CallExpr>(E))
+ return getDeclFromExpr(CE->getCallee());
+ if (CXXConstructExpr *CE = dyn_cast<CXXConstructExpr>(E))
+ if (!CE->isElidable())
+ return CE->getConstructor();
+ if (ObjCMessageExpr *OME = dyn_cast<ObjCMessageExpr>(E))
+ return OME->getMethodDecl();
+
+ if (ObjCProtocolExpr *PE = dyn_cast<ObjCProtocolExpr>(E))
+ return PE->getProtocol();
+ if (SubstNonTypeTemplateParmPackExpr *NTTP
+ = dyn_cast<SubstNonTypeTemplateParmPackExpr>(E))
+ return NTTP->getParameterPack();
+ if (SizeOfPackExpr *SizeOfPack = dyn_cast<SizeOfPackExpr>(E))
+ if (isa<NonTypeTemplateParmDecl>(SizeOfPack->getPack()) ||
+ isa<ParmVarDecl>(SizeOfPack->getPack()))
+ return SizeOfPack->getPack();
+
+ return 0;
+}
+
+static SourceLocation getLocationFromExpr(Expr *E) {
+ if (ImplicitCastExpr *CE = dyn_cast<ImplicitCastExpr>(E))
+ return getLocationFromExpr(CE->getSubExpr());
+
+ if (ObjCMessageExpr *Msg = dyn_cast<ObjCMessageExpr>(E))
+ return /*FIXME:*/Msg->getLeftLoc();
+ if (DeclRefExpr *DRE = dyn_cast<DeclRefExpr>(E))
+ return DRE->getLocation();
+ if (MemberExpr *Member = dyn_cast<MemberExpr>(E))
+ return Member->getMemberLoc();
+ if (ObjCIvarRefExpr *Ivar = dyn_cast<ObjCIvarRefExpr>(E))
+ return Ivar->getLocation();
+ if (SizeOfPackExpr *SizeOfPack = dyn_cast<SizeOfPackExpr>(E))
+ return SizeOfPack->getPackLoc();
+ if (ObjCPropertyRefExpr *PropRef = dyn_cast<ObjCPropertyRefExpr>(E))
+ return PropRef->getLocation();
+
+ return E->getLocStart();
+}
+
+extern "C" {
+
+unsigned clang_visitChildren(CXCursor parent,
+ CXCursorVisitor visitor,
+ CXClientData client_data) {
+ CursorVisitor CursorVis(getCursorTU(parent), visitor, client_data,
+ /*VisitPreprocessorLast=*/false);
+ return CursorVis.VisitChildren(parent);
+}
+
+#ifndef __has_feature
+#define __has_feature(x) 0
+#endif
+#if __has_feature(blocks)
+typedef enum CXChildVisitResult
+ (^CXCursorVisitorBlock)(CXCursor cursor, CXCursor parent);
+
+static enum CXChildVisitResult visitWithBlock(CXCursor cursor, CXCursor parent,
+ CXClientData client_data) {
+ CXCursorVisitorBlock block = (CXCursorVisitorBlock)client_data;
+ return block(cursor, parent);
+}
+#else
+// If we are compiled with a compiler that doesn't have native blocks support,
+// define and call the block manually, so the
+typedef struct _CXChildVisitResult
+{
+ void *isa;
+ int flags;
+ int reserved;
+ enum CXChildVisitResult(*invoke)(struct _CXChildVisitResult*, CXCursor,
+ CXCursor);
+} *CXCursorVisitorBlock;
+
+static enum CXChildVisitResult visitWithBlock(CXCursor cursor, CXCursor parent,
+ CXClientData client_data) {
+ CXCursorVisitorBlock block = (CXCursorVisitorBlock)client_data;
+ return block->invoke(block, cursor, parent);
+}
+#endif
+
+
+unsigned clang_visitChildrenWithBlock(CXCursor parent,
+ CXCursorVisitorBlock block) {
+ return clang_visitChildren(parent, visitWithBlock, block);
+}
+
+static CXString getDeclSpelling(Decl *D) {
+ if (!D)
+ return createCXString("");
+
+ NamedDecl *ND = dyn_cast<NamedDecl>(D);
+ if (!ND) {
+ if (ObjCPropertyImplDecl *PropImpl =dyn_cast<ObjCPropertyImplDecl>(D))
+ if (ObjCPropertyDecl *Property = PropImpl->getPropertyDecl())
+ return createCXString(Property->getIdentifier()->getName());
+
+ if (ImportDecl *ImportD = dyn_cast<ImportDecl>(D))
+ if (Module *Mod = ImportD->getImportedModule())
+ return createCXString(Mod->getFullModuleName());
+
+ return createCXString("");
+ }
+
+ if (ObjCMethodDecl *OMD = dyn_cast<ObjCMethodDecl>(ND))
+ return createCXString(OMD->getSelector().getAsString());
+
+ if (ObjCCategoryImplDecl *CIMP = dyn_cast<ObjCCategoryImplDecl>(ND))
+ // No, this isn't the same as the code below. getIdentifier() is non-virtual
+ // and returns different names. NamedDecl returns the class name and
+ // ObjCCategoryImplDecl returns the category name.
+ return createCXString(CIMP->getIdentifier()->getNameStart());
+
+ if (isa<UsingDirectiveDecl>(D))
+ return createCXString("");
+
+ SmallString<1024> S;
+ llvm::raw_svector_ostream os(S);
+ ND->printName(os);
+
+ return createCXString(os.str());
+}
+
+CXString clang_getCursorSpelling(CXCursor C) {
+ if (clang_isTranslationUnit(C.kind))
+ return clang_getTranslationUnitSpelling(
+ static_cast<CXTranslationUnit>(C.data[2]));
+
+ if (clang_isReference(C.kind)) {
+ switch (C.kind) {
+ case CXCursor_ObjCSuperClassRef: {
+ ObjCInterfaceDecl *Super = getCursorObjCSuperClassRef(C).first;
+ return createCXString(Super->getIdentifier()->getNameStart());
+ }
+ case CXCursor_ObjCClassRef: {
+ ObjCInterfaceDecl *Class = getCursorObjCClassRef(C).first;
+ return createCXString(Class->getIdentifier()->getNameStart());
+ }
+ case CXCursor_ObjCProtocolRef: {
+ ObjCProtocolDecl *OID = getCursorObjCProtocolRef(C).first;
+ assert(OID && "getCursorSpelling(): Missing protocol decl");
+ return createCXString(OID->getIdentifier()->getNameStart());
+ }
+ case CXCursor_CXXBaseSpecifier: {
+ CXXBaseSpecifier *B = getCursorCXXBaseSpecifier(C);
+ return createCXString(B->getType().getAsString());
+ }
+ case CXCursor_TypeRef: {
+ TypeDecl *Type = getCursorTypeRef(C).first;
+ assert(Type && "Missing type decl");
+
+ return createCXString(getCursorContext(C).getTypeDeclType(Type).
+ getAsString());
+ }
+ case CXCursor_TemplateRef: {
+ TemplateDecl *Template = getCursorTemplateRef(C).first;
+ assert(Template && "Missing template decl");
+
+ return createCXString(Template->getNameAsString());
+ }
+
+ case CXCursor_NamespaceRef: {
+ NamedDecl *NS = getCursorNamespaceRef(C).first;
+ assert(NS && "Missing namespace decl");
+
+ return createCXString(NS->getNameAsString());
+ }
+
+ case CXCursor_MemberRef: {
+ FieldDecl *Field = getCursorMemberRef(C).first;
+ assert(Field && "Missing member decl");
+
+ return createCXString(Field->getNameAsString());
+ }
+
+ case CXCursor_LabelRef: {
+ LabelStmt *Label = getCursorLabelRef(C).first;
+ assert(Label && "Missing label");
+
+ return createCXString(Label->getName());
+ }
+
+ case CXCursor_OverloadedDeclRef: {
+ OverloadedDeclRefStorage Storage = getCursorOverloadedDeclRef(C).first;
+ if (Decl *D = Storage.dyn_cast<Decl *>()) {
+ if (NamedDecl *ND = dyn_cast<NamedDecl>(D))
+ return createCXString(ND->getNameAsString());
+ return createCXString("");
+ }
+ if (OverloadExpr *E = Storage.dyn_cast<OverloadExpr *>())
+ return createCXString(E->getName().getAsString());
+ OverloadedTemplateStorage *Ovl
+ = Storage.get<OverloadedTemplateStorage*>();
+ if (Ovl->size() == 0)
+ return createCXString("");
+ return createCXString((*Ovl->begin())->getNameAsString());
+ }
+
+ case CXCursor_VariableRef: {
+ VarDecl *Var = getCursorVariableRef(C).first;
+ assert(Var && "Missing variable decl");
+
+ return createCXString(Var->getNameAsString());
+ }
+
+ default:
+ return createCXString("<not implemented>");
+ }
+ }
+
+ if (clang_isExpression(C.kind)) {
+ Decl *D = getDeclFromExpr(getCursorExpr(C));
+ if (D)
+ return getDeclSpelling(D);
+ return createCXString("");
+ }
+
+ if (clang_isStatement(C.kind)) {
+ Stmt *S = getCursorStmt(C);
+ if (LabelStmt *Label = dyn_cast_or_null<LabelStmt>(S))
+ return createCXString(Label->getName());
+
+ return createCXString("");
+ }
+
+ if (C.kind == CXCursor_MacroExpansion)
+ return createCXString(getCursorMacroExpansion(C)->getName()
+ ->getNameStart());
+
+ if (C.kind == CXCursor_MacroDefinition)
+ return createCXString(getCursorMacroDefinition(C)->getName()
+ ->getNameStart());
+
+ if (C.kind == CXCursor_InclusionDirective)
+ return createCXString(getCursorInclusionDirective(C)->getFileName());
+
+ if (clang_isDeclaration(C.kind))
+ return getDeclSpelling(getCursorDecl(C));
+
+ if (C.kind == CXCursor_AnnotateAttr) {
+ AnnotateAttr *AA = cast<AnnotateAttr>(cxcursor::getCursorAttr(C));
+ return createCXString(AA->getAnnotation());
+ }
+
+ if (C.kind == CXCursor_AsmLabelAttr) {
+ AsmLabelAttr *AA = cast<AsmLabelAttr>(cxcursor::getCursorAttr(C));
+ return createCXString(AA->getLabel());
+ }
+
+ return createCXString("");
+}
+
+CXSourceRange clang_Cursor_getSpellingNameRange(CXCursor C,
+ unsigned pieceIndex,
+ unsigned options) {
+ if (clang_Cursor_isNull(C))
+ return clang_getNullRange();
+
+ ASTContext &Ctx = getCursorContext(C);
+
+ if (clang_isStatement(C.kind)) {
+ Stmt *S = getCursorStmt(C);
+ if (LabelStmt *Label = dyn_cast_or_null<LabelStmt>(S)) {
+ if (pieceIndex > 0)
+ return clang_getNullRange();
+ return cxloc::translateSourceRange(Ctx, Label->getIdentLoc());
+ }
+
+ return clang_getNullRange();
+ }
+
+ if (C.kind == CXCursor_ObjCMessageExpr) {
+ if (ObjCMessageExpr *
+ ME = dyn_cast_or_null<ObjCMessageExpr>(getCursorExpr(C))) {
+ if (pieceIndex >= ME->getNumSelectorLocs())
+ return clang_getNullRange();
+ return cxloc::translateSourceRange(Ctx, ME->getSelectorLoc(pieceIndex));
+ }
+ }
+
+ if (C.kind == CXCursor_ObjCInstanceMethodDecl ||
+ C.kind == CXCursor_ObjCClassMethodDecl) {
+ if (ObjCMethodDecl *
+ MD = dyn_cast_or_null<ObjCMethodDecl>(getCursorDecl(C))) {
+ if (pieceIndex >= MD->getNumSelectorLocs())
+ return clang_getNullRange();
+ return cxloc::translateSourceRange(Ctx, MD->getSelectorLoc(pieceIndex));
+ }
+ }
+
+ if (C.kind == CXCursor_ObjCCategoryDecl ||
+ C.kind == CXCursor_ObjCCategoryImplDecl) {
+ if (pieceIndex > 0)
+ return clang_getNullRange();
+ if (ObjCCategoryDecl *
+ CD = dyn_cast_or_null<ObjCCategoryDecl>(getCursorDecl(C)))
+ return cxloc::translateSourceRange(Ctx, CD->getCategoryNameLoc());
+ if (ObjCCategoryImplDecl *
+ CID = dyn_cast_or_null<ObjCCategoryImplDecl>(getCursorDecl(C)))
+ return cxloc::translateSourceRange(Ctx, CID->getCategoryNameLoc());
+ }
+
+ if (C.kind == CXCursor_ModuleImportDecl) {
+ if (pieceIndex > 0)
+ return clang_getNullRange();
+ if (ImportDecl *ImportD = dyn_cast_or_null<ImportDecl>(getCursorDecl(C))) {
+ ArrayRef<SourceLocation> Locs = ImportD->getIdentifierLocs();
+ if (!Locs.empty())
+ return cxloc::translateSourceRange(Ctx,
+ SourceRange(Locs.front(), Locs.back()));
+ }
+ return clang_getNullRange();
+ }
+
+ // FIXME: A CXCursor_InclusionDirective should give the location of the
+ // filename, but we don't keep track of this.
+
+ // FIXME: A CXCursor_AnnotateAttr should give the location of the annotation
+ // but we don't keep track of this.
+
+ // FIXME: A CXCursor_AsmLabelAttr should give the location of the label
+ // but we don't keep track of this.
+
+ // Default handling, give the location of the cursor.
+
+ if (pieceIndex > 0)
+ return clang_getNullRange();
+
+ CXSourceLocation CXLoc = clang_getCursorLocation(C);
+ SourceLocation Loc = cxloc::translateSourceLocation(CXLoc);
+ return cxloc::translateSourceRange(Ctx, Loc);
+}
+
+CXString clang_getCursorDisplayName(CXCursor C) {
+ if (!clang_isDeclaration(C.kind))
+ return clang_getCursorSpelling(C);
+
+ Decl *D = getCursorDecl(C);
+ if (!D)
+ return createCXString("");
+
+ PrintingPolicy Policy = getCursorContext(C).getPrintingPolicy();
+ if (FunctionTemplateDecl *FunTmpl = dyn_cast<FunctionTemplateDecl>(D))
+ D = FunTmpl->getTemplatedDecl();
+
+ if (FunctionDecl *Function = dyn_cast<FunctionDecl>(D)) {
+ SmallString<64> Str;
+ llvm::raw_svector_ostream OS(Str);
+ OS << *Function;
+ if (Function->getPrimaryTemplate())
+ OS << "<>";
+ OS << "(";
+ for (unsigned I = 0, N = Function->getNumParams(); I != N; ++I) {
+ if (I)
+ OS << ", ";
+ OS << Function->getParamDecl(I)->getType().getAsString(Policy);
+ }
+
+ if (Function->isVariadic()) {
+ if (Function->getNumParams())
+ OS << ", ";
+ OS << "...";
+ }
+ OS << ")";
+ return createCXString(OS.str());
+ }
+
+ if (ClassTemplateDecl *ClassTemplate = dyn_cast<ClassTemplateDecl>(D)) {
+ SmallString<64> Str;
+ llvm::raw_svector_ostream OS(Str);
+ OS << *ClassTemplate;
+ OS << "<";
+ TemplateParameterList *Params = ClassTemplate->getTemplateParameters();
+ for (unsigned I = 0, N = Params->size(); I != N; ++I) {
+ if (I)
+ OS << ", ";
+
+ NamedDecl *Param = Params->getParam(I);
+ if (Param->getIdentifier()) {
+ OS << Param->getIdentifier()->getName();
+ continue;
+ }
+
+ // There is no parameter name, which makes this tricky. Try to come up
+ // with something useful that isn't too long.
+ if (TemplateTypeParmDecl *TTP = dyn_cast<TemplateTypeParmDecl>(Param))
+ OS << (TTP->wasDeclaredWithTypename()? "typename" : "class");
+ else if (NonTypeTemplateParmDecl *NTTP
+ = dyn_cast<NonTypeTemplateParmDecl>(Param))
+ OS << NTTP->getType().getAsString(Policy);
+ else
+ OS << "template<...> class";
+ }
+
+ OS << ">";
+ return createCXString(OS.str());
+ }
+
+ if (ClassTemplateSpecializationDecl *ClassSpec
+ = dyn_cast<ClassTemplateSpecializationDecl>(D)) {
+ // If the type was explicitly written, use that.
+ if (TypeSourceInfo *TSInfo = ClassSpec->getTypeAsWritten())
+ return createCXString(TSInfo->getType().getAsString(Policy));
+
+ SmallString<64> Str;
+ llvm::raw_svector_ostream OS(Str);
+ OS << *ClassSpec;
+ OS << TemplateSpecializationType::PrintTemplateArgumentList(
+ ClassSpec->getTemplateArgs().data(),
+ ClassSpec->getTemplateArgs().size(),
+ Policy);
+ return createCXString(OS.str());
+ }
+
+ return clang_getCursorSpelling(C);
+}
+
+CXString clang_getCursorKindSpelling(enum CXCursorKind Kind) {
+ switch (Kind) {
+ case CXCursor_FunctionDecl:
+ return createCXString("FunctionDecl");
+ case CXCursor_TypedefDecl:
+ return createCXString("TypedefDecl");
+ case CXCursor_EnumDecl:
+ return createCXString("EnumDecl");
+ case CXCursor_EnumConstantDecl:
+ return createCXString("EnumConstantDecl");
+ case CXCursor_StructDecl:
+ return createCXString("StructDecl");
+ case CXCursor_UnionDecl:
+ return createCXString("UnionDecl");
+ case CXCursor_ClassDecl:
+ return createCXString("ClassDecl");
+ case CXCursor_FieldDecl:
+ return createCXString("FieldDecl");
+ case CXCursor_VarDecl:
+ return createCXString("VarDecl");
+ case CXCursor_ParmDecl:
+ return createCXString("ParmDecl");
+ case CXCursor_ObjCInterfaceDecl:
+ return createCXString("ObjCInterfaceDecl");
+ case CXCursor_ObjCCategoryDecl:
+ return createCXString("ObjCCategoryDecl");
+ case CXCursor_ObjCProtocolDecl:
+ return createCXString("ObjCProtocolDecl");
+ case CXCursor_ObjCPropertyDecl:
+ return createCXString("ObjCPropertyDecl");
+ case CXCursor_ObjCIvarDecl:
+ return createCXString("ObjCIvarDecl");
+ case CXCursor_ObjCInstanceMethodDecl:
+ return createCXString("ObjCInstanceMethodDecl");
+ case CXCursor_ObjCClassMethodDecl:
+ return createCXString("ObjCClassMethodDecl");
+ case CXCursor_ObjCImplementationDecl:
+ return createCXString("ObjCImplementationDecl");
+ case CXCursor_ObjCCategoryImplDecl:
+ return createCXString("ObjCCategoryImplDecl");
+ case CXCursor_CXXMethod:
+ return createCXString("CXXMethod");
+ case CXCursor_UnexposedDecl:
+ return createCXString("UnexposedDecl");
+ case CXCursor_ObjCSuperClassRef:
+ return createCXString("ObjCSuperClassRef");
+ case CXCursor_ObjCProtocolRef:
+ return createCXString("ObjCProtocolRef");
+ case CXCursor_ObjCClassRef:
+ return createCXString("ObjCClassRef");
+ case CXCursor_TypeRef:
+ return createCXString("TypeRef");
+ case CXCursor_TemplateRef:
+ return createCXString("TemplateRef");
+ case CXCursor_NamespaceRef:
+ return createCXString("NamespaceRef");
+ case CXCursor_MemberRef:
+ return createCXString("MemberRef");
+ case CXCursor_LabelRef:
+ return createCXString("LabelRef");
+ case CXCursor_OverloadedDeclRef:
+ return createCXString("OverloadedDeclRef");
+ case CXCursor_VariableRef:
+ return createCXString("VariableRef");
+ case CXCursor_IntegerLiteral:
+ return createCXString("IntegerLiteral");
+ case CXCursor_FloatingLiteral:
+ return createCXString("FloatingLiteral");
+ case CXCursor_ImaginaryLiteral:
+ return createCXString("ImaginaryLiteral");
+ case CXCursor_StringLiteral:
+ return createCXString("StringLiteral");
+ case CXCursor_CharacterLiteral:
+ return createCXString("CharacterLiteral");
+ case CXCursor_ParenExpr:
+ return createCXString("ParenExpr");
+ case CXCursor_UnaryOperator:
+ return createCXString("UnaryOperator");
+ case CXCursor_ArraySubscriptExpr:
+ return createCXString("ArraySubscriptExpr");
+ case CXCursor_BinaryOperator:
+ return createCXString("BinaryOperator");
+ case CXCursor_CompoundAssignOperator:
+ return createCXString("CompoundAssignOperator");
+ case CXCursor_ConditionalOperator:
+ return createCXString("ConditionalOperator");
+ case CXCursor_CStyleCastExpr:
+ return createCXString("CStyleCastExpr");
+ case CXCursor_CompoundLiteralExpr:
+ return createCXString("CompoundLiteralExpr");
+ case CXCursor_InitListExpr:
+ return createCXString("InitListExpr");
+ case CXCursor_AddrLabelExpr:
+ return createCXString("AddrLabelExpr");
+ case CXCursor_StmtExpr:
+ return createCXString("StmtExpr");
+ case CXCursor_GenericSelectionExpr:
+ return createCXString("GenericSelectionExpr");
+ case CXCursor_GNUNullExpr:
+ return createCXString("GNUNullExpr");
+ case CXCursor_CXXStaticCastExpr:
+ return createCXString("CXXStaticCastExpr");
+ case CXCursor_CXXDynamicCastExpr:
+ return createCXString("CXXDynamicCastExpr");
+ case CXCursor_CXXReinterpretCastExpr:
+ return createCXString("CXXReinterpretCastExpr");
+ case CXCursor_CXXConstCastExpr:
+ return createCXString("CXXConstCastExpr");
+ case CXCursor_CXXFunctionalCastExpr:
+ return createCXString("CXXFunctionalCastExpr");
+ case CXCursor_CXXTypeidExpr:
+ return createCXString("CXXTypeidExpr");
+ case CXCursor_CXXBoolLiteralExpr:
+ return createCXString("CXXBoolLiteralExpr");
+ case CXCursor_CXXNullPtrLiteralExpr:
+ return createCXString("CXXNullPtrLiteralExpr");
+ case CXCursor_CXXThisExpr:
+ return createCXString("CXXThisExpr");
+ case CXCursor_CXXThrowExpr:
+ return createCXString("CXXThrowExpr");
+ case CXCursor_CXXNewExpr:
+ return createCXString("CXXNewExpr");
+ case CXCursor_CXXDeleteExpr:
+ return createCXString("CXXDeleteExpr");
+ case CXCursor_UnaryExpr:
+ return createCXString("UnaryExpr");
+ case CXCursor_ObjCStringLiteral:
+ return createCXString("ObjCStringLiteral");
+ case CXCursor_ObjCBoolLiteralExpr:
+ return createCXString("ObjCBoolLiteralExpr");
+ case CXCursor_ObjCEncodeExpr:
+ return createCXString("ObjCEncodeExpr");
+ case CXCursor_ObjCSelectorExpr:
+ return createCXString("ObjCSelectorExpr");
+ case CXCursor_ObjCProtocolExpr:
+ return createCXString("ObjCProtocolExpr");
+ case CXCursor_ObjCBridgedCastExpr:
+ return createCXString("ObjCBridgedCastExpr");
+ case CXCursor_BlockExpr:
+ return createCXString("BlockExpr");
+ case CXCursor_PackExpansionExpr:
+ return createCXString("PackExpansionExpr");
+ case CXCursor_SizeOfPackExpr:
+ return createCXString("SizeOfPackExpr");
+ case CXCursor_LambdaExpr:
+ return createCXString("LambdaExpr");
+ case CXCursor_UnexposedExpr:
+ return createCXString("UnexposedExpr");
+ case CXCursor_DeclRefExpr:
+ return createCXString("DeclRefExpr");
+ case CXCursor_MemberRefExpr:
+ return createCXString("MemberRefExpr");
+ case CXCursor_CallExpr:
+ return createCXString("CallExpr");
+ case CXCursor_ObjCMessageExpr:
+ return createCXString("ObjCMessageExpr");
+ case CXCursor_UnexposedStmt:
+ return createCXString("UnexposedStmt");
+ case CXCursor_DeclStmt:
+ return createCXString("DeclStmt");
+ case CXCursor_LabelStmt:
+ return createCXString("LabelStmt");
+ case CXCursor_CompoundStmt:
+ return createCXString("CompoundStmt");
+ case CXCursor_CaseStmt:
+ return createCXString("CaseStmt");
+ case CXCursor_DefaultStmt:
+ return createCXString("DefaultStmt");
+ case CXCursor_IfStmt:
+ return createCXString("IfStmt");
+ case CXCursor_SwitchStmt:
+ return createCXString("SwitchStmt");
+ case CXCursor_WhileStmt:
+ return createCXString("WhileStmt");
+ case CXCursor_DoStmt:
+ return createCXString("DoStmt");
+ case CXCursor_ForStmt:
+ return createCXString("ForStmt");
+ case CXCursor_GotoStmt:
+ return createCXString("GotoStmt");
+ case CXCursor_IndirectGotoStmt:
+ return createCXString("IndirectGotoStmt");
+ case CXCursor_ContinueStmt:
+ return createCXString("ContinueStmt");
+ case CXCursor_BreakStmt:
+ return createCXString("BreakStmt");
+ case CXCursor_ReturnStmt:
+ return createCXString("ReturnStmt");
+ case CXCursor_GCCAsmStmt:
+ return createCXString("GCCAsmStmt");
+ case CXCursor_MSAsmStmt:
+ return createCXString("MSAsmStmt");
+ case CXCursor_ObjCAtTryStmt:
+ return createCXString("ObjCAtTryStmt");
+ case CXCursor_ObjCAtCatchStmt:
+ return createCXString("ObjCAtCatchStmt");
+ case CXCursor_ObjCAtFinallyStmt:
+ return createCXString("ObjCAtFinallyStmt");
+ case CXCursor_ObjCAtThrowStmt:
+ return createCXString("ObjCAtThrowStmt");
+ case CXCursor_ObjCAtSynchronizedStmt:
+ return createCXString("ObjCAtSynchronizedStmt");
+ case CXCursor_ObjCAutoreleasePoolStmt:
+ return createCXString("ObjCAutoreleasePoolStmt");
+ case CXCursor_ObjCForCollectionStmt:
+ return createCXString("ObjCForCollectionStmt");
+ case CXCursor_CXXCatchStmt:
+ return createCXString("CXXCatchStmt");
+ case CXCursor_CXXTryStmt:
+ return createCXString("CXXTryStmt");
+ case CXCursor_CXXForRangeStmt:
+ return createCXString("CXXForRangeStmt");
+ case CXCursor_SEHTryStmt:
+ return createCXString("SEHTryStmt");
+ case CXCursor_SEHExceptStmt:
+ return createCXString("SEHExceptStmt");
+ case CXCursor_SEHFinallyStmt:
+ return createCXString("SEHFinallyStmt");
+ case CXCursor_NullStmt:
+ return createCXString("NullStmt");
+ case CXCursor_InvalidFile:
+ return createCXString("InvalidFile");
+ case CXCursor_InvalidCode:
+ return createCXString("InvalidCode");
+ case CXCursor_NoDeclFound:
+ return createCXString("NoDeclFound");
+ case CXCursor_NotImplemented:
+ return createCXString("NotImplemented");
+ case CXCursor_TranslationUnit:
+ return createCXString("TranslationUnit");
+ case CXCursor_UnexposedAttr:
+ return createCXString("UnexposedAttr");
+ case CXCursor_IBActionAttr:
+ return createCXString("attribute(ibaction)");
+ case CXCursor_IBOutletAttr:
+ return createCXString("attribute(iboutlet)");
+ case CXCursor_IBOutletCollectionAttr:
+ return createCXString("attribute(iboutletcollection)");
+ case CXCursor_CXXFinalAttr:
+ return createCXString("attribute(final)");
+ case CXCursor_CXXOverrideAttr:
+ return createCXString("attribute(override)");
+ case CXCursor_AnnotateAttr:
+ return createCXString("attribute(annotate)");
+ case CXCursor_AsmLabelAttr:
+ return createCXString("asm label");
+ case CXCursor_PreprocessingDirective:
+ return createCXString("preprocessing directive");
+ case CXCursor_MacroDefinition:
+ return createCXString("macro definition");
+ case CXCursor_MacroExpansion:
+ return createCXString("macro expansion");
+ case CXCursor_InclusionDirective:
+ return createCXString("inclusion directive");
+ case CXCursor_Namespace:
+ return createCXString("Namespace");
+ case CXCursor_LinkageSpec:
+ return createCXString("LinkageSpec");
+ case CXCursor_CXXBaseSpecifier:
+ return createCXString("C++ base class specifier");
+ case CXCursor_Constructor:
+ return createCXString("CXXConstructor");
+ case CXCursor_Destructor:
+ return createCXString("CXXDestructor");
+ case CXCursor_ConversionFunction:
+ return createCXString("CXXConversion");
+ case CXCursor_TemplateTypeParameter:
+ return createCXString("TemplateTypeParameter");
+ case CXCursor_NonTypeTemplateParameter:
+ return createCXString("NonTypeTemplateParameter");
+ case CXCursor_TemplateTemplateParameter:
+ return createCXString("TemplateTemplateParameter");
+ case CXCursor_FunctionTemplate:
+ return createCXString("FunctionTemplate");
+ case CXCursor_ClassTemplate:
+ return createCXString("ClassTemplate");
+ case CXCursor_ClassTemplatePartialSpecialization:
+ return createCXString("ClassTemplatePartialSpecialization");
+ case CXCursor_NamespaceAlias:
+ return createCXString("NamespaceAlias");
+ case CXCursor_UsingDirective:
+ return createCXString("UsingDirective");
+ case CXCursor_UsingDeclaration:
+ return createCXString("UsingDeclaration");
+ case CXCursor_TypeAliasDecl:
+ return createCXString("TypeAliasDecl");
+ case CXCursor_ObjCSynthesizeDecl:
+ return createCXString("ObjCSynthesizeDecl");
+ case CXCursor_ObjCDynamicDecl:
+ return createCXString("ObjCDynamicDecl");
+ case CXCursor_CXXAccessSpecifier:
+ return createCXString("CXXAccessSpecifier");
+ case CXCursor_ModuleImportDecl:
+ return createCXString("ModuleImport");
+ }
+
+ llvm_unreachable("Unhandled CXCursorKind");
+}
+
+struct GetCursorData {
+ SourceLocation TokenBeginLoc;
+ bool PointsAtMacroArgExpansion;
+ bool VisitedObjCPropertyImplDecl;
+ SourceLocation VisitedDeclaratorDeclStartLoc;
+ CXCursor &BestCursor;
+
+ GetCursorData(SourceManager &SM,
+ SourceLocation tokenBegin, CXCursor &outputCursor)
+ : TokenBeginLoc(tokenBegin), BestCursor(outputCursor) {
+ PointsAtMacroArgExpansion = SM.isMacroArgExpansion(tokenBegin);
+ VisitedObjCPropertyImplDecl = false;
+ }
+};
+
+static enum CXChildVisitResult GetCursorVisitor(CXCursor cursor,
+ CXCursor parent,
+ CXClientData client_data) {
+ GetCursorData *Data = static_cast<GetCursorData *>(client_data);
+ CXCursor *BestCursor = &Data->BestCursor;
+
+ // If we point inside a macro argument we should provide info of what the
+ // token is so use the actual cursor, don't replace it with a macro expansion
+ // cursor.
+ if (cursor.kind == CXCursor_MacroExpansion && Data->PointsAtMacroArgExpansion)
+ return CXChildVisit_Recurse;
+
+ if (clang_isDeclaration(cursor.kind)) {
+ // Avoid having the implicit methods override the property decls.
+ if (ObjCMethodDecl *MD
+ = dyn_cast_or_null<ObjCMethodDecl>(getCursorDecl(cursor))) {
+ if (MD->isImplicit())
+ return CXChildVisit_Break;
+
+ } else if (ObjCInterfaceDecl *ID
+ = dyn_cast_or_null<ObjCInterfaceDecl>(getCursorDecl(cursor))) {
+ // Check that when we have multiple @class references in the same line,
+ // that later ones do not override the previous ones.
+ // If we have:
+ // @class Foo, Bar;
+ // source ranges for both start at '@', so 'Bar' will end up overriding
+ // 'Foo' even though the cursor location was at 'Foo'.
+ if (BestCursor->kind == CXCursor_ObjCInterfaceDecl ||
+ BestCursor->kind == CXCursor_ObjCClassRef)
+ if (ObjCInterfaceDecl *PrevID
+ = dyn_cast_or_null<ObjCInterfaceDecl>(getCursorDecl(*BestCursor))){
+ if (PrevID != ID &&
+ !PrevID->isThisDeclarationADefinition() &&
+ !ID->isThisDeclarationADefinition())
+ return CXChildVisit_Break;
+ }
+
+ } else if (DeclaratorDecl *DD
+ = dyn_cast_or_null<DeclaratorDecl>(getCursorDecl(cursor))) {
+ SourceLocation StartLoc = DD->getSourceRange().getBegin();
+ // Check that when we have multiple declarators in the same line,
+ // that later ones do not override the previous ones.
+ // If we have:
+ // int Foo, Bar;
+ // source ranges for both start at 'int', so 'Bar' will end up overriding
+ // 'Foo' even though the cursor location was at 'Foo'.
+ if (Data->VisitedDeclaratorDeclStartLoc == StartLoc)
+ return CXChildVisit_Break;
+ Data->VisitedDeclaratorDeclStartLoc = StartLoc;
+
+ } else if (ObjCPropertyImplDecl *PropImp
+ = dyn_cast_or_null<ObjCPropertyImplDecl>(getCursorDecl(cursor))) {
+ (void)PropImp;
+ // Check that when we have multiple @synthesize in the same line,
+ // that later ones do not override the previous ones.
+ // If we have:
+ // @synthesize Foo, Bar;
+ // source ranges for both start at '@', so 'Bar' will end up overriding
+ // 'Foo' even though the cursor location was at 'Foo'.
+ if (Data->VisitedObjCPropertyImplDecl)
+ return CXChildVisit_Break;
+ Data->VisitedObjCPropertyImplDecl = true;
+ }
+ }
+
+ if (clang_isExpression(cursor.kind) &&
+ clang_isDeclaration(BestCursor->kind)) {
+ if (Decl *D = getCursorDecl(*BestCursor)) {
+ // Avoid having the cursor of an expression replace the declaration cursor
+ // when the expression source range overlaps the declaration range.
+ // This can happen for C++ constructor expressions whose range generally
+ // include the variable declaration, e.g.:
+ // MyCXXClass foo; // Make sure pointing at 'foo' returns a VarDecl cursor.
+ if (D->getLocation().isValid() && Data->TokenBeginLoc.isValid() &&
+ D->getLocation() == Data->TokenBeginLoc)
+ return CXChildVisit_Break;
+ }
+ }
+
+ // If our current best cursor is the construction of a temporary object,
+ // don't replace that cursor with a type reference, because we want
+ // clang_getCursor() to point at the constructor.
+ if (clang_isExpression(BestCursor->kind) &&
+ isa<CXXTemporaryObjectExpr>(getCursorExpr(*BestCursor)) &&
+ cursor.kind == CXCursor_TypeRef) {
+ // Keep the cursor pointing at CXXTemporaryObjectExpr but also mark it
+ // as having the actual point on the type reference.
+ *BestCursor = getTypeRefedCallExprCursor(*BestCursor);
+ return CXChildVisit_Recurse;
+ }
+
+ *BestCursor = cursor;
+ return CXChildVisit_Recurse;
+}
+
+CXCursor clang_getCursor(CXTranslationUnit TU, CXSourceLocation Loc) {
+ if (!TU)
+ return clang_getNullCursor();
+
+ ASTUnit *CXXUnit = static_cast<ASTUnit *>(TU->TUData);
+ ASTUnit::ConcurrencyCheck Check(*CXXUnit);
+
+ SourceLocation SLoc = cxloc::translateSourceLocation(Loc);
+ CXCursor Result = cxcursor::getCursor(TU, SLoc);
+
+ bool Logging = getenv("LIBCLANG_LOGGING");
+ if (Logging) {
+ CXFile SearchFile;
+ unsigned SearchLine, SearchColumn;
+ CXFile ResultFile;
+ unsigned ResultLine, ResultColumn;
+ CXString SearchFileName, ResultFileName, KindSpelling, USR;
+ const char *IsDef = clang_isCursorDefinition(Result)? " (Definition)" : "";
+ CXSourceLocation ResultLoc = clang_getCursorLocation(Result);
+
+ clang_getExpansionLocation(Loc, &SearchFile, &SearchLine, &SearchColumn, 0);
+ clang_getExpansionLocation(ResultLoc, &ResultFile, &ResultLine,
+ &ResultColumn, 0);
+ SearchFileName = clang_getFileName(SearchFile);
+ ResultFileName = clang_getFileName(ResultFile);
+ KindSpelling = clang_getCursorKindSpelling(Result.kind);
+ USR = clang_getCursorUSR(Result);
+ fprintf(stderr, "clang_getCursor(%s:%d:%d) = %s(%s:%d:%d):%s%s\n",
+ clang_getCString(SearchFileName), SearchLine, SearchColumn,
+ clang_getCString(KindSpelling),
+ clang_getCString(ResultFileName), ResultLine, ResultColumn,
+ clang_getCString(USR), IsDef);
+ clang_disposeString(SearchFileName);
+ clang_disposeString(ResultFileName);
+ clang_disposeString(KindSpelling);
+ clang_disposeString(USR);
+
+ CXCursor Definition = clang_getCursorDefinition(Result);
+ if (!clang_equalCursors(Definition, clang_getNullCursor())) {
+ CXSourceLocation DefinitionLoc = clang_getCursorLocation(Definition);
+ CXString DefinitionKindSpelling
+ = clang_getCursorKindSpelling(Definition.kind);
+ CXFile DefinitionFile;
+ unsigned DefinitionLine, DefinitionColumn;
+ clang_getExpansionLocation(DefinitionLoc, &DefinitionFile,
+ &DefinitionLine, &DefinitionColumn, 0);
+ CXString DefinitionFileName = clang_getFileName(DefinitionFile);
+ fprintf(stderr, " -> %s(%s:%d:%d)\n",
+ clang_getCString(DefinitionKindSpelling),
+ clang_getCString(DefinitionFileName),
+ DefinitionLine, DefinitionColumn);
+ clang_disposeString(DefinitionFileName);
+ clang_disposeString(DefinitionKindSpelling);
+ }
+ }
+
+ return Result;
+}
+
+CXCursor clang_getNullCursor(void) {
+ return MakeCXCursorInvalid(CXCursor_InvalidFile);
+}
+
+unsigned clang_equalCursors(CXCursor X, CXCursor Y) {
+ return X == Y;
+}
+
+unsigned clang_hashCursor(CXCursor C) {
+ unsigned Index = 0;
+ if (clang_isExpression(C.kind) || clang_isStatement(C.kind))
+ Index = 1;
+
+ return llvm::DenseMapInfo<std::pair<unsigned, void*> >::getHashValue(
+ std::make_pair(C.kind, C.data[Index]));
+}
+
+unsigned clang_isInvalid(enum CXCursorKind K) {
+ return K >= CXCursor_FirstInvalid && K <= CXCursor_LastInvalid;
+}
+
+unsigned clang_isDeclaration(enum CXCursorKind K) {
+ return (K >= CXCursor_FirstDecl && K <= CXCursor_LastDecl) ||
+ (K >= CXCursor_FirstExtraDecl && K <= CXCursor_LastExtraDecl);
+}
+
+unsigned clang_isReference(enum CXCursorKind K) {
+ return K >= CXCursor_FirstRef && K <= CXCursor_LastRef;
+}
+
+unsigned clang_isExpression(enum CXCursorKind K) {
+ return K >= CXCursor_FirstExpr && K <= CXCursor_LastExpr;
+}
+
+unsigned clang_isStatement(enum CXCursorKind K) {
+ return K >= CXCursor_FirstStmt && K <= CXCursor_LastStmt;
+}
+
+unsigned clang_isAttribute(enum CXCursorKind K) {
+ return K >= CXCursor_FirstAttr && K <= CXCursor_LastAttr;
+}
+
+unsigned clang_isTranslationUnit(enum CXCursorKind K) {
+ return K == CXCursor_TranslationUnit;
+}
+
+unsigned clang_isPreprocessing(enum CXCursorKind K) {
+ return K >= CXCursor_FirstPreprocessing && K <= CXCursor_LastPreprocessing;
+}
+
+unsigned clang_isUnexposed(enum CXCursorKind K) {
+ switch (K) {
+ case CXCursor_UnexposedDecl:
+ case CXCursor_UnexposedExpr:
+ case CXCursor_UnexposedStmt:
+ case CXCursor_UnexposedAttr:
+ return true;
+ default:
+ return false;
+ }
+}
+
+CXCursorKind clang_getCursorKind(CXCursor C) {
+ return C.kind;
+}
+
+CXSourceLocation clang_getCursorLocation(CXCursor C) {
+ if (clang_isReference(C.kind)) {
+ switch (C.kind) {
+ case CXCursor_ObjCSuperClassRef: {
+ std::pair<ObjCInterfaceDecl *, SourceLocation> P
+ = getCursorObjCSuperClassRef(C);
+ return cxloc::translateSourceLocation(P.first->getASTContext(), P.second);
+ }
+
+ case CXCursor_ObjCProtocolRef: {
+ std::pair<ObjCProtocolDecl *, SourceLocation> P
+ = getCursorObjCProtocolRef(C);
+ return cxloc::translateSourceLocation(P.first->getASTContext(), P.second);
+ }
+
+ case CXCursor_ObjCClassRef: {
+ std::pair<ObjCInterfaceDecl *, SourceLocation> P
+ = getCursorObjCClassRef(C);
+ return cxloc::translateSourceLocation(P.first->getASTContext(), P.second);
+ }
+
+ case CXCursor_TypeRef: {
+ std::pair<TypeDecl *, SourceLocation> P = getCursorTypeRef(C);
+ return cxloc::translateSourceLocation(P.first->getASTContext(), P.second);
+ }
+
+ case CXCursor_TemplateRef: {
+ std::pair<TemplateDecl *, SourceLocation> P = getCursorTemplateRef(C);
+ return cxloc::translateSourceLocation(P.first->getASTContext(), P.second);
+ }
+
+ case CXCursor_NamespaceRef: {
+ std::pair<NamedDecl *, SourceLocation> P = getCursorNamespaceRef(C);
+ return cxloc::translateSourceLocation(P.first->getASTContext(), P.second);
+ }
+
+ case CXCursor_MemberRef: {
+ std::pair<FieldDecl *, SourceLocation> P = getCursorMemberRef(C);
+ return cxloc::translateSourceLocation(P.first->getASTContext(), P.second);
+ }
+
+ case CXCursor_VariableRef: {
+ std::pair<VarDecl *, SourceLocation> P = getCursorVariableRef(C);
+ return cxloc::translateSourceLocation(P.first->getASTContext(), P.second);
+ }
+
+ case CXCursor_CXXBaseSpecifier: {
+ CXXBaseSpecifier *BaseSpec = getCursorCXXBaseSpecifier(C);
+ if (!BaseSpec)
+ return clang_getNullLocation();
+
+ if (TypeSourceInfo *TSInfo = BaseSpec->getTypeSourceInfo())
+ return cxloc::translateSourceLocation(getCursorContext(C),
+ TSInfo->getTypeLoc().getBeginLoc());
+
+ return cxloc::translateSourceLocation(getCursorContext(C),
+ BaseSpec->getLocStart());
+ }
+
+ case CXCursor_LabelRef: {
+ std::pair<LabelStmt *, SourceLocation> P = getCursorLabelRef(C);
+ return cxloc::translateSourceLocation(getCursorContext(C), P.second);
+ }
+
+ case CXCursor_OverloadedDeclRef:
+ return cxloc::translateSourceLocation(getCursorContext(C),
+ getCursorOverloadedDeclRef(C).second);
+
+ default:
+ // FIXME: Need a way to enumerate all non-reference cases.
+ llvm_unreachable("Missed a reference kind");
+ }
+ }
+
+ if (clang_isExpression(C.kind))
+ return cxloc::translateSourceLocation(getCursorContext(C),
+ getLocationFromExpr(getCursorExpr(C)));
+
+ if (clang_isStatement(C.kind))
+ return cxloc::translateSourceLocation(getCursorContext(C),
+ getCursorStmt(C)->getLocStart());
+
+ if (C.kind == CXCursor_PreprocessingDirective) {
+ SourceLocation L = cxcursor::getCursorPreprocessingDirective(C).getBegin();
+ return cxloc::translateSourceLocation(getCursorContext(C), L);
+ }
+
+ if (C.kind == CXCursor_MacroExpansion) {
+ SourceLocation L
+ = cxcursor::getCursorMacroExpansion(C)->getSourceRange().getBegin();
+ return cxloc::translateSourceLocation(getCursorContext(C), L);
+ }
+
+ if (C.kind == CXCursor_MacroDefinition) {
+ SourceLocation L = cxcursor::getCursorMacroDefinition(C)->getLocation();
+ return cxloc::translateSourceLocation(getCursorContext(C), L);
+ }
+
+ if (C.kind == CXCursor_InclusionDirective) {
+ SourceLocation L
+ = cxcursor::getCursorInclusionDirective(C)->getSourceRange().getBegin();
+ return cxloc::translateSourceLocation(getCursorContext(C), L);
+ }
+
+ if (!clang_isDeclaration(C.kind))
+ return clang_getNullLocation();
+
+ Decl *D = getCursorDecl(C);
+ if (!D)
+ return clang_getNullLocation();
+
+ SourceLocation Loc = D->getLocation();
+ // FIXME: Multiple variables declared in a single declaration
+ // currently lack the information needed to correctly determine their
+ // ranges when accounting for the type-specifier. We use context
+ // stored in the CXCursor to determine if the VarDecl is in a DeclGroup,
+ // and if so, whether it is the first decl.
+ if (VarDecl *VD = dyn_cast<VarDecl>(D)) {
+ if (!cxcursor::isFirstInDeclGroup(C))
+ Loc = VD->getLocation();
+ }
+
+ // For ObjC methods, give the start location of the method name.
+ if (ObjCMethodDecl *MD = dyn_cast<ObjCMethodDecl>(D))
+ Loc = MD->getSelectorStartLoc();
+
+ return cxloc::translateSourceLocation(getCursorContext(C), Loc);
+}
+
+} // end extern "C"
+
+CXCursor cxcursor::getCursor(CXTranslationUnit TU, SourceLocation SLoc) {
+ assert(TU);
+
+ // Guard against an invalid SourceLocation, or we may assert in one
+ // of the following calls.
+ if (SLoc.isInvalid())
+ return clang_getNullCursor();
+
+ ASTUnit *CXXUnit = static_cast<ASTUnit *>(TU->TUData);
+
+ // Translate the given source location to make it point at the beginning of
+ // the token under the cursor.
+ SLoc = Lexer::GetBeginningOfToken(SLoc, CXXUnit->getSourceManager(),
+ CXXUnit->getASTContext().getLangOpts());
+
+ CXCursor Result = MakeCXCursorInvalid(CXCursor_NoDeclFound);
+ if (SLoc.isValid()) {
+ GetCursorData ResultData(CXXUnit->getSourceManager(), SLoc, Result);
+ CursorVisitor CursorVis(TU, GetCursorVisitor, &ResultData,
+ /*VisitPreprocessorLast=*/true,
+ /*VisitIncludedEntities=*/false,
+ SourceLocation(SLoc));
+ CursorVis.visitFileRegion();
+ }
+
+ return Result;
+}
+
+static SourceRange getRawCursorExtent(CXCursor C) {
+ if (clang_isReference(C.kind)) {
+ switch (C.kind) {
+ case CXCursor_ObjCSuperClassRef:
+ return getCursorObjCSuperClassRef(C).second;
+
+ case CXCursor_ObjCProtocolRef:
+ return getCursorObjCProtocolRef(C).second;
+
+ case CXCursor_ObjCClassRef:
+ return getCursorObjCClassRef(C).second;
+
+ case CXCursor_TypeRef:
+ return getCursorTypeRef(C).second;
+
+ case CXCursor_TemplateRef:
+ return getCursorTemplateRef(C).second;
+
+ case CXCursor_NamespaceRef:
+ return getCursorNamespaceRef(C).second;
+
+ case CXCursor_MemberRef:
+ return getCursorMemberRef(C).second;
+
+ case CXCursor_CXXBaseSpecifier:
+ return getCursorCXXBaseSpecifier(C)->getSourceRange();
+
+ case CXCursor_LabelRef:
+ return getCursorLabelRef(C).second;
+
+ case CXCursor_OverloadedDeclRef:
+ return getCursorOverloadedDeclRef(C).second;
+
+ case CXCursor_VariableRef:
+ return getCursorVariableRef(C).second;
+
+ default:
+ // FIXME: Need a way to enumerate all non-reference cases.
+ llvm_unreachable("Missed a reference kind");
+ }
+ }
+
+ if (clang_isExpression(C.kind))
+ return getCursorExpr(C)->getSourceRange();
+
+ if (clang_isStatement(C.kind))
+ return getCursorStmt(C)->getSourceRange();
+
+ if (clang_isAttribute(C.kind))
+ return getCursorAttr(C)->getRange();
+
+ if (C.kind == CXCursor_PreprocessingDirective)
+ return cxcursor::getCursorPreprocessingDirective(C);
+
+ if (C.kind == CXCursor_MacroExpansion) {
+ ASTUnit *TU = getCursorASTUnit(C);
+ SourceRange Range = cxcursor::getCursorMacroExpansion(C)->getSourceRange();
+ return TU->mapRangeFromPreamble(Range);
+ }
+
+ if (C.kind == CXCursor_MacroDefinition) {
+ ASTUnit *TU = getCursorASTUnit(C);
+ SourceRange Range = cxcursor::getCursorMacroDefinition(C)->getSourceRange();
+ return TU->mapRangeFromPreamble(Range);
+ }
+
+ if (C.kind == CXCursor_InclusionDirective) {
+ ASTUnit *TU = getCursorASTUnit(C);
+ SourceRange Range = cxcursor::getCursorInclusionDirective(C)->getSourceRange();
+ return TU->mapRangeFromPreamble(Range);
+ }
+
+ if (C.kind == CXCursor_TranslationUnit) {
+ ASTUnit *TU = getCursorASTUnit(C);
+ FileID MainID = TU->getSourceManager().getMainFileID();
+ SourceLocation Start = TU->getSourceManager().getLocForStartOfFile(MainID);
+ SourceLocation End = TU->getSourceManager().getLocForEndOfFile(MainID);
+ return SourceRange(Start, End);
+ }
+
+ if (clang_isDeclaration(C.kind)) {
+ Decl *D = cxcursor::getCursorDecl(C);
+ if (!D)
+ return SourceRange();
+
+ SourceRange R = D->getSourceRange();
+ // FIXME: Multiple variables declared in a single declaration
+ // currently lack the information needed to correctly determine their
+ // ranges when accounting for the type-specifier. We use context
+ // stored in the CXCursor to determine if the VarDecl is in a DeclGroup,
+ // and if so, whether it is the first decl.
+ if (VarDecl *VD = dyn_cast<VarDecl>(D)) {
+ if (!cxcursor::isFirstInDeclGroup(C))
+ R.setBegin(VD->getLocation());
+ }
+ return R;
+ }
+ return SourceRange();
+}
+
+/// \brief Retrieves the "raw" cursor extent, which is then extended to include
+/// the decl-specifier-seq for declarations.
+static SourceRange getFullCursorExtent(CXCursor C, SourceManager &SrcMgr) {
+ if (clang_isDeclaration(C.kind)) {
+ Decl *D = cxcursor::getCursorDecl(C);
+ if (!D)
+ return SourceRange();
+
+ SourceRange R = D->getSourceRange();
+
+ // Adjust the start of the location for declarations preceded by
+ // declaration specifiers.
+ SourceLocation StartLoc;
+ if (const DeclaratorDecl *DD = dyn_cast<DeclaratorDecl>(D)) {
+ if (TypeSourceInfo *TI = DD->getTypeSourceInfo())
+ StartLoc = TI->getTypeLoc().getLocStart();
+ } else if (TypedefDecl *Typedef = dyn_cast<TypedefDecl>(D)) {
+ if (TypeSourceInfo *TI = Typedef->getTypeSourceInfo())
+ StartLoc = TI->getTypeLoc().getLocStart();
+ }
+
+ if (StartLoc.isValid() && R.getBegin().isValid() &&
+ SrcMgr.isBeforeInTranslationUnit(StartLoc, R.getBegin()))
+ R.setBegin(StartLoc);
+
+ // FIXME: Multiple variables declared in a single declaration
+ // currently lack the information needed to correctly determine their
+ // ranges when accounting for the type-specifier. We use context
+ // stored in the CXCursor to determine if the VarDecl is in a DeclGroup,
+ // and if so, whether it is the first decl.
+ if (VarDecl *VD = dyn_cast<VarDecl>(D)) {
+ if (!cxcursor::isFirstInDeclGroup(C))
+ R.setBegin(VD->getLocation());
+ }
+
+ return R;
+ }
+
+ return getRawCursorExtent(C);
+}
+
+extern "C" {
+
+CXSourceRange clang_getCursorExtent(CXCursor C) {
+ SourceRange R = getRawCursorExtent(C);
+ if (R.isInvalid())
+ return clang_getNullRange();
+
+ return cxloc::translateSourceRange(getCursorContext(C), R);
+}
+
+CXCursor clang_getCursorReferenced(CXCursor C) {
+ if (clang_isInvalid(C.kind))
+ return clang_getNullCursor();
+
+ CXTranslationUnit tu = getCursorTU(C);
+ if (clang_isDeclaration(C.kind)) {
+ Decl *D = getCursorDecl(C);
+ if (!D)
+ return clang_getNullCursor();
+ if (UsingDecl *Using = dyn_cast<UsingDecl>(D))
+ return MakeCursorOverloadedDeclRef(Using, D->getLocation(), tu);
+ if (ObjCPropertyImplDecl *PropImpl =dyn_cast<ObjCPropertyImplDecl>(D))
+ if (ObjCPropertyDecl *Property = PropImpl->getPropertyDecl())
+ return MakeCXCursor(Property, tu);
+
+ return C;
+ }
+
+ if (clang_isExpression(C.kind)) {
+ Expr *E = getCursorExpr(C);
+ Decl *D = getDeclFromExpr(E);
+ if (D) {
+ CXCursor declCursor = MakeCXCursor(D, tu);
+ declCursor = getSelectorIdentifierCursor(getSelectorIdentifierIndex(C),
+ declCursor);
+ return declCursor;
+ }
+
+ if (OverloadExpr *Ovl = dyn_cast_or_null<OverloadExpr>(E))
+ return MakeCursorOverloadedDeclRef(Ovl, tu);
+
+ return clang_getNullCursor();
+ }
+
+ if (clang_isStatement(C.kind)) {
+ Stmt *S = getCursorStmt(C);
+ if (GotoStmt *Goto = dyn_cast_or_null<GotoStmt>(S))
+ if (LabelDecl *label = Goto->getLabel())
+ if (LabelStmt *labelS = label->getStmt())
+ return MakeCXCursor(labelS, getCursorDecl(C), tu);
+
+ return clang_getNullCursor();
+ }
+
+ if (C.kind == CXCursor_MacroExpansion) {
+ if (MacroDefinition *Def = getCursorMacroExpansion(C)->getDefinition())
+ return MakeMacroDefinitionCursor(Def, tu);
+ }
+
+ if (!clang_isReference(C.kind))
+ return clang_getNullCursor();
+
+ switch (C.kind) {
+ case CXCursor_ObjCSuperClassRef:
+ return MakeCXCursor(getCursorObjCSuperClassRef(C).first, tu);
+
+ case CXCursor_ObjCProtocolRef: {
+ ObjCProtocolDecl *Prot = getCursorObjCProtocolRef(C).first;
+ if (ObjCProtocolDecl *Def = Prot->getDefinition())
+ return MakeCXCursor(Def, tu);
+
+ return MakeCXCursor(Prot, tu);
+ }
+
+ case CXCursor_ObjCClassRef: {
+ ObjCInterfaceDecl *Class = getCursorObjCClassRef(C).first;
+ if (ObjCInterfaceDecl *Def = Class->getDefinition())
+ return MakeCXCursor(Def, tu);
+
+ return MakeCXCursor(Class, tu);
+ }
+
+ case CXCursor_TypeRef:
+ return MakeCXCursor(getCursorTypeRef(C).first, tu );
+
+ case CXCursor_TemplateRef:
+ return MakeCXCursor(getCursorTemplateRef(C).first, tu );
+
+ case CXCursor_NamespaceRef:
+ return MakeCXCursor(getCursorNamespaceRef(C).first, tu );
+
+ case CXCursor_MemberRef:
+ return MakeCXCursor(getCursorMemberRef(C).first, tu );
+
+ case CXCursor_CXXBaseSpecifier: {
+ CXXBaseSpecifier *B = cxcursor::getCursorCXXBaseSpecifier(C);
+ return clang_getTypeDeclaration(cxtype::MakeCXType(B->getType(),
+ tu ));
+ }
+
+ case CXCursor_LabelRef:
+ // FIXME: We end up faking the "parent" declaration here because we
+ // don't want to make CXCursor larger.
+ return MakeCXCursor(getCursorLabelRef(C).first,
+ static_cast<ASTUnit*>(tu->TUData)->getASTContext()
+ .getTranslationUnitDecl(),
+ tu);
+
+ case CXCursor_OverloadedDeclRef:
+ return C;
+
+ case CXCursor_VariableRef:
+ return MakeCXCursor(getCursorVariableRef(C).first, tu);
+
+ default:
+ // We would prefer to enumerate all non-reference cursor kinds here.
+ llvm_unreachable("Unhandled reference cursor kind");
+ }
+}
+
+CXCursor clang_getCursorDefinition(CXCursor C) {
+ if (clang_isInvalid(C.kind))
+ return clang_getNullCursor();
+
+ CXTranslationUnit TU = getCursorTU(C);
+
+ bool WasReference = false;
+ if (clang_isReference(C.kind) || clang_isExpression(C.kind)) {
+ C = clang_getCursorReferenced(C);
+ WasReference = true;
+ }
+
+ if (C.kind == CXCursor_MacroExpansion)
+ return clang_getCursorReferenced(C);
+
+ if (!clang_isDeclaration(C.kind))
+ return clang_getNullCursor();
+
+ Decl *D = getCursorDecl(C);
+ if (!D)
+ return clang_getNullCursor();
+
+ switch (D->getKind()) {
+ // Declaration kinds that don't really separate the notions of
+ // declaration and definition.
+ case Decl::Namespace:
+ case Decl::Typedef:
+ case Decl::TypeAlias:
+ case Decl::TypeAliasTemplate:
+ case Decl::TemplateTypeParm:
+ case Decl::EnumConstant:
+ case Decl::Field:
+ case Decl::IndirectField:
+ case Decl::ObjCIvar:
+ case Decl::ObjCAtDefsField:
+ case Decl::ImplicitParam:
+ case Decl::ParmVar:
+ case Decl::NonTypeTemplateParm:
+ case Decl::TemplateTemplateParm:
+ case Decl::ObjCCategoryImpl:
+ case Decl::ObjCImplementation:
+ case Decl::AccessSpec:
+ case Decl::LinkageSpec:
+ case Decl::ObjCPropertyImpl:
+ case Decl::FileScopeAsm:
+ case Decl::StaticAssert:
+ case Decl::Block:
+ case Decl::Label: // FIXME: Is this right??
+ case Decl::ClassScopeFunctionSpecialization:
+ case Decl::Import:
+ return C;
+
+ // Declaration kinds that don't make any sense here, but are
+ // nonetheless harmless.
+ case Decl::TranslationUnit:
+ break;
+
+ // Declaration kinds for which the definition is not resolvable.
+ case Decl::UnresolvedUsingTypename:
+ case Decl::UnresolvedUsingValue:
+ break;
+
+ case Decl::UsingDirective:
+ return MakeCXCursor(cast<UsingDirectiveDecl>(D)->getNominatedNamespace(),
+ TU);
+
+ case Decl::NamespaceAlias:
+ return MakeCXCursor(cast<NamespaceAliasDecl>(D)->getNamespace(), TU);
+
+ case Decl::Enum:
+ case Decl::Record:
+ case Decl::CXXRecord:
+ case Decl::ClassTemplateSpecialization:
+ case Decl::ClassTemplatePartialSpecialization:
+ if (TagDecl *Def = cast<TagDecl>(D)->getDefinition())
+ return MakeCXCursor(Def, TU);
+ return clang_getNullCursor();
+
+ case Decl::Function:
+ case Decl::CXXMethod:
+ case Decl::CXXConstructor:
+ case Decl::CXXDestructor:
+ case Decl::CXXConversion: {
+ const FunctionDecl *Def = 0;
+ if (cast<FunctionDecl>(D)->getBody(Def))
+ return MakeCXCursor(const_cast<FunctionDecl *>(Def), TU);
+ return clang_getNullCursor();
+ }
+
+ case Decl::Var: {
+ // Ask the variable if it has a definition.
+ if (VarDecl *Def = cast<VarDecl>(D)->getDefinition())
+ return MakeCXCursor(Def, TU);
+ return clang_getNullCursor();
+ }
+
+ case Decl::FunctionTemplate: {
+ const FunctionDecl *Def = 0;
+ if (cast<FunctionTemplateDecl>(D)->getTemplatedDecl()->getBody(Def))
+ return MakeCXCursor(Def->getDescribedFunctionTemplate(), TU);
+ return clang_getNullCursor();
+ }
+
+ case Decl::ClassTemplate: {
+ if (RecordDecl *Def = cast<ClassTemplateDecl>(D)->getTemplatedDecl()
+ ->getDefinition())
+ return MakeCXCursor(cast<CXXRecordDecl>(Def)->getDescribedClassTemplate(),
+ TU);
+ return clang_getNullCursor();
+ }
+
+ case Decl::Using:
+ return MakeCursorOverloadedDeclRef(cast<UsingDecl>(D),
+ D->getLocation(), TU);
+
+ case Decl::UsingShadow:
+ return clang_getCursorDefinition(
+ MakeCXCursor(cast<UsingShadowDecl>(D)->getTargetDecl(),
+ TU));
+
+ case Decl::ObjCMethod: {
+ ObjCMethodDecl *Method = cast<ObjCMethodDecl>(D);
+ if (Method->isThisDeclarationADefinition())
+ return C;
+
+ // Dig out the method definition in the associated
+ // @implementation, if we have it.
+ // FIXME: The ASTs should make finding the definition easier.
+ if (ObjCInterfaceDecl *Class
+ = dyn_cast<ObjCInterfaceDecl>(Method->getDeclContext()))
+ if (ObjCImplementationDecl *ClassImpl = Class->getImplementation())
+ if (ObjCMethodDecl *Def = ClassImpl->getMethod(Method->getSelector(),
+ Method->isInstanceMethod()))
+ if (Def->isThisDeclarationADefinition())
+ return MakeCXCursor(Def, TU);
+
+ return clang_getNullCursor();
+ }
+
+ case Decl::ObjCCategory:
+ if (ObjCCategoryImplDecl *Impl
+ = cast<ObjCCategoryDecl>(D)->getImplementation())
+ return MakeCXCursor(Impl, TU);
+ return clang_getNullCursor();
+
+ case Decl::ObjCProtocol:
+ if (ObjCProtocolDecl *Def = cast<ObjCProtocolDecl>(D)->getDefinition())
+ return MakeCXCursor(Def, TU);
+ return clang_getNullCursor();
+
+ case Decl::ObjCInterface: {
+ // There are two notions of a "definition" for an Objective-C
+ // class: the interface and its implementation. When we resolved a
+ // reference to an Objective-C class, produce the @interface as
+ // the definition; when we were provided with the interface,
+ // produce the @implementation as the definition.
+ ObjCInterfaceDecl *IFace = cast<ObjCInterfaceDecl>(D);
+ if (WasReference) {
+ if (ObjCInterfaceDecl *Def = IFace->getDefinition())
+ return MakeCXCursor(Def, TU);
+ } else if (ObjCImplementationDecl *Impl = IFace->getImplementation())
+ return MakeCXCursor(Impl, TU);
+ return clang_getNullCursor();
+ }
+
+ case Decl::ObjCProperty:
+ // FIXME: We don't really know where to find the
+ // ObjCPropertyImplDecls that implement this property.
+ return clang_getNullCursor();
+
+ case Decl::ObjCCompatibleAlias:
+ if (ObjCInterfaceDecl *Class
+ = cast<ObjCCompatibleAliasDecl>(D)->getClassInterface())
+ if (ObjCInterfaceDecl *Def = Class->getDefinition())
+ return MakeCXCursor(Def, TU);
+
+ return clang_getNullCursor();
+
+ case Decl::Friend:
+ if (NamedDecl *Friend = cast<FriendDecl>(D)->getFriendDecl())
+ return clang_getCursorDefinition(MakeCXCursor(Friend, TU));
+ return clang_getNullCursor();
+
+ case Decl::FriendTemplate:
+ if (NamedDecl *Friend = cast<FriendTemplateDecl>(D)->getFriendDecl())
+ return clang_getCursorDefinition(MakeCXCursor(Friend, TU));
+ return clang_getNullCursor();
+ }
+
+ return clang_getNullCursor();
+}
+
+unsigned clang_isCursorDefinition(CXCursor C) {
+ if (!clang_isDeclaration(C.kind))
+ return 0;
+
+ return clang_getCursorDefinition(C) == C;
+}
+
+CXCursor clang_getCanonicalCursor(CXCursor C) {
+ if (!clang_isDeclaration(C.kind))
+ return C;
+
+ if (Decl *D = getCursorDecl(C)) {
+ if (ObjCCategoryImplDecl *CatImplD = dyn_cast<ObjCCategoryImplDecl>(D))
+ if (ObjCCategoryDecl *CatD = CatImplD->getCategoryDecl())
+ return MakeCXCursor(CatD, getCursorTU(C));
+
+ if (ObjCImplDecl *ImplD = dyn_cast<ObjCImplDecl>(D))
+ if (ObjCInterfaceDecl *IFD = ImplD->getClassInterface())
+ return MakeCXCursor(IFD, getCursorTU(C));
+
+ return MakeCXCursor(D->getCanonicalDecl(), getCursorTU(C));
+ }
+
+ return C;
+}
+
+int clang_Cursor_getObjCSelectorIndex(CXCursor cursor) {
+ return cxcursor::getSelectorIdentifierIndexAndLoc(cursor).first;
+}
+
+unsigned clang_getNumOverloadedDecls(CXCursor C) {
+ if (C.kind != CXCursor_OverloadedDeclRef)
+ return 0;
+
+ OverloadedDeclRefStorage Storage = getCursorOverloadedDeclRef(C).first;
+ if (OverloadExpr *E = Storage.dyn_cast<OverloadExpr *>())
+ return E->getNumDecls();
+
+ if (OverloadedTemplateStorage *S
+ = Storage.dyn_cast<OverloadedTemplateStorage*>())
+ return S->size();
+
+ Decl *D = Storage.get<Decl*>();
+ if (UsingDecl *Using = dyn_cast<UsingDecl>(D))
+ return Using->shadow_size();
+
+ return 0;
+}
+
+CXCursor clang_getOverloadedDecl(CXCursor cursor, unsigned index) {
+ if (cursor.kind != CXCursor_OverloadedDeclRef)
+ return clang_getNullCursor();
+
+ if (index >= clang_getNumOverloadedDecls(cursor))
+ return clang_getNullCursor();
+
+ CXTranslationUnit TU = getCursorTU(cursor);
+ OverloadedDeclRefStorage Storage = getCursorOverloadedDeclRef(cursor).first;
+ if (OverloadExpr *E = Storage.dyn_cast<OverloadExpr *>())
+ return MakeCXCursor(E->decls_begin()[index], TU);
+
+ if (OverloadedTemplateStorage *S
+ = Storage.dyn_cast<OverloadedTemplateStorage*>())
+ return MakeCXCursor(S->begin()[index], TU);
+
+ Decl *D = Storage.get<Decl*>();
+ if (UsingDecl *Using = dyn_cast<UsingDecl>(D)) {
+ // FIXME: This is, unfortunately, linear time.
+ UsingDecl::shadow_iterator Pos = Using->shadow_begin();
+ std::advance(Pos, index);
+ return MakeCXCursor(cast<UsingShadowDecl>(*Pos)->getTargetDecl(), TU);
+ }
+
+ return clang_getNullCursor();
+}
+
+void clang_getDefinitionSpellingAndExtent(CXCursor C,
+ const char **startBuf,
+ const char **endBuf,
+ unsigned *startLine,
+ unsigned *startColumn,
+ unsigned *endLine,
+ unsigned *endColumn) {
+ assert(getCursorDecl(C) && "CXCursor has null decl");
+ NamedDecl *ND = static_cast<NamedDecl *>(getCursorDecl(C));
+ FunctionDecl *FD = dyn_cast<FunctionDecl>(ND);
+ CompoundStmt *Body = dyn_cast<CompoundStmt>(FD->getBody());
+
+ SourceManager &SM = FD->getASTContext().getSourceManager();
+ *startBuf = SM.getCharacterData(Body->getLBracLoc());
+ *endBuf = SM.getCharacterData(Body->getRBracLoc());
+ *startLine = SM.getSpellingLineNumber(Body->getLBracLoc());
+ *startColumn = SM.getSpellingColumnNumber(Body->getLBracLoc());
+ *endLine = SM.getSpellingLineNumber(Body->getRBracLoc());
+ *endColumn = SM.getSpellingColumnNumber(Body->getRBracLoc());
+}
+
+
+CXSourceRange clang_getCursorReferenceNameRange(CXCursor C, unsigned NameFlags,
+ unsigned PieceIndex) {
+ RefNamePieces Pieces;
+
+ switch (C.kind) {
+ case CXCursor_MemberRefExpr:
+ if (MemberExpr *E = dyn_cast<MemberExpr>(getCursorExpr(C)))
+ Pieces = buildPieces(NameFlags, true, E->getMemberNameInfo(),
+ E->getQualifierLoc().getSourceRange());
+ break;
+
+ case CXCursor_DeclRefExpr:
+ if (DeclRefExpr *E = dyn_cast<DeclRefExpr>(getCursorExpr(C)))
+ Pieces = buildPieces(NameFlags, false, E->getNameInfo(),
+ E->getQualifierLoc().getSourceRange(),
+ E->getOptionalExplicitTemplateArgs());
+ break;
+
+ case CXCursor_CallExpr:
+ if (CXXOperatorCallExpr *OCE =
+ dyn_cast<CXXOperatorCallExpr>(getCursorExpr(C))) {
+ Expr *Callee = OCE->getCallee();
+ if (ImplicitCastExpr *ICE = dyn_cast<ImplicitCastExpr>(Callee))
+ Callee = ICE->getSubExpr();
+
+ if (DeclRefExpr *DRE = dyn_cast<DeclRefExpr>(Callee))
+ Pieces = buildPieces(NameFlags, false, DRE->getNameInfo(),
+ DRE->getQualifierLoc().getSourceRange());
+ }
+ break;
+
+ default:
+ break;
+ }
+
+ if (Pieces.empty()) {
+ if (PieceIndex == 0)
+ return clang_getCursorExtent(C);
+ } else if (PieceIndex < Pieces.size()) {
+ SourceRange R = Pieces[PieceIndex];
+ if (R.isValid())
+ return cxloc::translateSourceRange(getCursorContext(C), R);
+ }
+
+ return clang_getNullRange();
+}
+
+void clang_enableStackTraces(void) {
+ llvm::sys::PrintStackTraceOnErrorSignal();
+}
+
+void clang_executeOnThread(void (*fn)(void*), void *user_data,
+ unsigned stack_size) {
+ llvm::llvm_execute_on_thread(fn, user_data, stack_size);
+}
+
+} // end: extern "C"
+
+//===----------------------------------------------------------------------===//
+// Token-based Operations.
+//===----------------------------------------------------------------------===//
+
+/* CXToken layout:
+ * int_data[0]: a CXTokenKind
+ * int_data[1]: starting token location
+ * int_data[2]: token length
+ * int_data[3]: reserved
+ * ptr_data: for identifiers and keywords, an IdentifierInfo*.
+ * otherwise unused.
+ */
+extern "C" {
+
+CXTokenKind clang_getTokenKind(CXToken CXTok) {
+ return static_cast<CXTokenKind>(CXTok.int_data[0]);
+}
+
+CXString clang_getTokenSpelling(CXTranslationUnit TU, CXToken CXTok) {
+ switch (clang_getTokenKind(CXTok)) {
+ case CXToken_Identifier:
+ case CXToken_Keyword:
+ // We know we have an IdentifierInfo*, so use that.
+ return createCXString(static_cast<IdentifierInfo *>(CXTok.ptr_data)
+ ->getNameStart());
+
+ case CXToken_Literal: {
+ // We have stashed the starting pointer in the ptr_data field. Use it.
+ const char *Text = static_cast<const char *>(CXTok.ptr_data);
+ return createCXString(StringRef(Text, CXTok.int_data[2]));
+ }
+
+ case CXToken_Punctuation:
+ case CXToken_Comment:
+ break;
+ }
+
+ // We have to find the starting buffer pointer the hard way, by
+ // deconstructing the source location.
+ ASTUnit *CXXUnit = static_cast<ASTUnit *>(TU->TUData);
+ if (!CXXUnit)
+ return createCXString("");
+
+ SourceLocation Loc = SourceLocation::getFromRawEncoding(CXTok.int_data[1]);
+ std::pair<FileID, unsigned> LocInfo
+ = CXXUnit->getSourceManager().getDecomposedSpellingLoc(Loc);
+ bool Invalid = false;
+ StringRef Buffer
+ = CXXUnit->getSourceManager().getBufferData(LocInfo.first, &Invalid);
+ if (Invalid)
+ return createCXString("");
+
+ return createCXString(Buffer.substr(LocInfo.second, CXTok.int_data[2]));
+}
+
+CXSourceLocation clang_getTokenLocation(CXTranslationUnit TU, CXToken CXTok) {
+ ASTUnit *CXXUnit = static_cast<ASTUnit *>(TU->TUData);
+ if (!CXXUnit)
+ return clang_getNullLocation();
+
+ return cxloc::translateSourceLocation(CXXUnit->getASTContext(),
+ SourceLocation::getFromRawEncoding(CXTok.int_data[1]));
+}
+
+CXSourceRange clang_getTokenExtent(CXTranslationUnit TU, CXToken CXTok) {
+ ASTUnit *CXXUnit = static_cast<ASTUnit *>(TU->TUData);
+ if (!CXXUnit)
+ return clang_getNullRange();
+
+ return cxloc::translateSourceRange(CXXUnit->getASTContext(),
+ SourceLocation::getFromRawEncoding(CXTok.int_data[1]));
+}
+
+static void getTokens(ASTUnit *CXXUnit, SourceRange Range,
+ SmallVectorImpl<CXToken> &CXTokens) {
+ SourceManager &SourceMgr = CXXUnit->getSourceManager();
+ std::pair<FileID, unsigned> BeginLocInfo
+ = SourceMgr.getDecomposedLoc(Range.getBegin());
+ std::pair<FileID, unsigned> EndLocInfo
+ = SourceMgr.getDecomposedLoc(Range.getEnd());
+
+ // Cannot tokenize across files.
+ if (BeginLocInfo.first != EndLocInfo.first)
+ return;
+
+ // Create a lexer
+ bool Invalid = false;
+ StringRef Buffer
+ = SourceMgr.getBufferData(BeginLocInfo.first, &Invalid);
+ if (Invalid)
+ return;
+
+ Lexer Lex(SourceMgr.getLocForStartOfFile(BeginLocInfo.first),
+ CXXUnit->getASTContext().getLangOpts(),
+ Buffer.begin(), Buffer.data() + BeginLocInfo.second, Buffer.end());
+ Lex.SetCommentRetentionState(true);
+
+ // Lex tokens until we hit the end of the range.
+ const char *EffectiveBufferEnd = Buffer.data() + EndLocInfo.second;
+ Token Tok;
+ bool previousWasAt = false;
+ do {
+ // Lex the next token
+ Lex.LexFromRawLexer(Tok);
+ if (Tok.is(tok::eof))
+ break;
+
+ // Initialize the CXToken.
+ CXToken CXTok;
+
+ // - Common fields
+ CXTok.int_data[1] = Tok.getLocation().getRawEncoding();
+ CXTok.int_data[2] = Tok.getLength();
+ CXTok.int_data[3] = 0;
+
+ // - Kind-specific fields
+ if (Tok.isLiteral()) {
+ CXTok.int_data[0] = CXToken_Literal;
+ CXTok.ptr_data = (void *)Tok.getLiteralData();
+ } else if (Tok.is(tok::raw_identifier)) {
+ // Lookup the identifier to determine whether we have a keyword.
+ IdentifierInfo *II
+ = CXXUnit->getPreprocessor().LookUpIdentifierInfo(Tok);
+
+ if ((II->getObjCKeywordID() != tok::objc_not_keyword) && previousWasAt) {
+ CXTok.int_data[0] = CXToken_Keyword;
+ }
+ else {
+ CXTok.int_data[0] = Tok.is(tok::identifier)
+ ? CXToken_Identifier
+ : CXToken_Keyword;
+ }
+ CXTok.ptr_data = II;
+ } else if (Tok.is(tok::comment)) {
+ CXTok.int_data[0] = CXToken_Comment;
+ CXTok.ptr_data = 0;
+ } else {
+ CXTok.int_data[0] = CXToken_Punctuation;
+ CXTok.ptr_data = 0;
+ }
+ CXTokens.push_back(CXTok);
+ previousWasAt = Tok.is(tok::at);
+ } while (Lex.getBufferLocation() <= EffectiveBufferEnd);
+}
+
+void clang_tokenize(CXTranslationUnit TU, CXSourceRange Range,
+ CXToken **Tokens, unsigned *NumTokens) {
+ if (Tokens)
+ *Tokens = 0;
+ if (NumTokens)
+ *NumTokens = 0;
+
+ ASTUnit *CXXUnit = static_cast<ASTUnit *>(TU->TUData);
+ if (!CXXUnit || !Tokens || !NumTokens)
+ return;
+
+ ASTUnit::ConcurrencyCheck Check(*CXXUnit);
+
+ SourceRange R = cxloc::translateCXSourceRange(Range);
+ if (R.isInvalid())
+ return;
+
+ SmallVector<CXToken, 32> CXTokens;
+ getTokens(CXXUnit, R, CXTokens);
+
+ if (CXTokens.empty())
+ return;
+
+ *Tokens = (CXToken *)malloc(sizeof(CXToken) * CXTokens.size());
+ memmove(*Tokens, CXTokens.data(), sizeof(CXToken) * CXTokens.size());
+ *NumTokens = CXTokens.size();
+}
+
+void clang_disposeTokens(CXTranslationUnit TU,
+ CXToken *Tokens, unsigned NumTokens) {
+ free(Tokens);
+}
+
+} // end: extern "C"
+
+//===----------------------------------------------------------------------===//
+// Token annotation APIs.
+//===----------------------------------------------------------------------===//
+
+typedef llvm::DenseMap<unsigned, CXCursor> AnnotateTokensData;
+static enum CXChildVisitResult AnnotateTokensVisitor(CXCursor cursor,
+ CXCursor parent,
+ CXClientData client_data);
+static bool AnnotateTokensPostChildrenVisitor(CXCursor cursor,
+ CXClientData client_data);
+
+namespace {
+class AnnotateTokensWorker {
+ AnnotateTokensData &Annotated;
+ CXToken *Tokens;
+ CXCursor *Cursors;
+ unsigned NumTokens;
+ unsigned TokIdx;
+ unsigned PreprocessingTokIdx;
+ CursorVisitor AnnotateVis;
+ SourceManager &SrcMgr;
+ bool HasContextSensitiveKeywords;
+
+ struct PostChildrenInfo {
+ CXCursor Cursor;
+ SourceRange CursorRange;
+ unsigned BeforeChildrenTokenIdx;
+ };
+ llvm::SmallVector<PostChildrenInfo, 8> PostChildrenInfos;
+
+ bool MoreTokens() const { return TokIdx < NumTokens; }
+ unsigned NextToken() const { return TokIdx; }
+ void AdvanceToken() { ++TokIdx; }
+ SourceLocation GetTokenLoc(unsigned tokI) {
+ return SourceLocation::getFromRawEncoding(Tokens[tokI].int_data[1]);
+ }
+ bool isFunctionMacroToken(unsigned tokI) const {
+ return Tokens[tokI].int_data[3] != 0;
+ }
+ SourceLocation getFunctionMacroTokenLoc(unsigned tokI) const {
+ return SourceLocation::getFromRawEncoding(Tokens[tokI].int_data[3]);
+ }
+
+ void annotateAndAdvanceTokens(CXCursor, RangeComparisonResult, SourceRange);
+ void annotateAndAdvanceFunctionMacroTokens(CXCursor, RangeComparisonResult,
+ SourceRange);
+
+public:
+ AnnotateTokensWorker(AnnotateTokensData &annotated,
+ CXToken *tokens, CXCursor *cursors, unsigned numTokens,
+ CXTranslationUnit tu, SourceRange RegionOfInterest)
+ : Annotated(annotated), Tokens(tokens), Cursors(cursors),
+ NumTokens(numTokens), TokIdx(0), PreprocessingTokIdx(0),
+ AnnotateVis(tu,
+ AnnotateTokensVisitor, this,
+ /*VisitPreprocessorLast=*/true,
+ /*VisitIncludedEntities=*/false,
+ RegionOfInterest,
+ /*VisitDeclsOnly=*/false,
+ AnnotateTokensPostChildrenVisitor),
+ SrcMgr(static_cast<ASTUnit*>(tu->TUData)->getSourceManager()),
+ HasContextSensitiveKeywords(false) { }
+
+ void VisitChildren(CXCursor C) { AnnotateVis.VisitChildren(C); }
+ enum CXChildVisitResult Visit(CXCursor cursor, CXCursor parent);
+ bool postVisitChildren(CXCursor cursor);
+ void AnnotateTokens();
+
+ /// \brief Determine whether the annotator saw any cursors that have
+ /// context-sensitive keywords.
+ bool hasContextSensitiveKeywords() const {
+ return HasContextSensitiveKeywords;
+ }
+
+ ~AnnotateTokensWorker() {
+ assert(PostChildrenInfos.empty());
+ }
+};
+}
+
+void AnnotateTokensWorker::AnnotateTokens() {
+ // Walk the AST within the region of interest, annotating tokens
+ // along the way.
+ AnnotateVis.visitFileRegion();
+
+ for (unsigned I = 0 ; I < TokIdx ; ++I) {
+ AnnotateTokensData::iterator Pos = Annotated.find(Tokens[I].int_data[1]);
+ if (Pos != Annotated.end() && !clang_isPreprocessing(Cursors[I].kind))
+ Cursors[I] = Pos->second;
+ }
+
+ // Finish up annotating any tokens left.
+ if (!MoreTokens())
+ return;
+
+ const CXCursor &C = clang_getNullCursor();
+ for (unsigned I = TokIdx ; I < NumTokens ; ++I) {
+ if (I < PreprocessingTokIdx && clang_isPreprocessing(Cursors[I].kind))
+ continue;
+
+ AnnotateTokensData::iterator Pos = Annotated.find(Tokens[I].int_data[1]);
+ Cursors[I] = (Pos == Annotated.end()) ? C : Pos->second;
+ }
+}
+
+/// \brief It annotates and advances tokens with a cursor until the comparison
+//// between the cursor location and the source range is the same as
+/// \arg compResult.
+///
+/// Pass RangeBefore to annotate tokens with a cursor until a range is reached.
+/// Pass RangeOverlap to annotate tokens inside a range.
+void AnnotateTokensWorker::annotateAndAdvanceTokens(CXCursor updateC,
+ RangeComparisonResult compResult,
+ SourceRange range) {
+ while (MoreTokens()) {
+ const unsigned I = NextToken();
+ if (isFunctionMacroToken(I))
+ return annotateAndAdvanceFunctionMacroTokens(updateC, compResult, range);
+
+ SourceLocation TokLoc = GetTokenLoc(I);
+ if (LocationCompare(SrcMgr, TokLoc, range) == compResult) {
+ Cursors[I] = updateC;
+ AdvanceToken();
+ continue;
+ }
+ break;
+ }
+}
+
+/// \brief Special annotation handling for macro argument tokens.
+void AnnotateTokensWorker::annotateAndAdvanceFunctionMacroTokens(
+ CXCursor updateC,
+ RangeComparisonResult compResult,
+ SourceRange range) {
+ assert(MoreTokens());
+ assert(isFunctionMacroToken(NextToken()) &&
+ "Should be called only for macro arg tokens");
+
+ // This works differently than annotateAndAdvanceTokens; because expanded
+ // macro arguments can have arbitrary translation-unit source order, we do not
+ // advance the token index one by one until a token fails the range test.
+ // We only advance once past all of the macro arg tokens if all of them
+ // pass the range test. If one of them fails we keep the token index pointing
+ // at the start of the macro arg tokens so that the failing token will be
+ // annotated by a subsequent annotation try.
+
+ bool atLeastOneCompFail = false;
+
+ unsigned I = NextToken();
+ for (; I < NumTokens && isFunctionMacroToken(I); ++I) {
+ SourceLocation TokLoc = getFunctionMacroTokenLoc(I);
+ if (TokLoc.isFileID())
+ continue; // not macro arg token, it's parens or comma.
+ if (LocationCompare(SrcMgr, TokLoc, range) == compResult) {
+ if (clang_isInvalid(clang_getCursorKind(Cursors[I])))
+ Cursors[I] = updateC;
+ } else
+ atLeastOneCompFail = true;
+ }
+
+ if (!atLeastOneCompFail)
+ TokIdx = I; // All of the tokens were handled, advance beyond all of them.
+}
+
+enum CXChildVisitResult
+AnnotateTokensWorker::Visit(CXCursor cursor, CXCursor parent) {
+ CXSourceLocation Loc = clang_getCursorLocation(cursor);
+ SourceRange cursorRange = getRawCursorExtent(cursor);
+ if (cursorRange.isInvalid())
+ return CXChildVisit_Recurse;
+
+ if (!HasContextSensitiveKeywords) {
+ // Objective-C properties can have context-sensitive keywords.
+ if (cursor.kind == CXCursor_ObjCPropertyDecl) {
+ if (ObjCPropertyDecl *Property
+ = dyn_cast_or_null<ObjCPropertyDecl>(getCursorDecl(cursor)))
+ HasContextSensitiveKeywords = Property->getPropertyAttributesAsWritten() != 0;
+ }
+ // Objective-C methods can have context-sensitive keywords.
+ else if (cursor.kind == CXCursor_ObjCInstanceMethodDecl ||
+ cursor.kind == CXCursor_ObjCClassMethodDecl) {
+ if (ObjCMethodDecl *Method
+ = dyn_cast_or_null<ObjCMethodDecl>(getCursorDecl(cursor))) {
+ if (Method->getObjCDeclQualifier())
+ HasContextSensitiveKeywords = true;
+ else {
+ for (ObjCMethodDecl::param_iterator P = Method->param_begin(),
+ PEnd = Method->param_end();
+ P != PEnd; ++P) {
+ if ((*P)->getObjCDeclQualifier()) {
+ HasContextSensitiveKeywords = true;
+ break;
+ }
+ }
+ }
+ }
+ }
+ // C++ methods can have context-sensitive keywords.
+ else if (cursor.kind == CXCursor_CXXMethod) {
+ if (CXXMethodDecl *Method
+ = dyn_cast_or_null<CXXMethodDecl>(getCursorDecl(cursor))) {
+ if (Method->hasAttr<FinalAttr>() || Method->hasAttr<OverrideAttr>())
+ HasContextSensitiveKeywords = true;
+ }
+ }
+ // C++ classes can have context-sensitive keywords.
+ else if (cursor.kind == CXCursor_StructDecl ||
+ cursor.kind == CXCursor_ClassDecl ||
+ cursor.kind == CXCursor_ClassTemplate ||
+ cursor.kind == CXCursor_ClassTemplatePartialSpecialization) {
+ if (Decl *D = getCursorDecl(cursor))
+ if (D->hasAttr<FinalAttr>())
+ HasContextSensitiveKeywords = true;
+ }
+ }
+
+ if (clang_isPreprocessing(cursor.kind)) {
+ // Items in the preprocessing record are kept separate from items in
+ // declarations, so we keep a separate token index.
+ unsigned SavedTokIdx = TokIdx;
+ TokIdx = PreprocessingTokIdx;
+
+ // Skip tokens up until we catch up to the beginning of the preprocessing
+ // entry.
+ while (MoreTokens()) {
+ const unsigned I = NextToken();
+ SourceLocation TokLoc = GetTokenLoc(I);
+ switch (LocationCompare(SrcMgr, TokLoc, cursorRange)) {
+ case RangeBefore:
+ AdvanceToken();
+ continue;
+ case RangeAfter:
+ case RangeOverlap:
+ break;
+ }
+ break;
+ }
+
+ // Look at all of the tokens within this range.
+ while (MoreTokens()) {
+ const unsigned I = NextToken();
+ SourceLocation TokLoc = GetTokenLoc(I);
+ switch (LocationCompare(SrcMgr, TokLoc, cursorRange)) {
+ case RangeBefore:
+ llvm_unreachable("Infeasible");
+ case RangeAfter:
+ break;
+ case RangeOverlap:
+ Cursors[I] = cursor;
+ AdvanceToken();
+ // For macro expansions, just note where the beginning of the macro
+ // expansion occurs.
+ if (cursor.kind == CXCursor_MacroExpansion)
+ break;
+ continue;
+ }
+ break;
+ }
+
+ // Save the preprocessing token index; restore the non-preprocessing
+ // token index.
+ PreprocessingTokIdx = TokIdx;
+ TokIdx = SavedTokIdx;
+ return CXChildVisit_Recurse;
+ }
+
+ if (cursorRange.isInvalid())
+ return CXChildVisit_Continue;
+
+ SourceLocation L = SourceLocation::getFromRawEncoding(Loc.int_data);
+
+ // Adjust the annotated range based specific declarations.
+ const enum CXCursorKind cursorK = clang_getCursorKind(cursor);
+ if (clang_isDeclaration(cursorK)) {
+ Decl *D = cxcursor::getCursorDecl(cursor);
+
+ SourceLocation StartLoc;
+ if (const DeclaratorDecl *DD = dyn_cast_or_null<DeclaratorDecl>(D)) {
+ if (TypeSourceInfo *TI = DD->getTypeSourceInfo())
+ StartLoc = TI->getTypeLoc().getLocStart();
+ } else if (TypedefDecl *Typedef = dyn_cast_or_null<TypedefDecl>(D)) {
+ if (TypeSourceInfo *TI = Typedef->getTypeSourceInfo())
+ StartLoc = TI->getTypeLoc().getLocStart();
+ }
+
+ if (StartLoc.isValid() && L.isValid() &&
+ SrcMgr.isBeforeInTranslationUnit(StartLoc, L))
+ cursorRange.setBegin(StartLoc);
+ }
+
+ // If the location of the cursor occurs within a macro instantiation, record
+ // the spelling location of the cursor in our annotation map. We can then
+ // paper over the token labelings during a post-processing step to try and
+ // get cursor mappings for tokens that are the *arguments* of a macro
+ // instantiation.
+ if (L.isMacroID()) {
+ unsigned rawEncoding = SrcMgr.getSpellingLoc(L).getRawEncoding();
+ // Only invalidate the old annotation if it isn't part of a preprocessing
+ // directive. Here we assume that the default construction of CXCursor
+ // results in CXCursor.kind being an initialized value (i.e., 0). If
+ // this isn't the case, we can fix by doing lookup + insertion.
+
+ CXCursor &oldC = Annotated[rawEncoding];
+ if (!clang_isPreprocessing(oldC.kind))
+ oldC = cursor;
+ }
+
+ const enum CXCursorKind K = clang_getCursorKind(parent);
+ const CXCursor updateC =
+ (clang_isInvalid(K) || K == CXCursor_TranslationUnit)
+ ? clang_getNullCursor() : parent;
+
+ annotateAndAdvanceTokens(updateC, RangeBefore, cursorRange);
+
+ // Avoid having the cursor of an expression "overwrite" the annotation of the
+ // variable declaration that it belongs to.
+ // This can happen for C++ constructor expressions whose range generally
+ // include the variable declaration, e.g.:
+ // MyCXXClass foo; // Make sure we don't annotate 'foo' as a CallExpr cursor.
+ if (clang_isExpression(cursorK)) {
+ Expr *E = getCursorExpr(cursor);
+ if (Decl *D = getCursorParentDecl(cursor)) {
+ const unsigned I = NextToken();
+ if (E->getLocStart().isValid() && D->getLocation().isValid() &&
+ E->getLocStart() == D->getLocation() &&
+ E->getLocStart() == GetTokenLoc(I)) {
+ Cursors[I] = updateC;
+ AdvanceToken();
+ }
+ }
+ }
+
+ // Before recursing into the children keep some state that we are going
+ // to use in the AnnotateTokensWorker::postVisitChildren callback to do some
+ // extra work after the child nodes are visited.
+ // Note that we don't call VisitChildren here to avoid traversing statements
+ // code-recursively which can blow the stack.
+
+ PostChildrenInfo Info;
+ Info.Cursor = cursor;
+ Info.CursorRange = cursorRange;
+ Info.BeforeChildrenTokenIdx = NextToken();
+ PostChildrenInfos.push_back(Info);
+
+ return CXChildVisit_Recurse;
+}
+
+bool AnnotateTokensWorker::postVisitChildren(CXCursor cursor) {
+ if (PostChildrenInfos.empty())
+ return false;
+ const PostChildrenInfo &Info = PostChildrenInfos.back();
+ if (!clang_equalCursors(Info.Cursor, cursor))
+ return false;
+
+ const unsigned BeforeChildren = Info.BeforeChildrenTokenIdx;
+ const unsigned AfterChildren = NextToken();
+ SourceRange cursorRange = Info.CursorRange;
+
+ // Scan the tokens that are at the end of the cursor, but are not captured
+ // but the child cursors.
+ annotateAndAdvanceTokens(cursor, RangeOverlap, cursorRange);
+
+ // Scan the tokens that are at the beginning of the cursor, but are not
+ // capture by the child cursors.
+ for (unsigned I = BeforeChildren; I != AfterChildren; ++I) {
+ if (!clang_isInvalid(clang_getCursorKind(Cursors[I])))
+ break;
+
+ Cursors[I] = cursor;
+ }
+
+ PostChildrenInfos.pop_back();
+ return false;
+}
+
+static enum CXChildVisitResult AnnotateTokensVisitor(CXCursor cursor,
+ CXCursor parent,
+ CXClientData client_data) {
+ return static_cast<AnnotateTokensWorker*>(client_data)->Visit(cursor, parent);
+}
+
+static bool AnnotateTokensPostChildrenVisitor(CXCursor cursor,
+ CXClientData client_data) {
+ return static_cast<AnnotateTokensWorker*>(client_data)->
+ postVisitChildren(cursor);
+}
+
+namespace {
+
+/// \brief Uses the macro expansions in the preprocessing record to find
+/// and mark tokens that are macro arguments. This info is used by the
+/// AnnotateTokensWorker.
+class MarkMacroArgTokensVisitor {
+ SourceManager &SM;
+ CXToken *Tokens;
+ unsigned NumTokens;
+ unsigned CurIdx;
+
+public:
+ MarkMacroArgTokensVisitor(SourceManager &SM,
+ CXToken *tokens, unsigned numTokens)
+ : SM(SM), Tokens(tokens), NumTokens(numTokens), CurIdx(0) { }
+
+ CXChildVisitResult visit(CXCursor cursor, CXCursor parent) {
+ if (cursor.kind != CXCursor_MacroExpansion)
+ return CXChildVisit_Continue;
+
+ SourceRange macroRange = getCursorMacroExpansion(cursor)->getSourceRange();
+ if (macroRange.getBegin() == macroRange.getEnd())
+ return CXChildVisit_Continue; // it's not a function macro.
+
+ for (; CurIdx < NumTokens; ++CurIdx) {
+ if (!SM.isBeforeInTranslationUnit(getTokenLoc(CurIdx),
+ macroRange.getBegin()))
+ break;
+ }
+
+ if (CurIdx == NumTokens)
+ return CXChildVisit_Break;
+
+ for (; CurIdx < NumTokens; ++CurIdx) {
+ SourceLocation tokLoc = getTokenLoc(CurIdx);
+ if (!SM.isBeforeInTranslationUnit(tokLoc, macroRange.getEnd()))
+ break;
+
+ setFunctionMacroTokenLoc(CurIdx, SM.getMacroArgExpandedLocation(tokLoc));
+ }
+
+ if (CurIdx == NumTokens)
+ return CXChildVisit_Break;
+
+ return CXChildVisit_Continue;
+ }
+
+private:
+ SourceLocation getTokenLoc(unsigned tokI) {
+ return SourceLocation::getFromRawEncoding(Tokens[tokI].int_data[1]);
+ }
+
+ void setFunctionMacroTokenLoc(unsigned tokI, SourceLocation loc) {
+ // The third field is reserved and currently not used. Use it here
+ // to mark macro arg expanded tokens with their expanded locations.
+ Tokens[tokI].int_data[3] = loc.getRawEncoding();
+ }
+};
+
+} // end anonymous namespace
+
+static CXChildVisitResult
+MarkMacroArgTokensVisitorDelegate(CXCursor cursor, CXCursor parent,
+ CXClientData client_data) {
+ return static_cast<MarkMacroArgTokensVisitor*>(client_data)->visit(cursor,
+ parent);
+}
+
+namespace {
+ struct clang_annotateTokens_Data {
+ CXTranslationUnit TU;
+ ASTUnit *CXXUnit;
+ CXToken *Tokens;
+ unsigned NumTokens;
+ CXCursor *Cursors;
+ };
+}
+
+static void annotatePreprocessorTokens(CXTranslationUnit TU,
+ SourceRange RegionOfInterest,
+ AnnotateTokensData &Annotated) {
+ ASTUnit *CXXUnit = static_cast<ASTUnit *>(TU->TUData);
+
+ SourceManager &SourceMgr = CXXUnit->getSourceManager();
+ std::pair<FileID, unsigned> BeginLocInfo
+ = SourceMgr.getDecomposedLoc(RegionOfInterest.getBegin());
+ std::pair<FileID, unsigned> EndLocInfo
+ = SourceMgr.getDecomposedLoc(RegionOfInterest.getEnd());
+
+ if (BeginLocInfo.first != EndLocInfo.first)
+ return;
+
+ StringRef Buffer;
+ bool Invalid = false;
+ Buffer = SourceMgr.getBufferData(BeginLocInfo.first, &Invalid);
+ if (Buffer.empty() || Invalid)
+ return;
+
+ Lexer Lex(SourceMgr.getLocForStartOfFile(BeginLocInfo.first),
+ CXXUnit->getASTContext().getLangOpts(),
+ Buffer.begin(), Buffer.data() + BeginLocInfo.second,
+ Buffer.end());
+ Lex.SetCommentRetentionState(true);
+
+ // Lex tokens in raw mode until we hit the end of the range, to avoid
+ // entering #includes or expanding macros.
+ while (true) {
+ Token Tok;
+ Lex.LexFromRawLexer(Tok);
+
+ reprocess:
+ if (Tok.is(tok::hash) && Tok.isAtStartOfLine()) {
+ // We have found a preprocessing directive. Gobble it up so that we
+ // don't see it while preprocessing these tokens later, but keep track
+ // of all of the token locations inside this preprocessing directive so
+ // that we can annotate them appropriately.
+ //
+ // FIXME: Some simple tests here could identify macro definitions and
+ // #undefs, to provide specific cursor kinds for those.
+ SmallVector<SourceLocation, 32> Locations;
+ do {
+ Locations.push_back(Tok.getLocation());
+ Lex.LexFromRawLexer(Tok);
+ } while (!Tok.isAtStartOfLine() && !Tok.is(tok::eof));
+
+ using namespace cxcursor;
+ CXCursor Cursor
+ = MakePreprocessingDirectiveCursor(SourceRange(Locations.front(),
+ Locations.back()),
+ TU);
+ for (unsigned I = 0, N = Locations.size(); I != N; ++I) {
+ Annotated[Locations[I].getRawEncoding()] = Cursor;
+ }
+
+ if (Tok.isAtStartOfLine())
+ goto reprocess;
+
+ continue;
+ }
+
+ if (Tok.is(tok::eof))
+ break;
+ }
+}
+
+// This gets run a separate thread to avoid stack blowout.
+static void clang_annotateTokensImpl(void *UserData) {
+ CXTranslationUnit TU = ((clang_annotateTokens_Data*)UserData)->TU;
+ ASTUnit *CXXUnit = ((clang_annotateTokens_Data*)UserData)->CXXUnit;
+ CXToken *Tokens = ((clang_annotateTokens_Data*)UserData)->Tokens;
+ const unsigned NumTokens = ((clang_annotateTokens_Data*)UserData)->NumTokens;
+ CXCursor *Cursors = ((clang_annotateTokens_Data*)UserData)->Cursors;
+
+ CIndexer *CXXIdx = (CIndexer*)TU->CIdx;
+ if (CXXIdx->isOptEnabled(CXGlobalOpt_ThreadBackgroundPriorityForEditing))
+ setThreadBackgroundPriority();
+
+ // Determine the region of interest, which contains all of the tokens.
+ SourceRange RegionOfInterest;
+ RegionOfInterest.setBegin(
+ cxloc::translateSourceLocation(clang_getTokenLocation(TU, Tokens[0])));
+ RegionOfInterest.setEnd(
+ cxloc::translateSourceLocation(clang_getTokenLocation(TU,
+ Tokens[NumTokens-1])));
+
+ // A mapping from the source locations found when re-lexing or traversing the
+ // region of interest to the corresponding cursors.
+ AnnotateTokensData Annotated;
+
+ // Relex the tokens within the source range to look for preprocessing
+ // directives.
+ annotatePreprocessorTokens(TU, RegionOfInterest, Annotated);
+
+ if (CXXUnit->getPreprocessor().getPreprocessingRecord()) {
+ // Search and mark tokens that are macro argument expansions.
+ MarkMacroArgTokensVisitor Visitor(CXXUnit->getSourceManager(),
+ Tokens, NumTokens);
+ CursorVisitor MacroArgMarker(TU,
+ MarkMacroArgTokensVisitorDelegate, &Visitor,
+ /*VisitPreprocessorLast=*/true,
+ /*VisitIncludedEntities=*/false,
+ RegionOfInterest);
+ MacroArgMarker.visitPreprocessedEntitiesInRegion();
+ }
+
+ // Annotate all of the source locations in the region of interest that map to
+ // a specific cursor.
+ AnnotateTokensWorker W(Annotated, Tokens, Cursors, NumTokens,
+ TU, RegionOfInterest);
+
+ // FIXME: We use a ridiculous stack size here because the data-recursion
+ // algorithm uses a large stack frame than the non-data recursive version,
+ // and AnnotationTokensWorker currently transforms the data-recursion
+ // algorithm back into a traditional recursion by explicitly calling
+ // VisitChildren(). We will need to remove this explicit recursive call.
+ W.AnnotateTokens();
+
+ // If we ran into any entities that involve context-sensitive keywords,
+ // take another pass through the tokens to mark them as such.
+ if (W.hasContextSensitiveKeywords()) {
+ for (unsigned I = 0; I != NumTokens; ++I) {
+ if (clang_getTokenKind(Tokens[I]) != CXToken_Identifier)
+ continue;
+
+ if (Cursors[I].kind == CXCursor_ObjCPropertyDecl) {
+ IdentifierInfo *II = static_cast<IdentifierInfo *>(Tokens[I].ptr_data);
+ if (ObjCPropertyDecl *Property
+ = dyn_cast_or_null<ObjCPropertyDecl>(getCursorDecl(Cursors[I]))) {
+ if (Property->getPropertyAttributesAsWritten() != 0 &&
+ llvm::StringSwitch<bool>(II->getName())
+ .Case("readonly", true)
+ .Case("assign", true)
+ .Case("unsafe_unretained", true)
+ .Case("readwrite", true)
+ .Case("retain", true)
+ .Case("copy", true)
+ .Case("nonatomic", true)
+ .Case("atomic", true)
+ .Case("getter", true)
+ .Case("setter", true)
+ .Case("strong", true)
+ .Case("weak", true)
+ .Default(false))
+ Tokens[I].int_data[0] = CXToken_Keyword;
+ }
+ continue;
+ }
+
+ if (Cursors[I].kind == CXCursor_ObjCInstanceMethodDecl ||
+ Cursors[I].kind == CXCursor_ObjCClassMethodDecl) {
+ IdentifierInfo *II = static_cast<IdentifierInfo *>(Tokens[I].ptr_data);
+ if (llvm::StringSwitch<bool>(II->getName())
+ .Case("in", true)
+ .Case("out", true)
+ .Case("inout", true)
+ .Case("oneway", true)
+ .Case("bycopy", true)
+ .Case("byref", true)
+ .Default(false))
+ Tokens[I].int_data[0] = CXToken_Keyword;
+ continue;
+ }
+
+ if (Cursors[I].kind == CXCursor_CXXFinalAttr ||
+ Cursors[I].kind == CXCursor_CXXOverrideAttr) {
+ Tokens[I].int_data[0] = CXToken_Keyword;
+ continue;
+ }
+ }
+ }
+}
+
+extern "C" {
+
+void clang_annotateTokens(CXTranslationUnit TU,
+ CXToken *Tokens, unsigned NumTokens,
+ CXCursor *Cursors) {
+
+ if (NumTokens == 0 || !Tokens || !Cursors)
+ return;
+
+ // Any token we don't specifically annotate will have a NULL cursor.
+ CXCursor C = clang_getNullCursor();
+ for (unsigned I = 0; I != NumTokens; ++I)
+ Cursors[I] = C;
+
+ ASTUnit *CXXUnit = static_cast<ASTUnit *>(TU->TUData);
+ if (!CXXUnit)
+ return;
+
+ ASTUnit::ConcurrencyCheck Check(*CXXUnit);
+
+ clang_annotateTokens_Data data = { TU, CXXUnit, Tokens, NumTokens, Cursors };
+ llvm::CrashRecoveryContext CRC;
+ if (!RunSafely(CRC, clang_annotateTokensImpl, &data,
+ GetSafetyThreadStackSize() * 2)) {
+ fprintf(stderr, "libclang: crash detected while annotating tokens\n");
+ }
+}
+
+} // end: extern "C"
+
+//===----------------------------------------------------------------------===//
+// Operations for querying linkage of a cursor.
+//===----------------------------------------------------------------------===//
+
+extern "C" {
+CXLinkageKind clang_getCursorLinkage(CXCursor cursor) {
+ if (!clang_isDeclaration(cursor.kind))
+ return CXLinkage_Invalid;
+
+ Decl *D = cxcursor::getCursorDecl(cursor);
+ if (NamedDecl *ND = dyn_cast_or_null<NamedDecl>(D))
+ switch (ND->getLinkage()) {
+ case NoLinkage: return CXLinkage_NoLinkage;
+ case InternalLinkage: return CXLinkage_Internal;
+ case UniqueExternalLinkage: return CXLinkage_UniqueExternal;
+ case ExternalLinkage: return CXLinkage_External;
+ };
+
+ return CXLinkage_Invalid;
+}
+} // end: extern "C"
+
+//===----------------------------------------------------------------------===//
+// Operations for querying language of a cursor.
+//===----------------------------------------------------------------------===//
+
+static CXLanguageKind getDeclLanguage(const Decl *D) {
+ if (!D)
+ return CXLanguage_C;
+
+ switch (D->getKind()) {
+ default:
+ break;
+ case Decl::ImplicitParam:
+ case Decl::ObjCAtDefsField:
+ case Decl::ObjCCategory:
+ case Decl::ObjCCategoryImpl:
+ case Decl::ObjCCompatibleAlias:
+ case Decl::ObjCImplementation:
+ case Decl::ObjCInterface:
+ case Decl::ObjCIvar:
+ case Decl::ObjCMethod:
+ case Decl::ObjCProperty:
+ case Decl::ObjCPropertyImpl:
+ case Decl::ObjCProtocol:
+ return CXLanguage_ObjC;
+ case Decl::CXXConstructor:
+ case Decl::CXXConversion:
+ case Decl::CXXDestructor:
+ case Decl::CXXMethod:
+ case Decl::CXXRecord:
+ case Decl::ClassTemplate:
+ case Decl::ClassTemplatePartialSpecialization:
+ case Decl::ClassTemplateSpecialization:
+ case Decl::Friend:
+ case Decl::FriendTemplate:
+ case Decl::FunctionTemplate:
+ case Decl::LinkageSpec:
+ case Decl::Namespace:
+ case Decl::NamespaceAlias:
+ case Decl::NonTypeTemplateParm:
+ case Decl::StaticAssert:
+ case Decl::TemplateTemplateParm:
+ case Decl::TemplateTypeParm:
+ case Decl::UnresolvedUsingTypename:
+ case Decl::UnresolvedUsingValue:
+ case Decl::Using:
+ case Decl::UsingDirective:
+ case Decl::UsingShadow:
+ return CXLanguage_CPlusPlus;
+ }
+
+ return CXLanguage_C;
+}
+
+extern "C" {
+
+enum CXAvailabilityKind clang_getCursorAvailability(CXCursor cursor) {
+ if (clang_isDeclaration(cursor.kind))
+ if (Decl *D = cxcursor::getCursorDecl(cursor)) {
+ if (isa<FunctionDecl>(D) && cast<FunctionDecl>(D)->isDeleted())
+ return CXAvailability_Available;
+
+ switch (D->getAvailability()) {
+ case AR_Available:
+ case AR_NotYetIntroduced:
+ return CXAvailability_Available;
+
+ case AR_Deprecated:
+ return CXAvailability_Deprecated;
+
+ case AR_Unavailable:
+ return CXAvailability_NotAvailable;
+ }
+ }
+
+ return CXAvailability_Available;
+}
+
+static CXVersion convertVersion(VersionTuple In) {
+ CXVersion Out = { -1, -1, -1 };
+ if (In.empty())
+ return Out;
+
+ Out.Major = In.getMajor();
+
+ if (llvm::Optional<unsigned> Minor = In.getMinor())
+ Out.Minor = *Minor;
+ else
+ return Out;
+
+ if (llvm::Optional<unsigned> Subminor = In.getSubminor())
+ Out.Subminor = *Subminor;
+
+ return Out;
+}
+
+int clang_getCursorPlatformAvailability(CXCursor cursor,
+ int *always_deprecated,
+ CXString *deprecated_message,
+ int *always_unavailable,
+ CXString *unavailable_message,
+ CXPlatformAvailability *availability,
+ int availability_size) {
+ if (always_deprecated)
+ *always_deprecated = 0;
+ if (deprecated_message)
+ *deprecated_message = cxstring::createCXString("", /*DupString=*/false);
+ if (always_unavailable)
+ *always_unavailable = 0;
+ if (unavailable_message)
+ *unavailable_message = cxstring::createCXString("", /*DupString=*/false);
+
+ if (!clang_isDeclaration(cursor.kind))
+ return 0;
+
+ Decl *D = cxcursor::getCursorDecl(cursor);
+ if (!D)
+ return 0;
+
+ int N = 0;
+ for (Decl::attr_iterator A = D->attr_begin(), AEnd = D->attr_end(); A != AEnd;
+ ++A) {
+ if (DeprecatedAttr *Deprecated = dyn_cast<DeprecatedAttr>(*A)) {
+ if (always_deprecated)
+ *always_deprecated = 1;
+ if (deprecated_message)
+ *deprecated_message = cxstring::createCXString(Deprecated->getMessage());
+ continue;
+ }
+
+ if (UnavailableAttr *Unavailable = dyn_cast<UnavailableAttr>(*A)) {
+ if (always_unavailable)
+ *always_unavailable = 1;
+ if (unavailable_message) {
+ *unavailable_message
+ = cxstring::createCXString(Unavailable->getMessage());
+ }
+ continue;
+ }
+
+ if (AvailabilityAttr *Avail = dyn_cast<AvailabilityAttr>(*A)) {
+ if (N < availability_size) {
+ availability[N].Platform
+ = cxstring::createCXString(Avail->getPlatform()->getName());
+ availability[N].Introduced = convertVersion(Avail->getIntroduced());
+ availability[N].Deprecated = convertVersion(Avail->getDeprecated());
+ availability[N].Obsoleted = convertVersion(Avail->getObsoleted());
+ availability[N].Unavailable = Avail->getUnavailable();
+ availability[N].Message = cxstring::createCXString(Avail->getMessage());
+ }
+ ++N;
+ }
+ }
+
+ return N;
+}
+
+void clang_disposeCXPlatformAvailability(CXPlatformAvailability *availability) {
+ clang_disposeString(availability->Platform);
+ clang_disposeString(availability->Message);
+}
+
+CXLanguageKind clang_getCursorLanguage(CXCursor cursor) {
+ if (clang_isDeclaration(cursor.kind))
+ return getDeclLanguage(cxcursor::getCursorDecl(cursor));
+
+ return CXLanguage_Invalid;
+}
+
+ /// \brief If the given cursor is the "templated" declaration
+ /// descibing a class or function template, return the class or
+ /// function template.
+static Decl *maybeGetTemplateCursor(Decl *D) {
+ if (!D)
+ return 0;
+
+ if (FunctionDecl *FD = dyn_cast<FunctionDecl>(D))
+ if (FunctionTemplateDecl *FunTmpl = FD->getDescribedFunctionTemplate())
+ return FunTmpl;
+
+ if (CXXRecordDecl *RD = dyn_cast<CXXRecordDecl>(D))
+ if (ClassTemplateDecl *ClassTmpl = RD->getDescribedClassTemplate())
+ return ClassTmpl;
+
+ return D;
+}
+
+CXCursor clang_getCursorSemanticParent(CXCursor cursor) {
+ if (clang_isDeclaration(cursor.kind)) {
+ if (Decl *D = getCursorDecl(cursor)) {
+ DeclContext *DC = D->getDeclContext();
+ if (!DC)
+ return clang_getNullCursor();
+
+ return MakeCXCursor(maybeGetTemplateCursor(cast<Decl>(DC)),
+ getCursorTU(cursor));
+ }
+ }
+
+ if (clang_isStatement(cursor.kind) || clang_isExpression(cursor.kind)) {
+ if (Decl *D = getCursorDecl(cursor))
+ return MakeCXCursor(D, getCursorTU(cursor));
+ }
+
+ return clang_getNullCursor();
+}
+
+CXCursor clang_getCursorLexicalParent(CXCursor cursor) {
+ if (clang_isDeclaration(cursor.kind)) {
+ if (Decl *D = getCursorDecl(cursor)) {
+ DeclContext *DC = D->getLexicalDeclContext();
+ if (!DC)
+ return clang_getNullCursor();
+
+ return MakeCXCursor(maybeGetTemplateCursor(cast<Decl>(DC)),
+ getCursorTU(cursor));
+ }
+ }
+
+ // FIXME: Note that we can't easily compute the lexical context of a
+ // statement or expression, so we return nothing.
+ return clang_getNullCursor();
+}
+
+CXFile clang_getIncludedFile(CXCursor cursor) {
+ if (cursor.kind != CXCursor_InclusionDirective)
+ return 0;
+
+ InclusionDirective *ID = getCursorInclusionDirective(cursor);
+ return (void *)ID->getFile();
+}
+
+CXSourceRange clang_Cursor_getCommentRange(CXCursor C) {
+ if (!clang_isDeclaration(C.kind))
+ return clang_getNullRange();
+
+ const Decl *D = getCursorDecl(C);
+ ASTContext &Context = getCursorContext(C);
+ const RawComment *RC = Context.getRawCommentForAnyRedecl(D);
+ if (!RC)
+ return clang_getNullRange();
+
+ return cxloc::translateSourceRange(Context, RC->getSourceRange());
+}
+
+CXString clang_Cursor_getRawCommentText(CXCursor C) {
+ if (!clang_isDeclaration(C.kind))
+ return createCXString((const char *) NULL);
+
+ const Decl *D = getCursorDecl(C);
+ ASTContext &Context = getCursorContext(C);
+ const RawComment *RC = Context.getRawCommentForAnyRedecl(D);
+ StringRef RawText = RC ? RC->getRawText(Context.getSourceManager()) :
+ StringRef();
+
+ // Don't duplicate the string because RawText points directly into source
+ // code.
+ return createCXString(RawText, false);
+}
+
+CXString clang_Cursor_getBriefCommentText(CXCursor C) {
+ if (!clang_isDeclaration(C.kind))
+ return createCXString((const char *) NULL);
+
+ const Decl *D = getCursorDecl(C);
+ const ASTContext &Context = getCursorContext(C);
+ const RawComment *RC = Context.getRawCommentForAnyRedecl(D);
+
+ if (RC) {
+ StringRef BriefText = RC->getBriefText(Context);
+
+ // Don't duplicate the string because RawComment ensures that this memory
+ // will not go away.
+ return createCXString(BriefText, false);
+ }
+
+ return createCXString((const char *) NULL);
+}
+
+CXComment clang_Cursor_getParsedComment(CXCursor C) {
+ if (!clang_isDeclaration(C.kind))
+ return cxcomment::createCXComment(NULL, NULL);
+
+ const Decl *D = getCursorDecl(C);
+ const ASTContext &Context = getCursorContext(C);
+ const comments::FullComment *FC = Context.getCommentForDecl(D, /*PP=*/ NULL);
+
+ return cxcomment::createCXComment(FC, getCursorTU(C));
+}
+
+CXModule clang_Cursor_getModule(CXCursor C) {
+ if (C.kind == CXCursor_ModuleImportDecl) {
+ if (ImportDecl *ImportD = dyn_cast_or_null<ImportDecl>(getCursorDecl(C)))
+ return ImportD->getImportedModule();
+ }
+
+ return 0;
+}
+
+CXModule clang_Module_getParent(CXModule CXMod) {
+ if (!CXMod)
+ return 0;
+ Module *Mod = static_cast<Module*>(CXMod);
+ return Mod->Parent;
+}
+
+CXString clang_Module_getName(CXModule CXMod) {
+ if (!CXMod)
+ return createCXString("");
+ Module *Mod = static_cast<Module*>(CXMod);
+ return createCXString(Mod->Name);
+}
+
+CXString clang_Module_getFullName(CXModule CXMod) {
+ if (!CXMod)
+ return createCXString("");
+ Module *Mod = static_cast<Module*>(CXMod);
+ return createCXString(Mod->getFullModuleName());
+}
+
+unsigned clang_Module_getNumTopLevelHeaders(CXModule CXMod) {
+ if (!CXMod)
+ return 0;
+ Module *Mod = static_cast<Module*>(CXMod);
+ return Mod->TopHeaders.size();
+}
+
+CXFile clang_Module_getTopLevelHeader(CXModule CXMod, unsigned Index) {
+ if (!CXMod)
+ return 0;
+ Module *Mod = static_cast<Module*>(CXMod);
+
+ if (Index < Mod->TopHeaders.size())
+ return const_cast<FileEntry *>(Mod->TopHeaders[Index]);
+
+ return 0;
+}
+
+} // end: extern "C"
+
+//===----------------------------------------------------------------------===//
+// C++ AST instrospection.
+//===----------------------------------------------------------------------===//
+
+extern "C" {
+unsigned clang_CXXMethod_isStatic(CXCursor C) {
+ if (!clang_isDeclaration(C.kind))
+ return 0;
+
+ CXXMethodDecl *Method = 0;
+ Decl *D = cxcursor::getCursorDecl(C);
+ if (FunctionTemplateDecl *FunTmpl = dyn_cast_or_null<FunctionTemplateDecl>(D))
+ Method = dyn_cast<CXXMethodDecl>(FunTmpl->getTemplatedDecl());
+ else
+ Method = dyn_cast_or_null<CXXMethodDecl>(D);
+ return (Method && Method->isStatic()) ? 1 : 0;
+}
+
+unsigned clang_CXXMethod_isVirtual(CXCursor C) {
+ if (!clang_isDeclaration(C.kind))
+ return 0;
+
+ CXXMethodDecl *Method = 0;
+ Decl *D = cxcursor::getCursorDecl(C);
+ if (FunctionTemplateDecl *FunTmpl = dyn_cast_or_null<FunctionTemplateDecl>(D))
+ Method = dyn_cast<CXXMethodDecl>(FunTmpl->getTemplatedDecl());
+ else
+ Method = dyn_cast_or_null<CXXMethodDecl>(D);
+ return (Method && Method->isVirtual()) ? 1 : 0;
+}
+} // end: extern "C"
+
+//===----------------------------------------------------------------------===//
+// Attribute introspection.
+//===----------------------------------------------------------------------===//
+
+extern "C" {
+CXType clang_getIBOutletCollectionType(CXCursor C) {
+ if (C.kind != CXCursor_IBOutletCollectionAttr)
+ return cxtype::MakeCXType(QualType(), cxcursor::getCursorTU(C));
+
+ IBOutletCollectionAttr *A =
+ cast<IBOutletCollectionAttr>(cxcursor::getCursorAttr(C));
+
+ return cxtype::MakeCXType(A->getInterface(), cxcursor::getCursorTU(C));
+}
+} // end: extern "C"
+
+//===----------------------------------------------------------------------===//
+// Inspecting memory usage.
+//===----------------------------------------------------------------------===//
+
+typedef std::vector<CXTUResourceUsageEntry> MemUsageEntries;
+
+static inline void createCXTUResourceUsageEntry(MemUsageEntries &entries,
+ enum CXTUResourceUsageKind k,
+ unsigned long amount) {
+ CXTUResourceUsageEntry entry = { k, amount };
+ entries.push_back(entry);
+}
+
+extern "C" {
+
+const char *clang_getTUResourceUsageName(CXTUResourceUsageKind kind) {
+ const char *str = "";
+ switch (kind) {
+ case CXTUResourceUsage_AST:
+ str = "ASTContext: expressions, declarations, and types";
+ break;
+ case CXTUResourceUsage_Identifiers:
+ str = "ASTContext: identifiers";
+ break;
+ case CXTUResourceUsage_Selectors:
+ str = "ASTContext: selectors";
+ break;
+ case CXTUResourceUsage_GlobalCompletionResults:
+ str = "Code completion: cached global results";
+ break;
+ case CXTUResourceUsage_SourceManagerContentCache:
+ str = "SourceManager: content cache allocator";
+ break;
+ case CXTUResourceUsage_AST_SideTables:
+ str = "ASTContext: side tables";
+ break;
+ case CXTUResourceUsage_SourceManager_Membuffer_Malloc:
+ str = "SourceManager: malloc'ed memory buffers";
+ break;
+ case CXTUResourceUsage_SourceManager_Membuffer_MMap:
+ str = "SourceManager: mmap'ed memory buffers";
+ break;
+ case CXTUResourceUsage_ExternalASTSource_Membuffer_Malloc:
+ str = "ExternalASTSource: malloc'ed memory buffers";
+ break;
+ case CXTUResourceUsage_ExternalASTSource_Membuffer_MMap:
+ str = "ExternalASTSource: mmap'ed memory buffers";
+ break;
+ case CXTUResourceUsage_Preprocessor:
+ str = "Preprocessor: malloc'ed memory";
+ break;
+ case CXTUResourceUsage_PreprocessingRecord:
+ str = "Preprocessor: PreprocessingRecord";
+ break;
+ case CXTUResourceUsage_SourceManager_DataStructures:
+ str = "SourceManager: data structures and tables";
+ break;
+ case CXTUResourceUsage_Preprocessor_HeaderSearch:
+ str = "Preprocessor: header search tables";
+ break;
+ }
+ return str;
+}
+
+CXTUResourceUsage clang_getCXTUResourceUsage(CXTranslationUnit TU) {
+ if (!TU) {
+ CXTUResourceUsage usage = { (void*) 0, 0, 0 };
+ return usage;
+ }
+
+ ASTUnit *astUnit = static_cast<ASTUnit*>(TU->TUData);
+ OwningPtr<MemUsageEntries> entries(new MemUsageEntries());
+ ASTContext &astContext = astUnit->getASTContext();
+
+ // How much memory is used by AST nodes and types?
+ createCXTUResourceUsageEntry(*entries, CXTUResourceUsage_AST,
+ (unsigned long) astContext.getASTAllocatedMemory());
+
+ // How much memory is used by identifiers?
+ createCXTUResourceUsageEntry(*entries, CXTUResourceUsage_Identifiers,
+ (unsigned long) astContext.Idents.getAllocator().getTotalMemory());
+
+ // How much memory is used for selectors?
+ createCXTUResourceUsageEntry(*entries, CXTUResourceUsage_Selectors,
+ (unsigned long) astContext.Selectors.getTotalMemory());
+
+ // How much memory is used by ASTContext's side tables?
+ createCXTUResourceUsageEntry(*entries, CXTUResourceUsage_AST_SideTables,
+ (unsigned long) astContext.getSideTableAllocatedMemory());
+
+ // How much memory is used for caching global code completion results?
+ unsigned long completionBytes = 0;
+ if (GlobalCodeCompletionAllocator *completionAllocator =
+ astUnit->getCachedCompletionAllocator().getPtr()) {
+ completionBytes = completionAllocator->getTotalMemory();
+ }
+ createCXTUResourceUsageEntry(*entries,
+ CXTUResourceUsage_GlobalCompletionResults,
+ completionBytes);
+
+ // How much memory is being used by SourceManager's content cache?
+ createCXTUResourceUsageEntry(*entries,
+ CXTUResourceUsage_SourceManagerContentCache,
+ (unsigned long) astContext.getSourceManager().getContentCacheSize());
+
+ // How much memory is being used by the MemoryBuffer's in SourceManager?
+ const SourceManager::MemoryBufferSizes &srcBufs =
+ astUnit->getSourceManager().getMemoryBufferSizes();
+
+ createCXTUResourceUsageEntry(*entries,
+ CXTUResourceUsage_SourceManager_Membuffer_Malloc,
+ (unsigned long) srcBufs.malloc_bytes);
+ createCXTUResourceUsageEntry(*entries,
+ CXTUResourceUsage_SourceManager_Membuffer_MMap,
+ (unsigned long) srcBufs.mmap_bytes);
+ createCXTUResourceUsageEntry(*entries,
+ CXTUResourceUsage_SourceManager_DataStructures,
+ (unsigned long) astContext.getSourceManager()
+ .getDataStructureSizes());
+
+ // How much memory is being used by the ExternalASTSource?
+ if (ExternalASTSource *esrc = astContext.getExternalSource()) {
+ const ExternalASTSource::MemoryBufferSizes &sizes =
+ esrc->getMemoryBufferSizes();
+
+ createCXTUResourceUsageEntry(*entries,
+ CXTUResourceUsage_ExternalASTSource_Membuffer_Malloc,
+ (unsigned long) sizes.malloc_bytes);
+ createCXTUResourceUsageEntry(*entries,
+ CXTUResourceUsage_ExternalASTSource_Membuffer_MMap,
+ (unsigned long) sizes.mmap_bytes);
+ }
+
+ // How much memory is being used by the Preprocessor?
+ Preprocessor &pp = astUnit->getPreprocessor();
+ createCXTUResourceUsageEntry(*entries,
+ CXTUResourceUsage_Preprocessor,
+ pp.getTotalMemory());
+
+ if (PreprocessingRecord *pRec = pp.getPreprocessingRecord()) {
+ createCXTUResourceUsageEntry(*entries,
+ CXTUResourceUsage_PreprocessingRecord,
+ pRec->getTotalMemory());
+ }
+
+ createCXTUResourceUsageEntry(*entries,
+ CXTUResourceUsage_Preprocessor_HeaderSearch,
+ pp.getHeaderSearchInfo().getTotalMemory());
+
+ CXTUResourceUsage usage = { (void*) entries.get(),
+ (unsigned) entries->size(),
+ entries->size() ? &(*entries)[0] : 0 };
+ entries.take();
+ return usage;
+}
+
+void clang_disposeCXTUResourceUsage(CXTUResourceUsage usage) {
+ if (usage.data)
+ delete (MemUsageEntries*) usage.data;
+}
+
+} // end extern "C"
+
+void clang::PrintLibclangResourceUsage(CXTranslationUnit TU) {
+ CXTUResourceUsage Usage = clang_getCXTUResourceUsage(TU);
+ for (unsigned I = 0; I != Usage.numEntries; ++I)
+ fprintf(stderr, " %s: %lu\n",
+ clang_getTUResourceUsageName(Usage.entries[I].kind),
+ Usage.entries[I].amount);
+
+ clang_disposeCXTUResourceUsage(Usage);
+}
+
+//===----------------------------------------------------------------------===//
+// Misc. utility functions.
+//===----------------------------------------------------------------------===//
+
+/// Default to using an 8 MB stack size on "safety" threads.
+static unsigned SafetyStackThreadSize = 8 << 20;
+
+namespace clang {
+
+bool RunSafely(llvm::CrashRecoveryContext &CRC,
+ void (*Fn)(void*), void *UserData,
+ unsigned Size) {
+ if (!Size)
+ Size = GetSafetyThreadStackSize();
+ if (Size)
+ return CRC.RunSafelyOnThread(Fn, UserData, Size);
+ return CRC.RunSafely(Fn, UserData);
+}
+
+unsigned GetSafetyThreadStackSize() {
+ return SafetyStackThreadSize;
+}
+
+void SetSafetyThreadStackSize(unsigned Value) {
+ SafetyStackThreadSize = Value;
+}
+
+}
+
+void clang::setThreadBackgroundPriority() {
+ if (getenv("LIBCLANG_BGPRIO_DISABLE"))
+ return;
+
+ // FIXME: Move to llvm/Support and make it cross-platform.
+#ifdef __APPLE__
+ setpriority(PRIO_DARWIN_THREAD, 0, PRIO_DARWIN_BG);
+#endif
+}
+
+void cxindex::printDiagsToStderr(ASTUnit *Unit) {
+ if (!Unit)
+ return;
+
+ for (ASTUnit::stored_diag_iterator D = Unit->stored_diag_begin(),
+ DEnd = Unit->stored_diag_end();
+ D != DEnd; ++D) {
+ CXStoredDiagnostic Diag(*D, Unit->getASTContext().getLangOpts());
+ CXString Msg = clang_formatDiagnostic(&Diag,
+ clang_defaultDiagnosticDisplayOptions());
+ fprintf(stderr, "%s\n", clang_getCString(Msg));
+ clang_disposeString(Msg);
+ }
+#ifdef LLVM_ON_WIN32
+ // On Windows, force a flush, since there may be multiple copies of
+ // stderr and stdout in the file system, all with different buffers
+ // but writing to the same device.
+ fflush(stderr);
+#endif
+}
+
+extern "C" {
+
+CXString clang_getClangVersion() {
+ return createCXString(getClangFullVersion());
+}
+
+} // end: extern "C"
+
diff --git a/clang/tools/libclang/CIndexUSRs.cpp b/clang/tools/libclang/CIndexUSRs.cpp index b76363e3248..f88862b9137 100644 --- a/clang/tools/libclang/CIndexUSRs.cpp +++ b/clang/tools/libclang/CIndexUSRs.cpp @@ -1,906 +1,912 @@ -//===- CIndexUSR.cpp - Clang-C Source Indexing Library --------------------===// -// -// The LLVM Compiler Infrastructure -// -// This file is distributed under the University of Illinois Open Source -// License. See LICENSE.TXT for details. -// -//===----------------------------------------------------------------------===// -// -// This file implements the generation and use of USRs from CXEntities. -// -//===----------------------------------------------------------------------===// - -#include "CIndexer.h" -#include "CXCursor.h" -#include "CXString.h" -#include "clang/AST/DeclTemplate.h" -#include "clang/AST/DeclVisitor.h" -#include "clang/Frontend/ASTUnit.h" -#include "clang/Lex/PreprocessingRecord.h" -#include "llvm/ADT/SmallString.h" -#include "llvm/Support/raw_ostream.h" - -using namespace clang; -using namespace clang::cxstring; - -//===----------------------------------------------------------------------===// -// USR generation. -//===----------------------------------------------------------------------===// - -namespace { -class USRGenerator : public DeclVisitor<USRGenerator> { - OwningPtr<SmallString<128> > OwnedBuf; - SmallVectorImpl<char> &Buf; - llvm::raw_svector_ostream Out; - bool IgnoreResults; - ASTContext *Context; - bool generatedLoc; - - llvm::DenseMap<const Type *, unsigned> TypeSubstitutions; - -public: - explicit USRGenerator(ASTContext *Ctx = 0, SmallVectorImpl<char> *extBuf = 0) - : OwnedBuf(extBuf ? 0 : new SmallString<128>()), - Buf(extBuf ? *extBuf : *OwnedBuf.get()), - Out(Buf), - IgnoreResults(false), - Context(Ctx), - generatedLoc(false) - { - // Add the USR space prefix. - Out << "c:"; - } - - StringRef str() { - return Out.str(); - } - - USRGenerator* operator->() { return this; } - - template <typename T> - llvm::raw_svector_ostream &operator<<(const T &x) { - Out << x; - return Out; - } - - bool ignoreResults() const { return IgnoreResults; } - - // Visitation methods from generating USRs from AST elements. - void VisitDeclContext(DeclContext *D); - void VisitFieldDecl(FieldDecl *D); - void VisitFunctionDecl(FunctionDecl *D); - void VisitNamedDecl(NamedDecl *D); - void VisitNamespaceDecl(NamespaceDecl *D); - void VisitNamespaceAliasDecl(NamespaceAliasDecl *D); - void VisitFunctionTemplateDecl(FunctionTemplateDecl *D); - void VisitClassTemplateDecl(ClassTemplateDecl *D); - void VisitObjCContainerDecl(ObjCContainerDecl *CD); - void VisitObjCMethodDecl(ObjCMethodDecl *MD); - void VisitObjCPropertyDecl(ObjCPropertyDecl *D); - void VisitObjCPropertyImplDecl(ObjCPropertyImplDecl *D); - void VisitTagDecl(TagDecl *D); - void VisitTypedefDecl(TypedefDecl *D); - void VisitTemplateTypeParmDecl(TemplateTypeParmDecl *D); - void VisitVarDecl(VarDecl *D); - void VisitNonTypeTemplateParmDecl(NonTypeTemplateParmDecl *D); - void VisitTemplateTemplateParmDecl(TemplateTemplateParmDecl *D); - void VisitLinkageSpecDecl(LinkageSpecDecl *D) { - IgnoreResults = true; - } - void VisitUsingDirectiveDecl(UsingDirectiveDecl *D) { - IgnoreResults = true; - } - void VisitUsingDecl(UsingDecl *D) { - IgnoreResults = true; - } - void VisitUnresolvedUsingValueDecl(UnresolvedUsingValueDecl *D) { - IgnoreResults = true; - } - void VisitUnresolvedUsingTypenameDecl(UnresolvedUsingTypenameDecl *D) { - IgnoreResults = true; - } - - /// Generate the string component containing the location of the - /// declaration. - bool GenLoc(const Decl *D); - - /// String generation methods used both by the visitation methods - /// and from other clients that want to directly generate USRs. These - /// methods do not construct complete USRs (which incorporate the parents - /// of an AST element), but only the fragments concerning the AST element - /// itself. - - /// Generate a USR for an Objective-C class. - void GenObjCClass(StringRef cls); - /// Generate a USR for an Objective-C class category. - void GenObjCCategory(StringRef cls, StringRef cat); - /// Generate a USR fragment for an Objective-C instance variable. The - /// complete USR can be created by concatenating the USR for the - /// encompassing class with this USR fragment. - void GenObjCIvar(StringRef ivar); - /// Generate a USR fragment for an Objective-C method. - void GenObjCMethod(StringRef sel, bool isInstanceMethod); - /// Generate a USR fragment for an Objective-C property. - void GenObjCProperty(StringRef prop); - /// Generate a USR for an Objective-C protocol. - void GenObjCProtocol(StringRef prot); - - void VisitType(QualType T); - void VisitTemplateParameterList(const TemplateParameterList *Params); - void VisitTemplateName(TemplateName Name); - void VisitTemplateArgument(const TemplateArgument &Arg); - - /// Emit a Decl's name using NamedDecl::printName() and return true if - /// the decl had no name. - bool EmitDeclName(const NamedDecl *D); -}; - -} // end anonymous namespace - -//===----------------------------------------------------------------------===// -// Generating USRs from ASTS. -//===----------------------------------------------------------------------===// - -bool USRGenerator::EmitDeclName(const NamedDecl *D) { - Out.flush(); - const unsigned startSize = Buf.size(); - D->printName(Out); - Out.flush(); - const unsigned endSize = Buf.size(); - return startSize == endSize; -} - -static inline bool ShouldGenerateLocation(const NamedDecl *D) { - return D->getLinkage() != ExternalLinkage; -} - -void USRGenerator::VisitDeclContext(DeclContext *DC) { - if (NamedDecl *D = dyn_cast<NamedDecl>(DC)) - Visit(D); -} - -void USRGenerator::VisitFieldDecl(FieldDecl *D) { - // The USR for an ivar declared in a class extension is based on the - // ObjCInterfaceDecl, not the ObjCCategoryDecl. - if (ObjCInterfaceDecl *ID = Context->getObjContainingInterface(D)) - Visit(ID); - else - VisitDeclContext(D->getDeclContext()); - Out << (isa<ObjCIvarDecl>(D) ? "@" : "@FI@"); - if (EmitDeclName(D)) { - // Bit fields can be anonymous. - IgnoreResults = true; - return; - } -} - -void USRGenerator::VisitFunctionDecl(FunctionDecl *D) { - if (ShouldGenerateLocation(D) && GenLoc(D)) - return; - - VisitDeclContext(D->getDeclContext()); - if (FunctionTemplateDecl *FunTmpl = D->getDescribedFunctionTemplate()) { - Out << "@FT@"; - VisitTemplateParameterList(FunTmpl->getTemplateParameters()); - } else - Out << "@F@"; - D->printName(Out); - - ASTContext &Ctx = *Context; - if (!Ctx.getLangOpts().CPlusPlus || D->isExternC()) - return; - - if (const TemplateArgumentList * - SpecArgs = D->getTemplateSpecializationArgs()) { - Out << '<'; - for (unsigned I = 0, N = SpecArgs->size(); I != N; ++I) { - Out << '#'; - VisitTemplateArgument(SpecArgs->get(I)); - } - Out << '>'; - } - - // Mangle in type information for the arguments. - for (FunctionDecl::param_iterator I = D->param_begin(), E = D->param_end(); - I != E; ++I) { - Out << '#'; - if (ParmVarDecl *PD = *I) - VisitType(PD->getType()); - } - if (D->isVariadic()) - Out << '.'; - Out << '#'; - if (CXXMethodDecl *MD = dyn_cast<CXXMethodDecl>(D)) { - if (MD->isStatic()) - Out << 'S'; - if (unsigned quals = MD->getTypeQualifiers()) - Out << (char)('0' + quals); - } -} - -void USRGenerator::VisitNamedDecl(NamedDecl *D) { - VisitDeclContext(D->getDeclContext()); - Out << "@"; - - if (EmitDeclName(D)) { - // The string can be empty if the declaration has no name; e.g., it is - // the ParmDecl with no name for declaration of a function pointer type, - // e.g.: void (*f)(void *); - // In this case, don't generate a USR. - IgnoreResults = true; - } -} - -void USRGenerator::VisitVarDecl(VarDecl *D) { - // VarDecls can be declared 'extern' within a function or method body, - // but their enclosing DeclContext is the function, not the TU. We need - // to check the storage class to correctly generate the USR. - if (ShouldGenerateLocation(D) && GenLoc(D)) - return; - - VisitDeclContext(D->getDeclContext()); - - // Variables always have simple names. - StringRef s = D->getName(); - - // The string can be empty if the declaration has no name; e.g., it is - // the ParmDecl with no name for declaration of a function pointer type, e.g.: - // void (*f)(void *); - // In this case, don't generate a USR. - if (s.empty()) - IgnoreResults = true; - else - Out << '@' << s; -} - -void USRGenerator::VisitNonTypeTemplateParmDecl(NonTypeTemplateParmDecl *D) { - GenLoc(D); - return; -} - -void USRGenerator::VisitTemplateTemplateParmDecl(TemplateTemplateParmDecl *D) { - GenLoc(D); - return; -} - -void USRGenerator::VisitNamespaceDecl(NamespaceDecl *D) { - if (D->isAnonymousNamespace()) { - Out << "@aN"; - return; - } - - VisitDeclContext(D->getDeclContext()); - if (!IgnoreResults) - Out << "@N@" << D->getName(); -} - -void USRGenerator::VisitFunctionTemplateDecl(FunctionTemplateDecl *D) { - VisitFunctionDecl(D->getTemplatedDecl()); -} - -void USRGenerator::VisitClassTemplateDecl(ClassTemplateDecl *D) { - VisitTagDecl(D->getTemplatedDecl()); -} - -void USRGenerator::VisitNamespaceAliasDecl(NamespaceAliasDecl *D) { - VisitDeclContext(D->getDeclContext()); - if (!IgnoreResults) - Out << "@NA@" << D->getName(); -} - -void USRGenerator::VisitObjCMethodDecl(ObjCMethodDecl *D) { - DeclContext *container = D->getDeclContext(); - if (ObjCProtocolDecl *pd = dyn_cast<ObjCProtocolDecl>(container)) { - Visit(pd); - } - else { - // The USR for a method declared in a class extension or category is based on - // the ObjCInterfaceDecl, not the ObjCCategoryDecl. - ObjCInterfaceDecl *ID = D->getClassInterface(); - if (!ID) { - IgnoreResults = true; - return; - } - Visit(ID); - } - // Ideally we would use 'GenObjCMethod', but this is such a hot path - // for Objective-C code that we don't want to use - // DeclarationName::getAsString(). - Out << (D->isInstanceMethod() ? "(im)" : "(cm)"); - DeclarationName N(D->getSelector()); - N.printName(Out); -} - -void USRGenerator::VisitObjCContainerDecl(ObjCContainerDecl *D) { - switch (D->getKind()) { - default: - llvm_unreachable("Invalid ObjC container."); - case Decl::ObjCInterface: - case Decl::ObjCImplementation: - GenObjCClass(D->getName()); - break; - case Decl::ObjCCategory: { - ObjCCategoryDecl *CD = cast<ObjCCategoryDecl>(D); - ObjCInterfaceDecl *ID = CD->getClassInterface(); - if (!ID) { - // Handle invalid code where the @interface might not - // have been specified. - // FIXME: We should be able to generate this USR even if the - // @interface isn't available. - IgnoreResults = true; - return; - } - // Specially handle class extensions, which are anonymous categories. - // We want to mangle in the location to uniquely distinguish them. - if (CD->IsClassExtension()) { - Out << "objc(ext)" << ID->getName() << '@'; - GenLoc(CD); - } - else - GenObjCCategory(ID->getName(), CD->getName()); - - break; - } - case Decl::ObjCCategoryImpl: { - ObjCCategoryImplDecl *CD = cast<ObjCCategoryImplDecl>(D); - ObjCInterfaceDecl *ID = CD->getClassInterface(); - if (!ID) { - // Handle invalid code where the @interface might not - // have been specified. - // FIXME: We should be able to generate this USR even if the - // @interface isn't available. - IgnoreResults = true; - return; - } - GenObjCCategory(ID->getName(), CD->getName()); - break; - } - case Decl::ObjCProtocol: - GenObjCProtocol(cast<ObjCProtocolDecl>(D)->getName()); - break; - } -} - -void USRGenerator::VisitObjCPropertyDecl(ObjCPropertyDecl *D) { - // The USR for a property declared in a class extension or category is based - // on the ObjCInterfaceDecl, not the ObjCCategoryDecl. - if (ObjCInterfaceDecl *ID = Context->getObjContainingInterface(D)) - Visit(ID); - else - Visit(cast<Decl>(D->getDeclContext())); - GenObjCProperty(D->getName()); -} - -void USRGenerator::VisitObjCPropertyImplDecl(ObjCPropertyImplDecl *D) { - if (ObjCPropertyDecl *PD = D->getPropertyDecl()) { - VisitObjCPropertyDecl(PD); - return; - } - - IgnoreResults = true; -} - -void USRGenerator::VisitTagDecl(TagDecl *D) { - // Add the location of the tag decl to handle resolution across - // translation units. - if (ShouldGenerateLocation(D) && GenLoc(D)) - return; - - D = D->getCanonicalDecl(); - VisitDeclContext(D->getDeclContext()); - - bool AlreadyStarted = false; - if (CXXRecordDecl *CXXRecord = dyn_cast<CXXRecordDecl>(D)) { - if (ClassTemplateDecl *ClassTmpl = CXXRecord->getDescribedClassTemplate()) { - AlreadyStarted = true; - - switch (D->getTagKind()) { - case TTK_Interface: - case TTK_Struct: Out << "@ST"; break; - case TTK_Class: Out << "@CT"; break; - case TTK_Union: Out << "@UT"; break; - case TTK_Enum: llvm_unreachable("enum template"); - } - VisitTemplateParameterList(ClassTmpl->getTemplateParameters()); - } else if (ClassTemplatePartialSpecializationDecl *PartialSpec - = dyn_cast<ClassTemplatePartialSpecializationDecl>(CXXRecord)) { - AlreadyStarted = true; - - switch (D->getTagKind()) { - case TTK_Interface: - case TTK_Struct: Out << "@SP"; break; - case TTK_Class: Out << "@CP"; break; - case TTK_Union: Out << "@UP"; break; - case TTK_Enum: llvm_unreachable("enum partial specialization"); - } - VisitTemplateParameterList(PartialSpec->getTemplateParameters()); - } - } - - if (!AlreadyStarted) { - switch (D->getTagKind()) { - case TTK_Interface: - case TTK_Struct: Out << "@S"; break; - case TTK_Class: Out << "@C"; break; - case TTK_Union: Out << "@U"; break; - case TTK_Enum: Out << "@E"; break; - } - } - - Out << '@'; - Out.flush(); - assert(Buf.size() > 0); - const unsigned off = Buf.size() - 1; - - if (EmitDeclName(D)) { - if (const TypedefNameDecl *TD = D->getTypedefNameForAnonDecl()) { - Buf[off] = 'A'; - Out << '@' << *TD; - } - else - Buf[off] = 'a'; - } - - // For a class template specialization, mangle the template arguments. - if (ClassTemplateSpecializationDecl *Spec - = dyn_cast<ClassTemplateSpecializationDecl>(D)) { - const TemplateArgumentList &Args = Spec->getTemplateInstantiationArgs(); - Out << '>'; - for (unsigned I = 0, N = Args.size(); I != N; ++I) { - Out << '#'; - VisitTemplateArgument(Args.get(I)); - } - } -} - -void USRGenerator::VisitTypedefDecl(TypedefDecl *D) { - if (ShouldGenerateLocation(D) && GenLoc(D)) - return; - DeclContext *DC = D->getDeclContext(); - if (NamedDecl *DCN = dyn_cast<NamedDecl>(DC)) - Visit(DCN); - Out << "@T@"; - Out << D->getName(); -} - -void USRGenerator::VisitTemplateTypeParmDecl(TemplateTypeParmDecl *D) { - GenLoc(D); - return; -} - -bool USRGenerator::GenLoc(const Decl *D) { - if (generatedLoc) - return IgnoreResults; - generatedLoc = true; - - // Guard against null declarations in invalid code. - if (!D) { - IgnoreResults = true; - return true; - } - - // Use the location of canonical decl. - D = D->getCanonicalDecl(); - - const SourceManager &SM = Context->getSourceManager(); - SourceLocation L = D->getLocStart(); - if (L.isInvalid()) { - IgnoreResults = true; - return true; - } - L = SM.getExpansionLoc(L); - const std::pair<FileID, unsigned> &Decomposed = SM.getDecomposedLoc(L); - const FileEntry *FE = SM.getFileEntryForID(Decomposed.first); - if (FE) { - Out << llvm::sys::path::filename(FE->getName()); - } - else { - // This case really isn't interesting. - IgnoreResults = true; - return true; - } - // Use the offest into the FileID to represent the location. Using - // a line/column can cause us to look back at the original source file, - // which is expensive. - Out << '@' << Decomposed.second; - return IgnoreResults; -} - -void USRGenerator::VisitType(QualType T) { - // This method mangles in USR information for types. It can possibly - // just reuse the naming-mangling logic used by codegen, although the - // requirements for USRs might not be the same. - ASTContext &Ctx = *Context; - - do { - T = Ctx.getCanonicalType(T); - Qualifiers Q = T.getQualifiers(); - unsigned qVal = 0; - if (Q.hasConst()) - qVal |= 0x1; - if (Q.hasVolatile()) - qVal |= 0x2; - if (Q.hasRestrict()) - qVal |= 0x4; - if(qVal) - Out << ((char) ('0' + qVal)); - - // Mangle in ObjC GC qualifiers? - - if (const PackExpansionType *Expansion = T->getAs<PackExpansionType>()) { - Out << 'P'; - T = Expansion->getPattern(); - } - - if (const BuiltinType *BT = T->getAs<BuiltinType>()) { - unsigned char c = '\0'; - switch (BT->getKind()) { - case BuiltinType::Void: - c = 'v'; break; - case BuiltinType::Bool: - c = 'b'; break; - case BuiltinType::Char_U: - case BuiltinType::UChar: - c = 'c'; break; - case BuiltinType::Char16: - c = 'q'; break; - case BuiltinType::Char32: - c = 'w'; break; - case BuiltinType::UShort: - c = 's'; break; - case BuiltinType::UInt: - c = 'i'; break; - case BuiltinType::ULong: - c = 'l'; break; - case BuiltinType::ULongLong: - c = 'k'; break; - case BuiltinType::UInt128: - c = 'j'; break; - case BuiltinType::Char_S: - case BuiltinType::SChar: - c = 'C'; break; - case BuiltinType::WChar_S: - case BuiltinType::WChar_U: - c = 'W'; break; - case BuiltinType::Short: - c = 'S'; break; - case BuiltinType::Int: - c = 'I'; break; - case BuiltinType::Long: - c = 'L'; break; - case BuiltinType::LongLong: - c = 'K'; break; - case BuiltinType::Int128: - c = 'J'; break; - case BuiltinType::Half: - c = 'h'; break; - case BuiltinType::Float: - c = 'f'; break; - case BuiltinType::Double: - c = 'd'; break; - case BuiltinType::LongDouble: - c = 'D'; break; - case BuiltinType::NullPtr: - c = 'n'; break; -#define BUILTIN_TYPE(Id, SingletonId) -#define PLACEHOLDER_TYPE(Id, SingletonId) case BuiltinType::Id: -#include "clang/AST/BuiltinTypes.def" - case BuiltinType::Dependent: - IgnoreResults = true; - return; - case BuiltinType::ObjCId: - c = 'o'; break; - case BuiltinType::ObjCClass: - c = 'O'; break; - case BuiltinType::ObjCSel: - c = 'e'; break; - } - Out << c; - return; - } - - // If we have already seen this (non-built-in) type, use a substitution - // encoding. - llvm::DenseMap<const Type *, unsigned>::iterator Substitution - = TypeSubstitutions.find(T.getTypePtr()); - if (Substitution != TypeSubstitutions.end()) { - Out << 'S' << Substitution->second << '_'; - return; - } else { - // Record this as a substitution. - unsigned Number = TypeSubstitutions.size(); - TypeSubstitutions[T.getTypePtr()] = Number; - } - - if (const PointerType *PT = T->getAs<PointerType>()) { - Out << '*'; - T = PT->getPointeeType(); - continue; - } - if (const ReferenceType *RT = T->getAs<ReferenceType>()) { - Out << '&'; - T = RT->getPointeeType(); - continue; - } - if (const FunctionProtoType *FT = T->getAs<FunctionProtoType>()) { - Out << 'F'; - VisitType(FT->getResultType()); - for (FunctionProtoType::arg_type_iterator - I = FT->arg_type_begin(), E = FT->arg_type_end(); I!=E; ++I) { - VisitType(*I); - } - if (FT->isVariadic()) - Out << '.'; - return; - } - if (const BlockPointerType *BT = T->getAs<BlockPointerType>()) { - Out << 'B'; - T = BT->getPointeeType(); - continue; - } - if (const ComplexType *CT = T->getAs<ComplexType>()) { - Out << '<'; - T = CT->getElementType(); - continue; - } - if (const TagType *TT = T->getAs<TagType>()) { - Out << '$'; - VisitTagDecl(TT->getDecl()); - return; - } - if (const TemplateTypeParmType *TTP = T->getAs<TemplateTypeParmType>()) { - Out << 't' << TTP->getDepth() << '.' << TTP->getIndex(); - return; - } - if (const TemplateSpecializationType *Spec - = T->getAs<TemplateSpecializationType>()) { - Out << '>'; - VisitTemplateName(Spec->getTemplateName()); - Out << Spec->getNumArgs(); - for (unsigned I = 0, N = Spec->getNumArgs(); I != N; ++I) - VisitTemplateArgument(Spec->getArg(I)); - return; - } - - // Unhandled type. - Out << ' '; - break; - } while (true); -} - -void USRGenerator::VisitTemplateParameterList( - const TemplateParameterList *Params) { - if (!Params) - return; - Out << '>' << Params->size(); - for (TemplateParameterList::const_iterator P = Params->begin(), - PEnd = Params->end(); - P != PEnd; ++P) { - Out << '#'; - if (isa<TemplateTypeParmDecl>(*P)) { - if (cast<TemplateTypeParmDecl>(*P)->isParameterPack()) - Out<< 'p'; - Out << 'T'; - continue; - } - - if (NonTypeTemplateParmDecl *NTTP = dyn_cast<NonTypeTemplateParmDecl>(*P)) { - if (NTTP->isParameterPack()) - Out << 'p'; - Out << 'N'; - VisitType(NTTP->getType()); - continue; - } - - TemplateTemplateParmDecl *TTP = cast<TemplateTemplateParmDecl>(*P); - if (TTP->isParameterPack()) - Out << 'p'; - Out << 't'; - VisitTemplateParameterList(TTP->getTemplateParameters()); - } -} - -void USRGenerator::VisitTemplateName(TemplateName Name) { - if (TemplateDecl *Template = Name.getAsTemplateDecl()) { - if (TemplateTemplateParmDecl *TTP - = dyn_cast<TemplateTemplateParmDecl>(Template)) { - Out << 't' << TTP->getDepth() << '.' << TTP->getIndex(); - return; - } - - Visit(Template); - return; - } - - // FIXME: Visit dependent template names. -} - -void USRGenerator::VisitTemplateArgument(const TemplateArgument &Arg) { - switch (Arg.getKind()) { - case TemplateArgument::Null: - break; - - case TemplateArgument::Declaration: - Visit(Arg.getAsDecl()); - break; - - case TemplateArgument::NullPtr: - break; - - case TemplateArgument::TemplateExpansion: - Out << 'P'; // pack expansion of... - // Fall through - case TemplateArgument::Template: - VisitTemplateName(Arg.getAsTemplateOrTemplatePattern()); - break; - - case TemplateArgument::Expression: - // FIXME: Visit expressions. - break; - - case TemplateArgument::Pack: - Out << 'p' << Arg.pack_size(); - for (TemplateArgument::pack_iterator P = Arg.pack_begin(), PEnd = Arg.pack_end(); - P != PEnd; ++P) - VisitTemplateArgument(*P); - break; - - case TemplateArgument::Type: - VisitType(Arg.getAsType()); - break; - - case TemplateArgument::Integral: - Out << 'V'; - VisitType(Arg.getIntegralType()); - Out << Arg.getAsIntegral(); - break; - } -} - -//===----------------------------------------------------------------------===// -// General purpose USR generation methods. -//===----------------------------------------------------------------------===// - -void USRGenerator::GenObjCClass(StringRef cls) { - Out << "objc(cs)" << cls; -} - -void USRGenerator::GenObjCCategory(StringRef cls, StringRef cat) { - Out << "objc(cy)" << cls << '@' << cat; -} - -void USRGenerator::GenObjCIvar(StringRef ivar) { - Out << '@' << ivar; -} - -void USRGenerator::GenObjCMethod(StringRef meth, bool isInstanceMethod) { - Out << (isInstanceMethod ? "(im)" : "(cm)") << meth; -} - -void USRGenerator::GenObjCProperty(StringRef prop) { - Out << "(py)" << prop; -} - -void USRGenerator::GenObjCProtocol(StringRef prot) { - Out << "objc(pl)" << prot; -} - -//===----------------------------------------------------------------------===// -// API hooks. -//===----------------------------------------------------------------------===// - -static inline StringRef extractUSRSuffix(StringRef s) { - return s.startswith("c:") ? s.substr(2) : ""; -} - -bool cxcursor::getDeclCursorUSR(const Decl *D, SmallVectorImpl<char> &Buf) { - // Don't generate USRs for things with invalid locations. - if (!D || D->getLocStart().isInvalid()) - return true; - - USRGenerator UG(&D->getASTContext(), &Buf); - UG->Visit(const_cast<Decl*>(D)); - - if (UG->ignoreResults()) - return true; - - return false; -} - -extern "C" { - -CXString clang_getCursorUSR(CXCursor C) { - const CXCursorKind &K = clang_getCursorKind(C); - - if (clang_isDeclaration(K)) { - Decl *D = cxcursor::getCursorDecl(C); - if (!D) - return createCXString(""); - - CXTranslationUnit TU = cxcursor::getCursorTU(C); - if (!TU) - return createCXString(""); - - CXStringBuf *buf = cxstring::getCXStringBuf(TU); - if (!buf) - return createCXString(""); - - bool Ignore = cxcursor::getDeclCursorUSR(D, buf->Data); - if (Ignore) { - disposeCXStringBuf(buf); - return createCXString(""); - } - - // Return the C-string, but don't make a copy since it is already in - // the string buffer. - buf->Data.push_back('\0'); - return createCXString(buf); - } - - if (K == CXCursor_MacroDefinition) { - CXTranslationUnit TU = cxcursor::getCursorTU(C); - if (!TU) - return createCXString(""); - - CXStringBuf *buf = cxstring::getCXStringBuf(TU); - if (!buf) - return createCXString(""); - - { - USRGenerator UG(&cxcursor::getCursorASTUnit(C)->getASTContext(), - &buf->Data); - UG << "macro@" - << cxcursor::getCursorMacroDefinition(C)->getName()->getNameStart(); - } - buf->Data.push_back('\0'); - return createCXString(buf); - } - - return createCXString(""); -} - -CXString clang_constructUSR_ObjCIvar(const char *name, CXString classUSR) { - USRGenerator UG; - UG << extractUSRSuffix(clang_getCString(classUSR)); - UG->GenObjCIvar(name); - return createCXString(UG.str(), true); -} - -CXString clang_constructUSR_ObjCMethod(const char *name, - unsigned isInstanceMethod, - CXString classUSR) { - USRGenerator UG; - UG << extractUSRSuffix(clang_getCString(classUSR)); - UG->GenObjCMethod(name, isInstanceMethod); - return createCXString(UG.str(), true); -} - -CXString clang_constructUSR_ObjCClass(const char *name) { - USRGenerator UG; - UG->GenObjCClass(name); - return createCXString(UG.str(), true); -} - -CXString clang_constructUSR_ObjCProtocol(const char *name) { - USRGenerator UG; - UG->GenObjCProtocol(name); - return createCXString(UG.str(), true); -} - -CXString clang_constructUSR_ObjCCategory(const char *class_name, - const char *category_name) { - USRGenerator UG; - UG->GenObjCCategory(class_name, category_name); - return createCXString(UG.str(), true); -} - -CXString clang_constructUSR_ObjCProperty(const char *property, - CXString classUSR) { - USRGenerator UG; - UG << extractUSRSuffix(clang_getCString(classUSR)); - UG->GenObjCProperty(property); - return createCXString(UG.str(), true); -} - -} // end extern "C" +//===- CIndexUSR.cpp - Clang-C Source Indexing Library --------------------===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+//
+// This file implements the generation and use of USRs from CXEntities.
+//
+//===----------------------------------------------------------------------===//
+
+#include "CIndexer.h"
+#include "CXCursor.h"
+#include "CXString.h"
+#include "clang/AST/DeclTemplate.h"
+#include "clang/AST/DeclVisitor.h"
+#include "clang/Frontend/ASTUnit.h"
+#include "clang/Lex/PreprocessingRecord.h"
+#include "llvm/ADT/SmallString.h"
+#include "llvm/Support/raw_ostream.h"
+
+using namespace clang;
+using namespace clang::cxstring;
+
+//===----------------------------------------------------------------------===//
+// USR generation.
+//===----------------------------------------------------------------------===//
+
+namespace {
+class USRGenerator : public DeclVisitor<USRGenerator> {
+ OwningPtr<SmallString<128> > OwnedBuf;
+ SmallVectorImpl<char> &Buf;
+ llvm::raw_svector_ostream Out;
+ bool IgnoreResults;
+ ASTContext *Context;
+ bool generatedLoc;
+
+ llvm::DenseMap<const Type *, unsigned> TypeSubstitutions;
+
+public:
+ explicit USRGenerator(ASTContext *Ctx = 0, SmallVectorImpl<char> *extBuf = 0)
+ : OwnedBuf(extBuf ? 0 : new SmallString<128>()),
+ Buf(extBuf ? *extBuf : *OwnedBuf.get()),
+ Out(Buf),
+ IgnoreResults(false),
+ Context(Ctx),
+ generatedLoc(false)
+ {
+ // Add the USR space prefix.
+ Out << "c:";
+ }
+
+ StringRef str() {
+ return Out.str();
+ }
+
+ USRGenerator* operator->() { return this; }
+
+ template <typename T>
+ llvm::raw_svector_ostream &operator<<(const T &x) {
+ Out << x;
+ return Out;
+ }
+
+ bool ignoreResults() const { return IgnoreResults; }
+
+ // Visitation methods from generating USRs from AST elements.
+ void VisitDeclContext(DeclContext *D);
+ void VisitFieldDecl(FieldDecl *D);
+ void VisitFunctionDecl(FunctionDecl *D);
+ void VisitNamedDecl(NamedDecl *D);
+ void VisitNamespaceDecl(NamespaceDecl *D);
+ void VisitNamespaceAliasDecl(NamespaceAliasDecl *D);
+ void VisitFunctionTemplateDecl(FunctionTemplateDecl *D);
+ void VisitClassTemplateDecl(ClassTemplateDecl *D);
+ void VisitObjCContainerDecl(ObjCContainerDecl *CD);
+ void VisitObjCMethodDecl(ObjCMethodDecl *MD);
+ void VisitObjCPropertyDecl(ObjCPropertyDecl *D);
+ void VisitObjCPropertyImplDecl(ObjCPropertyImplDecl *D);
+ void VisitTagDecl(TagDecl *D);
+ void VisitTypedefDecl(TypedefDecl *D);
+ void VisitTemplateTypeParmDecl(TemplateTypeParmDecl *D);
+ void VisitVarDecl(VarDecl *D);
+ void VisitNonTypeTemplateParmDecl(NonTypeTemplateParmDecl *D);
+ void VisitTemplateTemplateParmDecl(TemplateTemplateParmDecl *D);
+ void VisitLinkageSpecDecl(LinkageSpecDecl *D) {
+ IgnoreResults = true;
+ }
+ void VisitUsingDirectiveDecl(UsingDirectiveDecl *D) {
+ IgnoreResults = true;
+ }
+ void VisitUsingDecl(UsingDecl *D) {
+ IgnoreResults = true;
+ }
+ void VisitUnresolvedUsingValueDecl(UnresolvedUsingValueDecl *D) {
+ IgnoreResults = true;
+ }
+ void VisitUnresolvedUsingTypenameDecl(UnresolvedUsingTypenameDecl *D) {
+ IgnoreResults = true;
+ }
+
+ /// Generate the string component containing the location of the
+ /// declaration.
+ bool GenLoc(const Decl *D);
+
+ /// String generation methods used both by the visitation methods
+ /// and from other clients that want to directly generate USRs. These
+ /// methods do not construct complete USRs (which incorporate the parents
+ /// of an AST element), but only the fragments concerning the AST element
+ /// itself.
+
+ /// Generate a USR for an Objective-C class.
+ void GenObjCClass(StringRef cls);
+ /// Generate a USR for an Objective-C class category.
+ void GenObjCCategory(StringRef cls, StringRef cat);
+ /// Generate a USR fragment for an Objective-C instance variable. The
+ /// complete USR can be created by concatenating the USR for the
+ /// encompassing class with this USR fragment.
+ void GenObjCIvar(StringRef ivar);
+ /// Generate a USR fragment for an Objective-C method.
+ void GenObjCMethod(StringRef sel, bool isInstanceMethod);
+ /// Generate a USR fragment for an Objective-C property.
+ void GenObjCProperty(StringRef prop);
+ /// Generate a USR for an Objective-C protocol.
+ void GenObjCProtocol(StringRef prot);
+
+ void VisitType(QualType T);
+ void VisitTemplateParameterList(const TemplateParameterList *Params);
+ void VisitTemplateName(TemplateName Name);
+ void VisitTemplateArgument(const TemplateArgument &Arg);
+
+ /// Emit a Decl's name using NamedDecl::printName() and return true if
+ /// the decl had no name.
+ bool EmitDeclName(const NamedDecl *D);
+};
+
+} // end anonymous namespace
+
+//===----------------------------------------------------------------------===//
+// Generating USRs from ASTS.
+//===----------------------------------------------------------------------===//
+
+bool USRGenerator::EmitDeclName(const NamedDecl *D) {
+ Out.flush();
+ const unsigned startSize = Buf.size();
+ D->printName(Out);
+ Out.flush();
+ const unsigned endSize = Buf.size();
+ return startSize == endSize;
+}
+
+static inline bool ShouldGenerateLocation(const NamedDecl *D) {
+ return D->getLinkage() != ExternalLinkage;
+}
+
+void USRGenerator::VisitDeclContext(DeclContext *DC) {
+ if (NamedDecl *D = dyn_cast<NamedDecl>(DC))
+ Visit(D);
+}
+
+void USRGenerator::VisitFieldDecl(FieldDecl *D) {
+ // The USR for an ivar declared in a class extension is based on the
+ // ObjCInterfaceDecl, not the ObjCCategoryDecl.
+ if (ObjCInterfaceDecl *ID = Context->getObjContainingInterface(D))
+ Visit(ID);
+ else
+ VisitDeclContext(D->getDeclContext());
+ Out << (isa<ObjCIvarDecl>(D) ? "@" : "@FI@");
+ if (EmitDeclName(D)) {
+ // Bit fields can be anonymous.
+ IgnoreResults = true;
+ return;
+ }
+}
+
+void USRGenerator::VisitFunctionDecl(FunctionDecl *D) {
+ if (ShouldGenerateLocation(D) && GenLoc(D))
+ return;
+
+ VisitDeclContext(D->getDeclContext());
+ if (FunctionTemplateDecl *FunTmpl = D->getDescribedFunctionTemplate()) {
+ Out << "@FT@";
+ VisitTemplateParameterList(FunTmpl->getTemplateParameters());
+ } else
+ Out << "@F@";
+ D->printName(Out);
+
+ ASTContext &Ctx = *Context;
+ if (!Ctx.getLangOpts().CPlusPlus || D->isExternC())
+ return;
+
+ if (const TemplateArgumentList *
+ SpecArgs = D->getTemplateSpecializationArgs()) {
+ Out << '<';
+ for (unsigned I = 0, N = SpecArgs->size(); I != N; ++I) {
+ Out << '#';
+ VisitTemplateArgument(SpecArgs->get(I));
+ }
+ Out << '>';
+ }
+
+ // Mangle in type information for the arguments.
+ for (FunctionDecl::param_iterator I = D->param_begin(), E = D->param_end();
+ I != E; ++I) {
+ Out << '#';
+ if (ParmVarDecl *PD = *I)
+ VisitType(PD->getType());
+ }
+ if (D->isVariadic())
+ Out << '.';
+ Out << '#';
+ if (CXXMethodDecl *MD = dyn_cast<CXXMethodDecl>(D)) {
+ if (MD->isStatic())
+ Out << 'S';
+ if (unsigned quals = MD->getTypeQualifiers())
+ Out << (char)('0' + quals);
+ }
+}
+
+void USRGenerator::VisitNamedDecl(NamedDecl *D) {
+ VisitDeclContext(D->getDeclContext());
+ Out << "@";
+
+ if (EmitDeclName(D)) {
+ // The string can be empty if the declaration has no name; e.g., it is
+ // the ParmDecl with no name for declaration of a function pointer type,
+ // e.g.: void (*f)(void *);
+ // In this case, don't generate a USR.
+ IgnoreResults = true;
+ }
+}
+
+void USRGenerator::VisitVarDecl(VarDecl *D) {
+ // VarDecls can be declared 'extern' within a function or method body,
+ // but their enclosing DeclContext is the function, not the TU. We need
+ // to check the storage class to correctly generate the USR.
+ if (ShouldGenerateLocation(D) && GenLoc(D))
+ return;
+
+ VisitDeclContext(D->getDeclContext());
+
+ // Variables always have simple names.
+ StringRef s = D->getName();
+
+ // The string can be empty if the declaration has no name; e.g., it is
+ // the ParmDecl with no name for declaration of a function pointer type, e.g.:
+ // void (*f)(void *);
+ // In this case, don't generate a USR.
+ if (s.empty())
+ IgnoreResults = true;
+ else
+ Out << '@' << s;
+}
+
+void USRGenerator::VisitNonTypeTemplateParmDecl(NonTypeTemplateParmDecl *D) {
+ GenLoc(D);
+ return;
+}
+
+void USRGenerator::VisitTemplateTemplateParmDecl(TemplateTemplateParmDecl *D) {
+ GenLoc(D);
+ return;
+}
+
+void USRGenerator::VisitNamespaceDecl(NamespaceDecl *D) {
+ if (D->isAnonymousNamespace()) {
+ Out << "@aN";
+ return;
+ }
+
+ VisitDeclContext(D->getDeclContext());
+ if (!IgnoreResults)
+ Out << "@N@" << D->getName();
+}
+
+void USRGenerator::VisitFunctionTemplateDecl(FunctionTemplateDecl *D) {
+ VisitFunctionDecl(D->getTemplatedDecl());
+}
+
+void USRGenerator::VisitClassTemplateDecl(ClassTemplateDecl *D) {
+ VisitTagDecl(D->getTemplatedDecl());
+}
+
+void USRGenerator::VisitNamespaceAliasDecl(NamespaceAliasDecl *D) {
+ VisitDeclContext(D->getDeclContext());
+ if (!IgnoreResults)
+ Out << "@NA@" << D->getName();
+}
+
+void USRGenerator::VisitObjCMethodDecl(ObjCMethodDecl *D) {
+ DeclContext *container = D->getDeclContext();
+ if (ObjCProtocolDecl *pd = dyn_cast<ObjCProtocolDecl>(container)) {
+ Visit(pd);
+ }
+ else {
+ // The USR for a method declared in a class extension or category is based on
+ // the ObjCInterfaceDecl, not the ObjCCategoryDecl.
+ ObjCInterfaceDecl *ID = D->getClassInterface();
+ if (!ID) {
+ IgnoreResults = true;
+ return;
+ }
+ Visit(ID);
+ }
+ // Ideally we would use 'GenObjCMethod', but this is such a hot path
+ // for Objective-C code that we don't want to use
+ // DeclarationName::getAsString().
+ Out << (D->isInstanceMethod() ? "(im)" : "(cm)");
+ DeclarationName N(D->getSelector());
+ N.printName(Out);
+}
+
+void USRGenerator::VisitObjCContainerDecl(ObjCContainerDecl *D) {
+ switch (D->getKind()) {
+ default:
+ llvm_unreachable("Invalid ObjC container.");
+ case Decl::ObjCInterface:
+ case Decl::ObjCImplementation:
+ GenObjCClass(D->getName());
+ break;
+ case Decl::ObjCCategory: {
+ ObjCCategoryDecl *CD = cast<ObjCCategoryDecl>(D);
+ ObjCInterfaceDecl *ID = CD->getClassInterface();
+ if (!ID) {
+ // Handle invalid code where the @interface might not
+ // have been specified.
+ // FIXME: We should be able to generate this USR even if the
+ // @interface isn't available.
+ IgnoreResults = true;
+ return;
+ }
+ // Specially handle class extensions, which are anonymous categories.
+ // We want to mangle in the location to uniquely distinguish them.
+ if (CD->IsClassExtension()) {
+ Out << "objc(ext)" << ID->getName() << '@';
+ GenLoc(CD);
+ }
+ else
+ GenObjCCategory(ID->getName(), CD->getName());
+
+ break;
+ }
+ case Decl::ObjCCategoryImpl: {
+ ObjCCategoryImplDecl *CD = cast<ObjCCategoryImplDecl>(D);
+ ObjCInterfaceDecl *ID = CD->getClassInterface();
+ if (!ID) {
+ // Handle invalid code where the @interface might not
+ // have been specified.
+ // FIXME: We should be able to generate this USR even if the
+ // @interface isn't available.
+ IgnoreResults = true;
+ return;
+ }
+ GenObjCCategory(ID->getName(), CD->getName());
+ break;
+ }
+ case Decl::ObjCProtocol:
+ GenObjCProtocol(cast<ObjCProtocolDecl>(D)->getName());
+ break;
+ }
+}
+
+void USRGenerator::VisitObjCPropertyDecl(ObjCPropertyDecl *D) {
+ // The USR for a property declared in a class extension or category is based
+ // on the ObjCInterfaceDecl, not the ObjCCategoryDecl.
+ if (ObjCInterfaceDecl *ID = Context->getObjContainingInterface(D))
+ Visit(ID);
+ else
+ Visit(cast<Decl>(D->getDeclContext()));
+ GenObjCProperty(D->getName());
+}
+
+void USRGenerator::VisitObjCPropertyImplDecl(ObjCPropertyImplDecl *D) {
+ if (ObjCPropertyDecl *PD = D->getPropertyDecl()) {
+ VisitObjCPropertyDecl(PD);
+ return;
+ }
+
+ IgnoreResults = true;
+}
+
+void USRGenerator::VisitTagDecl(TagDecl *D) {
+ // Add the location of the tag decl to handle resolution across
+ // translation units.
+ if (ShouldGenerateLocation(D) && GenLoc(D))
+ return;
+
+ D = D->getCanonicalDecl();
+ VisitDeclContext(D->getDeclContext());
+
+ bool AlreadyStarted = false;
+ if (CXXRecordDecl *CXXRecord = dyn_cast<CXXRecordDecl>(D)) {
+ if (ClassTemplateDecl *ClassTmpl = CXXRecord->getDescribedClassTemplate()) {
+ AlreadyStarted = true;
+
+ switch (D->getTagKind()) {
+ case TTK_Interface:
+ case TTK_Struct: Out << "@ST"; break;
+ case TTK_Class: Out << "@CT"; break;
+ case TTK_Union: Out << "@UT"; break;
+ case TTK_Enum: llvm_unreachable("enum template");
+ }
+ VisitTemplateParameterList(ClassTmpl->getTemplateParameters());
+ } else if (ClassTemplatePartialSpecializationDecl *PartialSpec
+ = dyn_cast<ClassTemplatePartialSpecializationDecl>(CXXRecord)) {
+ AlreadyStarted = true;
+
+ switch (D->getTagKind()) {
+ case TTK_Interface:
+ case TTK_Struct: Out << "@SP"; break;
+ case TTK_Class: Out << "@CP"; break;
+ case TTK_Union: Out << "@UP"; break;
+ case TTK_Enum: llvm_unreachable("enum partial specialization");
+ }
+ VisitTemplateParameterList(PartialSpec->getTemplateParameters());
+ }
+ }
+
+ if (!AlreadyStarted) {
+ switch (D->getTagKind()) {
+ case TTK_Interface:
+ case TTK_Struct: Out << "@S"; break;
+ case TTK_Class: Out << "@C"; break;
+ case TTK_Union: Out << "@U"; break;
+ case TTK_Enum: Out << "@E"; break;
+ }
+ }
+
+ Out << '@';
+ Out.flush();
+ assert(Buf.size() > 0);
+ const unsigned off = Buf.size() - 1;
+
+ if (EmitDeclName(D)) {
+ if (const TypedefNameDecl *TD = D->getTypedefNameForAnonDecl()) {
+ Buf[off] = 'A';
+ Out << '@' << *TD;
+ }
+ else
+ Buf[off] = 'a';
+ }
+
+ // For a class template specialization, mangle the template arguments.
+ if (ClassTemplateSpecializationDecl *Spec
+ = dyn_cast<ClassTemplateSpecializationDecl>(D)) {
+ const TemplateArgumentList &Args = Spec->getTemplateInstantiationArgs();
+ Out << '>';
+ for (unsigned I = 0, N = Args.size(); I != N; ++I) {
+ Out << '#';
+ VisitTemplateArgument(Args.get(I));
+ }
+ }
+}
+
+void USRGenerator::VisitTypedefDecl(TypedefDecl *D) {
+ if (ShouldGenerateLocation(D) && GenLoc(D))
+ return;
+ DeclContext *DC = D->getDeclContext();
+ if (NamedDecl *DCN = dyn_cast<NamedDecl>(DC))
+ Visit(DCN);
+ Out << "@T@";
+ Out << D->getName();
+}
+
+void USRGenerator::VisitTemplateTypeParmDecl(TemplateTypeParmDecl *D) {
+ GenLoc(D);
+ return;
+}
+
+bool USRGenerator::GenLoc(const Decl *D) {
+ if (generatedLoc)
+ return IgnoreResults;
+ generatedLoc = true;
+
+ // Guard against null declarations in invalid code.
+ if (!D) {
+ IgnoreResults = true;
+ return true;
+ }
+
+ // Use the location of canonical decl.
+ D = D->getCanonicalDecl();
+
+ const SourceManager &SM = Context->getSourceManager();
+ SourceLocation L = D->getLocStart();
+ if (L.isInvalid()) {
+ IgnoreResults = true;
+ return true;
+ }
+ L = SM.getExpansionLoc(L);
+ const std::pair<FileID, unsigned> &Decomposed = SM.getDecomposedLoc(L);
+ const FileEntry *FE = SM.getFileEntryForID(Decomposed.first);
+ if (FE) {
+ Out << llvm::sys::path::filename(FE->getName());
+ }
+ else {
+ // This case really isn't interesting.
+ IgnoreResults = true;
+ return true;
+ }
+ // Use the offest into the FileID to represent the location. Using
+ // a line/column can cause us to look back at the original source file,
+ // which is expensive.
+ Out << '@' << Decomposed.second;
+ return IgnoreResults;
+}
+
+void USRGenerator::VisitType(QualType T) {
+ // This method mangles in USR information for types. It can possibly
+ // just reuse the naming-mangling logic used by codegen, although the
+ // requirements for USRs might not be the same.
+ ASTContext &Ctx = *Context;
+
+ do {
+ T = Ctx.getCanonicalType(T);
+ Qualifiers Q = T.getQualifiers();
+ unsigned qVal = 0;
+ if (Q.hasConst())
+ qVal |= 0x1;
+ if (Q.hasVolatile())
+ qVal |= 0x2;
+ if (Q.hasRestrict())
+ qVal |= 0x4;
+ if(qVal)
+ Out << ((char) ('0' + qVal));
+
+ // Mangle in ObjC GC qualifiers?
+
+ if (const PackExpansionType *Expansion = T->getAs<PackExpansionType>()) {
+ Out << 'P';
+ T = Expansion->getPattern();
+ }
+
+ if (const BuiltinType *BT = T->getAs<BuiltinType>()) {
+ unsigned char c = '\0';
+ switch (BT->getKind()) {
+ case BuiltinType::Void:
+ c = 'v'; break;
+ case BuiltinType::Bool:
+ c = 'b'; break;
+ case BuiltinType::Char_U:
+ case BuiltinType::UChar:
+ c = 'c'; break;
+ case BuiltinType::Char16:
+ c = 'q'; break;
+ case BuiltinType::Char32:
+ c = 'w'; break;
+ case BuiltinType::UShort:
+ c = 's'; break;
+ case BuiltinType::UInt:
+ c = 'i'; break;
+ case BuiltinType::ULong:
+ c = 'l'; break;
+ case BuiltinType::ULongLong:
+ c = 'k'; break;
+ case BuiltinType::UInt128:
+ c = 'j'; break;
+ case BuiltinType::Char_S:
+ case BuiltinType::SChar:
+ c = 'C'; break;
+ case BuiltinType::WChar_S:
+ case BuiltinType::WChar_U:
+ c = 'W'; break;
+ case BuiltinType::Short:
+ c = 'S'; break;
+ case BuiltinType::Int:
+ c = 'I'; break;
+ case BuiltinType::Long:
+ c = 'L'; break;
+ case BuiltinType::LongLong:
+ c = 'K'; break;
+ case BuiltinType::Int128:
+ c = 'J'; break;
+ case BuiltinType::Half:
+ c = 'h'; break;
+ case BuiltinType::Float:
+ c = 'f'; break;
+ case BuiltinType::Double:
+ c = 'd'; break;
+ case BuiltinType::LongDouble:
+ c = 'D'; break;
+ case BuiltinType::NullPtr:
+ c = 'n'; break;
+#define BUILTIN_TYPE(Id, SingletonId)
+#define PLACEHOLDER_TYPE(Id, SingletonId) case BuiltinType::Id:
+#include "clang/AST/BuiltinTypes.def"
+ case BuiltinType::Dependent:
+ case BuiltinType::OCLImage1d:
+ case BuiltinType::OCLImage1dArray:
+ case BuiltinType::OCLImage1dBuffer:
+ case BuiltinType::OCLImage2d:
+ case BuiltinType::OCLImage2dArray:
+ case BuiltinType::OCLImage3d:
+ IgnoreResults = true;
+ return;
+ case BuiltinType::ObjCId:
+ c = 'o'; break;
+ case BuiltinType::ObjCClass:
+ c = 'O'; break;
+ case BuiltinType::ObjCSel:
+ c = 'e'; break;
+ }
+ Out << c;
+ return;
+ }
+
+ // If we have already seen this (non-built-in) type, use a substitution
+ // encoding.
+ llvm::DenseMap<const Type *, unsigned>::iterator Substitution
+ = TypeSubstitutions.find(T.getTypePtr());
+ if (Substitution != TypeSubstitutions.end()) {
+ Out << 'S' << Substitution->second << '_';
+ return;
+ } else {
+ // Record this as a substitution.
+ unsigned Number = TypeSubstitutions.size();
+ TypeSubstitutions[T.getTypePtr()] = Number;
+ }
+
+ if (const PointerType *PT = T->getAs<PointerType>()) {
+ Out << '*';
+ T = PT->getPointeeType();
+ continue;
+ }
+ if (const ReferenceType *RT = T->getAs<ReferenceType>()) {
+ Out << '&';
+ T = RT->getPointeeType();
+ continue;
+ }
+ if (const FunctionProtoType *FT = T->getAs<FunctionProtoType>()) {
+ Out << 'F';
+ VisitType(FT->getResultType());
+ for (FunctionProtoType::arg_type_iterator
+ I = FT->arg_type_begin(), E = FT->arg_type_end(); I!=E; ++I) {
+ VisitType(*I);
+ }
+ if (FT->isVariadic())
+ Out << '.';
+ return;
+ }
+ if (const BlockPointerType *BT = T->getAs<BlockPointerType>()) {
+ Out << 'B';
+ T = BT->getPointeeType();
+ continue;
+ }
+ if (const ComplexType *CT = T->getAs<ComplexType>()) {
+ Out << '<';
+ T = CT->getElementType();
+ continue;
+ }
+ if (const TagType *TT = T->getAs<TagType>()) {
+ Out << '$';
+ VisitTagDecl(TT->getDecl());
+ return;
+ }
+ if (const TemplateTypeParmType *TTP = T->getAs<TemplateTypeParmType>()) {
+ Out << 't' << TTP->getDepth() << '.' << TTP->getIndex();
+ return;
+ }
+ if (const TemplateSpecializationType *Spec
+ = T->getAs<TemplateSpecializationType>()) {
+ Out << '>';
+ VisitTemplateName(Spec->getTemplateName());
+ Out << Spec->getNumArgs();
+ for (unsigned I = 0, N = Spec->getNumArgs(); I != N; ++I)
+ VisitTemplateArgument(Spec->getArg(I));
+ return;
+ }
+
+ // Unhandled type.
+ Out << ' ';
+ break;
+ } while (true);
+}
+
+void USRGenerator::VisitTemplateParameterList(
+ const TemplateParameterList *Params) {
+ if (!Params)
+ return;
+ Out << '>' << Params->size();
+ for (TemplateParameterList::const_iterator P = Params->begin(),
+ PEnd = Params->end();
+ P != PEnd; ++P) {
+ Out << '#';
+ if (isa<TemplateTypeParmDecl>(*P)) {
+ if (cast<TemplateTypeParmDecl>(*P)->isParameterPack())
+ Out<< 'p';
+ Out << 'T';
+ continue;
+ }
+
+ if (NonTypeTemplateParmDecl *NTTP = dyn_cast<NonTypeTemplateParmDecl>(*P)) {
+ if (NTTP->isParameterPack())
+ Out << 'p';
+ Out << 'N';
+ VisitType(NTTP->getType());
+ continue;
+ }
+
+ TemplateTemplateParmDecl *TTP = cast<TemplateTemplateParmDecl>(*P);
+ if (TTP->isParameterPack())
+ Out << 'p';
+ Out << 't';
+ VisitTemplateParameterList(TTP->getTemplateParameters());
+ }
+}
+
+void USRGenerator::VisitTemplateName(TemplateName Name) {
+ if (TemplateDecl *Template = Name.getAsTemplateDecl()) {
+ if (TemplateTemplateParmDecl *TTP
+ = dyn_cast<TemplateTemplateParmDecl>(Template)) {
+ Out << 't' << TTP->getDepth() << '.' << TTP->getIndex();
+ return;
+ }
+
+ Visit(Template);
+ return;
+ }
+
+ // FIXME: Visit dependent template names.
+}
+
+void USRGenerator::VisitTemplateArgument(const TemplateArgument &Arg) {
+ switch (Arg.getKind()) {
+ case TemplateArgument::Null:
+ break;
+
+ case TemplateArgument::Declaration:
+ Visit(Arg.getAsDecl());
+ break;
+
+ case TemplateArgument::NullPtr:
+ break;
+
+ case TemplateArgument::TemplateExpansion:
+ Out << 'P'; // pack expansion of...
+ // Fall through
+ case TemplateArgument::Template:
+ VisitTemplateName(Arg.getAsTemplateOrTemplatePattern());
+ break;
+
+ case TemplateArgument::Expression:
+ // FIXME: Visit expressions.
+ break;
+
+ case TemplateArgument::Pack:
+ Out << 'p' << Arg.pack_size();
+ for (TemplateArgument::pack_iterator P = Arg.pack_begin(), PEnd = Arg.pack_end();
+ P != PEnd; ++P)
+ VisitTemplateArgument(*P);
+ break;
+
+ case TemplateArgument::Type:
+ VisitType(Arg.getAsType());
+ break;
+
+ case TemplateArgument::Integral:
+ Out << 'V';
+ VisitType(Arg.getIntegralType());
+ Out << Arg.getAsIntegral();
+ break;
+ }
+}
+
+//===----------------------------------------------------------------------===//
+// General purpose USR generation methods.
+//===----------------------------------------------------------------------===//
+
+void USRGenerator::GenObjCClass(StringRef cls) {
+ Out << "objc(cs)" << cls;
+}
+
+void USRGenerator::GenObjCCategory(StringRef cls, StringRef cat) {
+ Out << "objc(cy)" << cls << '@' << cat;
+}
+
+void USRGenerator::GenObjCIvar(StringRef ivar) {
+ Out << '@' << ivar;
+}
+
+void USRGenerator::GenObjCMethod(StringRef meth, bool isInstanceMethod) {
+ Out << (isInstanceMethod ? "(im)" : "(cm)") << meth;
+}
+
+void USRGenerator::GenObjCProperty(StringRef prop) {
+ Out << "(py)" << prop;
+}
+
+void USRGenerator::GenObjCProtocol(StringRef prot) {
+ Out << "objc(pl)" << prot;
+}
+
+//===----------------------------------------------------------------------===//
+// API hooks.
+//===----------------------------------------------------------------------===//
+
+static inline StringRef extractUSRSuffix(StringRef s) {
+ return s.startswith("c:") ? s.substr(2) : "";
+}
+
+bool cxcursor::getDeclCursorUSR(const Decl *D, SmallVectorImpl<char> &Buf) {
+ // Don't generate USRs for things with invalid locations.
+ if (!D || D->getLocStart().isInvalid())
+ return true;
+
+ USRGenerator UG(&D->getASTContext(), &Buf);
+ UG->Visit(const_cast<Decl*>(D));
+
+ if (UG->ignoreResults())
+ return true;
+
+ return false;
+}
+
+extern "C" {
+
+CXString clang_getCursorUSR(CXCursor C) {
+ const CXCursorKind &K = clang_getCursorKind(C);
+
+ if (clang_isDeclaration(K)) {
+ Decl *D = cxcursor::getCursorDecl(C);
+ if (!D)
+ return createCXString("");
+
+ CXTranslationUnit TU = cxcursor::getCursorTU(C);
+ if (!TU)
+ return createCXString("");
+
+ CXStringBuf *buf = cxstring::getCXStringBuf(TU);
+ if (!buf)
+ return createCXString("");
+
+ bool Ignore = cxcursor::getDeclCursorUSR(D, buf->Data);
+ if (Ignore) {
+ disposeCXStringBuf(buf);
+ return createCXString("");
+ }
+
+ // Return the C-string, but don't make a copy since it is already in
+ // the string buffer.
+ buf->Data.push_back('\0');
+ return createCXString(buf);
+ }
+
+ if (K == CXCursor_MacroDefinition) {
+ CXTranslationUnit TU = cxcursor::getCursorTU(C);
+ if (!TU)
+ return createCXString("");
+
+ CXStringBuf *buf = cxstring::getCXStringBuf(TU);
+ if (!buf)
+ return createCXString("");
+
+ {
+ USRGenerator UG(&cxcursor::getCursorASTUnit(C)->getASTContext(),
+ &buf->Data);
+ UG << "macro@"
+ << cxcursor::getCursorMacroDefinition(C)->getName()->getNameStart();
+ }
+ buf->Data.push_back('\0');
+ return createCXString(buf);
+ }
+
+ return createCXString("");
+}
+
+CXString clang_constructUSR_ObjCIvar(const char *name, CXString classUSR) {
+ USRGenerator UG;
+ UG << extractUSRSuffix(clang_getCString(classUSR));
+ UG->GenObjCIvar(name);
+ return createCXString(UG.str(), true);
+}
+
+CXString clang_constructUSR_ObjCMethod(const char *name,
+ unsigned isInstanceMethod,
+ CXString classUSR) {
+ USRGenerator UG;
+ UG << extractUSRSuffix(clang_getCString(classUSR));
+ UG->GenObjCMethod(name, isInstanceMethod);
+ return createCXString(UG.str(), true);
+}
+
+CXString clang_constructUSR_ObjCClass(const char *name) {
+ USRGenerator UG;
+ UG->GenObjCClass(name);
+ return createCXString(UG.str(), true);
+}
+
+CXString clang_constructUSR_ObjCProtocol(const char *name) {
+ USRGenerator UG;
+ UG->GenObjCProtocol(name);
+ return createCXString(UG.str(), true);
+}
+
+CXString clang_constructUSR_ObjCCategory(const char *class_name,
+ const char *category_name) {
+ USRGenerator UG;
+ UG->GenObjCCategory(class_name, category_name);
+ return createCXString(UG.str(), true);
+}
+
+CXString clang_constructUSR_ObjCProperty(const char *property,
+ CXString classUSR) {
+ USRGenerator UG;
+ UG << extractUSRSuffix(clang_getCString(classUSR));
+ UG->GenObjCProperty(property);
+ return createCXString(UG.str(), true);
+}
+
+} // end extern "C"
|