Skip to content

Commit 31e3269

Browse files
committed
[Attributes] Support Attributes being declared as only supporting late parsing when passing an experimental feature flag
This patch changes the `LateParsed` field of `Attr` in `Attr.td` to be an instantiation of the new `LateAttrParseKind` class. The instation can be one of the following: * `LateAttrParsingNever` - Corresponds with the false value of `LateParsed` prior to this patch (the default for an attribute). * `LateAttrParsingAlways` - Corresponds with the true value of `LateParsed` prior to this patch. * `LateAttrParsingExperimentalOnly` - A new mode described below. `LateAttrParsingExperimentalOnly` means that the attribute will be late parsed if the new the `ExperimentalLateParseAttributes` language option (also introduced in this patch) is enabled and will **not** be late parsed if the language option is disabled. The new `ExperimentalLateParseAttributes` language option is controlled by a new driver and frontend flag (`-fexperimental-late-parse-attributes`). A driver test is included to check that the driver passes the flag to CC1. In this patch the `LateAttrParsingExperimentalOnly` is not adopted by any attribute so `-fexperimental-late-pase-attributes` and the corresponding language option currently have no effect on compilation. This is why this patch does not include any test cases that test `LateAttrParsingExperimentalOnly`'s behavior. The motivation for this patch is to be able to late parse the new `counted_by` attribute but only do so when a feature flag is passed. This was discussed during the [bounds-safety RFC](https://discourse.llvm.org/t/rfc-enforcing-bounds-safety-in-c-fbounds-safety/70854/68). Adoption of `LateAttrParsingExperimentalOnly` for the `counted_by` attributed will be handled separately in another patch (likely #87596).
1 parent 9bd1085 commit 31e3269

File tree

8 files changed

+193
-37
lines changed

8 files changed

+193
-37
lines changed

clang/include/clang/Basic/Attr.td

Lines changed: 28 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -592,6 +592,16 @@ class AttrSubjectMatcherAggregateRule<AttrSubject subject> {
592592

593593
def SubjectMatcherForNamed : AttrSubjectMatcherAggregateRule<Named>;
594594

595+
// Late Attribute parsing mode enum
596+
class LateAttrParseKind <int val> {
597+
int Kind = val;
598+
}
599+
def LateAttrParseNever : LateAttrParseKind<0>; // Never late parsed
600+
def LateAttrParseAlways: LateAttrParseKind<1>; // Always late parsed
601+
// Late parsed if `-fexperimental-late-parse-attributes` is on and parsed
602+
// normally if off.
603+
def LateAttrParseExperimentalOnly : LateAttrParseKind<2>;
604+
595605
class Attr {
596606
// The various ways in which an attribute can be spelled in source
597607
list<Spelling> Spellings;
@@ -603,8 +613,8 @@ class Attr {
603613
list<Accessor> Accessors = [];
604614
// Specify targets for spellings.
605615
list<TargetSpecificSpelling> TargetSpecificSpellings = [];
606-
// Set to true for attributes with arguments which require delayed parsing.
607-
bit LateParsed = 0;
616+
// Specifies the late parsing kind.
617+
LateAttrParseKind LateParsed = LateAttrParseNever;
608618
// Set to false to prevent an attribute from being propagated from a template
609619
// to the instantiation.
610620
bit Clone = 1;
@@ -3173,7 +3183,7 @@ def DiagnoseIf : InheritableAttr {
31733183
BoolArgument<"ArgDependent", 0, /*fake*/ 1>,
31743184
DeclArgument<Named, "Parent", 0, /*fake*/ 1>];
31753185
let InheritEvenIfAlreadyPresent = 1;
3176-
let LateParsed = 1;
3186+
let LateParsed = LateAttrParseAlways;
31773187
let AdditionalMembers = [{
31783188
bool isError() const { return diagnosticType == DT_Error; }
31793189
bool isWarning() const { return diagnosticType == DT_Warning; }
@@ -3472,7 +3482,7 @@ def AssertCapability : InheritableAttr {
34723482
let Spellings = [Clang<"assert_capability", 0>,
34733483
Clang<"assert_shared_capability", 0>];
34743484
let Subjects = SubjectList<[Function]>;
3475-
let LateParsed = 1;
3485+
let LateParsed = LateAttrParseAlways;
34763486
let TemplateDependent = 1;
34773487
let ParseArgumentsAsUnevaluated = 1;
34783488
let InheritEvenIfAlreadyPresent = 1;
@@ -3488,7 +3498,7 @@ def AcquireCapability : InheritableAttr {
34883498
GNU<"exclusive_lock_function">,
34893499
GNU<"shared_lock_function">];
34903500
let Subjects = SubjectList<[Function]>;
3491-
let LateParsed = 1;
3501+
let LateParsed = LateAttrParseAlways;
34923502
let TemplateDependent = 1;
34933503
let ParseArgumentsAsUnevaluated = 1;
34943504
let InheritEvenIfAlreadyPresent = 1;
@@ -3504,7 +3514,7 @@ def TryAcquireCapability : InheritableAttr {
35043514
Clang<"try_acquire_shared_capability", 0>];
35053515
let Subjects = SubjectList<[Function],
35063516
ErrorDiag>;
3507-
let LateParsed = 1;
3517+
let LateParsed = LateAttrParseAlways;
35083518
let TemplateDependent = 1;
35093519
let ParseArgumentsAsUnevaluated = 1;
35103520
let InheritEvenIfAlreadyPresent = 1;
@@ -3520,7 +3530,7 @@ def ReleaseCapability : InheritableAttr {
35203530
Clang<"release_generic_capability", 0>,
35213531
Clang<"unlock_function", 0>];
35223532
let Subjects = SubjectList<[Function]>;
3523-
let LateParsed = 1;
3533+
let LateParsed = LateAttrParseAlways;
35243534
let TemplateDependent = 1;
35253535
let ParseArgumentsAsUnevaluated = 1;
35263536
let InheritEvenIfAlreadyPresent = 1;
@@ -3539,7 +3549,7 @@ def RequiresCapability : InheritableAttr {
35393549
Clang<"requires_shared_capability", 0>,
35403550
Clang<"shared_locks_required", 0>];
35413551
let Args = [VariadicExprArgument<"Args">];
3542-
let LateParsed = 1;
3552+
let LateParsed = LateAttrParseAlways;
35433553
let TemplateDependent = 1;
35443554
let ParseArgumentsAsUnevaluated = 1;
35453555
let InheritEvenIfAlreadyPresent = 1;
@@ -3559,7 +3569,7 @@ def NoThreadSafetyAnalysis : InheritableAttr {
35593569
def GuardedBy : InheritableAttr {
35603570
let Spellings = [GNU<"guarded_by">];
35613571
let Args = [ExprArgument<"Arg">];
3562-
let LateParsed = 1;
3572+
let LateParsed = LateAttrParseAlways;
35633573
let TemplateDependent = 1;
35643574
let ParseArgumentsAsUnevaluated = 1;
35653575
let InheritEvenIfAlreadyPresent = 1;
@@ -3570,7 +3580,7 @@ def GuardedBy : InheritableAttr {
35703580
def PtGuardedBy : InheritableAttr {
35713581
let Spellings = [GNU<"pt_guarded_by">];
35723582
let Args = [ExprArgument<"Arg">];
3573-
let LateParsed = 1;
3583+
let LateParsed = LateAttrParseAlways;
35743584
let TemplateDependent = 1;
35753585
let ParseArgumentsAsUnevaluated = 1;
35763586
let InheritEvenIfAlreadyPresent = 1;
@@ -3581,7 +3591,7 @@ def PtGuardedBy : InheritableAttr {
35813591
def AcquiredAfter : InheritableAttr {
35823592
let Spellings = [GNU<"acquired_after">];
35833593
let Args = [VariadicExprArgument<"Args">];
3584-
let LateParsed = 1;
3594+
let LateParsed = LateAttrParseAlways;
35853595
let TemplateDependent = 1;
35863596
let ParseArgumentsAsUnevaluated = 1;
35873597
let InheritEvenIfAlreadyPresent = 1;
@@ -3592,7 +3602,7 @@ def AcquiredAfter : InheritableAttr {
35923602
def AcquiredBefore : InheritableAttr {
35933603
let Spellings = [GNU<"acquired_before">];
35943604
let Args = [VariadicExprArgument<"Args">];
3595-
let LateParsed = 1;
3605+
let LateParsed = LateAttrParseAlways;
35963606
let TemplateDependent = 1;
35973607
let ParseArgumentsAsUnevaluated = 1;
35983608
let InheritEvenIfAlreadyPresent = 1;
@@ -3603,7 +3613,7 @@ def AcquiredBefore : InheritableAttr {
36033613
def AssertExclusiveLock : InheritableAttr {
36043614
let Spellings = [GNU<"assert_exclusive_lock">];
36053615
let Args = [VariadicExprArgument<"Args">];
3606-
let LateParsed = 1;
3616+
let LateParsed = LateAttrParseAlways;
36073617
let TemplateDependent = 1;
36083618
let ParseArgumentsAsUnevaluated = 1;
36093619
let InheritEvenIfAlreadyPresent = 1;
@@ -3614,7 +3624,7 @@ def AssertExclusiveLock : InheritableAttr {
36143624
def AssertSharedLock : InheritableAttr {
36153625
let Spellings = [GNU<"assert_shared_lock">];
36163626
let Args = [VariadicExprArgument<"Args">];
3617-
let LateParsed = 1;
3627+
let LateParsed = LateAttrParseAlways;
36183628
let TemplateDependent = 1;
36193629
let ParseArgumentsAsUnevaluated = 1;
36203630
let InheritEvenIfAlreadyPresent = 1;
@@ -3627,7 +3637,7 @@ def AssertSharedLock : InheritableAttr {
36273637
def ExclusiveTrylockFunction : InheritableAttr {
36283638
let Spellings = [GNU<"exclusive_trylock_function">];
36293639
let Args = [ExprArgument<"SuccessValue">, VariadicExprArgument<"Args">];
3630-
let LateParsed = 1;
3640+
let LateParsed = LateAttrParseAlways;
36313641
let TemplateDependent = 1;
36323642
let ParseArgumentsAsUnevaluated = 1;
36333643
let InheritEvenIfAlreadyPresent = 1;
@@ -3640,7 +3650,7 @@ def ExclusiveTrylockFunction : InheritableAttr {
36403650
def SharedTrylockFunction : InheritableAttr {
36413651
let Spellings = [GNU<"shared_trylock_function">];
36423652
let Args = [ExprArgument<"SuccessValue">, VariadicExprArgument<"Args">];
3643-
let LateParsed = 1;
3653+
let LateParsed = LateAttrParseAlways;
36443654
let TemplateDependent = 1;
36453655
let ParseArgumentsAsUnevaluated = 1;
36463656
let InheritEvenIfAlreadyPresent = 1;
@@ -3651,7 +3661,7 @@ def SharedTrylockFunction : InheritableAttr {
36513661
def LockReturned : InheritableAttr {
36523662
let Spellings = [GNU<"lock_returned">];
36533663
let Args = [ExprArgument<"Arg">];
3654-
let LateParsed = 1;
3664+
let LateParsed = LateAttrParseAlways;
36553665
let TemplateDependent = 1;
36563666
let ParseArgumentsAsUnevaluated = 1;
36573667
let Subjects = SubjectList<[Function]>;
@@ -3661,7 +3671,7 @@ def LockReturned : InheritableAttr {
36613671
def LocksExcluded : InheritableAttr {
36623672
let Spellings = [GNU<"locks_excluded">];
36633673
let Args = [VariadicExprArgument<"Args">];
3664-
let LateParsed = 1;
3674+
let LateParsed = LateAttrParseAlways;
36653675
let TemplateDependent = 1;
36663676
let ParseArgumentsAsUnevaluated = 1;
36673677
let InheritEvenIfAlreadyPresent = 1;

clang/include/clang/Basic/LangOptions.def

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -164,6 +164,7 @@ LANGOPT(ExperimentalLibrary, 1, 0, "enable unstable and experimental library fea
164164
LANGOPT(PointerAuthIntrinsics, 1, 0, "pointer authentication intrinsics")
165165

166166
LANGOPT(DoubleSquareBracketAttributes, 1, 0, "'[[]]' attributes extension for all language standard modes")
167+
LANGOPT(ExperimentalLateParseAttributes, 1, 0, "experimental late parsing of attributes")
167168

168169
COMPATIBLE_LANGOPT(RecoveryAST, 1, 1, "Preserve expressions in AST when encountering errors")
169170
COMPATIBLE_LANGOPT(RecoveryASTType, 1, 1, "Preserve the type in recovery expressions")

clang/include/clang/Driver/Options.td

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1603,6 +1603,13 @@ defm double_square_bracket_attributes : BoolFOption<"double-square-bracket-attri
16031603
LangOpts<"DoubleSquareBracketAttributes">, DefaultTrue, PosFlag<SetTrue>,
16041604
NegFlag<SetFalse>>;
16051605

1606+
defm experimental_late_parse_attributes : BoolFOption<"experimental-late-parse-attributes",
1607+
LangOpts<"ExperimentalLateParseAttributes">, DefaultFalse,
1608+
PosFlag<SetTrue, [], [ClangOption], "Enable">,
1609+
NegFlag<SetFalse, [], [ClangOption], "Disable">,
1610+
BothFlags<[], [ClangOption, CC1Option],
1611+
" experimental late parsing of attributes">>;
1612+
16061613
defm autolink : BoolFOption<"autolink",
16071614
CodeGenOpts<"Autolink">, DefaultTrue,
16081615
NegFlag<SetFalse, [], [ClangOption, CC1Option],

clang/include/clang/Parse/Parser.h

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2959,6 +2959,10 @@ class Parser : public CodeCompletionHandler {
29592959
SourceLocation AttrNameLoc,
29602960
SourceLocation *EndLoc);
29612961

2962+
/// isAttributeLateParsed - Return true if the attribute has arguments that
2963+
/// require late parsing.
2964+
bool isAttributeLateParsed(const IdentifierInfo &II);
2965+
29622966
IdentifierInfo *TryParseCXX11AttributeIdentifier(
29632967
SourceLocation &Loc,
29642968
Sema::AttributeCompletion Completion = Sema::AttributeCompletion::None,

clang/lib/Driver/ToolChains/Clang.cpp

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7480,6 +7480,9 @@ void Clang::ConstructJob(Compilation &C, const JobAction &JA,
74807480
Args.addOptInFlag(CmdArgs, options::OPT_fsafe_buffer_usage_suggestions,
74817481
options::OPT_fno_safe_buffer_usage_suggestions);
74827482

7483+
Args.addOptInFlag(CmdArgs, options::OPT_fexperimental_late_parse_attributes,
7484+
options::OPT_fno_experimental_late_parse_attributes);
7485+
74837486
// Setup statistics file output.
74847487
SmallString<128> StatsFile = getStatsFileName(Args, Output, Input, D);
74857488
if (!StatsFile.empty()) {

clang/lib/Parse/ParseDecl.cpp

Lines changed: 16 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -91,11 +91,24 @@ static StringRef normalizeAttrName(StringRef Name) {
9191

9292
/// isAttributeLateParsed - Return true if the attribute has arguments that
9393
/// require late parsing.
94-
static bool isAttributeLateParsed(const IdentifierInfo &II) {
94+
bool Parser::isAttributeLateParsed(const IdentifierInfo &II) {
95+
// Some attributes might only be late parsed when in the experimental
96+
// language mode.
97+
if (getLangOpts().ExperimentalLateParseAttributes) {
98+
#define CLANG_ATTR_LATE_PARSED_EXPERIMENTAL_LIST
99+
bool IsExperimentalLateParseAttr =
100+
llvm::StringSwitch<bool>(normalizeAttrName(II.getName()))
101+
#include "clang/Parse/AttrParserStringSwitches.inc"
102+
.Default(false);
103+
#undef CLANG_ATTR_LATE_PARSED_EXPERIMENTAL_LIST
104+
if (IsExperimentalLateParseAttr)
105+
return true;
106+
}
107+
95108
#define CLANG_ATTR_LATE_PARSED_LIST
96-
return llvm::StringSwitch<bool>(normalizeAttrName(II.getName()))
109+
return llvm::StringSwitch<bool>(normalizeAttrName(II.getName()))
97110
#include "clang/Parse/AttrParserStringSwitches.inc"
98-
.Default(false);
111+
.Default(false);
99112
#undef CLANG_ATTR_LATE_PARSED_LIST
100113
}
101114

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,12 @@
1+
// RUN: %clang %s -c -fexperimental-late-parse-attributes 2>&1 -### | FileCheck %s -check-prefix=CHECK-ON
2+
// RUN: %clang %s -c -fno-experimental-late-parse-attributes -fexperimental-late-parse-attributes 2>&1 -### | FileCheck %s -check-prefix=CHECK-ON
3+
4+
// CHECK-ON: -cc1
5+
// CHECK-ON: -fexperimental-late-parse-attributes
6+
7+
// RUN: %clang %s -c 2>&1 -### | FileCheck %s -check-prefix=CHECK-OFF
8+
// RUN: %clang %s -c -fno-experimental-late-parse-attributes 2>&1 -### | FileCheck %s -check-prefix=CHECK-OFF
9+
// RUN: %clang %s -c -fexperimental-late-parse-attributes -fno-experimental-late-parse-attributes 2>&1 -### | FileCheck %s -check-prefix=CHECK-OFF
10+
11+
// CHECK-OFF: -cc1
12+
// CHECK-OFF-NOT: -fexperimental-late-parse-attributes

0 commit comments

Comments
 (0)