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>