jdenny updated this revision to Diff 145092.
jdenny removed a reviewer: jbcoe.
jdenny added a comment.

Rebased.  Ping.


https://reviews.llvm.org/D45463

Files:
  include/clang-c/Index.h
  include/clang/AST/PrettyPrinter.h
  lib/AST/DeclPrinter.cpp
  lib/AST/TypePrinter.cpp
  test/Misc/ast-print-enum-decl.c
  test/Misc/ast-print-record-decl.c
  tools/c-index-test/c-index-test.c
  tools/libclang/CIndex.cpp

Index: tools/libclang/CIndex.cpp
===================================================================
--- tools/libclang/CIndex.cpp
+++ tools/libclang/CIndex.cpp
@@ -4743,8 +4743,6 @@
     return P->SuppressSpecifiers;
   case CXPrintingPolicy_SuppressTagKeyword:
     return P->SuppressTagKeyword;
-  case CXPrintingPolicy_IncludeTagDefinition:
-    return P->IncludeTagDefinition;
   case CXPrintingPolicy_SuppressScope:
     return P->SuppressScope;
   case CXPrintingPolicy_SuppressUnwrittenScope:
@@ -4812,9 +4810,6 @@
   case CXPrintingPolicy_SuppressTagKeyword:
     P->SuppressTagKeyword = Value;
     return;
-  case CXPrintingPolicy_IncludeTagDefinition:
-    P->IncludeTagDefinition = Value;
-    return;
   case CXPrintingPolicy_SuppressScope:
     P->SuppressScope = Value;
     return;
Index: tools/c-index-test/c-index-test.c
===================================================================
--- tools/c-index-test/c-index-test.c
+++ tools/c-index-test/c-index-test.c
@@ -97,8 +97,6 @@
        CXPrintingPolicy_SuppressSpecifiers},
       {"CINDEXTEST_PRINTINGPOLICY_SUPPRESSTAGKEYWORD",
        CXPrintingPolicy_SuppressTagKeyword},
-      {"CINDEXTEST_PRINTINGPOLICY_INCLUDETAGDEFINITION",
-       CXPrintingPolicy_IncludeTagDefinition},
       {"CINDEXTEST_PRINTINGPOLICY_SUPPRESSSCOPE",
        CXPrintingPolicy_SuppressScope},
       {"CINDEXTEST_PRINTINGPOLICY_SUPPRESSUNWRITTENSCOPE",
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/AST/TypePrinter.cpp
===================================================================
--- lib/AST/TypePrinter.cpp
+++ lib/AST/TypePrinter.cpp
@@ -454,7 +454,7 @@
     OS << '(';
 
   PrintingPolicy InnerPolicy(Policy);
-  InnerPolicy.IncludeTagDefinition = false;
+  InnerPolicy.TagSpecifierAs = nullptr;
   TypePrinter(InnerPolicy).print(QualType(T->getClass(), 0), OS, StringRef());
 
   OS << "::*";
@@ -1054,10 +1054,12 @@
 }
 
 void TypePrinter::printTag(TagDecl *D, raw_ostream &OS) {
-  if (Policy.IncludeTagDefinition) {
+  if (TagDecl *As = Policy.TagSpecifierAs) {
+    assert(D->getTypeForDecl() == As->getTypeForDecl() &&
+           "tag declarations expected to be for the same type");
     PrintingPolicy SubPolicy = Policy;
-    SubPolicy.IncludeTagDefinition = false;
-    D->print(OS, SubPolicy, Indentation);
+    SubPolicy.TagSpecifierAs = nullptr;
+    As->print(OS, SubPolicy, Indentation);
     spaceBeforePlaceHolder(OS);
     return;
   }
@@ -1210,8 +1212,7 @@
 void TypePrinter::printElaboratedBefore(const ElaboratedType *T,
                                         raw_ostream &OS) {
   // The tag definition will take care of these.
-  if (!Policy.IncludeTagDefinition)
-  {
+  if (!Policy.TagSpecifierAs) {
     OS << TypeWithKeyword::getKeywordName(T->getKeyword());
     if (T->getKeyword() != ETK_None)
       OS << " ";
Index: lib/AST/DeclPrinter.cpp
===================================================================
--- lib/AST/DeclPrinter.cpp
+++ lib/AST/DeclPrinter.cpp
@@ -177,13 +177,13 @@
   bool isFirst = true;
   for ( ; Begin != End; ++Begin) {
     if (isFirst) {
-      if(TD)
-        SubPolicy.IncludeTagDefinition = true;
+      if (TD)
+        SubPolicy.TagSpecifierAs = TD;
       SubPolicy.SuppressSpecifiers = false;
       isFirst = false;
     } else {
       if (!isFirst) Out << ", ";
-      SubPolicy.IncludeTagDefinition = false;
+      SubPolicy.TagSpecifierAs = nullptr;
       SubPolicy.SuppressSpecifiers = true;
     }
 
@@ -845,7 +845,7 @@
       }
       PrintingPolicy SubPolicy(Policy);
       SubPolicy.SuppressSpecifiers = false;
-      SubPolicy.IncludeTagDefinition = false;
+      SubPolicy.TagSpecifierAs = nullptr;
       Init->printPretty(Out, nullptr, SubPolicy, Indentation);
       if ((D->getInitStyle() == VarDecl::CallInit) && !isa<ParenListExpr>(Init))
         Out << ")";
Index: include/clang/AST/PrettyPrinter.h
===================================================================
--- include/clang/AST/PrettyPrinter.h
+++ include/clang/AST/PrettyPrinter.h
@@ -39,8 +39,7 @@
   /// \brief Create a default printing policy for the specified language.
   PrintingPolicy(const LangOptions &LO)
     : Indentation(2), SuppressSpecifiers(false),
-      SuppressTagKeyword(LO.CPlusPlus),
-      IncludeTagDefinition(false), SuppressScope(false),
+      SuppressTagKeyword(LO.CPlusPlus), SuppressScope(false),
       SuppressUnwrittenScope(false), SuppressInitializers(false),
       ConstantArraySizeAsWritten(false), AnonymousTagLocations(true),
       SuppressStrongLifetime(false), SuppressLifetimeQualifiers(false),
@@ -52,7 +51,7 @@
       Half(LO.Half), MSWChar(LO.MicrosoftExt && !LO.WChar),
       IncludeNewlines(true), MSVCFormatting(false),
       ConstantsAsWritten(false), SuppressImplicitBase(false),
-      FullyQualifiedName(false) { }
+      FullyQualifiedName(false), TagSpecifierAs(nullptr) { }
 
   /// Adjust this printing policy for cases where it's known that we're
   /// printing C++ code (for instance, if AST dumping reaches a C++-only
@@ -93,16 +92,6 @@
   /// \endcode
   bool SuppressTagKeyword : 1;
 
-  /// When true, include the body of a tag definition.
-  ///
-  /// This is used to place the definition of a struct
-  /// in the middle of another declaration as with:
-  ///
-  /// \code
-  /// typedef struct { int x, y; } Point;
-  /// \endcode
-  bool IncludeTagDefinition : 1;
-
   /// Suppresses printing of scope specifiers.
   bool SuppressScope : 1;
 
@@ -225,6 +214,31 @@
   /// When true, print the fully qualified name of function declarations.
   /// This is the opposite of SuppressScope and thus overrules it.
   bool FullyQualifiedName : 1;
+
+  /// When not nullptr, print the tag specifier in the immediate specifier list
+  /// using this tag declaration, but do not do so again for nested
+  /// occurrences.
+  ///
+  /// \c TagSpecifierAs is designed specifically to be used by
+  /// \c Decl::printGroup to print tag specifiers as recorded in the AST so
+  /// that the printed source compiles successfully if the original source did.
+  /// \c TagSpecifierAs does not easily fit the \c CXPrintingPolicyProperty
+  /// interface and so currently is not exposed there.
+  ///
+  /// FIXME: The TagSpecifierAs mechanism does not always print source that is
+  /// 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.  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.  Moreover, fixing them
+  /// would require the parser to build the AST with an exact record of which
+  /// attributes are introduced at each tag (re)declaration.
+  TagDecl *TagSpecifierAs;
 };
 
 } // end namespace clang
Index: include/clang-c/Index.h
===================================================================
--- include/clang-c/Index.h
+++ include/clang-c/Index.h
@@ -4113,7 +4113,6 @@
   CXPrintingPolicy_Indentation,
   CXPrintingPolicy_SuppressSpecifiers,
   CXPrintingPolicy_SuppressTagKeyword,
-  CXPrintingPolicy_IncludeTagDefinition,
   CXPrintingPolicy_SuppressScope,
   CXPrintingPolicy_SuppressUnwrittenScope,
   CXPrintingPolicy_SuppressInitializers,
_______________________________________________
cfe-commits mailing list
cfe-commits@lists.llvm.org
http://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits

Reply via email to