jdenny updated this revision to Diff 146145.
jdenny edited the summary of this revision.
jdenny added a comment.

I've implemented the suggestion to use ElaboratedType.  See the last paragraph 
of the revised summary for details.

There might be trouble for CXPrintingPolicyProperty users.  That is, this patch 
shifts the semantics of IncludeTagDefinition away from the documented semantics 
and from what the name implies.  Then again, both were already misleading for a 
tag type without a member list (that is, definition).

I see a few possible paths:

1. Update the documentation for IncludeTagDefinition and assume the new 
behavior was the expected behavior all along.

2. #1 and rename IncludeTagDefinition to something like OwnedTagDeclaration.

3. Add OwnedTagDeclaration alongside IncludeTagDefinition.  
CXPrintingPolicyProperty users could set either.  We'd have to decide which 
would have precedence.  Internally, we would change Decl::printGroup to set 
OwnedTagDeclaration instead of IncludeTagDefinition, which otherwise would not 
be used internally.


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/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,251 @@
+// 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]]
+  // PRINT-DAG:  __attribute__((aligned(16)))
+  // PRINT-DAG:  __attribute__((deprecated("")))
+  // PRINT-NOT:  __attribute__
+  // PRINT-SAME: 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]]
+  // PRINT-DAG:  __attribute__((deprecated("")))
+  // PRINT-DAG:  __attribute__((aligned(16)))
+  // PRINT-NOT:  __attribute__
+  // PRINT-SAME: 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]]
+  // PRINT-DAG:  __attribute__((deprecated("")))
+  // PRINT-DAG:  __attribute__((aligned(16)))
+  // PRINT-NOT:  __attribute__
+  // PRINT-SAME: 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]]
+  // PRINT-DAG:  __attribute__((may_alias))
+  // PRINT-DAG:  __attribute__((deprecated("")))
+  // PRINT-NOT:  __attribute__
+  // PRINT-SAME: 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,91 @@
+// 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
+  // PRINT-DAG:  __attribute__((aligned(16)))
+  // PRINT-DAG:  __attribute__((deprecated("")))
+  // PRINT-SAME: 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
+  // PRINT-DAG:  __attribute__((deprecated("")))
+  // PRINT-DAG:  __attribute__((aligned(16)))
+  // PRINT-SAME: 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->getOwnedDecl());
   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);
+    TypeDecl *OwnedDecl = ReadDeclAs<TypeDecl>(*Loc.F, Record, Idx);
+    return Context.getElaboratedType(Keyword, NNS, NamedType, OwnedDecl);
   }
 
   case TYPE_OBJC_INTERFACE: {
Index: lib/Sema/SemaType.cpp
===================================================================
--- lib/Sema/SemaType.cpp
+++ lib/Sema/SemaType.cpp
@@ -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 OwnedDecl, 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,
+                                 TypeDecl *OwnedDecl) {
   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, OwnedDecl);
 }
 
 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->getOwnedDecl()) {
+    TypeDecl *OwnedDecl = T->getOwnedDecl();
+    assert(OwnedDecl->getTypeForDecl() == T->getNamedType().getTypePtr() &&
+           "OwnedDecl expected to be a declaration for the type");
+    PrintingPolicy SubPolicy = Policy;
+    SubPolicy.IncludeTagDefinition = false;
+    OwnedDecl->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->getOwnedDecl())
+    return;
   ElaboratedTypePolicyRAII PolicyRAII(Policy);
   printAfter(T->getNamedType(), OS);
 }
Index: lib/AST/ASTImporter.cpp
===================================================================
--- lib/AST/ASTImporter.cpp
+++ lib/AST/ASTImporter.cpp
@@ -908,8 +908,14 @@
   if (ToNamedType.isNull())
     return {};
 
+  TypeDecl *OwnedDecl =
+      cast_or_null<TypeDecl>(Importer.Import(T->getOwnedDecl()));
+  if (!OwnedDecl && T->getOwnedDecl())
+    return {};
+
   return Importer.getToContext().getElaboratedType(T->getKeyword(),
-                                                   ToQualifier, ToNamedType);
+                                                   ToQualifier, ToNamedType,
+                                                   OwnedDecl);
 }
 
 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,
+                                       TypeDecl *OwnedDecl) const {
   llvm::FoldingSetNodeID ID;
-  ElaboratedType::Profile(ID, Keyword, NNS, NamedType);
+  ElaboratedType::Profile(ID, Keyword, NNS, NamedType, OwnedDecl);
 
   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, OwnedDecl);
   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,
+                             TypeDecl *OwnedDecl = 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
@@ -57,6 +57,7 @@
 class ExtQuals;
 class QualType;
 class Type;
+class TypeDecl;
 
 enum {
   TypeAlignmentInBits = 4,
@@ -4848,9 +4849,10 @@
   static CannotCastToThisType classof(const Type *);
 };
 
-/// \brief Represents a type that was referred to using an elaborated type
-/// keyword, e.g., struct S, or via a qualified name, e.g., N::M::type,
-/// or both.
+/// \brief Represents a type occurrence that either (1) refers to the type
+/// using an elaborated type keyword, e.g., struct S, (2) refers to the type
+/// via a qualified name, e.g., N::M::type, (3) owns a (re)declaration of that
+/// type, or (4) some combination of those.
 ///
 /// This type is used to keep track of a type name as written in the
 /// source code, including tag keywords and any nested-name-specifiers.
@@ -4865,14 +4867,18 @@
   /// The type that this qualified name refers to.
   QualType NamedType;
 
+  /// The (re)declaration of this type owned by this occurrence of this type,
+  /// or nullptr if none.
+  TypeDecl *OwnedDecl;
+
   ElaboratedType(ElaboratedTypeKeyword Keyword, NestedNameSpecifier *NNS,
-                 QualType NamedType, QualType CanonType)
+                 QualType NamedType, QualType CanonType, TypeDecl *OwnedDecl)
     : TypeWithKeyword(Keyword, Elaborated, CanonType,
                       NamedType->isDependentType(),
                       NamedType->isInstantiationDependentType(),
                       NamedType->isVariablyModifiedType(),
                       NamedType->containsUnexpandedParameterPack()),
-      NNS(NNS), NamedType(NamedType) {
+      NNS(NNS), NamedType(NamedType), OwnedDecl(OwnedDecl) {
     assert(!(Keyword == ETK_None && NNS == nullptr) &&
            "ElaboratedType cannot have elaborated type keyword "
            "and name qualifier both null.");
@@ -4893,15 +4899,34 @@
   /// 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: This is set for tag types but not necessarily other types.
+  /// FIXME: The TypeDecl returned is not always exactly faithful to the
+  /// original source because, when building the AST, the parser (1) adds
+  /// all attributes declared on a tag to all later redeclarations of that
+  /// tag (that is, tag occurrences declaring an attribute or member list),
+  /// and (2) drops attributes declared on a tag after an occurrence of that
+  /// tag declaring a member list.  When printing the AST, the first change
+  /// should not affect semantics or diagnostics because it merely reveals
+  /// the accumulated attributes.  The second 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 these changes doesn't seem vital.
+  TypeDecl *getOwnedDecl() const { return OwnedDecl; }
+
   void Profile(llvm::FoldingSetNodeID &ID) {
-    Profile(ID, getKeyword(), NNS, NamedType);
+    Profile(ID, getKeyword(), NNS, NamedType, OwnedDecl);
   }
 
   static void Profile(llvm::FoldingSetNodeID &ID, ElaboratedTypeKeyword Keyword,
-                      NestedNameSpecifier *NNS, QualType NamedType) {
+                      NestedNameSpecifier *NNS, QualType NamedType,
+                      TypeDecl *OwnedDecl) {
     ID.AddInteger(Keyword);
     ID.AddPointer(NNS);
     NamedType.Profile(ID);
+    ID.AddPointer(OwnedDecl);
   }
 
   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,
+                             TypeDecl *OwnedDecl = 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