forked from OSchip/llvm-project
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. llvm-svn: 171757
This commit is contained in:
parent
e68cf27225
commit
309af291ef
|
@ -2060,7 +2060,10 @@ private:
|
||||||
AccessSpecifier AS, bool EnteringContext,
|
AccessSpecifier AS, bool EnteringContext,
|
||||||
DeclSpecContext DSC,
|
DeclSpecContext DSC,
|
||||||
ParsedAttributesWithRange &Attributes);
|
ParsedAttributesWithRange &Attributes);
|
||||||
void ParseCXXMemberSpecification(SourceLocation StartLoc, unsigned TagType,
|
void ParseCXXMemberSpecification(SourceLocation StartLoc,
|
||||||
|
SourceLocation AttrFixitLoc,
|
||||||
|
ParsedAttributes &Attrs,
|
||||||
|
unsigned TagType,
|
||||||
Decl *TagDecl);
|
Decl *TagDecl);
|
||||||
ExprResult ParseCXXMemberInitializer(Decl *D, bool IsFunction,
|
ExprResult ParseCXXMemberInitializer(Decl *D, bool IsFunction,
|
||||||
SourceLocation &EqualLoc);
|
SourceLocation &EqualLoc);
|
||||||
|
|
|
@ -1106,6 +1106,10 @@ void Parser::ParseClassSpecifier(tok::TokenKind TagTokKind,
|
||||||
// styles of attributes?
|
// styles of attributes?
|
||||||
MaybeParseCXX11Attributes(attrs);
|
MaybeParseCXX11Attributes(attrs);
|
||||||
|
|
||||||
|
// Source location used by FIXIT to insert misplaced
|
||||||
|
// C++11 attributes
|
||||||
|
SourceLocation AttrFixitLoc = Tok.getLocation();
|
||||||
|
|
||||||
if (TagType == DeclSpec::TST_struct &&
|
if (TagType == DeclSpec::TST_struct &&
|
||||||
!Tok.is(tok::identifier) &&
|
!Tok.is(tok::identifier) &&
|
||||||
Tok.getIdentifierInfo() &&
|
Tok.getIdentifierInfo() &&
|
||||||
|
@ -1322,9 +1326,25 @@ void Parser::ParseClassSpecifier(tok::TokenKind TagTokKind,
|
||||||
|
|
||||||
// Forbid misplaced attributes. In cases of a reference, we pass attributes
|
// Forbid misplaced attributes. In cases of a reference, we pass attributes
|
||||||
// to caller to handle.
|
// to caller to handle.
|
||||||
// FIXME: provide fix-it hints if we can.
|
if (TUK != Sema::TUK_Reference) {
|
||||||
if (TUK != Sema::TUK_Reference)
|
// If this is not a reference, then the only possible
|
||||||
ProhibitAttributes(Attributes);
|
// 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
|
// If this is an elaborated type specifier, and we delayed
|
||||||
// diagnostics before, just merge them into the current pool.
|
// diagnostics before, just merge them into the current pool.
|
||||||
|
@ -1508,7 +1528,8 @@ void Parser::ParseClassSpecifier(tok::TokenKind TagTokKind,
|
||||||
(getLangOpts().CPlusPlus && Tok.is(tok::colon)) ||
|
(getLangOpts().CPlusPlus && Tok.is(tok::colon)) ||
|
||||||
isCXX11FinalKeyword());
|
isCXX11FinalKeyword());
|
||||||
if (getLangOpts().CPlusPlus)
|
if (getLangOpts().CPlusPlus)
|
||||||
ParseCXXMemberSpecification(StartLoc, TagType, TagOrTempResult.get());
|
ParseCXXMemberSpecification(StartLoc, AttrFixitLoc, attrs, TagType,
|
||||||
|
TagOrTempResult.get());
|
||||||
else
|
else
|
||||||
ParseStructUnionBody(StartLoc, TagType, TagOrTempResult.get());
|
ParseStructUnionBody(StartLoc, TagType, TagOrTempResult.get());
|
||||||
}
|
}
|
||||||
|
@ -2346,6 +2367,8 @@ ExprResult Parser::ParseCXXMemberInitializer(Decl *D, bool IsFunction,
|
||||||
/// access-specifier ':' member-specification[opt]
|
/// access-specifier ':' member-specification[opt]
|
||||||
///
|
///
|
||||||
void Parser::ParseCXXMemberSpecification(SourceLocation RecordLoc,
|
void Parser::ParseCXXMemberSpecification(SourceLocation RecordLoc,
|
||||||
|
SourceLocation AttrFixitLoc,
|
||||||
|
ParsedAttributes &Attrs,
|
||||||
unsigned TagType, Decl *TagDecl) {
|
unsigned TagType, Decl *TagDecl) {
|
||||||
assert((TagType == DeclSpec::TST_struct ||
|
assert((TagType == DeclSpec::TST_struct ||
|
||||||
TagType == DeclSpec::TST_interface ||
|
TagType == DeclSpec::TST_interface ||
|
||||||
|
@ -2414,10 +2437,24 @@ void Parser::ParseCXXMemberSpecification(SourceLocation RecordLoc,
|
||||||
diag::ext_override_control_keyword) << "final";
|
diag::ext_override_control_keyword) << "final";
|
||||||
}
|
}
|
||||||
|
|
||||||
// Forbid C++11 attributes that appear here.
|
// Parse any C++11 attributes after 'final' keyword.
|
||||||
ParsedAttributesWithRange Attrs(AttrFactory);
|
// These attributes are not allowed to appear here,
|
||||||
MaybeParseCXX11Attributes(Attrs);
|
// and the only possible place for them to appertain
|
||||||
ProhibitAttributes(Attrs);
|
// 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)) {
|
if (Tok.is(tok::colon)) {
|
||||||
|
|
|
@ -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}
|
||||||
|
}
|
|
@ -64,7 +64,6 @@ class [[]] class_attr {};
|
||||||
union [[]] union_attr;
|
union [[]] union_attr;
|
||||||
|
|
||||||
// Checks attributes placed at wrong syntactic locations of class specifiers.
|
// Checks attributes placed at wrong syntactic locations of class specifiers.
|
||||||
// FIXME: provide fix-it hint.
|
|
||||||
class [[]] [[]]
|
class [[]] [[]]
|
||||||
attr_after_class_name_decl [[]] [[]]; // expected-error {{an attribute list cannot appear here}}
|
attr_after_class_name_decl [[]] [[]]; // expected-error {{an attribute list cannot appear here}}
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue