Improve source-location information for builtin TypeLocs, from Enea
Zaffanella (with a couple of my tweaks).
git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@93733 91177308-0d34-0410-b5e6-96231b3b80d8
diff --git a/include/clang/AST/TypeLoc.h b/include/clang/AST/TypeLoc.h
index c36c0ff..0a40ea1 100644
--- a/include/clang/AST/TypeLoc.h
+++ b/include/clang/AST/TypeLoc.h
@@ -16,6 +16,7 @@
#include "clang/AST/Type.h"
#include "clang/AST/TemplateBase.h"
+#include "clang/Basic/Specifiers.h"
namespace clang {
class ParmVarDecl;
@@ -372,6 +373,111 @@
};
+struct BuiltinLocInfo {
+ SourceLocation BuiltinLoc;
+};
+
+/// \brief Wrapper for source info for builtin types.
+class BuiltinTypeLoc : public ConcreteTypeLoc<UnqualTypeLoc,
+ BuiltinTypeLoc,
+ BuiltinType,
+ BuiltinLocInfo> {
+public:
+ enum { LocalDataSize = sizeof(BuiltinLocInfo) };
+
+ SourceLocation getBuiltinLoc() const {
+ return getLocalData()->BuiltinLoc;
+ }
+ void setBuiltinLoc(SourceLocation Loc) {
+ getLocalData()->BuiltinLoc = Loc;
+ }
+
+ SourceLocation getNameLoc() const { return getBuiltinLoc(); }
+
+ WrittenBuiltinSpecs& getWrittenBuiltinSpecs() {
+ return *(static_cast<WrittenBuiltinSpecs*>(getExtraLocalData()));
+ }
+ const WrittenBuiltinSpecs& getWrittenBuiltinSpecs() const {
+ return *(static_cast<WrittenBuiltinSpecs*>(getExtraLocalData()));
+ }
+
+ bool needsExtraLocalData() const {
+ BuiltinType::Kind bk = getTypePtr()->getKind();
+ return (bk >= BuiltinType::UShort && bk <= BuiltinType::UInt128)
+ || (bk >= BuiltinType::Short && bk <= BuiltinType::Int128)
+ || bk == BuiltinType::UChar
+ || bk == BuiltinType::SChar;
+ }
+
+ unsigned getExtraLocalDataSize() const {
+ return needsExtraLocalData() ? 4 : 0;
+ }
+
+ SourceRange getSourceRange() const {
+ return SourceRange(getBuiltinLoc(), getBuiltinLoc());
+ }
+
+ TypeSpecifierSign getWrittenSignSpec() const {
+ if (needsExtraLocalData())
+ return static_cast<TypeSpecifierSign>(getWrittenBuiltinSpecs().Sign);
+ else
+ return TSS_unspecified;
+ }
+ bool hasWrittenSignSpec() const {
+ return getWrittenSignSpec() != TSS_unspecified;
+ }
+ void setWrittenSignSpec(TypeSpecifierSign written) {
+ if (needsExtraLocalData())
+ getWrittenBuiltinSpecs().Sign = written;
+ }
+
+ TypeSpecifierWidth getWrittenWidthSpec() const {
+ if (needsExtraLocalData())
+ return static_cast<TypeSpecifierWidth>(getWrittenBuiltinSpecs().Width);
+ else
+ return TSW_unspecified;
+ }
+ bool hasWrittenWidthSpec() const {
+ return getWrittenWidthSpec() != TSW_unspecified;
+ }
+ void setWrittenWidthSpec(TypeSpecifierWidth written) {
+ if (needsExtraLocalData())
+ getWrittenBuiltinSpecs().Width = written;
+ }
+
+ TypeSpecifierType getWrittenTypeSpec() const;
+ bool hasWrittenTypeSpec() const {
+ return getWrittenTypeSpec() != TST_unspecified;
+ }
+ void setWrittenTypeSpec(TypeSpecifierType written) {
+ if (needsExtraLocalData())
+ getWrittenBuiltinSpecs().Type = written;
+ }
+
+ bool hasModeAttr() const {
+ if (needsExtraLocalData())
+ return getWrittenBuiltinSpecs().ModeAttr;
+ else
+ return false;
+ }
+ void setModeAttr(bool written) {
+ if (needsExtraLocalData())
+ getWrittenBuiltinSpecs().ModeAttr = written;
+ }
+
+ void initializeLocal(SourceLocation Loc) {
+ setBuiltinLoc(Loc);
+ if (needsExtraLocalData()) {
+ WrittenBuiltinSpecs &wbs = getWrittenBuiltinSpecs();
+ wbs.Sign = TSS_unspecified;
+ wbs.Width = TSW_unspecified;
+ wbs.Type = TST_unspecified;
+ wbs.ModeAttr = false;
+ }
+ }
+};
+
+
/// \brief Wrapper for source info for typedefs.
class TypedefTypeLoc : public InheritingConcreteTypeLoc<TypeSpecTypeLoc,
TypedefTypeLoc,
@@ -421,12 +527,6 @@
EnumDecl *getDecl() const { return getTypePtr()->getDecl(); }
};
-/// \brief Wrapper for source info for builtin types.
-class BuiltinTypeLoc : public InheritingConcreteTypeLoc<TypeSpecTypeLoc,
- BuiltinTypeLoc,
- BuiltinType> {
-};
-
/// \brief Wrapper for template type parameters.
class TemplateTypeParmTypeLoc :
public InheritingConcreteTypeLoc<TypeSpecTypeLoc,
diff --git a/include/clang/Basic/Specifiers.h b/include/clang/Basic/Specifiers.h
new file mode 100644
index 0000000..6869274
--- /dev/null
+++ b/include/clang/Basic/Specifiers.h
@@ -0,0 +1,72 @@
+//===--- 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.
+//
+//===----------------------------------------------------------------------===//
+//
+// This file 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_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_typename, // Typedef, C++ class-name or enum name, etc.
+ TST_typeofType,
+ TST_typeofExpr,
+ TST_decltype, // C++0x decltype
+ TST_auto, // C++0x auto
+ TST_error // erroneous type
+ };
+
+ /// WrittenBuiltinSpecs - 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;
+ };
+}
+
+#endif // LLVM_CLANG_BASIC_SPECIFIERS_H
\ No newline at end of file
diff --git a/include/clang/Parse/DeclSpec.h b/include/clang/Parse/DeclSpec.h
index 6a3d8a9..f923b5e 100644
--- a/include/clang/Parse/DeclSpec.h
+++ b/include/clang/Parse/DeclSpec.h
@@ -17,6 +17,7 @@
#include "clang/Parse/AttributeList.h"
#include "clang/Lex/Token.h"
#include "clang/Basic/OperatorKinds.h"
+#include "clang/Basic/Specifiers.h"
#include "llvm/ADT/SmallVector.h"
namespace clang {
@@ -78,51 +79,50 @@
SCS_mutable
};
- // type-specifier
- enum TSW {
- TSW_unspecified,
- TSW_short,
- TSW_long,
- TSW_longlong
- };
-
+ // Import type specifier width enumeration and constants.
+ typedef TypeSpecifierWidth TSW;
+ static const TSW TSW_unspecified = clang::TSW_unspecified;
+ static const TSW TSW_short = clang::TSW_short;
+ static const TSW TSW_long = clang::TSW_long;
+ static const TSW TSW_longlong = clang::TSW_longlong;
+
enum TSC {
TSC_unspecified,
TSC_imaginary,
TSC_complex
};
- enum TSS {
- TSS_unspecified,
- TSS_signed,
- TSS_unsigned
- };
+ // Import type specifier sign enumeration and constants.
+ typedef TypeSpecifierSign TSS;
+ static const TSS TSS_unspecified = clang::TSS_unspecified;
+ static const TSS TSS_signed = clang::TSS_signed;
+ static const TSS TSS_unsigned = clang::TSS_unsigned;
- enum TST {
- 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_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_typename, // Typedef, C++ class-name or enum name, etc.
- TST_typeofType,
- TST_typeofExpr,
- TST_decltype, // C++0x decltype
- TST_auto, // C++0x auto
- TST_error // erroneous type
- };
+ // Import type specifier type enumeration and constants.
+ typedef TypeSpecifierType TST;
+ static const TST TST_unspecified = clang::TST_unspecified;
+ static const TST TST_void = clang::TST_void;
+ static const TST TST_char = clang::TST_char;
+ static const TST TST_wchar = clang::TST_wchar;
+ static const TST TST_char16 = clang::TST_char16;
+ static const TST TST_char32 = clang::TST_char32;
+ static const TST TST_int = clang::TST_int;
+ static const TST TST_float = clang::TST_float;
+ static const TST TST_double = clang::TST_double;
+ static const TST TST_bool = clang::TST_bool;
+ static const TST TST_decimal32 = clang::TST_decimal32;
+ static const TST TST_decimal64 = clang::TST_decimal64;
+ static const TST TST_decimal128 = clang::TST_decimal128;
+ static const TST TST_enum = clang::TST_enum;
+ static const TST TST_union = clang::TST_union;
+ static const TST TST_struct = clang::TST_struct;
+ static const TST TST_class = clang::TST_class;
+ static const TST TST_typename = clang::TST_typename;
+ static const TST TST_typeofType = clang::TST_typeofType;
+ static const TST TST_typeofExpr = clang::TST_typeofExpr;
+ static const TST TST_decltype = clang::TST_decltype;
+ static const TST TST_auto = clang::TST_auto;
+ static const TST TST_error = clang::TST_error;
// type-qualifiers
enum TQ { // NOTE: These flags must be kept in sync with Qualifiers::TQ.
@@ -199,6 +199,9 @@
SourceLocation FS_inlineLoc, FS_virtualLoc, FS_explicitLoc;
SourceLocation FriendLoc, ConstexprLoc;
+ WrittenBuiltinSpecs writtenBS;
+ void SaveWrittenBuiltinSpecs();
+
DeclSpec(const DeclSpec&); // DO NOT IMPLEMENT
void operator=(const DeclSpec&); // DO NOT IMPLEMENT
public:
@@ -411,6 +414,10 @@
/// DeclSpec is guaranteed self-consistent, even if an error occurred.
void Finish(Diagnostic &D, Preprocessor &PP);
+ const WrittenBuiltinSpecs& getWrittenBuiltinSpecs() const {
+ return writtenBS;
+ }
+
/// isMissingDeclaratorOk - This checks if this DeclSpec can stand alone,
/// without a Declarator. Only tag declspecs can stand alone.
bool isMissingDeclaratorOk();
diff --git a/lib/AST/TypeLoc.cpp b/lib/AST/TypeLoc.cpp
index 0840c52..6da2ab0 100644
--- a/lib/AST/TypeLoc.cpp
+++ b/lib/AST/TypeLoc.cpp
@@ -14,6 +14,7 @@
#include "llvm/Support/raw_ostream.h"
#include "clang/AST/TypeLocVisitor.h"
#include "clang/AST/Expr.h"
+#include "llvm/Support/ErrorHandling.h"
using namespace clang;
//===----------------------------------------------------------------------===//
@@ -135,3 +136,58 @@
return SourceRange(getTypeofLoc(),
getUnderlyingExpr()->getSourceRange().getEnd());
}
+
+
+TypeSpecifierType BuiltinTypeLoc::getWrittenTypeSpec() const {
+ if (needsExtraLocalData())
+ return static_cast<TypeSpecifierType>(getWrittenBuiltinSpecs().Type);
+ else {
+ 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:
+ return TST_wchar;
+ case BuiltinType::Float:
+ return TST_float;
+ case BuiltinType::Double:
+ case BuiltinType::LongDouble:
+ return TST_double;
+ case BuiltinType::UndeducedAuto:
+ return TST_auto;
+
+ 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:
+ 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::ObjCId:
+ case BuiltinType::ObjCClass:
+ case BuiltinType::ObjCSel:
+ return TST_unspecified;
+ }
+ }
+
+ return TST_unspecified;
+}
diff --git a/lib/Frontend/PCHReader.cpp b/lib/Frontend/PCHReader.cpp
index 1f23bd2..77fa11e 100644
--- a/lib/Frontend/PCHReader.cpp
+++ b/lib/Frontend/PCHReader.cpp
@@ -2042,7 +2042,13 @@
// nothing to do
}
void TypeLocReader::VisitBuiltinTypeLoc(BuiltinTypeLoc TL) {
- TL.setNameLoc(SourceLocation::getFromRawEncoding(Record[Idx++]));
+ TL.setBuiltinLoc(SourceLocation::getFromRawEncoding(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(SourceLocation::getFromRawEncoding(Record[Idx++]));
diff --git a/lib/Frontend/PCHWriter.cpp b/lib/Frontend/PCHWriter.cpp
index 21e0974..97cd84f 100644
--- a/lib/Frontend/PCHWriter.cpp
+++ b/lib/Frontend/PCHWriter.cpp
@@ -277,7 +277,13 @@
// nothing to do
}
void TypeLocWriter::VisitBuiltinTypeLoc(BuiltinTypeLoc TL) {
- Writer.AddSourceLocation(TL.getNameLoc(), Record);
+ Writer.AddSourceLocation(TL.getBuiltinLoc(), Record);
+ if (TL.needsExtraLocalData()) {
+ Record.push_back(TL.getWrittenTypeSpec());
+ Record.push_back(TL.getWrittenSignSpec());
+ Record.push_back(TL.getWrittenWidthSpec());
+ Record.push_back(TL.hasModeAttr());
+ }
}
void TypeLocWriter::VisitComplexTypeLoc(ComplexTypeLoc TL) {
Writer.AddSourceLocation(TL.getNameLoc(), Record);
diff --git a/lib/Parse/DeclSpec.cpp b/lib/Parse/DeclSpec.cpp
index f52d8b9..9e5f5a2 100644
--- a/lib/Parse/DeclSpec.cpp
+++ b/lib/Parse/DeclSpec.cpp
@@ -373,11 +373,30 @@
ProtocolLAngleLoc = LAngleLoc;
}
+void DeclSpec::SaveWrittenBuiltinSpecs() {
+ writtenBS.Sign = getTypeSpecSign();
+ writtenBS.Width = getTypeSpecWidth();
+ writtenBS.Type = getTypeSpecType();
+ // Search the list of attributes for the presence of a mode attribute.
+ writtenBS.ModeAttr = false;
+ AttributeList* attrs = getAttributes();
+ while (attrs) {
+ if (attrs->getKind() == AttributeList::AT_mode) {
+ writtenBS.ModeAttr = true;
+ break;
+ }
+ attrs = attrs->getNext();
+ }
+}
+
/// Finish - This does final analysis of the declspec, rejecting things like
/// "_Imaginary" (lacking an FP type). This returns a diagnostic to issue or
/// diag::NUM_DIAGNOSTICS if there is no error. After calling this method,
/// DeclSpec is guaranteed self-consistent, even if an error occurred.
void DeclSpec::Finish(Diagnostic &D, Preprocessor &PP) {
+ // Before possibly changing their values, save specs as written.
+ SaveWrittenBuiltinSpecs();
+
// Check the type specifier components first.
SourceManager &SrcMgr = PP.getSourceManager();
diff --git a/lib/Sema/SemaType.cpp b/lib/Sema/SemaType.cpp
index 9515834..9065761 100644
--- a/lib/Sema/SemaType.cpp
+++ b/lib/Sema/SemaType.cpp
@@ -1374,6 +1374,21 @@
Sema::GetTypeFromParser(DS.getTypeRep(), &TInfo);
TL.setUnderlyingTInfo(TInfo);
}
+ void VisitBuiltinTypeLoc(BuiltinTypeLoc TL) {
+ // By default, use the source location of the type specifier.
+ TL.setBuiltinLoc(DS.getTypeSpecTypeLoc());
+ if (TL.needsExtraLocalData()) {
+ // Set info for the written builtin specifiers.
+ TL.getWrittenBuiltinSpecs() = DS.getWrittenBuiltinSpecs();
+ // Try to have a meaningful source location.
+ if (TL.getWrittenSignSpec() != TSS_unspecified)
+ // Sign spec loc overrides the others (e.g., 'unsigned long').
+ TL.setBuiltinLoc(DS.getTypeSpecSignLoc());
+ else if (TL.getWrittenWidthSpec() != TSW_unspecified)
+ // Width spec loc overrides type spec loc (e.g., 'short int').
+ TL.setBuiltinLoc(DS.getTypeSpecWidthLoc());
+ }
+ }
void VisitTypeLoc(TypeLoc TL) {
// FIXME: add other typespec types and change this to an assert.
TL.initialize(DS.getTypeSpecTypeLoc());
diff --git a/lib/Sema/TreeTransform.h b/lib/Sema/TreeTransform.h
index 41f465f..aba6455 100644
--- a/lib/Sema/TreeTransform.h
+++ b/lib/Sema/TreeTransform.h
@@ -2138,7 +2138,11 @@
template<typename Derived>
QualType TreeTransform<Derived>::TransformBuiltinType(TypeLocBuilder &TLB,
BuiltinTypeLoc T) {
- return TransformTypeSpecType(TLB, T);
+ BuiltinTypeLoc NewT = TLB.push<BuiltinTypeLoc>(T.getType());
+ NewT.setBuiltinLoc(T.getBuiltinLoc());
+ if (T.needsExtraLocalData())
+ NewT.getWrittenBuiltinSpecs() = T.getWrittenBuiltinSpecs();
+ return T.getType();
}
template<typename Derived>