Add fixit hints for misplaced C++11 attributes around class specifiers.

Following r168626, in class declaration or definition, there are a combination of syntactic locations 
where C++11 attributes could appear, and among those the only valid location permitted by standard is
between class-key and class-name. So for those attributes appear at wrong locations, fixit is used to 
move them to expected location and we recover by applying them to the class specifier.
 


git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@171757 91177308-0d34-0410-b5e6-96231b3b80d8
diff --git a/include/clang/Parse/Parser.h b/include/clang/Parse/Parser.h
index e66ae85..1781649 100644
--- a/include/clang/Parse/Parser.h
+++ b/include/clang/Parse/Parser.h
@@ -2060,7 +2060,10 @@
                            AccessSpecifier AS, bool EnteringContext,
                            DeclSpecContext DSC, 
                            ParsedAttributesWithRange &Attributes);
-  void ParseCXXMemberSpecification(SourceLocation StartLoc, unsigned TagType,
+  void ParseCXXMemberSpecification(SourceLocation StartLoc,
+                                   SourceLocation AttrFixitLoc,
+                                   ParsedAttributes &Attrs,
+                                   unsigned TagType,
                                    Decl *TagDecl);
   ExprResult ParseCXXMemberInitializer(Decl *D, bool IsFunction,
                                        SourceLocation &EqualLoc);
diff --git a/lib/Parse/ParseDeclCXX.cpp b/lib/Parse/ParseDeclCXX.cpp
index 5fa8240..2638983 100644
--- a/lib/Parse/ParseDeclCXX.cpp
+++ b/lib/Parse/ParseDeclCXX.cpp
@@ -1106,6 +1106,10 @@
   // styles of attributes?
   MaybeParseCXX11Attributes(attrs);
 
+  // Source location used by FIXIT to insert misplaced
+  // C++11 attributes
+  SourceLocation AttrFixitLoc = Tok.getLocation();
+
   if (TagType == DeclSpec::TST_struct &&
       !Tok.is(tok::identifier) &&
       Tok.getIdentifierInfo() &&
@@ -1322,9 +1326,25 @@
 
   // Forbid misplaced attributes. In cases of a reference, we pass attributes
   // to caller to handle.
-  // FIXME: provide fix-it hints if we can.
-  if (TUK != Sema::TUK_Reference)
-    ProhibitAttributes(Attributes);
+  if (TUK != Sema::TUK_Reference) {
+    // If this is not a reference, then the only possible
+    // valid place for C++11 attributes to appear here
+    // is between class-key and class-name. If there are
+    // any attributes after class-name, we try a fixit to move
+    // them to the right place.
+    SourceRange AttrRange = Attributes.Range;
+    if (AttrRange.isValid()) {
+      Diag(AttrRange.getBegin(), diag::err_attributes_not_allowed)
+        << AttrRange
+        << FixItHint::CreateInsertionFromRange(AttrFixitLoc,
+                                               CharSourceRange(AttrRange, true))
+        << FixItHint::CreateRemoval(AttrRange);
+
+      // Recover by adding misplaced attributes to the attribute list
+      // of the class so they can be applied on the class later.
+      attrs.takeAllFrom(Attributes);
+    }
+  }
 
   // If this is an elaborated type specifier, and we delayed
   // diagnostics before, just merge them into the current pool.
@@ -1508,7 +1528,8 @@
            (getLangOpts().CPlusPlus && Tok.is(tok::colon)) ||
            isCXX11FinalKeyword());
     if (getLangOpts().CPlusPlus)
-      ParseCXXMemberSpecification(StartLoc, TagType, TagOrTempResult.get());
+      ParseCXXMemberSpecification(StartLoc, AttrFixitLoc, attrs, TagType,
+                                  TagOrTempResult.get());
     else
       ParseStructUnionBody(StartLoc, TagType, TagOrTempResult.get());
   }
@@ -2346,6 +2367,8 @@
 ///         access-specifier ':' member-specification[opt]
 ///
 void Parser::ParseCXXMemberSpecification(SourceLocation RecordLoc,
+                                         SourceLocation AttrFixitLoc,
+                                         ParsedAttributes &Attrs,
                                          unsigned TagType, Decl *TagDecl) {
   assert((TagType == DeclSpec::TST_struct ||
          TagType == DeclSpec::TST_interface ||
@@ -2414,10 +2437,24 @@
            diag::ext_override_control_keyword) << "final";
     }
 
-    // Forbid C++11 attributes that appear here.
-    ParsedAttributesWithRange Attrs(AttrFactory);
-    MaybeParseCXX11Attributes(Attrs);
-    ProhibitAttributes(Attrs);
+    // Parse any C++11 attributes after 'final' keyword.
+    // These attributes are not allowed to appear here,
+    // and the only possible place for them to appertain
+    // to the class would be between class-key and class-name.
+    ParsedAttributesWithRange Attributes(AttrFactory);
+    MaybeParseCXX11Attributes(Attributes);
+    SourceRange AttrRange = Attributes.Range;
+    if (AttrRange.isValid()) {
+      Diag(AttrRange.getBegin(), diag::err_attributes_not_allowed)
+        << AttrRange
+        << FixItHint::CreateInsertionFromRange(AttrFixitLoc,
+                                               CharSourceRange(AttrRange, true))
+        << FixItHint::CreateRemoval(AttrRange);
+
+      // Recover by adding attributes to the attribute list of the class
+      // so they can be applied on the class later.
+      Attrs.takeAllFrom(Attributes);
+    }
   }
 
   if (Tok.is(tok::colon)) {
diff --git a/test/FixIt/fixit-cxx11-attributes.cpp b/test/FixIt/fixit-cxx11-attributes.cpp
new file mode 100644
index 0000000..7c8efcb
--- /dev/null
+++ b/test/FixIt/fixit-cxx11-attributes.cpp
@@ -0,0 +1,34 @@
+// RUN: %clang_cc1 -verify -std=c++11 %s
+// RUN: cp %s %t
+// RUN: not %clang_cc1 -x c++ -std=c++11 -fixit %t
+// RUN: %clang_cc1 -Wall -pedantic -x c++ -std=c++11 %t
+// RUN: %clang_cc1 -std=c++11 -fsyntax-only -fdiagnostics-parseable-fixits %s 2>&1 | FileCheck %s
+
+namespace ClassSpecifier {
+  class [[]] [[]]
+    attr_after_class_name_decl [[]] [[]]; // expected-error {{an attribute list cannot appear here}}
+    // CHECK: fix-it:{{.*}}:{9:5-9:5}
+    // CHECK: fix-it:{{.*}}:{9:32-9:41}
+
+  class [[]] [[]]
+   attr_after_class_name_definition [[]] [[]] [[]]{}; // expected-error {{an attribute list cannot appear here}}
+   // CHECK: fix-it:{{.*}}:{14:4-14:4}
+   // CHECK: fix-it:{{.*}}:{14:37-14:51}
+
+  class base {};
+  class [[]] [[]] final_class 
+    alignas(float) [[]] final // expected-error {{an attribute list cannot appear here}}
+    alignas(float) [[]] [[]] alignas(float): base{}; // expected-error {{an attribute list cannot appear here}}
+    // CHECK: fix-it:{{.*}}:{19:19-19:19}
+    // CHECK: fix-it:{{.*}}:{20:5-20:25}
+    // CHECK: fix-it:{{.*}}:{19:19-19:19}
+    // CHECK: fix-it:{{.*}}:{21:5-21:44}
+
+  class [[]] [[]] final_class_another 
+    [[]] [[]] alignas(16) final // expected-error {{an attribute list cannot appear here}}
+    [[]] [[]] alignas(16) [[]]{}; // expected-error {{an attribute list cannot appear here}}
+    // CHECK: fix-it:{{.*}}:{27:19-27:19}
+    // CHECK: fix-it:{{.*}}:{28:5-28:27}
+    // CHECK: fix-it:{{.*}}:{27:19-27:19}
+    // CHECK: fix-it:{{.*}}:{29:5-29:31}
+}
diff --git a/test/Parser/cxx0x-attributes.cpp b/test/Parser/cxx0x-attributes.cpp
index 90e7300..a1268a8 100644
--- a/test/Parser/cxx0x-attributes.cpp
+++ b/test/Parser/cxx0x-attributes.cpp
@@ -64,7 +64,6 @@
 union [[]] union_attr;
 
 // Checks attributes placed at wrong syntactic locations of class specifiers.
-// FIXME: provide fix-it hint.
 class [[]] [[]]
   attr_after_class_name_decl [[]] [[]]; // expected-error {{an attribute list cannot appear here}}