@@ -2061,7 +2061,7 @@ class LLVM_NODISCARD AttrOptionSwitch {
2061
2061
bool isDeclModifier;
2062
2062
2063
2063
// State:
2064
- StringRef exampleName; // empty: when() was never called
2064
+ Diagnostic misparseDiagnostic = diag::invalid_diagnostic;
2065
2065
Optional<R> result; // None: no when() has matched
2066
2066
2067
2067
public:
@@ -2084,8 +2084,9 @@ class LLVM_NODISCARD AttrOptionSwitch {
2084
2084
// / If the option has the identifier \p name, give it value \p value.
2085
2085
AttrOptionSwitch<R, T> &when (StringLiteral name, T value) {
2086
2086
// Save this to use in a future diagnostic, if needed.
2087
- if (exampleName.empty () && !name.empty ())
2088
- exampleName = name;
2087
+ if (misparseDiagnostic.is (diag::invalid_diagnostic) && !name.empty ())
2088
+ misparseDiagnostic = Diagnostic (diag::attr_expected_option_such_as,
2089
+ attrName, name);
2089
2090
2090
2091
// Does this string match?
2091
2092
if (parsedName && *parsedName == name) {
@@ -2096,10 +2097,32 @@ class LLVM_NODISCARD AttrOptionSwitch {
2096
2097
return *this ;
2097
2098
}
2098
2099
2100
+ template <typename Body>
2101
+ AttrOptionSwitch<R, T> &whenAny (Diagnostic misparse, Body body) {
2102
+ if (misparseDiagnostic.is (diag::invalid_diagnostic))
2103
+ misparseDiagnostic = misparse;
2104
+
2105
+ if (parsedName && !parsedName->empty ()) {
2106
+ assert (!result && " overlapping AttrOptionSwitch::whenAny()?" );
2107
+ result = std::move (body (*parsedName));
2108
+ }
2109
+
2110
+ return *this ;
2111
+ }
2112
+
2113
+ template <typename Ret = AttrOptionSwitch<R, T>>
2114
+ std::enable_if_t <std::is_same<T, Identifier>::value, Ret> &
2115
+ whenAny (Diagnostic misparse) {
2116
+ return whenAny (misparse, [&](StringRef parsed) {
2117
+ return P.Context .getIdentifier (parsed);
2118
+ });
2119
+ }
2120
+
2099
2121
// / Diagnose if the option is missing or was not matched, returning either the
2100
2122
// / option's value or \c None if an error was diagnosed.
2101
2123
Optional<R> diagnoseWhenOmitted () {
2102
- assert (!exampleName.empty () && " No AttrOptionSwitch::when() calls" );
2124
+ assert (!misparseDiagnostic.is (diag::invalid_diagnostic)
2125
+ && " No AttrOptionSwitch::when() calls" );
2103
2126
2104
2127
if (attrName.empty ())
2105
2128
// An error has already been diagnosed; nothing to do.
@@ -2108,8 +2131,7 @@ class LLVM_NODISCARD AttrOptionSwitch {
2108
2131
if (!result) {
2109
2132
if (!parsedName)
2110
2133
// We parsed a non-identifier; diagnose it with `exampleName`.
2111
- P.diagnose (loc, diag::attr_expected_option_such_as, attrName,
2112
- exampleName);
2134
+ P.diagnose (loc, misparseDiagnostic);
2113
2135
else if (*parsedName == " " )
2114
2136
// Option list was omitted; apparently this attr doesn't allow that.
2115
2137
P.diagnose (loc, diag::attr_expected_lparen, attrName, isDeclModifier);
@@ -2601,29 +2623,15 @@ bool Parser::parseNewDeclAttribute(DeclAttributes &Attributes, SourceLoc AtLoc,
2601
2623
}
2602
2624
2603
2625
case DAK_SwiftNativeObjCRuntimeBase: {
2604
- if (!consumeIf (tok::l_paren)) {
2605
- diagnose (Loc, diag::attr_expected_lparen, AttrName,
2606
- DeclAttribute::isDeclModifier (DK));
2607
- return false ;
2608
- }
2609
-
2610
- if (Tok.isNot (tok::identifier)) {
2611
- diagnose (Loc, diag::swift_native_objc_runtime_base_must_be_identifier);
2626
+ SourceRange range;
2627
+ auto name = parseSingleAttrOption<Identifier>
2628
+ (*this , Loc, range, AttrName, DK)
2629
+ .whenAny (diag::swift_native_objc_runtime_base_must_be_identifier)
2630
+ .diagnoseWhenOmitted ();
2631
+ if (!name)
2612
2632
return false ;
2613
- }
2614
-
2615
- Identifier name;
2616
- consumeIdentifier (name, /* diagnoseDollarPrefix=*/ false );
2617
-
2618
- auto range = SourceRange (Loc, Tok.getRange ().getStart ());
2619
2633
2620
- if (!consumeIf (tok::r_paren)) {
2621
- diagnose (Loc, diag::attr_expected_rparen, AttrName,
2622
- DeclAttribute::isDeclModifier (DK));
2623
- return false ;
2624
- }
2625
-
2626
- Attributes.add (new (Context) SwiftNativeObjCRuntimeBaseAttr (name,
2634
+ Attributes.add (new (Context) SwiftNativeObjCRuntimeBaseAttr (*name,
2627
2635
AtLoc, range, /* implicit*/ false ));
2628
2636
break ;
2629
2637
}
@@ -2864,30 +2872,15 @@ bool Parser::parseNewDeclAttribute(DeclAttributes &Attributes, SourceLoc AtLoc,
2864
2872
break ;
2865
2873
}
2866
2874
case DAK_ObjCRuntimeName: {
2867
- if (!consumeIf (tok::l_paren)) {
2868
- diagnose (Loc, diag::attr_expected_lparen, AttrName,
2869
- DeclAttribute::isDeclModifier (DK));
2870
- return false ;
2871
- }
2872
-
2873
- if (Tok.isNot (tok::identifier)) {
2874
- diagnose (Loc, diag::objc_runtime_name_must_be_identifier);
2875
- return false ;
2876
- }
2877
-
2878
- auto name = Tok.getText ();
2879
-
2880
- consumeToken (tok::identifier);
2881
-
2882
- auto range = SourceRange (Loc, Tok.getRange ().getStart ());
2883
-
2884
- if (!consumeIf (tok::r_paren)) {
2885
- diagnose (Loc, diag::attr_expected_rparen, AttrName,
2886
- DeclAttribute::isDeclModifier (DK));
2875
+ SourceRange range;
2876
+ auto name = parseSingleAttrOption<Identifier>
2877
+ (*this , Loc, range, AttrName, DK)
2878
+ .whenAny (diag::objc_runtime_name_must_be_identifier)
2879
+ .diagnoseWhenOmitted ();
2880
+ if (!name)
2887
2881
return false ;
2888
- }
2889
2882
2890
- Attributes.add (new (Context) ObjCRuntimeNameAttr (name, AtLoc, range,
2883
+ Attributes.add (new (Context) ObjCRuntimeNameAttr (name-> str () , AtLoc, range,
2891
2884
/* implicit*/ false ));
2892
2885
break ;
2893
2886
}
@@ -3032,30 +3025,16 @@ bool Parser::parseNewDeclAttribute(DeclAttributes &Attributes, SourceLoc AtLoc,
3032
3025
}
3033
3026
3034
3027
case DAK_ProjectedValueProperty: {
3035
- if (!consumeIf (tok::l_paren)) {
3036
- diagnose (Loc, diag::attr_expected_lparen, AttrName,
3037
- DeclAttribute::isDeclModifier (DK));
3038
- return false ;
3039
- }
3040
-
3041
- if (Tok.isNot (tok::identifier)) {
3042
- diagnose (Loc, diag::projection_value_property_not_identifier);
3043
- return false ;
3044
- }
3045
-
3046
- Identifier name;
3047
- consumeIdentifier (name, /* diagnoseDollarPrefix=*/ false );
3048
-
3049
- auto range = SourceRange (Loc, Tok.getRange ().getStart ());
3050
-
3051
- if (!consumeIf (tok::r_paren)) {
3052
- diagnose (Loc, diag::attr_expected_rparen, AttrName,
3053
- DeclAttribute::isDeclModifier (DK));
3028
+ SourceRange range;
3029
+ auto name = parseSingleAttrOption<Identifier>
3030
+ (*this , Loc, range, AttrName, DK)
3031
+ .whenAny (diag::projection_value_property_not_identifier)
3032
+ .diagnoseWhenOmitted ();
3033
+ if (!name)
3054
3034
return false ;
3055
- }
3056
3035
3057
3036
Attributes.add (new (Context) ProjectedValuePropertyAttr (
3058
- name, AtLoc, range, /* implicit*/ false ));
3037
+ * name, AtLoc, range, /* implicit*/ false ));
3059
3038
break ;
3060
3039
}
3061
3040
case DAK_TypeSequence: {
0 commit comments