!isa<ClassTemplateSpecializationDecl>(DC))
continue;
- // The next bits of code handles stuff like "struct {int x;} a,b"; we're
+ // The next bits of code handle stuff like "struct {int x;} a,b"; we're
// forced to merge the declarations because there's no other way to
- // refer to the struct in question. This limited merging is safe without
- // a bunch of other checks because it only merges declarations directly
- // referring to the tag, not typedefs.
+ // refer to the struct in question. When that struct is named instead, we
+ // also need to merge to avoid splitting off a stand-alone struct
+ // declaration that produces the warning ext_no_declarators in some
+ // contexts.
+ //
+ // This limited merging is safe without a bunch of other checks because it
+ // only merges declarations directly referring to the tag, not typedefs.
//
// Check whether the current declaration should be grouped with a previous
- // unnamed struct.
+ // non-free-standing tag declaration.
QualType CurDeclType = getDeclType(*D);
if (!Decls.empty() && !CurDeclType.isNull()) {
QualType BaseType = GetBaseType(CurDeclType);
- if (!BaseType.isNull() && isa<ElaboratedType>(BaseType))
- BaseType = cast<ElaboratedType>(BaseType)->getNamedType();
- if (!BaseType.isNull() && isa<TagType>(BaseType) &&
- cast<TagType>(BaseType)->getDecl() == Decls[0]) {
+ if (!BaseType.isNull() && isa<ElaboratedType>(BaseType) &&
+ cast<ElaboratedType>(BaseType)->getOwnedTagDecl() == Decls[0]) {
Decls.push_back(*D);
continue;
}
if (!Decls.empty())
ProcessDeclGroup(Decls);
- // If the current declaration is an unnamed tag type, save it
+ // If the current declaration is not a free standing declaration, save it
// so we can merge it with the subsequent declaration(s) using it.
- if (isa<TagDecl>(*D) && !cast<TagDecl>(*D)->getIdentifier()) {
+ if (isa<TagDecl>(*D) && !cast<TagDecl>(*D)->isFreeStanding()) {
Decls.push_back(*D);
continue;
}
// 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
+// RUN: FileCheck --check-prefixes=CHECK,PRINT,PRINT-C -DKW=struct -DBASES= \
+// RUN: %s --input-file %t.c
//
// Now check compiling and printing of the printed file.
//
// 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
+// RUN: | FileCheck --check-prefixes=CHECK,PRINT,PRINT-C -DKW=struct \
+// RUN: -DBASES= %s
// Repeat for union:
//
// 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
+// RUN: FileCheck --check-prefixes=CHECK,PRINT,PRINT-C -DKW=union -DBASES= \
+// RUN: %s --input-file %t.c
//
// Now check compiling and printing of the printed file.
//
// 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
+// RUN: | FileCheck --check-prefixes=CHECK,PRINT,PRINT-C -DKW=union \
+// RUN: -DBASES= %s
// Repeat for C++ (BASES helps ensure we're printing as C++ not as C):
//
//
// 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: FileCheck --check-prefixes=CHECK,PRINT,PRINT-CXX -DKW=struct \
// RUN: -DBASES=' : B' %s --input-file %t.cpp
//
// Now check compiling and printing of the printed file.
// 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: | FileCheck --check-prefixes=CHECK,PRINT,PRINT-CXX -DKW=struct \
// RUN: -DBASES=' : B' %s
// END.
// 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}}
+ // PRINT-NEXT: [[KW]] __attribute__((aligned(64))) T[[BASES]] {
+ // PRINT-NEXT: int i;
+ // PRINT-NEXT: [[KW]] T *p2;
+ // PRINT-NEXT: [[KW]] __attribute__((may_alias)) T *p3;
+ // PRINT-NEXT: [[KW]] T *p4;
+ // PRINT-NEXT: } *p1;
+ KW __attribute__((aligned(64))) T BASES { // expected-warning {{'T' is deprecated}}
int i;
KW T *p2;
+ // FIXME: For C++, T at p3 loses aligned and deprecated, perhaps because
+ // that RecordDecl isn't in the same redecl list. Perhaps the redecl lists
+ // are split here but not in C due to the different scoping rules in C++
+ // classes.
+ KW __attribute__((may_alias)) T *p3;
+ KW T *p4;
} *p1;
- // LLVM: store i64 16
+ // LLVM: store i64 64
long s0 = sizeof *p0;
- // LLVM-NEXT: store i64 16
+ // LLVM-NEXT: store i64 64
long s1 = sizeof *p1;
- // LLVM-NEXT: store i64 16
+ // LLVM-NEXT: store i64 64
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;
+ // LLVM-NEXT: store i64 64
+ long s3 = sizeof *p1->p3;
+ // LLVM-NEXT: store i64 64
+ long s4 = sizeof *p1->p4->p2;
}
// CHECK-LABEL: declsOnly
}
#ifdef __cplusplus
-// CXX-LABEL: inMemberPtr
+// PRINT-CXX-LABEL: inMemberPtr
void inMemberPtr() {
- // CXX-NEXT: [[KW]] T1 {
- // CXX-NEXT: int i;
- // CXX-NEXT: };
+ // PRINT-CXX-NEXT: [[KW]] T1 {
+ // PRINT-CXX-NEXT: int i;
+ // PRINT-CXX-NEXT: };
KW T1 { int i; };
- // CXX-NEXT: [[KW]] T2 {
- // CXX-NEXT: } T1::*p;
+ // PRINT-CXX-NEXT: [[KW]] T2 {
+ // PRINT-CXX-NEXT: } T1::*p;
KW T2 {} T1::*p;
}
#endif
+
+// Check that tag decl groups stay together in decl contexts.
+
+// PRINT-LABEL: DeclGroupAtFileScope {
+// PRINT-NEXT: int i;
+// PRINT-NEXT: } *DeclGroupAtFileScopePtr;
+KW DeclGroupAtFileScope { int i; } *DeclGroupAtFileScopePtr;
+
+// PRINT-LABEL: DeclGroupInMemberList {
+KW DeclGroupInMemberList {
+ // PRINT-NEXT: struct T1 {
+ // PRINT-NEXT: int i;
+ // PRINT-NEXT: } t1;
+ struct T1 { int i; } t1;
+ // PRINT-NEXT: union T2 {
+ // PRINT-NEXT: int i;
+ // PRINT-NEXT: } *t20, t21[2];
+ union T2 { int i; } *t20, t21[2];
+ // PRINT-NEXT: enum T3 {
+ // PRINT-NEXT: T30
+ // PRINT-NEXT: } t30;
+ enum T3 { T30 } t30;
+ // PRINT-NEXT: };
+};
+
+// A tag decl group in the tag decl's own member list is exercised in
+// defSelfRef above.