forked from OSchip/llvm-project
PR15300: Support C++11 attributes on base-specifiers. We don't support any such
attributes yet, so just issue the appropriate diagnostics. Also generalize the fixit for attributes-in-the-wrong-place code and reuse it here, if attributes are placed after the access-specifier or 'virtual' in a base specifier. llvm-svn: 175575
This commit is contained in:
parent
9d6f7037ba
commit
4c96e99235
|
@ -1801,9 +1801,8 @@ def warn_cxx11_gnu_attribute_on_type : Warning<
|
|||
def warn_unhandled_ms_attribute_ignored : Warning<
|
||||
"__declspec attribute %0 is not supported">,
|
||||
InGroup<IgnoredAttributes>;
|
||||
def warn_attribute_invalid_on_stmt : Warning<
|
||||
"attribute %0 cannot be specified on a statement">,
|
||||
InGroup<IgnoredAttributes>;
|
||||
def err_attribute_invalid_on_stmt : Error<
|
||||
"%0 attribute cannot be applied to a statement">;
|
||||
def warn_declspec_attribute_ignored : Warning<
|
||||
"attribute %0 is ignored, place it after "
|
||||
"\"%select{class|struct|union|interface|enum}1\" to apply attribute to "
|
||||
|
@ -1905,6 +1904,8 @@ def err_attribute_can_be_applied_only_to_value_decl : Error<
|
|||
"%0 attribute can only be applied to value declarations">;
|
||||
def warn_attribute_not_on_decl : Warning<
|
||||
"%0 attribute ignored when parsing type">, InGroup<IgnoredAttributes>;
|
||||
def err_base_specifier_attribute : Error<
|
||||
"%0 attribute cannot be applied to a base specifier">;
|
||||
|
||||
// Availability attribute
|
||||
def warn_availability_unknown_platform : Warning<
|
||||
|
|
|
@ -1814,6 +1814,17 @@ private:
|
|||
return DiagnoseProhibitedCXX11Attribute();
|
||||
}
|
||||
bool DiagnoseProhibitedCXX11Attribute();
|
||||
void CheckMisplacedCXX11Attribute(ParsedAttributesWithRange &Attrs,
|
||||
SourceLocation CorrectLocation) {
|
||||
if (!getLangOpts().CPlusPlus11)
|
||||
return;
|
||||
if ((Tok.isNot(tok::l_square) || NextToken().isNot(tok::l_square)) &&
|
||||
Tok.isNot(tok::kw_alignas))
|
||||
return;
|
||||
DiagnoseMisplacedCXX11Attribute(Attrs, CorrectLocation);
|
||||
}
|
||||
void DiagnoseMisplacedCXX11Attribute(ParsedAttributesWithRange &Attrs,
|
||||
SourceLocation CorrectLocation);
|
||||
|
||||
void ProhibitAttributes(ParsedAttributesWithRange &attrs) {
|
||||
if (!attrs.Range.isValid()) return;
|
||||
|
@ -2059,7 +2070,7 @@ private:
|
|||
ParsedAttributesWithRange &Attributes);
|
||||
void ParseCXXMemberSpecification(SourceLocation StartLoc,
|
||||
SourceLocation AttrFixitLoc,
|
||||
ParsedAttributes &Attrs,
|
||||
ParsedAttributesWithRange &Attrs,
|
||||
unsigned TagType,
|
||||
Decl *TagDecl);
|
||||
ExprResult ParseCXXMemberInitializer(Decl *D, bool IsFunction,
|
||||
|
|
|
@ -4526,6 +4526,7 @@ public:
|
|||
|
||||
BaseResult ActOnBaseSpecifier(Decl *classdecl,
|
||||
SourceRange SpecifierRange,
|
||||
ParsedAttributes &Attrs,
|
||||
bool Virtual, AccessSpecifier Access,
|
||||
ParsedType basetype,
|
||||
SourceLocation BaseLoc,
|
||||
|
|
|
@ -1144,6 +1144,25 @@ bool Parser::DiagnoseProhibitedCXX11Attribute() {
|
|||
llvm_unreachable("All cases handled above.");
|
||||
}
|
||||
|
||||
/// DiagnoseMisplacedCXX11Attribute - We have found the opening square brackets
|
||||
/// of a C++11 attribute-specifier in a location where an attribute is not
|
||||
/// permitted, but we know where the attributes ought to be written. Parse them
|
||||
/// anyway, and provide a fixit moving them to the right place.
|
||||
void Parser::DiagnoseMisplacedCXX11Attribute(ParsedAttributesWithRange &Attrs,
|
||||
SourceLocation CorrectLocation) {
|
||||
assert((Tok.is(tok::l_square) && NextToken().is(tok::l_square)) ||
|
||||
Tok.is(tok::kw_alignas));
|
||||
|
||||
// Consume the attributes.
|
||||
SourceLocation Loc = Tok.getLocation();
|
||||
ParseCXX11Attributes(Attrs);
|
||||
CharSourceRange AttrRange(SourceRange(Loc, Attrs.Range.getEnd()), true);
|
||||
|
||||
Diag(Loc, diag::err_attributes_not_allowed)
|
||||
<< FixItHint::CreateInsertionFromRange(CorrectLocation, AttrRange)
|
||||
<< FixItHint::CreateRemoval(AttrRange);
|
||||
}
|
||||
|
||||
void Parser::DiagnoseProhibitedAttributes(ParsedAttributesWithRange &attrs) {
|
||||
Diag(attrs.Range.getBegin(), diag::err_attributes_not_allowed)
|
||||
<< attrs.Range;
|
||||
|
|
|
@ -802,15 +802,18 @@ void Parser::ParseUnderlyingTypeSpecifier(DeclSpec &DS) {
|
|||
/// class. The result is either a type or null, depending on whether a type
|
||||
/// name was found.
|
||||
///
|
||||
/// base-type-specifier: [C++ 10.1]
|
||||
/// base-type-specifier: [C++11 class.derived]
|
||||
/// class-or-decltype
|
||||
/// class-or-decltype: [C++ 10.1]
|
||||
/// class-or-decltype: [C++11 class.derived]
|
||||
/// nested-name-specifier[opt] class-name
|
||||
/// decltype-specifier
|
||||
/// class-name: [C++ 9.1]
|
||||
/// class-name: [C++ class.name]
|
||||
/// identifier
|
||||
/// simple-template-id
|
||||
///
|
||||
/// In C++98, instead of base-type-specifier, we have:
|
||||
///
|
||||
/// ::[opt] nested-name-specifier[opt] class-name
|
||||
Parser::TypeResult Parser::ParseBaseTypeSpecifier(SourceLocation &BaseLoc,
|
||||
SourceLocation &EndLocation) {
|
||||
// Ignore attempts to use typename
|
||||
|
@ -1636,26 +1639,33 @@ void Parser::ParseBaseClause(Decl *ClassDecl) {
|
|||
/// 'public bar' and 'virtual private baz' are each base-specifiers.
|
||||
///
|
||||
/// base-specifier: [C++ class.derived]
|
||||
/// ::[opt] nested-name-specifier[opt] class-name
|
||||
/// 'virtual' access-specifier[opt] ::[opt] nested-name-specifier[opt]
|
||||
/// base-type-specifier
|
||||
/// access-specifier 'virtual'[opt] ::[opt] nested-name-specifier[opt]
|
||||
/// base-type-specifier
|
||||
/// attribute-specifier-seq[opt] base-type-specifier
|
||||
/// attribute-specifier-seq[opt] 'virtual' access-specifier[opt]
|
||||
/// base-type-specifier
|
||||
/// attribute-specifier-seq[opt] access-specifier 'virtual'[opt]
|
||||
/// base-type-specifier
|
||||
Parser::BaseResult Parser::ParseBaseSpecifier(Decl *ClassDecl) {
|
||||
bool IsVirtual = false;
|
||||
SourceLocation StartLoc = Tok.getLocation();
|
||||
|
||||
ParsedAttributesWithRange Attributes(AttrFactory);
|
||||
MaybeParseCXX11Attributes(Attributes);
|
||||
|
||||
// Parse the 'virtual' keyword.
|
||||
if (Tok.is(tok::kw_virtual)) {
|
||||
ConsumeToken();
|
||||
IsVirtual = true;
|
||||
}
|
||||
|
||||
CheckMisplacedCXX11Attribute(Attributes, StartLoc);
|
||||
|
||||
// Parse an (optional) access specifier.
|
||||
AccessSpecifier Access = getAccessSpecifierIfPresent();
|
||||
if (Access != AS_none)
|
||||
ConsumeToken();
|
||||
|
||||
CheckMisplacedCXX11Attribute(Attributes, StartLoc);
|
||||
|
||||
// Parse the 'virtual' keyword (again!), in case it came after the
|
||||
// access specifier.
|
||||
if (Tok.is(tok::kw_virtual)) {
|
||||
|
@ -1669,6 +1679,8 @@ Parser::BaseResult Parser::ParseBaseSpecifier(Decl *ClassDecl) {
|
|||
IsVirtual = true;
|
||||
}
|
||||
|
||||
CheckMisplacedCXX11Attribute(Attributes, StartLoc);
|
||||
|
||||
// Parse the class-name.
|
||||
SourceLocation EndLocation;
|
||||
SourceLocation BaseLoc;
|
||||
|
@ -1688,8 +1700,9 @@ Parser::BaseResult Parser::ParseBaseSpecifier(Decl *ClassDecl) {
|
|||
|
||||
// Notify semantic analysis that we have parsed a complete
|
||||
// base-specifier.
|
||||
return Actions.ActOnBaseSpecifier(ClassDecl, Range, IsVirtual, Access,
|
||||
BaseType.get(), BaseLoc, EllipsisLoc);
|
||||
return Actions.ActOnBaseSpecifier(ClassDecl, Range, Attributes, IsVirtual,
|
||||
Access, BaseType.get(), BaseLoc,
|
||||
EllipsisLoc);
|
||||
}
|
||||
|
||||
/// getAccessSpecifierIfPresent - Determine whether the next token is
|
||||
|
@ -2384,7 +2397,7 @@ ExprResult Parser::ParseCXXMemberInitializer(Decl *D, bool IsFunction,
|
|||
///
|
||||
void Parser::ParseCXXMemberSpecification(SourceLocation RecordLoc,
|
||||
SourceLocation AttrFixitLoc,
|
||||
ParsedAttributes &Attrs,
|
||||
ParsedAttributesWithRange &Attrs,
|
||||
unsigned TagType, Decl *TagDecl) {
|
||||
assert((TagType == DeclSpec::TST_struct ||
|
||||
TagType == DeclSpec::TST_interface ||
|
||||
|
@ -2457,20 +2470,7 @@ void Parser::ParseCXXMemberSpecification(SourceLocation RecordLoc,
|
|||
// 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);
|
||||
}
|
||||
CheckMisplacedCXX11Attribute(Attrs, AttrFixitLoc);
|
||||
}
|
||||
|
||||
if (Tok.is(tok::colon)) {
|
||||
|
|
|
@ -1172,6 +1172,7 @@ Sema::CheckBaseSpecifier(CXXRecordDecl *Class,
|
|||
/// 'public bar' and 'virtual private baz' are each base-specifiers.
|
||||
BaseResult
|
||||
Sema::ActOnBaseSpecifier(Decl *classdecl, SourceRange SpecifierRange,
|
||||
ParsedAttributes &Attributes,
|
||||
bool Virtual, AccessSpecifier Access,
|
||||
ParsedType basetype, SourceLocation BaseLoc,
|
||||
SourceLocation EllipsisLoc) {
|
||||
|
@ -1183,6 +1184,22 @@ Sema::ActOnBaseSpecifier(Decl *classdecl, SourceRange SpecifierRange,
|
|||
if (!Class)
|
||||
return true;
|
||||
|
||||
// We do not support any C++11 attributes on base-specifiers yet.
|
||||
// Diagnose any attributes we see.
|
||||
if (!Attributes.empty()) {
|
||||
for (AttributeList *Attr = Attributes.getList(); Attr;
|
||||
Attr = Attr->getNext()) {
|
||||
if (Attr->isInvalid() ||
|
||||
Attr->getKind() == AttributeList::IgnoredAttribute)
|
||||
continue;
|
||||
Diag(Attr->getLoc(),
|
||||
Attr->getKind() == AttributeList::UnknownAttribute
|
||||
? diag::warn_unknown_attribute_ignored
|
||||
: diag::err_base_specifier_attribute)
|
||||
<< Attr->getName();
|
||||
}
|
||||
}
|
||||
|
||||
TypeSourceInfo *TInfo = 0;
|
||||
GetTypeFromParser(basetype, &TInfo);
|
||||
|
||||
|
|
|
@ -58,8 +58,8 @@ static Attr *ProcessStmtAttribute(Sema &S, Stmt *St, const AttributeList &A,
|
|||
default:
|
||||
// if we're here, then we parsed a known attribute, but didn't recognize
|
||||
// it as a statement attribute => it is declaration attribute
|
||||
S.Diag(A.getRange().getBegin(), diag::warn_attribute_invalid_on_stmt)
|
||||
<< A.getName()->getName() << St->getLocStart();
|
||||
S.Diag(A.getRange().getBegin(), diag::err_attribute_invalid_on_stmt)
|
||||
<< A.getName() << St->getLocStart();
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -32,3 +32,20 @@ namespace ClassSpecifier {
|
|||
// CHECK: fix-it:{{.*}}:{27:19-27:19}
|
||||
// CHECK: fix-it:{{.*}}:{29:5-29:31}
|
||||
}
|
||||
|
||||
namespace BaseSpecifier {
|
||||
struct base1 {};
|
||||
struct base2 {};
|
||||
class with_base_spec : public [[a]] // expected-error {{an attribute list cannot appear here}} expected-warning {{unknown}}
|
||||
// CHECK: fix-it:"{{.*}}":{[[@LINE-1]]:26-[[@LINE-1]]:26}:"[{{\[}}a]]"
|
||||
// CHECK: fix-it:"{{.*}}":{[[@LINE-2]]:33-[[@LINE-2]]:39}:""
|
||||
virtual [[b]] base1, // expected-error {{an attribute list cannot appear here}} expected-warning {{unknown}}
|
||||
// CHECK: fix-it:"{{.*}}":{[[@LINE-4]]:26-[[@LINE-4]]:26}:"[{{\[}}b]]"
|
||||
// CHECK: fix-it:"{{.*}}":{[[@LINE-2]]:34-[[@LINE-2]]:40}:""
|
||||
virtual [[c]] // expected-error {{an attribute list cannot appear here}} expected-warning {{unknown}}
|
||||
// CHECK: fix-it:"{{.*}}":{[[@LINE-1]]:26-[[@LINE-1]]:26}:"[{{\[}}c]]"
|
||||
// CHECK: fix-it:"{{.*}}":{[[@LINE-2]]:34-[[@LINE-2]]:40}:""
|
||||
public [[d]] base2 {}; // expected-error {{an attribute list cannot appear here}} expected-warning {{unknown}}
|
||||
// CHECK: fix-it:"{{.*}}":{[[@LINE-4]]:26-[[@LINE-4]]:26}:"[{{\[}}d]]"
|
||||
// CHECK: fix-it:"{{.*}}":{[[@LINE-2]]:33-[[@LINE-2]]:39}:""
|
||||
}
|
||||
|
|
|
@ -0,0 +1,10 @@
|
|||
// RUN: %clang_cc1 -std=c++11 %s -verify
|
||||
|
||||
struct A {};
|
||||
struct B : [[]] A {};
|
||||
struct C : [[]] virtual A {};
|
||||
struct D : [[]] public virtual A {};
|
||||
struct E : public [[]] virtual A {}; // expected-error {{an attribute list cannot appear here}}
|
||||
struct F : virtual [[]] public A {}; // expected-error {{an attribute list cannot appear here}}
|
||||
struct G : [[noreturn]] A {}; // expected-error {{'noreturn' attribute cannot be applied to a base specifier}}
|
||||
struct H : [[unknown::foobar]] A {}; // expected-warning {{unknown attribute 'foobar' ignored}}
|
|
@ -27,11 +27,11 @@ void foo(int i) {
|
|||
[[unknown_attribute]] return; // expected-warning {{unknown attribute 'unknown_attribute' ignored}}
|
||||
|
||||
|
||||
alignas(8) ; // expected-warning {{attribute alignas cannot be specified on a statement}}
|
||||
[[noreturn]] { } // expected-warning {{attribute noreturn cannot be specified on a statement}}
|
||||
[[noreturn]] if (0) { } // expected-warning {{attribute noreturn cannot be specified on a statement}}
|
||||
[[noreturn]] for (;;); // expected-warning {{attribute noreturn cannot be specified on a statement}}
|
||||
[[noreturn]] do { // expected-warning {{attribute noreturn cannot be specified on a statement}}
|
||||
alignas(8) ; // expected-error {{'alignas' attribute cannot be applied to a statement}}
|
||||
[[noreturn]] { } // expected-error {{'noreturn' attribute cannot be applied to a statement}}
|
||||
[[noreturn]] if (0) { } // expected-error {{'noreturn' attribute cannot be applied to a statement}}
|
||||
[[noreturn]] for (;;); // expected-error {{'noreturn' attribute cannot be applied to a statement}}
|
||||
[[noreturn]] do { // expected-error {{'noreturn' attribute cannot be applied to a statement}}
|
||||
[[unavailable]] continue; // expected-warning {{unknown attribute 'unavailable' ignored}}
|
||||
} while (0);
|
||||
[[unknown_attributqqq]] while (0); // expected-warning {{unknown attribute 'unknown_attributqqq' ignored}}
|
||||
|
@ -42,7 +42,7 @@ void foo(int i) {
|
|||
[[unused]] switch (i) { // expected-warning {{unknown attribute 'unused' ignored}}
|
||||
[[uuid]] case 0: // expected-warning {{unknown attribute 'uuid' ignored}}
|
||||
[[visibility]] default: // expected-warning {{unknown attribute 'visibility' ignored}}
|
||||
[[carries_dependency]] break; // expected-warning {{attribute carries_dependency cannot be specified on a statement}}
|
||||
[[carries_dependency]] break; // expected-error {{'carries_dependency' attribute cannot be applied to a statement}}
|
||||
}
|
||||
|
||||
[[fastcall]] goto there; // expected-warning {{unknown attribute 'fastcall' ignored}}
|
||||
|
@ -54,26 +54,26 @@ void foo(int i) {
|
|||
|
||||
[[weakref]] return; // expected-warning {{unknown attribute 'weakref' ignored}}
|
||||
|
||||
[[carries_dependency]] ; // expected-warning {{attribute carries_dependency cannot be specified on a statement}}
|
||||
[[carries_dependency]] { } // expected-warning {{attribute carries_dependency cannot be specified on a statement}}
|
||||
[[carries_dependency]] if (0) { } // expected-warning {{attribute carries_dependency cannot be specified on a statement}}
|
||||
[[carries_dependency]] for (;;); // expected-warning {{attribute carries_dependency cannot be specified on a statement}}
|
||||
[[carries_dependency]] do { // expected-warning {{attribute carries_dependency cannot be specified on a statement}}
|
||||
[[carries_dependency]] continue; // expected-warning {{attribute carries_dependency cannot be specified on a statement}} ignored}}
|
||||
[[carries_dependency]] ; // expected-error {{'carries_dependency' attribute cannot be applied to a statement}}
|
||||
[[carries_dependency]] { } // expected-error {{'carries_dependency' attribute cannot be applied to a statement}}
|
||||
[[carries_dependency]] if (0) { } // expected-error {{'carries_dependency' attribute cannot be applied to a statement}}
|
||||
[[carries_dependency]] for (;;); // expected-error {{'carries_dependency' attribute cannot be applied to a statement}}
|
||||
[[carries_dependency]] do { // expected-error {{'carries_dependency' attribute cannot be applied to a statement}}
|
||||
[[carries_dependency]] continue; // expected-error {{'carries_dependency' attribute cannot be applied to a statement}} ignored}}
|
||||
} while (0);
|
||||
[[carries_dependency]] while (0); // expected-warning {{attribute carries_dependency cannot be specified on a statement}}
|
||||
[[carries_dependency]] while (0); // expected-error {{'carries_dependency' attribute cannot be applied to a statement}}
|
||||
|
||||
[[carries_dependency]] switch (i) { // expected-warning {{attribute carries_dependency cannot be specified on a statement}} ignored}}
|
||||
[[carries_dependency]] case 0: // expected-warning {{attribute carries_dependency cannot be specified on a statement}}
|
||||
[[carries_dependency]] default: // expected-warning {{attribute carries_dependency cannot be specified on a statement}}
|
||||
[[carries_dependency]] break; // expected-warning {{attribute carries_dependency cannot be specified on a statement}}
|
||||
[[carries_dependency]] switch (i) { // expected-error {{'carries_dependency' attribute cannot be applied to a statement}} ignored}}
|
||||
[[carries_dependency]] case 0: // expected-error {{'carries_dependency' attribute cannot be applied to a statement}}
|
||||
[[carries_dependency]] default: // expected-error {{'carries_dependency' attribute cannot be applied to a statement}}
|
||||
[[carries_dependency]] break; // expected-error {{'carries_dependency' attribute cannot be applied to a statement}}
|
||||
}
|
||||
|
||||
[[carries_dependency]] goto here; // expected-warning {{attribute carries_dependency cannot be specified on a statement}}
|
||||
[[carries_dependency]] goto here; // expected-error {{'carries_dependency' attribute cannot be applied to a statement}}
|
||||
|
||||
[[carries_dependency]] try { // expected-warning {{attribute carries_dependency cannot be specified on a statement}}
|
||||
[[carries_dependency]] try { // expected-error {{'carries_dependency' attribute cannot be applied to a statement}}
|
||||
} catch (...) {
|
||||
}
|
||||
|
||||
[[carries_dependency]] return; // expected-warning {{attribute carries_dependency cannot be specified on a statement}}
|
||||
[[carries_dependency]] return; // expected-error {{'carries_dependency' attribute cannot be applied to a statement}}
|
||||
}
|
||||
|
|
|
@ -32,11 +32,11 @@ void f(X *noreturn) {
|
|||
// An attribute is OK.
|
||||
[[]];
|
||||
[[int(), noreturn]]; // expected-warning {{unknown attribute 'int' ignored}} \
|
||||
// expected-warning {{attribute noreturn cannot be specified on a statement}}
|
||||
// expected-error {{'noreturn' attribute cannot be applied to a statement}}
|
||||
[[class, test(foo 'x' bar),,,]]; // expected-warning {{unknown attribute 'test' ignored}}\
|
||||
// expected-warning {{unknown attribute 'class' ignored}}
|
||||
|
||||
[[bitand, noreturn]]; // expected-warning {{attribute noreturn cannot be specified on a statement}} \
|
||||
[[bitand, noreturn]]; // expected-error {{'noreturn' attribute cannot be applied to a statement}} \
|
||||
expected-warning {{unknown attribute 'bitand' ignored}}
|
||||
|
||||
// FIXME: Suppress vexing parse warning
|
||||
|
|
Loading…
Reference in New Issue