@@ -2078,62 +2078,37 @@ Parser::parseDocumentationAttribute(SourceLoc AtLoc, SourceLoc Loc) {
2078
2078
return makeParserResult (new (Context) DocumentationAttr (Loc, range, FinalMetadata, Visibility, false ));
2079
2079
}
2080
2080
2081
- enum class SingleAttrOptionParseStatus : uint8_t {
2082
- Success,
2083
- ExpectedLParen,
2084
- ExpectedIdentifier,
2085
- ExpectedRParen
2086
- };
2087
-
2088
- void diagnoseSingleAttrOptionParseStatus (
2089
- Parser &P, SingleAttrOptionParseStatus status,
2090
- SourceLoc Loc, StringRef AttrName,
2091
- DeclAttrKind DK, Diagnostic nonIdentifierDiagnostic) {
2092
- bool isDeclModifier = DeclAttribute::isDeclModifier (DK);
2093
-
2094
- switch (status) {
2095
- case SingleAttrOptionParseStatus::Success:
2096
- break ;
2097
-
2098
- case SingleAttrOptionParseStatus::ExpectedLParen:
2099
- P.diagnose (Loc, diag::attr_expected_lparen, AttrName, isDeclModifier);
2100
- break ;
2101
-
2102
- case SingleAttrOptionParseStatus::ExpectedIdentifier:
2103
- P.diagnose (Loc, nonIdentifierDiagnostic);
2104
- break ;
2105
-
2106
- case SingleAttrOptionParseStatus::ExpectedRParen:
2107
- P.diagnose (Loc, diag::attr_expected_rparen, AttrName, isDeclModifier);
2108
- break ;
2109
- }
2110
- }
2111
-
2112
- // / Parses an attribute argument list that allows a single identifier with a
2113
- // / known set of permitted options:
2081
+ // / Guts of \c parseSingleAttrOption and \c parseSingleAttrOptionIdentifier.
2114
2082
// /
2115
- // / \verbatim
2116
- // / '(' identifier ')'
2117
- // / \endverbatim
2083
+ // / \param P The parser object.
2084
+ // / \param Loc The location of the attribute name (before the \c tok::l_paren, if any).
2085
+ // / \param AttrRange Will be set to the range of the entire attribute, including its option if any.
2086
+ // / \param AttrName The spelling of the attribute in the source code. Used in diagnostics.
2087
+ // / \param DK The kind of the attribute being parsed.
2088
+ // / \param allowOmitted If true, treat a missing argument list as permitted and return
2089
+ // / \c Identifier() ; if false, diagnose a missing argument list as an error.
2090
+ // / \param nonIdentifierDiagnostic The diagnostic to emit if something other than a
2091
+ // / \c tok::identifier is used as an argument.
2118
2092
// /
2119
- // / Returns an object of type \c AttrOptionSwitch, a type loosely inspired by
2120
- // / \c llvm::StringSwitch which can be used in a fluent style to map each
2121
- // / permitted identifier to a value. Together, they will automatically
2122
- // / diagnose \c diag::attr_expected_lparen,
2123
- // / \c diag::attr_expected_option_such_as, \c diag::attr_unknown_option, and
2124
- // / \c diag::attr_expected_rparen when needed.
2125
- // /
2126
- // / \seealso AttrOptionSwitch
2127
- static SingleAttrOptionParseStatus
2093
+ // / \returns \c None if an error was diagnosed; \c Identifier() if the argument list was permissibly
2094
+ // / omitted; the identifier written by the user otherwise.
2095
+ static Optional<Identifier>
2128
2096
parseSingleAttrOptionImpl (Parser &P, SourceLoc Loc, SourceRange &AttrRange,
2129
- DeclAttrKind DK, StringRef &Result) {
2130
- Result = " " ;
2097
+ StringRef AttrName, DeclAttrKind DK,
2098
+ bool allowOmitted,
2099
+ Diagnostic nonIdentifierDiagnostic) {
2131
2100
SWIFT_DEFER {
2132
2101
AttrRange = SourceRange (Loc, P.PreviousLoc );
2133
2102
};
2134
-
2135
- if (!P.Tok .is (tok::l_paren))
2136
- return SingleAttrOptionParseStatus::ExpectedLParen;
2103
+ bool isDeclModifier = DeclAttribute::isDeclModifier (DK);
2104
+
2105
+ if (!P.Tok .is (tok::l_paren)) {
2106
+ if (allowOmitted)
2107
+ return Identifier ();
2108
+
2109
+ P.diagnose (Loc, diag::attr_expected_lparen, AttrName, isDeclModifier);
2110
+ return None;
2111
+ }
2137
2112
2138
2113
llvm::Optional<SyntaxParsingContext> ModDetailContext;
2139
2114
if (DK == DAK_ReferenceOwnership) {
@@ -2143,147 +2118,78 @@ parseSingleAttrOptionImpl(Parser &P, SourceLoc Loc, SourceRange &AttrRange,
2143
2118
P.consumeToken (tok::l_paren);
2144
2119
2145
2120
StringRef parsedName = P.Tok .getText ();
2146
- if (!P.consumeIf (tok::identifier))
2147
- return SingleAttrOptionParseStatus::ExpectedIdentifier;
2121
+ if (!P.consumeIf (tok::identifier)) {
2122
+ P.diagnose (Loc, nonIdentifierDiagnostic);
2123
+ return None;
2124
+ }
2148
2125
2149
- if (!P.consumeIf (tok::r_paren))
2150
- return SingleAttrOptionParseStatus::ExpectedRParen;
2151
-
2152
- Result = parsedName;
2153
- return SingleAttrOptionParseStatus::Success;
2154
- }
2155
-
2156
- // / Processes a parsed option name by attempting to match it to a list of
2157
- // / alternative name/value pairs provided by a chain of \c when() calls, ending
2158
- // / in either \c whenOmitted() if omitting the option is allowed, or
2159
- // / \c diagnoseWhenOmitted() if the option is mandatory.
2160
- template <typename T, typename R = T>
2161
- class LLVM_NODISCARD AttrOptionSwitch {
2162
- // Inputs:
2163
- StringRef parsedName; // empty: omitted or parse error
2164
- Parser &P;
2165
- SourceLoc loc;
2166
- StringRef attrName;
2167
- SingleAttrOptionParseStatus parseStatus;
2168
- DeclAttrKind attrKind;
2169
-
2170
- // State:
2171
- StringRef exampleName; // empty: when() was never called
2172
- Optional<R> result; // None: no when() has matched
2173
-
2174
- public:
2175
- // / \param parseStatus The status of the option parse (whether it succeeded or expeienced
2176
- // / some error). If
2177
- // / \param parsedName The name of the option parsed out of the source code. If \p parseStatus is
2178
- // / an error, this should be empty.
2179
- // / \param P The parser used to diagnose errors concerning this attribute
2180
- // / option.
2181
- // / \param loc The source location to diagnose errors at.
2182
- // / \param attrName The name of the attribute, used in diagnostics.
2183
- // / \param attrKind The kind of the attribute, used in diagnostics.
2184
- AttrOptionSwitch (SingleAttrOptionParseStatus parseStatus,
2185
- StringRef parsedName, Parser &P, SourceLoc loc,
2186
- StringRef attrName, DeclAttrKind attrKind)
2187
- : parsedName(parsedName), P(P), loc(loc), attrName(attrName),
2188
- parseStatus (parseStatus), attrKind(attrKind) { }
2189
-
2190
- // / If the option has the identifier \p name, give it value \p value.
2191
- AttrOptionSwitch<R, T> &when (StringLiteral name, T value) {
2192
- // Save this to use in a future diagnostic, if needed.
2193
- if (exampleName.empty () && !name.empty ())
2194
- exampleName = name;
2195
-
2196
- // Does this string match?
2197
- if (parseStatus == SingleAttrOptionParseStatus::Success
2198
- && parsedName == name) {
2199
- assert (!result && " overlapping AttrOptionSwitch::when()s?" );
2200
- result = std::move (value);
2201
- }
2202
-
2203
- return *this ;
2204
- }
2205
-
2206
- // / Diagnose if the option is missing or was not matched, returning either the
2207
- // / option's value or \c None if an error was diagnosed.
2208
- Optional<R> diagnoseWhenOmitted () {
2209
- assert (!exampleName.empty () && " No AttrOptionSwitch::when() calls" );
2210
-
2211
- if (parseStatus != SingleAttrOptionParseStatus::Success) {
2212
- // Any sort of parse error (other than an ExpectedLParen permitted by
2213
- // whenOmitted().)
2214
- diagnoseSingleAttrOptionParseStatus (
2215
- P, parseStatus, loc, attrName, attrKind,
2216
- { diag::attr_expected_option_such_as, attrName, exampleName });
2217
- }
2218
- else if (!result)
2219
- // We parsed an identifier, but it didn't match any of the when() calls.
2220
- P.diagnose (loc, diag::attr_unknown_option, parsedName, attrName);
2221
-
2222
- return result;
2126
+ if (!P.consumeIf (tok::r_paren)) {
2127
+ P.diagnose (Loc, diag::attr_expected_rparen, AttrName, isDeclModifier);
2128
+ return None;
2223
2129
}
2224
2130
2225
- // / Diagnose if the option is missing or not matched, returning:
2226
- // /
2227
- // / \returns \c None if an error was diagnosed; \p value if the option was
2228
- // / omitted; the value the option was matched to otherwise.
2229
- Optional<R> whenOmitted (T value) {
2230
- // Treat an ExpectedLParen as successful.
2231
- if (parseStatus == SingleAttrOptionParseStatus::ExpectedLParen)
2232
- parseStatus = SingleAttrOptionParseStatus::Success;
2233
-
2234
- return when (" " , value).diagnoseWhenOmitted ();
2235
- }
2236
- };
2131
+ return P.Context .getIdentifier (parsedName);
2132
+ }
2237
2133
2238
- // / Parses an attribute argument list that allows a single identifier with a
2239
- // / known set of permitted options:
2134
+ // / Parses a (possibly optional) argument for an attribute containing a single, arbitrary identifier.
2240
2135
// /
2241
- // / \verbatim
2242
- // / '(' identifier ')'
2243
- // / \endverbatim
2244
- // /
2245
- // / Returns an object of type \c AttrOptionSwitch, a type loosely inspired by
2246
- // / \c llvm::StringSwitch which can be used in a fluent style to map each
2247
- // / permitted identifier to a value. Together, they will automatically
2248
- // / diagnose \c diag::attr_expected_lparen,
2249
- // / \c diag::attr_expected_option_such_as, \c diag::attr_unknown_option, and
2250
- // / \c diag::attr_expected_rparen when needed.
2136
+ // / \param P The parser object.
2137
+ // / \param Loc The location of the attribute name (before the \c tok::l_paren, if any).
2138
+ // / \param AttrRange Will be set to the range of the entire attribute, including its option if any.
2139
+ // / \param AttrName The spelling of the attribute in the source code. Used in diagnostics.
2140
+ // / \param DK The kind of the attribute being parsed.
2141
+ // / \param allowOmitted If true, treat a missing argument list as permitted and return
2142
+ // / \c Identifier() ; if false, diagnose a missing argument list as an error.
2251
2143
// /
2252
- // / \seealso AttrOptionSwitch
2253
- template <typename R>
2254
- static AttrOptionSwitch<R>
2255
- parseSingleAttrOption (Parser &P, SourceLoc Loc, SourceRange &AttrRange,
2256
- StringRef AttrName, DeclAttrKind DK) {
2257
- StringRef parsedName;
2258
- auto status = parseSingleAttrOptionImpl (P, Loc, AttrRange, DK, parsedName);
2259
- return AttrOptionSwitch<R>(status, parsedName, P, Loc, AttrName, DK);
2260
- }
2261
-
2144
+ // / \returns \c None if an error was diagnosed; \c Identifier() if the argument list was permissibly
2145
+ // / omitted; the identifier written by the user otherwise.
2262
2146
static Optional<Identifier>
2263
2147
parseSingleAttrOptionIdentifier (Parser &P, SourceLoc Loc,
2264
2148
SourceRange &AttrRange, StringRef AttrName,
2265
2149
DeclAttrKind DK, bool allowOmitted = false ) {
2266
- StringRef parsedName;
2267
- auto status = parseSingleAttrOptionImpl (P, Loc, AttrRange, DK, parsedName);
2268
-
2269
- switch (status) {
2270
- case SingleAttrOptionParseStatus::Success:
2271
- break ;
2272
-
2273
- case SingleAttrOptionParseStatus::ExpectedLParen:
2274
- if (allowOmitted)
2275
- break ;
2276
- LLVM_FALLTHROUGH;
2277
-
2278
- case SingleAttrOptionParseStatus::ExpectedRParen:
2279
- case SingleAttrOptionParseStatus::ExpectedIdentifier:
2280
- diagnoseSingleAttrOptionParseStatus (
2281
- P, status, Loc, AttrName, DK,
2282
- { diag::attr_expected_option_identifier, AttrName });
2150
+ return parseSingleAttrOptionImpl (
2151
+ P, Loc, AttrRange, AttrName, DK, allowOmitted,
2152
+ { diag::attr_expected_option_identifier, AttrName });
2153
+ }
2154
+
2155
+ // / Parses a (possibly optional) argument for an attribute containing a single identifier from a known set of
2156
+ // / supported values, mapping it to a domain-specific type.
2157
+ // /
2158
+ // / \param P The parser object.
2159
+ // / \param Loc The location of the attribute name (before the \c tok::l_paren, if any).
2160
+ // / \param AttrRange Will be set to the range of the entire attribute, including its option if any.
2161
+ // / \param AttrName The spelling of the attribute in the source code. Used in diagnostics.
2162
+ // / \param DK The kind of the attribute being parsed.
2163
+ // / \param options The set of permitted keywords and their corresponding values.
2164
+ // / \param valueIfOmitted If present, treat a missing argument list as permitted and return
2165
+ // / the provided value; if absent, diagnose a missing argument list as an error.
2166
+ // /
2167
+ // / \returns \c None if an error was diagnosed; the value corresponding to the identifier written by the
2168
+ // / user otherwise.
2169
+ template <typename R>
2170
+ static Optional<R>
2171
+ parseSingleAttrOption (Parser &P, SourceLoc Loc, SourceRange &AttrRange,
2172
+ StringRef AttrName, DeclAttrKind DK,
2173
+ ArrayRef<std::tuple<Identifier, R>> options,
2174
+ Optional<R> valueIfOmitted = None) {
2175
+ auto parsedIdentifier = parseSingleAttrOptionImpl (
2176
+ P, Loc, AttrRange,AttrName, DK,
2177
+ /* allowOmitted=*/ valueIfOmitted.hasValue (),
2178
+ Diagnostic (diag::attr_expected_option_such_as, AttrName,
2179
+ std::get<0 >(options.front ()).str ()));
2180
+ if (!parsedIdentifier)
2283
2181
return None;
2284
- }
2285
2182
2286
- return P.Context .getIdentifier (parsedName);
2183
+ // If omitted (and omission is permitted), return valueIfOmitted.
2184
+ if (parsedIdentifier == Identifier ())
2185
+ return *valueIfOmitted;
2186
+
2187
+ for (auto &option : options)
2188
+ if (std::get<0 >(option) == *parsedIdentifier)
2189
+ return std::get<1 >(option);
2190
+
2191
+ P.diagnose (Loc, diag::attr_unknown_option, parsedIdentifier->str (), AttrName);
2192
+ return None;
2287
2193
}
2288
2194
2289
2195
bool Parser::parseNewDeclAttribute (DeclAttributes &Attributes, SourceLoc AtLoc,
@@ -2418,11 +2324,11 @@ bool Parser::parseNewDeclAttribute(DeclAttributes &Attributes, SourceLoc AtLoc,
2418
2324
}
2419
2325
2420
2326
case DAK_Inline: {
2421
- auto kind = parseSingleAttrOption<InlineKind>
2422
- ( *this , Loc, AttrRange, AttrName, DK)
2423
- . when ( " never " , InlineKind::Never)
2424
- . when ( " __always " , InlineKind::Always)
2425
- . diagnoseWhenOmitted ( );
2327
+ auto kind = parseSingleAttrOption<InlineKind>(
2328
+ *this , Loc, AttrRange, AttrName, DK, {
2329
+ { Context. Id_never , InlineKind::Never },
2330
+ { Context. Id__always , InlineKind::Always }
2331
+ } );
2426
2332
if (!kind)
2427
2333
return false ;
2428
2334
@@ -2433,12 +2339,12 @@ bool Parser::parseNewDeclAttribute(DeclAttributes &Attributes, SourceLoc AtLoc,
2433
2339
}
2434
2340
2435
2341
case DAK_Optimize: {
2436
- auto optMode = parseSingleAttrOption<OptimizationMode>
2437
- ( *this , Loc, AttrRange, AttrName, DK)
2438
- . when ( " speed " , OptimizationMode::ForSpeed)
2439
- . when ( " size " , OptimizationMode::ForSize)
2440
- . when ( " none " , OptimizationMode::NoOptimization)
2441
- . diagnoseWhenOmitted ( );
2342
+ auto optMode = parseSingleAttrOption<OptimizationMode>(
2343
+ *this , Loc, AttrRange, AttrName, DK, {
2344
+ { Context. Id_speed , OptimizationMode::ForSpeed },
2345
+ { Context. Id_size , OptimizationMode::ForSize },
2346
+ { Context. Id_none , OptimizationMode::NoOptimization }
2347
+ } );
2442
2348
if (!optMode)
2443
2349
return false ;
2444
2350
@@ -2449,11 +2355,11 @@ bool Parser::parseNewDeclAttribute(DeclAttributes &Attributes, SourceLoc AtLoc,
2449
2355
}
2450
2356
2451
2357
case DAK_Exclusivity: {
2452
- auto mode = parseSingleAttrOption<ExclusivityAttr::Mode>
2453
- ( *this , Loc, AttrRange, AttrName, DK)
2454
- . when ( " checked " , ExclusivityAttr::Mode::Checked)
2455
- . when ( " unchecked " , ExclusivityAttr::Mode::Unchecked)
2456
- . diagnoseWhenOmitted ( );
2358
+ auto mode = parseSingleAttrOption<ExclusivityAttr::Mode>(
2359
+ *this , Loc, AttrRange, AttrName, DK, {
2360
+ { Context. Id_checked , ExclusivityAttr::Mode::Checked },
2361
+ { Context. Id_unchecked , ExclusivityAttr::Mode::Unchecked }
2362
+ } );
2457
2363
if (!mode)
2458
2364
return false ;
2459
2365
@@ -2470,11 +2376,11 @@ bool Parser::parseNewDeclAttribute(DeclAttributes &Attributes, SourceLoc AtLoc,
2470
2376
2471
2377
if (Kind == ReferenceOwnership::Unowned) {
2472
2378
// Parse an optional specifier after unowned.
2473
- Kind = parseSingleAttrOption<ReferenceOwnership>
2474
- ( *this , Loc, AttrRange, AttrName, DK)
2475
- . when ( " unsafe " , ReferenceOwnership::Unmanaged)
2476
- . when ( " safe " , ReferenceOwnership::Unowned)
2477
- . whenOmitted ( ReferenceOwnership::Unowned)
2379
+ Kind = parseSingleAttrOption<ReferenceOwnership>(
2380
+ *this , Loc, AttrRange, AttrName, DK, {
2381
+ { Context. Id_unsafe , ReferenceOwnership::Unmanaged },
2382
+ { Context. Id_safe , ReferenceOwnership::Unowned }
2383
+ }, ReferenceOwnership::Unowned)
2478
2384
// Recover from errors by going back to Unowned.
2479
2385
.getValueOr (ReferenceOwnership::Unowned);
2480
2386
}
@@ -2490,10 +2396,10 @@ bool Parser::parseNewDeclAttribute(DeclAttributes &Attributes, SourceLoc AtLoc,
2490
2396
}
2491
2397
2492
2398
case DAK_NonSendable: {
2493
- auto kind = parseSingleAttrOption<NonSendableKind>
2494
- ( *this , Loc, AttrRange, AttrName, DK)
2495
- . when ( " _assumed " , NonSendableKind::Assumed)
2496
- . whenOmitted ( NonSendableKind::Specific);
2399
+ auto kind = parseSingleAttrOption<NonSendableKind>(
2400
+ *this , Loc, AttrRange, AttrName, DK, {
2401
+ { Context. Id_assumed , NonSendableKind::Assumed }
2402
+ }, NonSendableKind::Specific);
2497
2403
if (!kind)
2498
2404
return false ;
2499
2405
0 commit comments