jdenny updated this revision to Diff 146351.
jdenny marked 10 inline comments as done.
jdenny edited the summary of this revision.
jdenny added a comment.

Made the suggested changes.  Thanks.


https://reviews.llvm.org/D45463

Files:
  include/clang/AST/ASTContext.h
  include/clang/AST/Type.h
  include/clang/Sema/Sema.h
  lib/AST/ASTContext.cpp
  lib/AST/ASTImporter.cpp
  lib/AST/DeclPrinter.cpp
  lib/AST/TypePrinter.cpp
  lib/Sema/SemaType.cpp
  lib/Serialization/ASTReader.cpp
  lib/Serialization/ASTWriter.cpp
  test/Misc/ast-print-enum-decl.c
  test/Misc/ast-print-record-decl.c

Index: test/Misc/ast-print-record-decl.c
===================================================================
--- /dev/null
+++ test/Misc/ast-print-record-decl.c
@@ -0,0 +1,235 @@
+// Check struct:
+//
+//   First check compiling and printing of this file.
+//
+//   RUN: %clang -Xclang -verify -S -emit-llvm -DKW=struct -DBASES= -o - %s \
+//   RUN: | FileCheck --check-prefixes=CHECK,LLVM %s
+//
+//   RUN: %clang_cc1 -verify -ast-print -DKW=struct -DBASES= %s > %t.c
+//   RUN: FileCheck --check-prefixes=CHECK,PRINT -DKW=struct -DBASES= %s \
+//   RUN:           --input-file %t.c
+//
+//   Now check compiling and printing of the printed file.
+//
+//   RUN: echo "// expected""-warning@* 10 {{'T' is deprecated}}" >> %t.c
+//   RUN: echo "// expected""-note@* 10 {{'T' has been explicitly marked deprecated here}}" >> %t.c
+//
+//   RUN: %clang -Xclang -verify -S -emit-llvm -o - %t.c \
+//   RUN: | FileCheck --check-prefixes=CHECK,LLVM %s
+//
+//   RUN: %clang_cc1 -verify -ast-print %t.c \
+//   RUN: | FileCheck --check-prefixes=CHECK,PRINT -DKW=struct -DBASES= %s
+
+// Repeat for union:
+//
+//   First check compiling and printing of this file.
+//
+//   RUN: %clang -Xclang -verify -S -emit-llvm -DKW=union -DBASES= -o - %s \
+//   RUN: | FileCheck --check-prefixes=CHECK,LLVM %s
+//
+//   RUN: %clang_cc1 -verify -ast-print -DKW=union -DBASES= %s > %t.c
+//   RUN: FileCheck --check-prefixes=CHECK,PRINT -DKW=union -DBASES= %s \
+//   RUN:           --input-file %t.c
+//
+//   Now check compiling and printing of the printed file.
+//
+//   RUN: echo "// expected""-warning@* 10 {{'T' is deprecated}}" >> %t.c
+//   RUN: echo "// expected""-note@* 10 {{'T' has been explicitly marked deprecated here}}" >> %t.c
+//
+//   RUN: %clang -Xclang -verify -S -emit-llvm -o - %t.c \
+//   RUN: | FileCheck --check-prefixes=CHECK,LLVM %s
+//
+//   RUN: %clang_cc1 -verify -ast-print %t.c \
+//   RUN: | FileCheck --check-prefixes=CHECK,PRINT -DKW=union -DBASES= %s
+
+// Repeat for C++ (BASES helps ensure we're printing as C++ not as C):
+//
+//   First check compiling and printing of this file.
+//
+//   RUN: %clang -Xclang -verify -S -emit-llvm -DKW=struct -DBASES=' : B' -o - \
+//   RUN:        -xc++ %s \
+//   RUN: | FileCheck --check-prefixes=CHECK,LLVM %s
+//
+//   RUN: %clang_cc1 -verify -ast-print -DKW=struct -DBASES=' : B' -xc++ %s \
+//   RUN: > %t.cpp
+//   RUN: FileCheck --check-prefixes=CHECK,PRINT,CXX -DKW=struct \
+//   RUN:           -DBASES=' : B' %s --input-file %t.cpp
+//
+//   Now check compiling and printing of the printed file.
+//
+//   RUN: echo "// expected""-warning@* 10 {{'T' is deprecated}}" >> %t.cpp
+//   RUN: echo "// expected""-note@* 10 {{'T' has been explicitly marked deprecated here}}" >> %t.cpp
+//
+//   RUN: %clang -Xclang -verify -S -emit-llvm -o - %t.cpp \
+//   RUN: | FileCheck --check-prefixes=CHECK,LLVM %s
+//
+//   RUN: %clang_cc1 -verify -ast-print %t.cpp \
+//   RUN: | FileCheck --check-prefixes=CHECK,PRINT,CXX -DKW=struct \
+//   RUN:             -DBASES=' : B' %s
+
+// END.
+
+#ifndef KW
+# error KW undefined
+# define KW struct // help syntax checkers
+#endif
+
+#ifndef BASES
+# error BASES undefined
+# define BASES // help syntax checkers
+#endif
+
+struct B {};
+
+// CHECK-LABEL: defFirst
+void defFirst() {
+  // PRINT-NEXT: [[KW]]
+  // PRINT-DAG:  __attribute__((aligned(16)))
+  // PRINT-DAG:  __attribute__((deprecated("")))
+  // PRINT-NOT:  __attribute__
+  // PRINT-SAME: T[[BASES]] {
+  // PRINT-NEXT:   int i;
+  // PRINT-NEXT: } *p0;
+  // expected-warning@+2 {{'T' is deprecated}}
+  // expected-note@+1 2 {{'T' has been explicitly marked deprecated here}}
+  KW __attribute__((aligned(16))) __attribute__((deprecated(""))) T BASES {
+    int i;
+  } *p0;
+
+  // PRINT-NEXT: [[KW]] T *p1;
+  KW T *p1; // expected-warning {{'T' is deprecated}}
+
+  // LLVM: store i64 16
+  long s0 = sizeof *p0;
+  // LLVM-NEXT: store i64 16
+  long s1 = sizeof *p1;
+}
+
+// CHECK-LABEL: defLast
+void defLast() {
+  // PRINT-NEXT: [[KW]] __attribute__((aligned(16))) T *p0;
+  KW __attribute__((aligned(16))) T *p0;
+
+  // PRINT-NEXT: [[KW]] __attribute__((deprecated(""))) T[[BASES]] {
+  // PRINT-NEXT:   int i;
+  // PRINT-NEXT: } *p1;
+  // expected-warning@+2 {{'T' is deprecated}}
+  // expected-note@+1 {{'T' has been explicitly marked deprecated here}}
+  KW __attribute__((deprecated(""))) T BASES { int i; } *p1;
+
+  // LLVM: store i64 16
+  long s0 = sizeof *p0;
+  // LLVM-NEXT: store i64 16
+  long s1 = sizeof *p1;
+}
+
+// CHECK-LABEL: defMiddle
+void defMiddle() {
+  // PRINT-NEXT: [[KW]] __attribute__((deprecated(""))) T *p0;
+  // expected-warning@+2 {{'T' is deprecated}}
+  // expected-note@+1 3 {{'T' has been explicitly marked deprecated here}}
+  KW __attribute__((deprecated(""))) T *p0;
+
+  // PRINT-NEXT: [[KW]] __attribute__((aligned(16))) T[[BASES]] {
+  // PRINT-NEXT:   int i;
+  // PRINT-NEXT: } *p1;
+  KW __attribute__((aligned(16))) T BASES { int i; } *p1; // expected-warning {{'T' is deprecated}}
+
+  // PRINT-NEXT: [[KW]] T *p2;
+  KW T *p2; // expected-warning {{'T' is deprecated}}
+
+  // LLVM: store i64 16
+  long s0 = sizeof *p0;
+  // LLVM-NEXT: store i64 16
+  long s1 = sizeof *p1;
+  // LLVM-NEXT: store i64 16
+  long s2 = sizeof *p2;
+}
+
+// CHECK-LABEL: defSelfRef
+void defSelfRef() {
+  // PRINT-NEXT: [[KW]] __attribute__((deprecated(""))) T *p0;
+  // expected-warning@+2 {{'T' is deprecated}}
+  // expected-note@+1 2 {{'T' has been explicitly marked deprecated here}}
+  KW __attribute__((deprecated(""))) T *p0;
+
+  // PRINT-NEXT: [[KW]] __attribute__((aligned(16))) T[[BASES]] {
+  // PRINT-NEXT:   int i;
+  // PRINT-NEXT:   [[KW]] T *p2;
+  // PRINT-NEXT: } *p1;
+  KW __attribute__((aligned(16))) T BASES { // expected-warning {{'T' is deprecated}}
+    int i;
+    KW T *p2;
+  } *p1;
+
+  // LLVM: store i64 16
+  long s0 = sizeof *p0;
+  // LLVM-NEXT: store i64 16
+  long s1 = sizeof *p1;
+  // LLVM-NEXT: store i64 16
+  long s2 = sizeof *p0->p2;
+  // LLVM-NEXT: store i64 16
+  long s3 = sizeof *p1->p2;
+  // LLVM-NEXT: store i64 16
+  long s4 = sizeof *p1->p2->p2;
+}
+
+// CHECK-LABEL: declsOnly
+void declsOnly() {
+  // PRINT-NEXT: [[KW]] T *p0;
+  KW T *p0;
+
+  // PRINT-NEXT: [[KW]] __attribute__((may_alias)) T *p1;
+  KW __attribute__((may_alias)) T *p1;
+
+  // PRINT-NEXT: [[KW]] T *p2;
+  KW T *p2;
+
+  // PRINT-NEXT: [[KW]] __attribute__((deprecated(""))) T *p3;
+  // expected-warning@+2 {{'T' is deprecated}}
+  // expected-note@+1 2 {{'T' has been explicitly marked deprecated here}}
+  KW __attribute__((deprecated(""))) T *p3;
+
+  // PRINT-NEXT: [[KW]] T *p4;
+  KW T *p4; // expected-warning {{'T' is deprecated}}
+}
+
+// Make sure expanded printing of tag types is turned back off in other parts
+// of a tag declaration.  The base class list is checked above.
+
+// CHECK-LABEL: inMembers
+void inMembers() {
+  // PRINT-NEXT: [[KW]] T1 {
+  // PRINT-NEXT:   int i;
+  // PRINT-NEXT: };
+  KW T1 { int i; };
+  // PRINT-NEXT: [[KW]] T2 {
+  // PRINT-NEXT:   [[KW]] T1 i;
+  // PRINT-NEXT: };
+  KW T2 { KW T1 i; };
+}
+
+// CHECK-LABEL: inInit
+void inInit() {
+  // PRINT-NEXT: [[KW]] T1 {
+  // PRINT-NEXT:   int i;
+  // PRINT-NEXT: };
+  KW T1 { int i; };
+  // PRINT-NEXT: [[KW]] T2 {
+  // PRINT-NEXT:   long i;
+  // PRINT-NEXT: } t2 = {sizeof([[KW]] T1)};
+  KW T2 { long i; } t2 = {sizeof(KW T1)};
+}
+
+#ifdef __cplusplus
+// CXX-LABEL: inMemberPtr
+void inMemberPtr() {
+  // CXX-NEXT: [[KW]] T1 {
+  // CXX-NEXT:   int i;
+  // CXX-NEXT: };
+  KW T1 { int i; };
+  // CXX-NEXT: [[KW]] T2 {
+  // CXX-NEXT: } T1::*p;
+  KW T2 {} T1::*p;
+}
+#endif
Index: test/Misc/ast-print-enum-decl.c
===================================================================
--- /dev/null
+++ test/Misc/ast-print-enum-decl.c
@@ -0,0 +1,85 @@
+// First check compiling and printing of this file.
+//
+// RUN: %clang_cc1 -verify -ast-print %s > %t.c
+// RUN: FileCheck --check-prefixes=CHECK,PRINT %s --input-file %t.c
+//
+// Now check compiling and printing of the printed file.
+//
+// RUN: echo "// expected""-warning@* 6 {{'T' is deprecated}}" >> %t.c
+// RUN: echo "// expected""-note@* 6 {{'T' has been explicitly marked deprecated here}}" >> %t.c
+//
+// RUN: %clang_cc1 -verify -ast-print %t.c \
+// RUN: | FileCheck --check-prefixes=CHECK,PRINT %s
+
+// END.
+
+// CHECK-LABEL: defFirst
+void defFirst() {
+  // PRINT-NEXT: enum
+  // PRINT-DAG:  __attribute__((aligned(16)))
+  // PRINT-DAG:  __attribute__((deprecated("")))
+  // PRINT-SAME: T {
+  // PRINT-NEXT:   E0,
+  // PRINT-NEXT:   E1
+  // PRINT-NEXT: } *p0;
+  // expected-warning@+2 {{'T' is deprecated}}
+  // expected-note@+1 2 {{'T' has been explicitly marked deprecated here}}
+  enum __attribute__((aligned(16))) __attribute__((deprecated(""))) T {
+    E0, E1
+  } *p0;
+
+  // PRINT-NEXT: enum T *p1;
+  enum T *p1; // expected-warning {{'T' is deprecated}}
+}
+
+// CHECK-LABEL: defLast
+void defLast() {
+  // PRINT-NEXT: enum __attribute__((aligned(16))) T *p0;
+  enum __attribute__((aligned(16))) T *p0;
+
+  // PRINT-NEXT: enum __attribute__((deprecated(""))) T {
+  // PRINT-NEXT:   E0,
+  // PRINT-NEXT:   E1
+  // PRINT-NEXT: } *p1;
+  // expected-warning@+2 {{'T' is deprecated}}
+  // expected-note@+1 {{'T' has been explicitly marked deprecated here}}
+  enum __attribute__((deprecated(""))) T { E0, E1 } *p1;
+}
+
+// CHECK-LABEL: defMiddle
+void defMiddle() {
+  // PRINT-NEXT: enum __attribute__((deprecated(""))) T *p0;
+  // expected-warning@+2 {{'T' is deprecated}}
+  // expected-note@+1 3 {{'T' has been explicitly marked deprecated here}}
+  enum __attribute__((deprecated(""))) T *p0;
+
+  // PRINT-NEXT: enum __attribute__((aligned(16))) T {
+  // PRINT-NEXT:   E0
+  // PRINT-NEXT:   E1
+  // PRINT-NEXT: } *p1;
+  enum __attribute__((aligned(16))) T { E0, E1 } *p1; // expected-warning {{'T' is deprecated}}
+
+  // PRINT-NEXT: enum T *p2;
+  enum T *p2; // expected-warning {{'T' is deprecated}}
+}
+
+// CHECK-LABEL: declsOnly
+void declsOnly() {
+  // FIXME: For some reason, attributes are ignored if they're not on the first
+  // declaration and not on the definition.
+
+  // PRINT-NEXT: enum __attribute__((aligned)) T *p0;
+  enum __attribute__((aligned)) T *p0;
+
+  // PRINT-NEXT: enum T *p1;
+  enum __attribute__((may_alias)) T *p1;
+
+  // PRINT-NEXT: enum T *p2;
+  enum T *p2;
+
+  // PRINT-NEXT: enum T *p3;
+  enum __attribute__((deprecated(""))) T *p3;
+
+  // PRINT-NEXT: enum T *p4;
+  enum T *p4;
+}
Index: lib/Serialization/ASTWriter.cpp
===================================================================
--- lib/Serialization/ASTWriter.cpp
+++ lib/Serialization/ASTWriter.cpp
@@ -512,6 +512,7 @@
   Record.push_back(T->getKeyword());
   Record.AddNestedNameSpecifier(T->getQualifier());
   Record.AddTypeRef(T->getNamedType());
+  Record.AddDeclRef(T->getOwnedTagDecl());
   Code = TYPE_ELABORATED;
 }
 
Index: lib/Serialization/ASTReader.cpp
===================================================================
--- lib/Serialization/ASTReader.cpp
+++ lib/Serialization/ASTReader.cpp
@@ -6185,7 +6185,8 @@
     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);
+    TagDecl *OwnedTagDecl = ReadDeclAs<TagDecl>(*Loc.F, Record, Idx);
+    return Context.getElaboratedType(Keyword, NNS, NamedType, OwnedTagDecl);
   }
 
   case TYPE_OBJC_INTERFACE: {
Index: lib/Sema/SemaType.cpp
===================================================================
--- lib/Sema/SemaType.cpp
+++ lib/Sema/SemaType.cpp
@@ -1429,7 +1429,7 @@
   case DeclSpec::TST_union:
   case DeclSpec::TST_struct:
   case DeclSpec::TST_interface: {
-    TypeDecl *D = dyn_cast_or_null<TypeDecl>(DS.getRepAsDecl());
+    TagDecl *D = dyn_cast_or_null<TagDecl>(DS.getRepAsDecl());
     if (!D) {
       // This can happen in C++ with ambiguous lookups.
       Result = Context.IntTy;
@@ -1449,7 +1449,8 @@
     // In both C and C++, make an ElaboratedType.
     ElaboratedTypeKeyword Keyword
       = ElaboratedType::getKeywordForTypeSpec(DS.getTypeSpecType());
-    Result = S.getElaboratedType(Keyword, DS.getTypeSpecScope(), Result);
+    Result = S.getElaboratedType(Keyword, DS.getTypeSpecScope(), Result,
+                                 DS.isTypeSpecOwned() ? D : nullptr);
     break;
   }
   case DeclSpec::TST_typename: {
@@ -7863,10 +7864,13 @@
   return RequireLiteralType(Loc, T, Diagnoser);
 }
 
-/// \brief Retrieve a version of the type 'T' that is elaborated by Keyword
-/// and qualified by the nested-name-specifier contained in SS.
+/// \brief Retrieve a version of the type 'T' that is elaborated by Keyword,
+/// qualified by the nested-name-specifier contained in SS, and that is
+/// (re)declared by OwnedTagDecl, which is nullptr if this is not a
+/// (re)declaration.
 QualType Sema::getElaboratedType(ElaboratedTypeKeyword Keyword,
-                                 const CXXScopeSpec &SS, QualType T) {
+                                 const CXXScopeSpec &SS, QualType T,
+                                 TagDecl *OwnedTagDecl) {
   if (T.isNull())
     return T;
   NestedNameSpecifier *NNS;
@@ -7877,7 +7881,7 @@
       return T;
     NNS = nullptr;
   }
-  return Context.getElaboratedType(Keyword, NNS, T);
+  return Context.getElaboratedType(Keyword, NNS, T, OwnedTagDecl);
 }
 
 QualType Sema::BuildTypeofExprType(Expr *E, SourceLocation Loc) {
Index: lib/AST/TypePrinter.cpp
===================================================================
--- lib/AST/TypePrinter.cpp
+++ lib/AST/TypePrinter.cpp
@@ -1209,6 +1209,17 @@
 
 void TypePrinter::printElaboratedBefore(const ElaboratedType *T,
                                         raw_ostream &OS) {
+  if (Policy.IncludeTagDefinition && T->getOwnedTagDecl()) {
+    TagDecl *OwnedTagDecl = T->getOwnedTagDecl();
+    assert(OwnedTagDecl->getTypeForDecl() == T->getNamedType().getTypePtr() &&
+           "OwnedTagDecl expected to be a declaration for the type");
+    PrintingPolicy SubPolicy = Policy;
+    SubPolicy.IncludeTagDefinition = false;
+    OwnedTagDecl->print(OS, SubPolicy, Indentation);
+    spaceBeforePlaceHolder(OS);
+    return;
+  }
+
   // The tag definition will take care of these.
   if (!Policy.IncludeTagDefinition)
   {
@@ -1226,6 +1237,8 @@
 
 void TypePrinter::printElaboratedAfter(const ElaboratedType *T,
                                         raw_ostream &OS) {
+  if (Policy.IncludeTagDefinition && T->getOwnedTagDecl())
+    return;
   ElaboratedTypePolicyRAII PolicyRAII(Policy);
   printAfter(T->getNamedType(), OS);
 }
Index: lib/AST/DeclPrinter.cpp
===================================================================
--- lib/AST/DeclPrinter.cpp
+++ lib/AST/DeclPrinter.cpp
@@ -215,6 +215,8 @@
   if (D->hasAttrs()) {
     AttrVec &Attrs = D->getAttrs();
     for (auto *A : Attrs) {
+      if (A->isInherited())
+        continue;
       switch (A->getKind()) {
 #define ATTR(X)
 #define PRAGMA_SPELLING_ATTR(X) case attr::X:
Index: lib/AST/ASTImporter.cpp
===================================================================
--- lib/AST/ASTImporter.cpp
+++ lib/AST/ASTImporter.cpp
@@ -908,8 +908,14 @@
   if (ToNamedType.isNull())
     return {};
 
+  TagDecl *OwnedTagDecl =
+      cast_or_null<TagDecl>(Importer.Import(T->getOwnedTagDecl()));
+  if (!OwnedTagDecl && T->getOwnedTagDecl())
+    return {};
+
   return Importer.getToContext().getElaboratedType(T->getKeyword(),
-                                                   ToQualifier, ToNamedType);
+                                                   ToQualifier, ToNamedType,
+                                                   OwnedTagDecl);
 }
 
 QualType ASTNodeImporter::VisitPackExpansionType(const PackExpansionType *T) {
Index: lib/AST/ASTContext.cpp
===================================================================
--- lib/AST/ASTContext.cpp
+++ lib/AST/ASTContext.cpp
@@ -3966,12 +3966,12 @@
   return QualType(Spec, 0);
 }
 
-QualType
-ASTContext::getElaboratedType(ElaboratedTypeKeyword Keyword,
-                              NestedNameSpecifier *NNS,
-                              QualType NamedType) const {
+QualType ASTContext::getElaboratedType(ElaboratedTypeKeyword Keyword,
+                                       NestedNameSpecifier *NNS,
+                                       QualType NamedType,
+                                       TagDecl *OwnedTagDecl) const {
   llvm::FoldingSetNodeID ID;
-  ElaboratedType::Profile(ID, Keyword, NNS, NamedType);
+  ElaboratedType::Profile(ID, Keyword, NNS, NamedType, OwnedTagDecl);
 
   void *InsertPos = nullptr;
   ElaboratedType *T = ElaboratedTypes.FindNodeOrInsertPos(ID, InsertPos);
@@ -3986,7 +3986,8 @@
     (void)CheckT;
   }
 
-  T = new (*this, TypeAlignment) ElaboratedType(Keyword, NNS, NamedType, Canon);
+  T = new (*this, TypeAlignment)
+      ElaboratedType(Keyword, NNS, NamedType, Canon, OwnedTagDecl);
   Types.push_back(T);
   ElaboratedTypes.InsertNode(T, InsertPos);
   return QualType(T, 0);
Index: include/clang/Sema/Sema.h
===================================================================
--- include/clang/Sema/Sema.h
+++ include/clang/Sema/Sema.h
@@ -1636,7 +1636,8 @@
   }
 
   QualType getElaboratedType(ElaboratedTypeKeyword Keyword,
-                             const CXXScopeSpec &SS, QualType T);
+                             const CXXScopeSpec &SS, QualType T,
+                             TagDecl *OwnedTagDecl = nullptr);
 
   QualType BuildTypeofExprType(Expr *E, SourceLocation Loc);
   /// If AsUnevaluated is false, E is treated as though it were an evaluated
Index: include/clang/AST/Type.h
===================================================================
--- include/clang/AST/Type.h
+++ include/clang/AST/Type.h
@@ -56,6 +56,7 @@
 
 class ExtQuals;
 class QualType;
+class TagDecl;
 class Type;
 
 enum {
@@ -4865,14 +4866,18 @@
   /// The type that this qualified name refers to.
   QualType NamedType;
 
+  /// The (re)declaration of this tag type owned by this occurrence, or nullptr
+  /// if none.
+  TagDecl *OwnedTagDecl;
+
   ElaboratedType(ElaboratedTypeKeyword Keyword, NestedNameSpecifier *NNS,
-                 QualType NamedType, QualType CanonType)
+                 QualType NamedType, QualType CanonType, TagDecl *OwnedTagDecl)
     : TypeWithKeyword(Keyword, Elaborated, CanonType,
                       NamedType->isDependentType(),
                       NamedType->isInstantiationDependentType(),
                       NamedType->isVariablyModifiedType(),
                       NamedType->containsUnexpandedParameterPack()),
-      NNS(NNS), NamedType(NamedType) {
+      NNS(NNS), NamedType(NamedType), OwnedTagDecl(OwnedTagDecl) {
     assert(!(Keyword == ETK_None && NNS == nullptr) &&
            "ElaboratedType cannot have elaborated type keyword "
            "and name qualifier both null.");
@@ -4893,15 +4898,29 @@
   /// Returns whether this type directly provides sugar.
   bool isSugared() const { return true; }
 
+  /// Return the (re)declaration of this type owned by this occurrence of this
+  /// type, or nullptr if none.
+  ///
+  /// FIXME: The TagDecl returned is not always exactly faithful to the
+  /// original source because, when building the AST, the parser drops
+  /// attributes declared on a tag type after a declaration of a member list
+  /// for that tag type.  When printing the AST, this change only loses
+  /// warnings about how an attribute cannot be declared after the member
+  /// list has been specified, and such attributes otherwise should have no
+  /// effect.  Thus, fixing this change doesn't seem vital.
+  TagDecl *getOwnedTagDecl() const { return OwnedTagDecl; }
+
   void Profile(llvm::FoldingSetNodeID &ID) {
-    Profile(ID, getKeyword(), NNS, NamedType);
+    Profile(ID, getKeyword(), NNS, NamedType, OwnedTagDecl);
   }
 
   static void Profile(llvm::FoldingSetNodeID &ID, ElaboratedTypeKeyword Keyword,
-                      NestedNameSpecifier *NNS, QualType NamedType) {
+                      NestedNameSpecifier *NNS, QualType NamedType,
+                      TagDecl *OwnedTagDecl) {
     ID.AddInteger(Keyword);
     ID.AddPointer(NNS);
     NamedType.Profile(ID);
+    ID.AddPointer(OwnedTagDecl);
   }
 
   static bool classof(const Type *T) {
Index: include/clang/AST/ASTContext.h
===================================================================
--- include/clang/AST/ASTContext.h
+++ include/clang/AST/ASTContext.h
@@ -1416,8 +1416,8 @@
   QualType getParenType(QualType NamedType) const;
 
   QualType getElaboratedType(ElaboratedTypeKeyword Keyword,
-                             NestedNameSpecifier *NNS,
-                             QualType NamedType) const;
+                             NestedNameSpecifier *NNS, QualType NamedType,
+                             TagDecl *OwnedTagDecl = nullptr) const;
   QualType getDependentNameType(ElaboratedTypeKeyword Keyword,
                                 NestedNameSpecifier *NNS,
                                 const IdentifierInfo *Name,
_______________________________________________
cfe-commits mailing list
cfe-commits@lists.llvm.org
http://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits

Reply via email to