[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
llvm-svn: 332281
2018-05-15 03:36:45 +08:00
|
|
|
// 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;
|
|
|
|
}
|
2018-05-15 08:44:14 +08:00
|
|
|
|
|
|
|
// Check that tag decl groups stay together in decl contexts.
|
|
|
|
|
|
|
|
// PRINT-LABEL: enum DeclGroupAtFileScope {
|
|
|
|
// PRINT-NEXT: DeclGroupAtFileScope0
|
|
|
|
// PRINT-NEXT: } *DeclGroupAtFileScopePtr;
|
|
|
|
enum DeclGroupAtFileScope { DeclGroupAtFileScope0 } *DeclGroupAtFileScopePtr;
|
|
|
|
|
|
|
|
// PRINT-LABEL: struct DeclGroupInMemberList
|
|
|
|
struct DeclGroupInMemberList {
|
|
|
|
// PRINT-NEXT: enum T1 {
|
|
|
|
// PRINT-NEXT: T10
|
|
|
|
// PRINT-NEXT: } *p0;
|
|
|
|
enum T1 { T10 } *p0;
|
|
|
|
// PRINT-NEXT: enum T2 {
|
|
|
|
// PRINT-NEXT: T20
|
|
|
|
// PRINT-NEXT: } *p1, *p2;
|
|
|
|
enum T2 { T20 } *p1, *p2;
|
|
|
|
// PRINT-NEXT: };
|
|
|
|
};
|
2020-05-06 02:01:04 +08:00
|
|
|
|
|
|
|
enum fixedEnum : int { fixedEnumerator };
|
|
|
|
// PRINT-LABEL: enum fixedEnum : int {
|
|
|
|
// PRINT-NEXT: fixedEnumerator
|
|
|
|
// PRINT-NEXT: };
|