nickdesaulniers created this revision.
nickdesaulniers added reviewers: rsmith, aaron.ballman.
nickdesaulniers requested review of this revision.
Herald added a project: clang.
Herald added a subscriber: cfe-commits.

When declaring an anonymous struct with `const` or `volatile`
qualifiers, ensure the members of that anonymous struct are created with
that qualifier.

GCC behaves this way, and WG14 is currently discussing this behavior.

See also:

- https://bugs.llvm.org/show_bug.cgi?id=48755
- https://gcc.gnu.org/bugzilla/show_bug.cgi?id=98826


Repository:
  rG LLVM Github Monorepo

https://reviews.llvm.org/D95408

Files:
  clang/lib/Sema/SemaDecl.cpp
  clang/test/AST/ast-dump-decl.c
  clang/test/AST/ast-dump-records.c
  clang/test/Sema/struct-decl-anonymous-members.c
  clang/test/Sema/struct-decl.c

Index: clang/test/Sema/struct-decl.c
===================================================================
--- clang/test/Sema/struct-decl.c
+++ 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; };
+};
Index: clang/test/Sema/struct-decl-anonymous-members.c
===================================================================
--- /dev/null
+++ 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}}
+}
Index: clang/test/AST/ast-dump-records.c
===================================================================
--- clang/test/AST/ast-dump-records.c
+++ 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]]:1, line:[[@LINE-1]]:1> line:[[@LINE-8]]:8 struct H definition
+// CHECK-NEXT: RecordDecl 0x{{[^ ]*}} <line:[[@LINE-8]]:9, line:[[@LINE-6]]:3> line:[[@LINE-8]]:9 struct definition
+// CHECK-NEXT: FieldDecl 0x{{[^ ]*}} <line:[[@LINE-8]]:5, col:9> col:9 bar 'int'
+// CHECK-NEXT: FieldDecl 0x{{[^ ]*}} <line:[[@LINE-10]]:3, col:9> col:9 implicit 'const struct H::(anonymous at {{.*}}:[[@LINE-10]]:9)'
+// CHECK-NEXT: IndirectFieldDecl 0x{{[^ ]*}} <line:[[@LINE-10]]:9> 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, line:[[@LINE-9]]:3> line:[[@LINE-11]]:12 struct definition
+// CHECK-NEXT: FieldDecl 0x{{[^ ]*}} <line:[[@LINE-11]]:5, col:9> col:9 baz 'int'
+// CHECK-NEXT: FieldDecl 0x{{[^ ]*}} <line:[[@LINE-13]]:3, col:12> col:12 implicit 'volatile struct H::(anonymous at {{.*}}:[[@LINE-13]]:12)'
+// CHECK-NEXT: IndirectFieldDecl 0x{{[^ ]*}} <line:[[@LINE-13]]:9> col:9 implicit baz 'int'
+// CHECK-NEXT: Field 0x{{[^ ]*}} '' 'volatile struct H::(anonymous at {{.*}}:[[@LINE-15]]:12)'
+// CHECK-NEXT: Field 0x{{[^ ]*}} 'baz' 'int'
Index: clang/test/AST/ast-dump-decl.c
===================================================================
--- clang/test/AST/ast-dump-decl.c
+++ 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;
Index: clang/lib/Sema/SemaDecl.cpp
===================================================================
--- clang/lib/Sema/SemaDecl.cpp
+++ 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<RecordDecl>(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);
 
_______________________________________________
cfe-commits mailing list
cfe-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits

Reply via email to