Revert changes from r170428, as I accidentally changed the line endings of these files to Windows style.
git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@170431 91177308-0d34-0410-b5e6-96231b3b80d8
diff --git a/include/clang/AST/ASTContext.h b/include/clang/AST/ASTContext.h
index d750ba9..86b2c42 100644
--- a/include/clang/AST/ASTContext.h
+++ b/include/clang/AST/ASTContext.h
@@ -716,9 +716,6 @@
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/include/clang/AST/BuiltinTypes.def b/include/clang/AST/BuiltinTypes.def
index 75ebb2c..ba322fb 100644
--- a/include/clang/AST/BuiltinTypes.def
+++ b/include/clang/AST/BuiltinTypes.def
@@ -1,234 +1,226 @@
-//===-- 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
+//===-- 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
diff --git a/include/clang/AST/Type.h b/include/clang/AST/Type.h
index cf3b565..368be8d 100644
--- a/include/clang/AST/Type.h
+++ b/include/clang/AST/Type.h
@@ -1580,17 +1580,6 @@
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.
@@ -4894,40 +4883,6 @@
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/include/clang/Basic/Specifiers.h b/include/clang/Basic/Specifiers.h
index 8a6c629..c82b8cb 100644
--- a/include/clang/Basic/Specifiers.h
+++ b/include/clang/Basic/Specifiers.h
@@ -1,200 +1,194 @@
-//===--- 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
+//===--- 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
diff --git a/include/clang/Basic/TokenKinds.def b/include/clang/Basic/TokenKinds.def
index 7bc489b..f02ba64 100644
--- a/include/clang/Basic/TokenKinds.def
+++ b/include/clang/Basic/TokenKinds.def
@@ -448,12 +448,6 @@
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/include/clang/Sema/DeclSpec.h b/include/clang/Sema/DeclSpec.h
index bc8fc64..d261810 100644
--- a/include/clang/Sema/DeclSpec.h
+++ b/include/clang/Sema/DeclSpec.h
@@ -276,12 +276,6 @@
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
@@ -312,7 +306,7 @@
/*TSW*/unsigned TypeSpecWidth : 2;
/*TSC*/unsigned TypeSpecComplex : 2;
/*TSS*/unsigned TypeSpecSign : 2;
- /*TST*/unsigned TypeSpecType : 6;
+ /*TST*/unsigned TypeSpecType : 5;
unsigned TypeAltiVecVector : 1;
unsigned TypeAltiVecPixel : 1;
unsigned TypeAltiVecBool : 1;
diff --git a/include/clang/Serialization/ASTBitCodes.h b/include/clang/Serialization/ASTBitCodes.h
index 868a175..4273e14 100644
--- a/include/clang/Serialization/ASTBitCodes.h
+++ b/include/clang/Serialization/ASTBitCodes.h
@@ -1,1367 +1,1355 @@
-//===- 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
+//===- 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
diff --git a/lib/AST/ASTContext.cpp b/lib/AST/ASTContext.cpp
index b04b830..f3fa135 100644
--- a/lib/AST/ASTContext.cpp
+++ b/lib/AST/ASTContext.cpp
@@ -874,15 +874,6 @@
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() ?
@@ -1421,16 +1412,6 @@
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/lib/AST/ItaniumMangle.cpp b/lib/AST/ItaniumMangle.cpp
index 65907f9..566a389 100644
--- a/lib/AST/ItaniumMangle.cpp
+++ b/lib/AST/ItaniumMangle.cpp
@@ -1,3580 +1,3574 @@
-//===--- 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);
-}
+//===--- 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);
+}
diff --git a/lib/AST/MicrosoftMangle.cpp b/lib/AST/MicrosoftMangle.cpp
index a8737e7..0da7f51 100644
--- a/lib/AST/MicrosoftMangle.cpp
+++ b/lib/AST/MicrosoftMangle.cpp
@@ -1,1725 +1,1718 @@
-//===--- 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);
-}
+//===--- 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);
+}
diff --git a/lib/AST/NSAPI.cpp b/lib/AST/NSAPI.cpp
index 6218da2..0837509 100644
--- a/lib/AST/NSAPI.cpp
+++ b/lib/AST/NSAPI.cpp
@@ -1,420 +1,414 @@
-//===--- 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;
-}
+//===--- 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;
+}
diff --git a/lib/AST/Type.cpp b/lib/AST/Type.cpp
index 26eee2d..97448ee 100644
--- a/lib/AST/Type.cpp
+++ b/lib/AST/Type.cpp
@@ -1512,12 +1512,6 @@
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/lib/AST/TypeLoc.cpp b/lib/AST/TypeLoc.cpp
index b86d226..c021cf8 100644
--- a/lib/AST/TypeLoc.cpp
+++ b/lib/AST/TypeLoc.cpp
@@ -1,367 +1,361 @@
-//===--- 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;
- }
- }
-}
+//===--- 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;
+ }
+ }
+}
diff --git a/lib/CodeGen/CGDebugInfo.cpp b/lib/CodeGen/CGDebugInfo.cpp
index c16081f..844514b 100644
--- a/lib/CodeGen/CGDebugInfo.cpp
+++ b/lib/CodeGen/CGDebugInfo.cpp
@@ -1,2834 +1,2802 @@
-//===--- 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();
-}
+//===--- 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();
+}
diff --git a/lib/CodeGen/CGDebugInfo.h b/lib/CodeGen/CGDebugInfo.h
index 5a3b122..cb9ce8b 100644
--- a/lib/CodeGen/CGDebugInfo.h
+++ b/lib/CodeGen/CGDebugInfo.h
@@ -1,330 +1,325 @@
-//===--- 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
+//===--- 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
diff --git a/lib/CodeGen/CGOpenCLRuntime.cpp b/lib/CodeGen/CGOpenCLRuntime.cpp
index 61d6286..3a0e116 100644
--- a/lib/CodeGen/CGOpenCLRuntime.cpp
+++ b/lib/CodeGen/CGOpenCLRuntime.cpp
@@ -1,59 +1,28 @@
-//===----- 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);
- }
-}
+//===----- 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);
+}
diff --git a/lib/CodeGen/CGOpenCLRuntime.h b/lib/CodeGen/CGOpenCLRuntime.h
index 7b33951..9a8430f 100644
--- a/lib/CodeGen/CGOpenCLRuntime.h
+++ b/lib/CodeGen/CGOpenCLRuntime.h
@@ -1,52 +1,46 @@
-//===----- 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
+//===----- 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
diff --git a/lib/CodeGen/CGRTTI.cpp b/lib/CodeGen/CGRTTI.cpp
index 0a1fb4b..53716a0 100644
--- a/lib/CodeGen/CGRTTI.cpp
+++ b/lib/CodeGen/CGRTTI.cpp
@@ -1,1017 +1,1011 @@
-//===--- 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]);
-}
+//===--- 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]);
+}
diff --git a/lib/CodeGen/CodeGenTypes.cpp b/lib/CodeGen/CodeGenTypes.cpp
index 8cb6dd0..a0effa8 100644
--- a/lib/CodeGen/CodeGenTypes.cpp
+++ b/lib/CodeGen/CodeGenTypes.cpp
@@ -14,7 +14,6 @@
#include "CodeGenTypes.h"
#include "CGCXXABI.h"
#include "CGCall.h"
-#include "CGOpenCLRuntime.h"
#include "CGRecordLayout.h"
#include "TargetInfo.h"
#include "clang/AST/ASTContext.h"
@@ -367,15 +366,6 @@
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/lib/Parse/ParseDecl.cpp b/lib/Parse/ParseDecl.cpp
index 390fd34..518c8a07 100644
--- a/lib/Parse/ParseDecl.cpp
+++ b/lib/Parse/ParseDecl.cpp
@@ -2753,30 +2753,6 @@
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);
@@ -3620,14 +3596,6 @@
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:
@@ -3700,14 +3668,6 @@
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:
@@ -3852,14 +3812,6 @@
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/lib/Parse/ParseExpr.cpp b/lib/Parse/ParseExpr.cpp
index b7705f8..14980ee 100644
--- a/lib/Parse/ParseExpr.cpp
+++ b/lib/Parse/ParseExpr.cpp
@@ -1078,13 +1078,7 @@
case tok::kw_void:
case tok::kw_typename:
case tok::kw_typeof:
- 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: {
+ case tok::kw___vector: {
if (!getLangOpts().CPlusPlus) {
Diag(Tok, diag::err_expected_expression);
return ExprError();
diff --git a/lib/Parse/ParseTentative.cpp b/lib/Parse/ParseTentative.cpp
index e411899..b26181f 100644
--- a/lib/Parse/ParseTentative.cpp
+++ b/lib/Parse/ParseTentative.cpp
@@ -1,1580 +1,1574 @@
-//===--- 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();
-}
+//===--- 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();
+}
diff --git a/lib/Sema/DeclSpec.cpp b/lib/Sema/DeclSpec.cpp
index b34b953..040e638 100644
--- a/lib/Sema/DeclSpec.cpp
+++ b/lib/Sema/DeclSpec.cpp
@@ -280,12 +280,6 @@
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:
@@ -420,12 +414,6 @@
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/lib/Sema/SemaTemplateVariadic.cpp b/lib/Sema/SemaTemplateVariadic.cpp
index 6c70320..f797825 100644
--- a/lib/Sema/SemaTemplateVariadic.cpp
+++ b/lib/Sema/SemaTemplateVariadic.cpp
@@ -731,12 +731,6 @@
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/lib/Sema/SemaType.cpp b/lib/Sema/SemaType.cpp
index 1afc8c7..2c7b7c1 100644
--- a/lib/Sema/SemaType.cpp
+++ b/lib/Sema/SemaType.cpp
@@ -903,30 +903,6 @@
}
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/lib/Serialization/ASTCommon.cpp b/lib/Serialization/ASTCommon.cpp
index 91eec73..aec8a81 100644
--- a/lib/Serialization/ASTCommon.cpp
+++ b/lib/Serialization/ASTCommon.cpp
@@ -1,86 +1,80 @@
-//===--- 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;
-}
+//===--- 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;
+}
diff --git a/lib/Serialization/ASTReader.cpp b/lib/Serialization/ASTReader.cpp
index 88b5614..c0976ee 100644
--- a/lib/Serialization/ASTReader.cpp
+++ b/lib/Serialization/ASTReader.cpp
@@ -1,6998 +1,6992 @@
-//===--- 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;
- }
-}
+//===--- 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;
+ }
+}
diff --git a/test/CodeGenOpenCL/opencl_types.cl b/test/CodeGenOpenCL/opencl_types.cl
deleted file mode 100644
index 5bebc5e..0000000
--- a/test/CodeGenOpenCL/opencl_types.cl
+++ /dev/null
@@ -1,22 +0,0 @@
-// 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/test/PCH/ocl_types.cl b/test/PCH/ocl_types.cl
deleted file mode 100644
index d5c4428..0000000
--- a/test/PCH/ocl_types.cl
+++ /dev/null
@@ -1,18 +0,0 @@
-// 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/test/PCH/ocl_types.h b/test/PCH/ocl_types.h
deleted file mode 100644
index 6afa016..0000000
--- a/test/PCH/ocl_types.h
+++ /dev/null
@@ -1,19 +0,0 @@
-/* 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/test/Parser/opencl-image-access.cl b/test/Parser/opencl-image-access.cl
index 3496d12..313587c 100644
--- a/test/Parser/opencl-image-access.cl
+++ b/test/Parser/opencl-image-access.cl
@@ -1,14 +1,16 @@
-// 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) { }
+// 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) { }
diff --git a/tools/libclang/CIndex.cpp b/tools/libclang/CIndex.cpp
index c28c181..1fb9a70 100644
--- a/tools/libclang/CIndex.cpp
+++ b/tools/libclang/CIndex.cpp
@@ -1,6175 +1,6169 @@
-//===- 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"
-
+//===- 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"
+
diff --git a/tools/libclang/CIndexUSRs.cpp b/tools/libclang/CIndexUSRs.cpp
index f88862b..b76363e 100644
--- a/tools/libclang/CIndexUSRs.cpp
+++ b/tools/libclang/CIndexUSRs.cpp
@@ -1,912 +1,906 @@
-//===- 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"
+//===- 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"