Skip to content

Commit ef0f355

Browse files
committed
[Clang] restrict use of attribute names reserved by the C++ standard
1 parent 6e14f9b commit ef0f355

File tree

13 files changed

+115
-22
lines changed

13 files changed

+115
-22
lines changed

clang/docs/ReleaseNotes.rst

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -788,6 +788,8 @@ Improvements to Clang's diagnostics
788788
require(scope); // Warning! Requires mu1.
789789
}
790790

791+
- Clang now diagnoses the use of attribute names reserved by the C++ standard (#GH92196).
792+
791793
Improvements to Clang's time-trace
792794
----------------------------------
793795

clang/include/clang/Basic/AttributeCommonInfo.h

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -61,7 +61,7 @@ class AttributeCommonInfo {
6161
};
6262
enum Kind {
6363
#define PARSED_ATTR(NAME) AT_##NAME,
64-
#include "clang/Sema/AttrParsedAttrList.inc"
64+
#include "clang/Basic/AttrParsedAttrList.inc"
6565
#undef PARSED_ATTR
6666
NoSemaHandlerAttribute,
6767
IgnoredAttribute,

clang/include/clang/Basic/CMakeLists.txt

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -31,6 +31,11 @@ clang_tablegen(AttrList.inc -gen-clang-attr-list
3131
SOURCE Attr.td
3232
TARGET ClangAttrList)
3333

34+
clang_tablegen(AttrParsedAttrList.inc -gen-clang-attr-parsed-attr-list
35+
-I ${CMAKE_CURRENT_SOURCE_DIR}/../../
36+
SOURCE Attr.td
37+
TARGET ClangAttrParsedAttrList)
38+
3439
clang_tablegen(AttrSubMatchRulesList.inc -gen-clang-attr-subject-match-rule-list
3540
-I ${CMAKE_CURRENT_SOURCE_DIR}/../../
3641
SOURCE Attr.td

clang/include/clang/Basic/DiagnosticGroups.td

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -760,6 +760,7 @@ def AmbiguousMacro : DiagGroup<"ambiguous-macro">;
760760
def KeywordAsMacro : DiagGroup<"keyword-macro">;
761761
def ReservedIdAsMacro : DiagGroup<"reserved-macro-identifier">;
762762
def ReservedIdAsMacroAlias : DiagGroup<"reserved-id-macro", [ReservedIdAsMacro]>;
763+
def ReservedAttributeIdentifier : DiagGroup<"reserved-attribute-identifier">;
763764
def RestrictExpansionMacro : DiagGroup<"restrict-expansion">;
764765
def FinalMacro : DiagGroup<"final-macro">;
765766

clang/include/clang/Basic/DiagnosticLexKinds.td

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -407,6 +407,8 @@ def warn_pp_macro_hides_keyword : Extension<
407407
def warn_pp_macro_is_reserved_id : Warning<
408408
"macro name is a reserved identifier">, DefaultIgnore,
409409
InGroup<ReservedIdAsMacro>;
410+
def warn_pp_macro_is_reserved_attribute_id : Warning<
411+
"%0 is a reserved attribute identifier">, InGroup<ReservedAttributeIdentifier>;
410412
def warn_pp_objc_macro_redef_ignored : Warning<
411413
"ignoring redefinition of Objective-C qualifier macro">,
412414
InGroup<DiagGroup<"objc-macro-redefinition">>;

clang/include/clang/Lex/Preprocessor.h

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -2271,6 +2271,11 @@ class Preprocessor {
22712271
}
22722272
}
22732273

2274+
/// Determine whether the next preprocessor token to be
2275+
/// lexed is a '('. If so, consume the token and return true, if not, this
2276+
/// method should have no observable side-effect on the lexed tokens.
2277+
bool isNextPPTokenLParen();
2278+
22742279
private:
22752280
/// Identifiers used for SEH handling in Borland. These are only
22762281
/// allowed in particular circumstances
@@ -2648,11 +2653,6 @@ class Preprocessor {
26482653

26492654
void removeCachedMacroExpandedTokensOfLastLexer();
26502655

2651-
/// Determine whether the next preprocessor token to be
2652-
/// lexed is a '('. If so, consume the token and return true, if not, this
2653-
/// method should have no observable side-effect on the lexed tokens.
2654-
bool isNextPPTokenLParen();
2655-
26562656
/// After reading "MACRO(", this method is invoked to read all of the formal
26572657
/// arguments specified for the macro invocation. Returns null on error.
26582658
MacroArgs *ReadMacroCallArgumentList(Token &MacroName, MacroInfo *MI,

clang/include/clang/Sema/CMakeLists.txt

Lines changed: 0 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -3,11 +3,6 @@ clang_tablegen(AttrTemplateInstantiate.inc -gen-clang-attr-template-instantiate
33
SOURCE ../Basic/Attr.td
44
TARGET ClangAttrTemplateInstantiate)
55

6-
clang_tablegen(AttrParsedAttrList.inc -gen-clang-attr-parsed-attr-list
7-
-I ${CMAKE_CURRENT_SOURCE_DIR}/../../
8-
SOURCE ../Basic/Attr.td
9-
TARGET ClangAttrParsedAttrList)
10-
116
clang_tablegen(AttrParsedAttrKinds.inc -gen-clang-attr-parsed-attr-kinds
127
-I ${CMAKE_CURRENT_SOURCE_DIR}/../../
138
SOURCE ../Basic/Attr.td

clang/lib/Lex/PPDirectives.cpp

Lines changed: 25 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,8 @@
1111
///
1212
//===----------------------------------------------------------------------===//
1313

14+
#include "clang/Basic/AttributeCommonInfo.h"
15+
#include "clang/Basic/Attributes.h"
1416
#include "clang/Basic/CharInfo.h"
1517
#include "clang/Basic/DirectoryEntry.h"
1618
#include "clang/Basic/FileManager.h"
@@ -97,7 +99,8 @@ SourceRange Preprocessor::DiscardUntilEndOfDirective(Token &Tmp) {
9799
enum MacroDiag {
98100
MD_NoWarn, //> Not a reserved identifier
99101
MD_KeywordDef, //> Macro hides keyword, enabled by default
100-
MD_ReservedMacro //> #define of #undef reserved id, disabled by default
102+
MD_ReservedMacro, //> #define of #undef reserved id, disabled by default
103+
MD_ReservedAttributeIdentifier
101104
};
102105

103106
/// Enumerates possible %select values for the pp_err_elif_after_else and
@@ -173,6 +176,20 @@ static bool isLanguageDefinedBuiltin(const SourceManager &SourceMgr,
173176
return false;
174177
}
175178

179+
static bool isReservedCXXAttributeName(Preprocessor &PP, IdentifierInfo *II) {
180+
const LangOptions &Lang = PP.getLangOpts();
181+
if (Lang.CPlusPlus &&
182+
hasAttribute(AttributeCommonInfo::Syntax::AS_CXX11, /*Scope*/ nullptr, II,
183+
PP.getTargetInfo(), Lang) > 0) {
184+
AttributeCommonInfo::Kind AttrKind = AttributeCommonInfo::getParsedKind(
185+
II, /*Scope*/ nullptr, AttributeCommonInfo::Syntax::AS_CXX11);
186+
return !((AttrKind == AttributeCommonInfo::Kind::AT_Likely ||
187+
AttrKind == AttributeCommonInfo::Kind::AT_Unlikely) &&
188+
PP.isNextPPTokenLParen());
189+
}
190+
return false;
191+
}
192+
176193
static MacroDiag shouldWarnOnMacroDef(Preprocessor &PP, IdentifierInfo *II) {
177194
const LangOptions &Lang = PP.getLangOpts();
178195
StringRef Text = II->getName();
@@ -182,6 +199,8 @@ static MacroDiag shouldWarnOnMacroDef(Preprocessor &PP, IdentifierInfo *II) {
182199
return MD_KeywordDef;
183200
if (Lang.CPlusPlus11 && (Text == "override" || Text == "final"))
184201
return MD_KeywordDef;
202+
if (isReservedCXXAttributeName(PP, II))
203+
return MD_ReservedAttributeIdentifier;
185204
return MD_NoWarn;
186205
}
187206

@@ -190,6 +209,8 @@ static MacroDiag shouldWarnOnMacroUndef(Preprocessor &PP, IdentifierInfo *II) {
190209
// Do not warn on keyword undef. It is generally harmless and widely used.
191210
if (isReservedInAllContexts(II->isReserved(Lang)))
192211
return MD_ReservedMacro;
212+
if (isReservedCXXAttributeName(PP, II))
213+
return MD_ReservedAttributeIdentifier;
193214
return MD_NoWarn;
194215
}
195216

@@ -365,6 +386,9 @@ bool Preprocessor::CheckMacroName(Token &MacroNameTok, MacroUse isDefineUndef,
365386
}
366387
if (D == MD_ReservedMacro)
367388
Diag(MacroNameTok, diag::warn_pp_macro_is_reserved_id);
389+
if (D == MD_ReservedAttributeIdentifier)
390+
Diag(MacroNameTok, diag::warn_pp_macro_is_reserved_attribute_id)
391+
<< II->getName();
368392
}
369393

370394
// Okay, we got a good identifier.
Lines changed: 34 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,34 @@
1+
// RUN: %clang_cc1 -std=c++11 -fsyntax-only -verify -pedantic %s
2+
3+
#define noreturn 1 // expected-warning {{noreturn is a reserved attribute identifier}}
4+
#undef noreturn // expected-warning {{noreturn is a reserved attribute identifier}}
5+
6+
#define assume 1 // expected-warning {{assume is a reserved attribute identifier}}
7+
#undef assume // expected-warning {{assume is a reserved attribute identifier}}
8+
9+
#define carries_dependency 1 // expected-warning {{carries_dependency is a reserved attribute identifier}}
10+
#undef carries_dependency // expected-warning {{carries_dependency is a reserved attribute identifier}}
11+
12+
#define deprecated 1 // expected-warning {{deprecated is a reserved attribute identifier}}
13+
#undef deprecated // expected-warning {{deprecated is a reserved attribute identifier}}
14+
15+
#define fallthrough 1 // expected-warning {{fallthrough is a reserved attribute identifier}}
16+
#undef fallthrough // expected-warning {{fallthrough is a reserved attribute identifier}}
17+
18+
#define likely 1 // expected-warning {{likely is a reserved attribute identifier}}
19+
#undef likely // expected-warning {{likely is a reserved attribute identifier}}
20+
21+
#define no_unique_address 1 // expected-warning {{no_unique_address is a reserved attribute identifier}}
22+
#undef no_unique_address // expected-warning {{no_unique_address is a reserved attribute identifier}}
23+
24+
#define unlikely 1 // expected-warning {{unlikely is a reserved attribute identifier}}
25+
#undef unlikely // expected-warning {{unlikely is a reserved attribute identifier}}
26+
27+
#define maybe_unused 1 // expected-warning {{maybe_unused is a reserved attribute identifier}}
28+
#undef maybe_unused // expected-warning {{maybe_unused is a reserved attribute identifier}}
29+
30+
#define nodiscard 1 // expected-warning {{nodiscard is a reserved attribute identifier}}
31+
#undef nodiscard // expected-warning {{nodiscard is a reserved attribute identifier}}
32+
33+
#define likely() 1 // ok
34+
#define unlikely() 1 // ok
Lines changed: 34 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,34 @@
1+
// RUN: %clang_cc1 -std=c++11 -fsyntax-only -verify -pedantic %s
2+
3+
#define noreturn // expected-warning {{noreturn is a reserved attribute identifier}}
4+
#undef noreturn // expected-warning {{noreturn is a reserved attribute identifier}}
5+
6+
#define assume // expected-warning {{assume is a reserved attribute identifier}}
7+
#undef assume // expected-warning {{assume is a reserved attribute identifier}}
8+
9+
#define carries_dependency // expected-warning {{carries_dependency is a reserved attribute identifier}}
10+
#undef carries_dependency // expected-warning {{carries_dependency is a reserved attribute identifier}}
11+
12+
#define deprecated // expected-warning {{deprecated is a reserved attribute identifier}}
13+
#undef deprecated // expected-warning {{deprecated is a reserved attribute identifier}}
14+
15+
#define fallthrough // expected-warning {{fallthrough is a reserved attribute identifier}}
16+
#undef fallthrough // expected-warning {{fallthrough is a reserved attribute identifier}}
17+
18+
#define likely // expected-warning {{likely is a reserved attribute identifier}}
19+
#undef likely // expected-warning {{likely is a reserved attribute identifier}}
20+
21+
#define no_unique_address // expected-warning {{no_unique_address is a reserved attribute identifier}}
22+
#undef no_unique_address // expected-warning {{no_unique_address is a reserved attribute identifier}}
23+
24+
#define unlikely // expected-warning {{unlikely is a reserved attribute identifier}}
25+
#undef unlikely // expected-warning {{unlikely is a reserved attribute identifier}}
26+
27+
#define maybe_unused // expected-warning {{maybe_unused is a reserved attribute identifier}}
28+
#undef maybe_unused // expected-warning {{maybe_unused is a reserved attribute identifier}}
29+
30+
#define nodiscard // expected-warning {{nodiscard is a reserved attribute identifier}}
31+
#undef nodiscard // expected-warning {{nodiscard is a reserved attribute identifier}}
32+
33+
#define likely() // ok
34+
#define unlikely() // ok

0 commit comments

Comments
 (0)