Ignore const/volatile/restrict qualifiers on anonymous structs and
unions. Fixes PR8326.


git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@131109 91177308-0d34-0410-b5e6-96231b3b80d8
diff --git a/include/clang/Basic/DiagnosticSemaKinds.td b/include/clang/Basic/DiagnosticSemaKinds.td
index 6d90ba1..1e54686 100644
--- a/include/clang/Basic/DiagnosticSemaKinds.td
+++ b/include/clang/Basic/DiagnosticSemaKinds.td
@@ -758,7 +758,9 @@
   "static data member %0 not allowed in %select{anonymous struct|union}1">; 
 def err_union_member_of_reference_type : Error<
   "union member %0 has reference type %1">;
-
+def ext_anonymous_struct_union_qualified : Extension<
+  "anonymous %select{struct|union}0 cannot be '%select{const|volatile|"
+  "restrict}1'">;
 def err_different_return_type_for_overriding_virtual_function : Error<
   "virtual function %0 has a different return type (%1) than the "
   "function it overrides (which has return type %2)">;
diff --git a/include/clang/Sema/DeclSpec.h b/include/clang/Sema/DeclSpec.h
index 8179b63..da40f14 100644
--- a/include/clang/Sema/DeclSpec.h
+++ b/include/clang/Sema/DeclSpec.h
@@ -462,6 +462,14 @@
   SourceLocation getRestrictSpecLoc() const { return TQ_restrictLoc; }
   SourceLocation getVolatileSpecLoc() const { return TQ_volatileLoc; }
 
+  /// \brief Clear out all of the type qualifiers.
+  void ClearTypeQualifiers() {
+    TypeQualifiers = 0;
+    TQ_constLoc = SourceLocation();
+    TQ_restrictLoc = SourceLocation();
+    TQ_volatileLoc = SourceLocation();
+  }
+
   // function-specifier
   bool isInlineSpecified() const { return FS_inline_specified; }
   SourceLocation getInlineSpecLoc() const { return FS_inlineLoc; }
diff --git a/lib/Sema/SemaDecl.cpp b/lib/Sema/SemaDecl.cpp
index cd6dc92..15f1681 100644
--- a/lib/Sema/SemaDecl.cpp
+++ b/lib/Sema/SemaDecl.cpp
@@ -2489,6 +2489,24 @@
                              PrevSpec, DiagID, getLangOptions());
     }
 
+    // Ignore const/volatile/restrict qualifiers.
+    if (DS.getTypeQualifiers()) {
+      if (DS.getTypeQualifiers() & DeclSpec::TQ_const)
+        Diag(DS.getConstSpecLoc(), diag::ext_anonymous_struct_union_qualified)
+          << Record->isUnion() << 0 
+          << FixItHint::CreateRemoval(DS.getConstSpecLoc());
+      if (DS.getTypeQualifiers() & DeclSpec::TQ_volatile)
+        Diag(DS.getVolatileSpecLoc(), diag::ext_anonymous_struct_union_qualified)
+          << Record->isUnion() << 1
+          << FixItHint::CreateRemoval(DS.getVolatileSpecLoc());
+      if (DS.getTypeQualifiers() & DeclSpec::TQ_restrict)
+        Diag(DS.getRestrictSpecLoc(), diag::ext_anonymous_struct_union_qualified)
+          << Record->isUnion() << 2 
+          << FixItHint::CreateRemoval(DS.getRestrictSpecLoc());
+
+      DS.ClearTypeQualifiers();
+    }
+
     // C++ [class.union]p2:
     //   The member-specification of an anonymous union shall only
     //   define non-static data members. [Note: nested types and
diff --git a/test/SemaCXX/anonymous-union.cpp b/test/SemaCXX/anonymous-union.cpp
index 553ae65..2dd7ab8 100644
--- a/test/SemaCXX/anonymous-union.cpp
+++ b/test/SemaCXX/anonymous-union.cpp
@@ -1,4 +1,4 @@
-// RUN: %clang_cc1 -fsyntax-only -verify %s
+// RUN: %clang_cc1 -fsyntax-only -verify -pedantic %s
 struct X {
   union {
     float f3;
@@ -17,7 +17,7 @@
 
   void test_unqual_references();
 
-  struct {
+  struct { // expected-warning{{anonymous structs are a GNU extension}}
     int a;
     float b;
   };
@@ -125,7 +125,7 @@
 // <rdar://problem/7987650>
 namespace test4 {
   class A {
-    struct {
+    struct { // expected-warning{{anonymous structs are a GNU extension}}
       int s0; // expected-note {{declared private here}}
       double s1; // expected-note {{declared private here}}
       union {
@@ -136,7 +136,7 @@
     union {
       int u0; // expected-note {{declared private here}}
       double u1; // expected-note {{declared private here}}
-      struct {
+      struct { // expected-warning{{anonymous structs are a GNU extension}}
         int us0; // expected-note {{declared private here}}
         double us1; // expected-note {{declared private here}}
       };
@@ -175,3 +175,25 @@
         };
     }
 }
+
+namespace PR8326 {
+  template <class T>
+  class Foo {
+  public:
+    Foo()
+      : x(0)
+      , y(1){
+    }
+  
+  private:
+    const union { // expected-warning{{anonymous union cannot be 'const'}}
+      struct { // expected-warning{{anonymous structs are a GNU extension}}
+        T x;
+        T y;
+      };
+      T v[2];
+    };
+  };
+
+  Foo<int> baz;
+}