diff --git a/clang/lib/Sema/SemaDecl.cpp b/clang/lib/Sema/SemaDecl.cpp --- a/clang/lib/Sema/SemaDecl.cpp +++ b/clang/lib/Sema/SemaDecl.cpp @@ -5176,11 +5176,18 @@ // Create a declaration for this anonymous struct/union. NamedDecl *Anon = nullptr; if (RecordDecl *OwningClass = dyn_cast(Owner)) { - Anon = FieldDecl::Create( - Context, OwningClass, DS.getBeginLoc(), Record->getLocation(), - /*IdentifierInfo=*/nullptr, Context.getTypeDeclType(Record), TInfo, - /*BitWidth=*/nullptr, /*Mutable=*/false, - /*InitStyle=*/ICIS_NoInit); + QualType QT = Context.getTypeDeclType(Record); + if (!getLangOpts().CPlusPlus) { + if (DS.getTypeQualifiers() & DeclSpec::TQ_const) + QT.addConst(); + if (DS.getTypeQualifiers() & DeclSpec::TQ_volatile) + QT.addVolatile(); + } + Anon = FieldDecl::Create(Context, OwningClass, DS.getBeginLoc(), + Record->getLocation(), + /*IdentifierInfo=*/nullptr, QT, TInfo, + /*BitWidth=*/nullptr, /*Mutable=*/false, + /*InitStyle=*/ICIS_NoInit); Anon->setAccess(AS); ProcessDeclAttributes(S, Anon, Dc); diff --git a/clang/test/AST/ast-dump-decl.c b/clang/test/AST/ast-dump-decl.c --- a/clang/test/AST/ast-dump-decl.c +++ b/clang/test/AST/ast-dump-decl.c @@ -118,11 +118,24 @@ struct { int TestIndirectFieldDecl; }; + const struct { + int Test48755Const; + }; + volatile struct { + int Test48755Volatile; + }; }; // CHECK: IndirectFieldDecl{{.*}} TestIndirectFieldDecl 'int' // CHECK-NEXT: Field{{.*}} '' // CHECK-NEXT: Field{{.*}} 'TestIndirectFieldDecl' +// CHECK: IndirectFieldDecl{{.*}} Test48755Const 'int' +// CHECK-NEXT: Field{{.*}} 'const struct testIndirectFieldDecl::{{.*}}' + +// CHECK: IndirectFieldDecl{{.*}} Test48755Volatile 'int' +// CHECK-NEXT: Field{{.*}} 'volatile struct testIndirectFieldDecl::{{.*}}' + + // FIXME: It would be nice to dump the enum and its enumerators. int TestFunctionDecl(int x, enum { e } y) { return x; diff --git a/clang/test/AST/ast-dump-records.c b/clang/test/AST/ast-dump-records.c --- a/clang/test/AST/ast-dump-records.c +++ b/clang/test/AST/ast-dump-records.c @@ -156,3 +156,24 @@ // CHECK-NEXT: Field 0x{{[^ ]*}} 'f' 'int' }; +struct H { + const struct { + int bar; + }; + volatile struct { + int baz; + }; +}; +// CHECK: RecordDecl 0x{{[^ ]*}} line:[[@LINE-8]]:8 struct H definition +// CHECK-NEXT: RecordDecl 0x{{[^ ]*}} line:[[@LINE-8]]:9 struct definition +// CHECK-NEXT: FieldDecl 0x{{[^ ]*}} col:9 bar 'int' +// CHECK-NEXT: FieldDecl 0x{{[^ ]*}} col:9 implicit 'const struct H::(anonymous at {{.*}}:[[@LINE-10]]:9)' +// CHECK-NEXT: IndirectFieldDecl 0x{{[^ ]*}} col:9 implicit bar 'int' +// CHECK-NEXT: Field 0x{{[^ ]*}} '' 'const struct H::(anonymous at {{.*}}:[[@LINE-12]]:9)' +// CHECK-NEXT: Field 0x{{[^ ]*}} 'bar' 'int' +// CHECK-NEXT: RecordDecl 0x{{[^ ]*}} line:[[@LINE-11]]:12 struct definition +// CHECK-NEXT: FieldDecl 0x{{[^ ]*}} col:9 baz 'int' +// CHECK-NEXT: FieldDecl 0x{{[^ ]*}} col:12 implicit 'volatile struct H::(anonymous at {{.*}}:[[@LINE-13]]:12)' +// CHECK-NEXT: IndirectFieldDecl 0x{{[^ ]*}} col:9 implicit baz 'int' +// CHECK-NEXT: Field 0x{{[^ ]*}} '' 'volatile struct H::(anonymous at {{.*}}:[[@LINE-15]]:12)' +// CHECK-NEXT: Field 0x{{[^ ]*}} 'baz' 'int' diff --git a/clang/test/Sema/struct-decl-anonymous-members.c b/clang/test/Sema/struct-decl-anonymous-members.c new file mode 100644 --- /dev/null +++ b/clang/test/Sema/struct-decl-anonymous-members.c @@ -0,0 +1,18 @@ +// RUN: %clang_cc1 %s -fsyntax-only -verify +struct dummy { + const struct { // expected-note {{non-static data member '' declared const here}} + int a; + // 'b' here should be 'const volatile' qualified. + volatile struct { int b; }; + }; + int c; +}; + +extern void fn(const int *); // expected-note {{passing argument to parameter here}} +extern void fn2(volatile int *); // expected-note {{passing argument to parameter here}} + +void test(struct dummy *a) { + fn(&a->b); // expected-warning {{passing 'const volatile int *' to parameter of type 'const int *' discards qualifiers}} + fn2(&a->b); // expected-warning {{passing 'const volatile int *' to parameter of type 'volatile int *' discards qualifiers}} + a->a = a->c; // expected-error {{cannot assign to non-static data member '' with const-qualified type}} +} diff --git a/clang/test/Sema/struct-decl.c b/clang/test/Sema/struct-decl.c --- a/clang/test/Sema/struct-decl.c +++ b/clang/test/Sema/struct-decl.c @@ -110,3 +110,8 @@ struct FlexibleArrayMem a; // expected-warning {{field 'a' with variable sized type 'struct FlexibleArrayMem' not at the end of a struct or class is a GNU extension}} struct {}; }; + +struct QualifiedAnonymousMembers { + const struct { int foo; }; + volatile struct { int bar; }; +};