Skip to content

Commit 33ee5c4

Browse files
committed
[clang] Add Parse and Sema support for RegularKeyword attributes
This patch adds the Parse and Sema support for RegularKeyword attributes, following on from a previous patch that added Attr.td support. The patch is quite large. However, nothing outside the tests is specific to the first RegularKeyword attribute (__arm_streaming). The patch should therefore be a one-off, up-front cost. Other attributes just need an entry in Attr.td and the usual Sema support. The approach taken in the patch is that the keywords can be used with any language version. If standard attributes were added in language version Y, the keyword rules for version X<Y are the same as they were for version Y (to the extent possible). Any extensions beyond Y are handled in the same way for both keywords and attributes. This ensures that existing C++11 successors like C++17 are not treated differently from versions that have yet to be defined. Some notes on the implementation: * The patch emits errors rather than warnings for diagnostics that relate to keywords. * Where possible, the patch drops “attribute” from diagnostics relating to keywords. * One exception to the previous point is that warnings about C++ extensions do still mention attributes. The use there seemed OK since the diagnostics are noting a change in the production rules. * If a diagnostic string needs to be different for keywords and attributes, the patch standardizes on passing the attribute/ name/token followed by 0 for attributes and 1 for keywords. * Although the patch updates warn_attribute_wrong_decl_type_str, warn_attribute_wrong_decl_type, and warn_attribute_wrong_decl_type, only the error forms of these strings are used for keywords. * I couldn't trigger the warnings in checkUnusedDeclAttributes, even for existing attributes. An assert on the warnings caused no failures in the testsuite. I think in practice all standard attributes would be diagnosed before this. * The patch drops a call to standardAttributesAllowed in ParseFunctionDeclarator. This is because MaybeParseCXX11Attributes checks the same thing itself, where appropriate. * The new tests are based on c2x-attributes.c and cxx0x-attributes.cpp. The C++ test also incorporates a version of cxx11-base-spec-attributes.cpp. The FIXMEs are carried across from the originals. Differential Revision: https://reviews.llvm.org/D148702
1 parent 301eb6b commit 33ee5c4

25 files changed

+807
-163
lines changed

clang/examples/Attribute/Attribute.cpp

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -43,7 +43,7 @@ struct ExampleAttrInfo : public ParsedAttrInfo {
4343
// This attribute appertains to functions only.
4444
if (!isa<FunctionDecl>(D)) {
4545
S.Diag(Attr.getLoc(), diag::warn_attribute_wrong_decl_type_str)
46-
<< Attr << "functions";
46+
<< Attr << Attr.isRegularKeywordAttribute() << "functions";
4747
return false;
4848
}
4949
return true;

clang/examples/CallSuperAttribute/CallSuperAttrInfo.cpp

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -169,7 +169,7 @@ struct CallSuperAttrInfo : public ParsedAttrInfo {
169169
const auto *TheMethod = dyn_cast_or_null<CXXMethodDecl>(D);
170170
if (!TheMethod || !TheMethod->isVirtual()) {
171171
S.Diag(Attr.getLoc(), diag::warn_attribute_wrong_decl_type_str)
172-
<< Attr << "virtual functions";
172+
<< Attr << Attr.isRegularKeywordAttribute() << "virtual functions";
173173
return false;
174174
}
175175
MarkedMethods.insert(TheMethod);

clang/include/clang/Basic/DiagnosticCommonKinds.td

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -121,7 +121,7 @@ def note_pragma_entered_here : Note<"#pragma entered here">;
121121
def note_decl_hiding_tag_type : Note<
122122
"%1 %0 is hidden by a non-type declaration of %0 here">;
123123
def err_attribute_not_type_attr : Error<
124-
"%0 attribute cannot be applied to types">;
124+
"%0%select{ attribute|}1 cannot be applied to types">;
125125
def err_enum_template : Error<"enumeration cannot be a template">;
126126

127127
def warn_cxx20_compat_consteval : Warning<
@@ -175,6 +175,8 @@ def warn_unknown_attribute_ignored : Warning<
175175
"unknown attribute %0 ignored">, InGroup<UnknownAttributes>;
176176
def warn_attribute_ignored : Warning<"%0 attribute ignored">,
177177
InGroup<IgnoredAttributes>;
178+
def err_keyword_not_supported_on_target : Error<
179+
"%0 is not supported on this target">;
178180
def err_use_of_tag_name_without_tag : Error<
179181
"must use '%1' tag to refer to type %0%select{| in this scope}2">;
180182

clang/include/clang/Basic/DiagnosticParseKinds.td

Lines changed: 12 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -733,10 +733,12 @@ def ext_using_attribute_ns : ExtWarn<
733733
def err_using_attribute_ns_conflict : Error<
734734
"attribute with scope specifier cannot follow default scope specifier">;
735735
def err_attributes_not_allowed : Error<"an attribute list cannot appear here">;
736+
def err_keyword_not_allowed : Error<"%0 cannot appear here">;
736737
def ext_cxx11_attr_placement : ExtWarn<
737-
"ISO C++ does not allow an attribute list to appear here">,
738+
"ISO C++ does not allow %select{an attribute list|%0}1 to appear here">,
738739
InGroup<DiagGroup<"cxx-attribute-extension">>;
739740
def err_attributes_misplaced : Error<"misplaced attributes; expected attributes here">;
741+
def err_keyword_misplaced : Error<"misplaced %0; expected %0 here">;
740742
def err_l_square_l_square_not_attribute : Error<
741743
"C++11 only allows consecutive left square brackets when "
742744
"introducing an attribute">;
@@ -1014,14 +1016,15 @@ def err_lambda_capture_multiple_ellipses : Error<
10141016
def err_capture_default_first : Error<
10151017
"capture default must be first">;
10161018
def ext_decl_attrs_on_lambda : ExtWarn<
1017-
"an attribute specifier sequence in this position is a C++23 extension">,
1018-
InGroup<CXX23>;
1019+
"%select{an attribute specifier sequence|%0}1 in this position "
1020+
"is a C++23 extension">, InGroup<CXX23>;
10191021
def ext_lambda_missing_parens : ExtWarn<
10201022
"lambda without a parameter clause is a C++23 extension">,
10211023
InGroup<CXX23>;
10221024
def warn_cxx20_compat_decl_attrs_on_lambda : Warning<
1023-
"an attribute specifier sequence in this position is incompatible with C++ "
1024-
"standards before C++23">, InGroup<CXXPre23Compat>, DefaultIgnore;
1025+
"%select{an attribute specifier sequence|%1}0 in this position "
1026+
"is incompatible with C++ standards before C++23">,
1027+
InGroup<CXXPre23Compat>, DefaultIgnore;
10251028

10261029
// C++17 lambda expressions
10271030
def err_expected_star_this_capture : Error<
@@ -1582,8 +1585,12 @@ def err_module_expected_ident : Error<
15821585
"expected a module name after '%select{module|import}0'">;
15831586
def err_attribute_not_module_attr : Error<
15841587
"%0 attribute cannot be applied to a module">;
1588+
def err_keyword_not_module_attr : Error<
1589+
"%0 cannot be applied to a module">;
15851590
def err_attribute_not_import_attr : Error<
15861591
"%0 attribute cannot be applied to a module import">;
1592+
def err_keyword_not_import_attr : Error<
1593+
"%0 cannot be applied to a module import">;
15871594
def err_module_expected_semi : Error<
15881595
"expected ';' after module name">;
15891596
def err_global_module_introducer_not_at_start : Error<

clang/include/clang/Basic/DiagnosticSemaKinds.td

Lines changed: 13 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -3022,7 +3022,7 @@ def err_musttail_no_variadic : Error<
30223022
def err_nsobject_attribute : Error<
30233023
"'NSObject' attribute is for pointer types only">;
30243024
def err_attributes_are_not_compatible : Error<
3025-
"%0 and %1 attributes are not compatible">;
3025+
"%0 and %1%select{ attributes|}2 are not compatible">;
30263026
def err_attribute_invalid_argument : Error<
30273027
"%select{a reference type|an array type|a non-vector or "
30283028
"non-vectorizable scalar type}0 is an invalid argument to attribute %1">;
@@ -3430,16 +3430,20 @@ def warn_attribute_has_no_effect_on_compile_time_if : Warning<
34303430
def note_attribute_has_no_effect_on_compile_time_if_here : Note<
34313431
"annotating the 'if %select{constexpr|consteval}0' statement here">;
34323432
def err_decl_attribute_invalid_on_stmt : Error<
3433-
"%0 attribute cannot be applied to a statement">;
3433+
"%0%select{ attribute|}1 cannot be applied to a statement">;
34343434
def err_attribute_invalid_on_decl : Error<
3435-
"%0 attribute cannot be applied to a declaration">;
3435+
"%0%select{ attribute|}1 cannot be applied to a declaration">;
34363436
def warn_type_attribute_deprecated_on_decl : Warning<
34373437
"applying attribute %0 to a declaration is deprecated; apply it to the type instead">,
34383438
InGroup<DeprecatedAttributes>;
34393439
def warn_declspec_attribute_ignored : Warning<
34403440
"attribute %0 is ignored, place it after "
34413441
"\"%select{class|struct|interface|union|enum|enum class|enum struct}1\" to apply attribute to "
34423442
"type declaration">, InGroup<IgnoredAttributes>;
3443+
def err_declspec_keyword_has_no_effect : Error<
3444+
"%0 cannot appear here, place it after "
3445+
"\"%select{class|struct|interface|union|enum}1\" to apply it to the "
3446+
"type declaration">;
34433447
def warn_attribute_precede_definition : Warning<
34443448
"attribute declaration must precede definition">,
34453449
InGroup<IgnoredAttributes>;
@@ -3538,11 +3542,11 @@ def err_attribute_weakref_without_alias : Error<
35383542
def err_alias_not_supported_on_darwin : Error <
35393543
"aliases are not supported on darwin">;
35403544
def warn_attribute_wrong_decl_type_str : Warning<
3541-
"%0 attribute only applies to %1">, InGroup<IgnoredAttributes>;
3545+
"%0%select{ attribute|}1 only applies to %2">, InGroup<IgnoredAttributes>;
35423546
def err_attribute_wrong_decl_type_str : Error<
35433547
warn_attribute_wrong_decl_type_str.Summary>;
35443548
def warn_attribute_wrong_decl_type : Warning<
3545-
"%0 attribute only applies to %select{"
3549+
"%0%select{ attribute|}1 only applies to %select{"
35463550
"functions"
35473551
"|unions"
35483552
"|variables and functions"
@@ -3555,13 +3559,15 @@ def warn_attribute_wrong_decl_type : Warning<
35553559
"|types and namespaces"
35563560
"|variables, functions and classes"
35573561
"|kernel functions"
3558-
"|non-K&R-style functions}1">,
3562+
"|non-K&R-style functions}2">,
35593563
InGroup<IgnoredAttributes>;
35603564
def err_attribute_wrong_decl_type : Error<warn_attribute_wrong_decl_type.Summary>;
35613565
def warn_type_attribute_wrong_type : Warning<
35623566
"'%0' only applies to %select{function|pointer|"
35633567
"Objective-C object or block pointer}1 types; type here is %2">,
35643568
InGroup<IgnoredAttributes>;
3569+
def err_type_attribute_wrong_type : Error<
3570+
warn_type_attribute_wrong_type.Summary>;
35653571
def warn_incomplete_encoded_type : Warning<
35663572
"encoding of %0 type is incomplete because %1 component has unknown encoding">,
35673573
InGroup<DiagGroup<"encode-type">>;
@@ -3612,7 +3618,7 @@ def err_invalid_pcs : Error<"invalid PCS type">;
36123618
def warn_attribute_not_on_decl : Warning<
36133619
"%0 attribute ignored when parsing type">, InGroup<IgnoredAttributes>;
36143620
def err_base_specifier_attribute : Error<
3615-
"%0 attribute cannot be applied to a base specifier">;
3621+
"%0%select{ attribute|}1 cannot be applied to a base specifier">;
36163622
def warn_declspec_allocator_nonpointer : Warning<
36173623
"ignoring __declspec(allocator) because the function return type %0 is not "
36183624
"a pointer or reference type">, InGroup<IgnoredAttributes>;

clang/include/clang/Parse/Parser.h

Lines changed: 27 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -2691,6 +2691,18 @@ class Parser : public CodeCompletionHandler {
26912691
return LO.DoubleSquareBracketAttributes;
26922692
}
26932693

2694+
/// Return true if the next token should be treated as a [[]] attribute,
2695+
/// or as a keyword that behaves like one. The former is only true if
2696+
/// [[]] attributes are enabled, whereas the latter is true whenever
2697+
/// such a keyword appears. The arguments are as for
2698+
/// isCXX11AttributeSpecifier.
2699+
bool isAllowedCXX11AttributeSpecifier(bool Disambiguate = false,
2700+
bool OuterMightBeMessageSend = false) {
2701+
return (Tok.isRegularKeywordAttribute() ||
2702+
(standardAttributesAllowed() &&
2703+
isCXX11AttributeSpecifier(Disambiguate, OuterMightBeMessageSend)));
2704+
}
2705+
26942706
// Check for the start of an attribute-specifier-seq in a context where an
26952707
// attribute is not allowed.
26962708
bool CheckProhibitedCXX11Attribute() {
@@ -2703,11 +2715,13 @@ class Parser : public CodeCompletionHandler {
27032715
bool DiagnoseProhibitedCXX11Attribute();
27042716
void CheckMisplacedCXX11Attribute(ParsedAttributes &Attrs,
27052717
SourceLocation CorrectLocation) {
2706-
if (!standardAttributesAllowed())
2707-
return;
2708-
if ((Tok.isNot(tok::l_square) || NextToken().isNot(tok::l_square)) &&
2709-
Tok.isNot(tok::kw_alignas))
2710-
return;
2718+
if (!Tok.isRegularKeywordAttribute()) {
2719+
if (!standardAttributesAllowed())
2720+
return;
2721+
if ((Tok.isNot(tok::l_square) || NextToken().isNot(tok::l_square)) &&
2722+
Tok.isNot(tok::kw_alignas))
2723+
return;
2724+
}
27112725
DiagnoseMisplacedCXX11Attribute(Attrs, CorrectLocation);
27122726
}
27132727
void DiagnoseMisplacedCXX11Attribute(ParsedAttributes &Attrs,
@@ -2721,18 +2735,18 @@ class Parser : public CodeCompletionHandler {
27212735
SourceLocation FixItLoc = SourceLocation()) {
27222736
if (Attrs.Range.isInvalid())
27232737
return;
2724-
DiagnoseProhibitedAttributes(Attrs.Range, FixItLoc);
2738+
DiagnoseProhibitedAttributes(Attrs, FixItLoc);
27252739
Attrs.clear();
27262740
}
27272741

27282742
void ProhibitAttributes(ParsedAttributesView &Attrs,
27292743
SourceLocation FixItLoc = SourceLocation()) {
27302744
if (Attrs.Range.isInvalid())
27312745
return;
2732-
DiagnoseProhibitedAttributes(Attrs.Range, FixItLoc);
2746+
DiagnoseProhibitedAttributes(Attrs, FixItLoc);
27332747
Attrs.clearListOnly();
27342748
}
2735-
void DiagnoseProhibitedAttributes(const SourceRange &Range,
2749+
void DiagnoseProhibitedAttributes(const ParsedAttributesView &Attrs,
27362750
SourceLocation FixItLoc);
27372751

27382752
// Forbid C++11 and C2x attributes that appear on certain syntactic locations
@@ -2741,7 +2755,8 @@ class Parser : public CodeCompletionHandler {
27412755
// For the most cases we don't want to warn on unknown type attributes, but
27422756
// left them to later diagnoses. However, for a few cases like module
27432757
// declarations and module import declarations, we should do it.
2744-
void ProhibitCXX11Attributes(ParsedAttributes &Attrs, unsigned DiagID,
2758+
void ProhibitCXX11Attributes(ParsedAttributes &Attrs, unsigned AttrDiagID,
2759+
unsigned KeywordDiagId,
27452760
bool DiagnoseEmptyAttrs = false,
27462761
bool WarnOnUnknownAttrs = false);
27472762

@@ -2795,7 +2810,7 @@ class Parser : public CodeCompletionHandler {
27952810
bool MaybeParseAttributes(unsigned WhichAttrKinds, ParsedAttributes &Attrs,
27962811
LateParsedAttrList *LateAttrs = nullptr) {
27972812
if (Tok.isOneOf(tok::kw___attribute, tok::kw___declspec) ||
2798-
(standardAttributesAllowed() && isCXX11AttributeSpecifier())) {
2813+
isAllowedCXX11AttributeSpecifier()) {
27992814
ParseAttributes(WhichAttrKinds, Attrs, LateAttrs);
28002815
return true;
28012816
}
@@ -2847,7 +2862,7 @@ class Parser : public CodeCompletionHandler {
28472862
}
28482863
}
28492864
void MaybeParseCXX11Attributes(Declarator &D) {
2850-
if (standardAttributesAllowed() && isCXX11AttributeSpecifier()) {
2865+
if (isAllowedCXX11AttributeSpecifier()) {
28512866
ParsedAttributes Attrs(AttrFactory);
28522867
ParseCXX11Attributes(Attrs);
28532868
D.takeAttributes(Attrs);
@@ -2856,8 +2871,7 @@ class Parser : public CodeCompletionHandler {
28562871

28572872
bool MaybeParseCXX11Attributes(ParsedAttributes &Attrs,
28582873
bool OuterMightBeMessageSend = false) {
2859-
if (standardAttributesAllowed() &&
2860-
isCXX11AttributeSpecifier(false, OuterMightBeMessageSend)) {
2874+
if (isAllowedCXX11AttributeSpecifier(false, OuterMightBeMessageSend)) {
28612875
ParseCXX11Attributes(Attrs);
28622876
return true;
28632877
}

clang/include/clang/Sema/DeclSpec.h

Lines changed: 3 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -1972,9 +1972,10 @@ class Declarator {
19721972
InventedTemplateParameterList(nullptr) {
19731973
assert(llvm::all_of(DeclarationAttrs,
19741974
[](const ParsedAttr &AL) {
1975-
return AL.isStandardAttributeSyntax();
1975+
return (AL.isStandardAttributeSyntax() ||
1976+
AL.isRegularKeywordAttribute());
19761977
}) &&
1977-
"DeclarationAttrs may only contain [[]] attributes");
1978+
"DeclarationAttrs may only contain [[]] and keyword attributes");
19781979
}
19791980

19801981
~Declarator() {
@@ -2619,14 +2620,6 @@ class Declarator {
26192620
return false;
26202621
}
26212622

2622-
/// Return a source range list of C++11 attributes associated
2623-
/// with the declarator.
2624-
void getCXX11AttributeRanges(SmallVectorImpl<SourceRange> &Ranges) {
2625-
for (const ParsedAttr &AL : Attrs)
2626-
if (AL.isCXX11Attribute())
2627-
Ranges.push_back(AL.getRange());
2628-
}
2629-
26302623
void setAsmLabel(Expr *E) { AsmLabel = E; }
26312624
Expr *getAsmLabel() const { return AsmLabel; }
26322625

0 commit comments

Comments
 (0)