r332281 - [AST] Print correct tag decl for tag specifier

Joel E. Denny via cfe-commits cfe-commits at lists.llvm.org
Mon May 14 12:36:45 PDT 2018


Author: jdenny
Date: Mon May 14 12:36:45 2018
New Revision: 332281

URL: http://llvm.org/viewvc/llvm-project?rev=332281&view=rev
Log:
[AST] Print correct tag decl for tag specifier

For example, given:

  void fn() {
    struct T *p0;
    struct T { int i; } *p1;
  }

-ast-print produced:

  void fn() {
    struct T { int i; } *p0;
    struct T { int i; } *p1;
  }

Compiling that fails with a redefinition error.

Given:

  void fn() {
    struct T *p0;
    struct __attribute__((deprecated)) T *p1;
  }

-ast-print dropped the attribute.

Details:

For a tag specifier (that is, struct/union/class/enum used as a type
specifier in a declaration) that was also a tag declaration (that is,
first occurrence of the tag) or tag redeclaration (that is, later
occurrence that specifies attributes or a member list), clang printed
the tag specifier as either (1) the full tag definition if one
existed, or (2) the first tag declaration otherwise.  Redefinition
errors were sometimes introduced, as in the first example above.  Even
when that was impossible because no member list was ever specified,
attributes were sometimes lost, thus changing semantics and
diagnostics, as in the second example above.

This patch fixes a major culprit for these problems.  It does so by
creating an ElaboratedType with a new OwnedDecl member wherever an
occurrence of a tag type is a (re)declaration of that tag type.
PrintingPolicy's IncludeTagDefinition used to trigger printing of the
member list, attributes, etc. for a tag specifier by using a tag
(re)declaration selected as described above.  Now, it triggers the
same thing except it uses the tag (re)declaration stored in the
OwnedDecl.  Of course, other tooling can now make use of the new
OwnedDecl as well.

Also, to be more faithful to the original source, this patch
suppresses printing of attributes inherited from previous
declarations.

Reviewed by: rsmith, aaron.ballman

Differential Revision: https://reviews.llvm.org/D45463

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

Modified: cfe/trunk/include/clang/AST/ASTContext.h
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/AST/ASTContext.h?rev=332281&r1=332280&r2=332281&view=diff
==============================================================================
--- cfe/trunk/include/clang/AST/ASTContext.h (original)
+++ cfe/trunk/include/clang/AST/ASTContext.h Mon May 14 12:36:45 2018
@@ -1419,8 +1419,8 @@ public:
   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,

Modified: cfe/trunk/include/clang/AST/Type.h
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/AST/Type.h?rev=332281&r1=332280&r2=332281&view=diff
==============================================================================
--- cfe/trunk/include/clang/AST/Type.h (original)
+++ cfe/trunk/include/clang/AST/Type.h Mon May 14 12:36:45 2018
@@ -56,6 +56,7 @@ namespace clang {
 
 class ExtQuals;
 class QualType;
+class TagDecl;
 class Type;
 
 enum {
@@ -4865,14 +4866,18 @@ class ElaboratedType : public TypeWithKe
   /// 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,21 @@ public:
   /// 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.
+  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) {

Modified: cfe/trunk/include/clang/Sema/Sema.h
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/Sema/Sema.h?rev=332281&r1=332280&r2=332281&view=diff
==============================================================================
--- cfe/trunk/include/clang/Sema/Sema.h (original)
+++ cfe/trunk/include/clang/Sema/Sema.h Mon May 14 12:36:45 2018
@@ -1638,7 +1638,8 @@ public:
   }
 
   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

Modified: cfe/trunk/lib/AST/ASTContext.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/AST/ASTContext.cpp?rev=332281&r1=332280&r2=332281&view=diff
==============================================================================
--- cfe/trunk/lib/AST/ASTContext.cpp (original)
+++ cfe/trunk/lib/AST/ASTContext.cpp Mon May 14 12:36:45 2018
@@ -3979,12 +3979,12 @@ QualType ASTContext::getCanonicalTemplat
   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);
@@ -3999,7 +3999,8 @@ ASTContext::getElaboratedType(Elaborated
     (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);

Modified: cfe/trunk/lib/AST/ASTImporter.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/AST/ASTImporter.cpp?rev=332281&r1=332280&r2=332281&view=diff
==============================================================================
--- cfe/trunk/lib/AST/ASTImporter.cpp (original)
+++ cfe/trunk/lib/AST/ASTImporter.cpp Mon May 14 12:36:45 2018
@@ -908,8 +908,14 @@ QualType ASTNodeImporter::VisitElaborate
   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) {

Modified: cfe/trunk/lib/AST/DeclPrinter.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/AST/DeclPrinter.cpp?rev=332281&r1=332280&r2=332281&view=diff
==============================================================================
--- cfe/trunk/lib/AST/DeclPrinter.cpp (original)
+++ cfe/trunk/lib/AST/DeclPrinter.cpp Mon May 14 12:36:45 2018
@@ -215,6 +215,8 @@ void DeclPrinter::prettyPrintAttributes(
   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:

Modified: cfe/trunk/lib/AST/TypePrinter.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/AST/TypePrinter.cpp?rev=332281&r1=332280&r2=332281&view=diff
==============================================================================
--- cfe/trunk/lib/AST/TypePrinter.cpp (original)
+++ cfe/trunk/lib/AST/TypePrinter.cpp Mon May 14 12:36:45 2018
@@ -1209,6 +1209,17 @@ void TypePrinter::printInjectedClassName
 
 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::printElaboratedBefore(
 
 void TypePrinter::printElaboratedAfter(const ElaboratedType *T,
                                         raw_ostream &OS) {
+  if (Policy.IncludeTagDefinition && T->getOwnedTagDecl())
+    return;
   ElaboratedTypePolicyRAII PolicyRAII(Policy);
   printAfter(T->getNamedType(), OS);
 }

Modified: cfe/trunk/lib/Sema/SemaType.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Sema/SemaType.cpp?rev=332281&r1=332280&r2=332281&view=diff
==============================================================================
--- cfe/trunk/lib/Sema/SemaType.cpp (original)
+++ cfe/trunk/lib/Sema/SemaType.cpp Mon May 14 12:36:45 2018
@@ -1429,7 +1429,7 @@ static QualType ConvertDeclSpecToType(Ty
   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 @@ static QualType ConvertDeclSpecToType(Ty
     // 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,12 @@ bool Sema::RequireLiteralType(SourceLoca
   return RequireLiteralType(Loc, T, Diagnoser);
 }
 
-/// Retrieve a version of the type 'T' that is elaborated by Keyword
-/// and qualified by the nested-name-specifier contained in SS.
+/// 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 +7880,7 @@ QualType Sema::getElaboratedType(Elabora
       return T;
     NNS = nullptr;
   }
-  return Context.getElaboratedType(Keyword, NNS, T);
+  return Context.getElaboratedType(Keyword, NNS, T, OwnedTagDecl);
 }
 
 QualType Sema::BuildTypeofExprType(Expr *E, SourceLocation Loc) {

Modified: cfe/trunk/lib/Serialization/ASTReader.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Serialization/ASTReader.cpp?rev=332281&r1=332280&r2=332281&view=diff
==============================================================================
--- cfe/trunk/lib/Serialization/ASTReader.cpp (original)
+++ cfe/trunk/lib/Serialization/ASTReader.cpp Mon May 14 12:36:45 2018
@@ -6185,7 +6185,8 @@ QualType ASTReader::readTypeRecord(unsig
     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: {

Modified: cfe/trunk/lib/Serialization/ASTWriter.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Serialization/ASTWriter.cpp?rev=332281&r1=332280&r2=332281&view=diff
==============================================================================
--- cfe/trunk/lib/Serialization/ASTWriter.cpp (original)
+++ cfe/trunk/lib/Serialization/ASTWriter.cpp Mon May 14 12:36:45 2018
@@ -512,6 +512,7 @@ void ASTTypeWriter::VisitElaboratedType(
   Record.push_back(T->getKeyword());
   Record.AddNestedNameSpecifier(T->getQualifier());
   Record.AddTypeRef(T->getNamedType());
+  Record.AddDeclRef(T->getOwnedTagDecl());
   Code = TYPE_ELABORATED;
 }
 

Added: cfe/trunk/test/Misc/ast-print-enum-decl.c
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/Misc/ast-print-enum-decl.c?rev=332281&view=auto
==============================================================================
--- cfe/trunk/test/Misc/ast-print-enum-decl.c (added)
+++ cfe/trunk/test/Misc/ast-print-enum-decl.c Mon May 14 12:36:45 2018
@@ -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 at +2 {{'T' is deprecated}}
+  // expected-note at +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 at +2 {{'T' is deprecated}}
+  // expected-note at +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 at +2 {{'T' is deprecated}}
+  // expected-note at +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;
+}

Added: cfe/trunk/test/Misc/ast-print-record-decl.c
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/Misc/ast-print-record-decl.c?rev=332281&view=auto
==============================================================================
--- cfe/trunk/test/Misc/ast-print-record-decl.c (added)
+++ cfe/trunk/test/Misc/ast-print-record-decl.c Mon May 14 12:36:45 2018
@@ -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 at +2 {{'T' is deprecated}}
+  // expected-note at +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 at +2 {{'T' is deprecated}}
+  // expected-note at +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 at +2 {{'T' is deprecated}}
+  // expected-note at +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 at +2 {{'T' is deprecated}}
+  // expected-note at +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 at +2 {{'T' is deprecated}}
+  // expected-note at +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




More information about the cfe-commits mailing list