@@ -1735,6 +1735,133 @@ void Parser::parseAllAvailabilityMacroArguments() {
1735
1735
AvailabilityMacrosComputed = true ;
1736
1736
}
1737
1737
1738
+ // / Processes a parsed option name by attempting to match it to a list of
1739
+ // / alternative name/value pairs provided by a chain of \c when() calls, ending
1740
+ // / in either \c whenOmitted() if omitting the option is allowed, or
1741
+ // / \c diagnoseWhenOmitted() if the option is mandatory.
1742
+ template <typename T, typename R = T>
1743
+ class LLVM_NODISCARD AttrOptionSwitch {
1744
+ // Inputs:
1745
+ Optional<StringRef> parsedName; // None: parse error, empty: omitted
1746
+ Parser &P;
1747
+ SourceLoc loc;
1748
+ StringRef attrName; // empty: error already diagnosed
1749
+ bool isDeclModifier;
1750
+
1751
+ // State:
1752
+ StringRef exampleName; // empty: when() was never called
1753
+ Optional<R> result; // None: no when() has matched
1754
+
1755
+ public:
1756
+ // / \param parsedName The name of the option parsed out of the source code. If
1757
+ // / \c None, there was some sort of parse error; this will normally be
1758
+ // / diagnosed as \c diag::attr_expected_option_such_as using the name
1759
+ // / from the first \c when() call as an example.
1760
+ // / \param P The parser used to diagnose errors concerning this attribute
1761
+ // / option.
1762
+ // / \param loc The source location to diagnose errors at.
1763
+ // / \param attrName The name of the attribute, used in diagnostics. If empty,
1764
+ // / an error has already been diagnosed and the AttrOptionSwitch should
1765
+ // / just fall through.
1766
+ // / \param isDeclModifier Are we parsing an attribute or a modifier?
1767
+ AttrOptionSwitch (Optional<StringRef> parsedName, Parser &P, SourceLoc loc,
1768
+ StringRef attrName, bool isDeclModifier)
1769
+ : parsedName(parsedName), P(P), loc(loc), attrName(attrName),
1770
+ isDeclModifier (isDeclModifier) { }
1771
+
1772
+ // / If the option has the identifier \p name, give it value \p value.
1773
+ AttrOptionSwitch<R, T> &when (StringLiteral name, T value) {
1774
+ // Save this to use in a future diagnostic, if needed.
1775
+ if (exampleName.empty () && !name.empty ())
1776
+ exampleName = name;
1777
+
1778
+ // Does this string match?
1779
+ if (parsedName && *parsedName == name) {
1780
+ assert (!result && " overlapping AttrOptionSwitch::when()s?" );
1781
+ result = std::move (value);
1782
+ }
1783
+
1784
+ return *this ;
1785
+ }
1786
+
1787
+ // / Diagnose if the option is missing or was not matched, returning either the
1788
+ // / option's value or \c None if an error was diagnosed.
1789
+ Optional<R> diagnoseWhenOmitted () {
1790
+ assert (!exampleName.empty () && " No AttrOptionSwitch::when() calls" );
1791
+
1792
+ if (attrName.empty ())
1793
+ // An error has already been diagnosed; nothing to do.
1794
+ return None;
1795
+
1796
+ if (!result) {
1797
+ if (!parsedName)
1798
+ // We parsed a non-identifier; diagnose it with `exampleName`.
1799
+ P.diagnose (loc, diag::attr_expected_option_such_as, attrName,
1800
+ exampleName);
1801
+ else if (*parsedName == " " )
1802
+ // Option list was omitted; apparently this attr doesn't allow that.
1803
+ P.diagnose (loc, diag::attr_expected_lparen, attrName, isDeclModifier);
1804
+ else
1805
+ // The identifier didn't match any of the when() calls.
1806
+ P.diagnose (loc, diag::attr_unknown_option, *parsedName, attrName);
1807
+ }
1808
+
1809
+ return result;
1810
+ }
1811
+
1812
+ // / Diagnose if the option is missing or not matched, returning:
1813
+ // /
1814
+ // / \returns \c None if an error was diagnosed; \p value if the option was
1815
+ // / omitted; the value the option was matched to otherwise.
1816
+ Optional<R> whenOmitted (T value) {
1817
+ return when (" " , value).diagnoseWhenOmitted ();
1818
+ }
1819
+ };
1820
+
1821
+ // / Parses an attribute argument list that allows a single identifier with a
1822
+ // / known set of permitted options:
1823
+ // /
1824
+ // / \verbatim
1825
+ // / '(' identifier ')'
1826
+ // / \endverbatim
1827
+ // /
1828
+ // / Returns an object of type \c AttrOptionSwitch, a type loosely inspired by
1829
+ // / \c llvm::StringSwitch which can be used in a fluent style to map each
1830
+ // / permitted identifier to a value. Together, they will automatically
1831
+ // / diagnose \c diag::attr_expected_lparen,
1832
+ // / \c diag::attr_expected_option_such_as, \c diag::attr_unknown_option, and
1833
+ // / \c diag::attr_expected_rparen when needed.
1834
+ // /
1835
+ // / \seealso AttrOptionSwitch
1836
+ template <typename R>
1837
+ static AttrOptionSwitch<R>
1838
+ parseSingleAttrOption (Parser &P, SourceLoc Loc, SourceRange &AttrRange,
1839
+ StringRef AttrName, DeclAttrKind DK) {
1840
+ bool isModifier = DeclAttribute::isDeclModifier (DK);
1841
+ if (!P.consumeIf (tok::l_paren)) {
1842
+ AttrRange = SourceRange (Loc);
1843
+ // Create an AttrOptionSwitch with an empty value. The calls on it will
1844
+ // decide whether or not that's valid.
1845
+ return AttrOptionSwitch<R>(StringRef (), P, Loc, AttrName, isModifier);
1846
+ }
1847
+
1848
+ StringRef parsedName = P.Tok .getText ();
1849
+ if (!P.consumeIf (tok::identifier)) {
1850
+ // Once we have an example of a valid option, diagnose this with
1851
+ // diag::attr_expected_option_such_as.
1852
+ return AttrOptionSwitch<R>(None, P, Loc, AttrName, isModifier);
1853
+ }
1854
+
1855
+ if (!P.consumeIf (tok::r_paren)) {
1856
+ P.diagnose (Loc, diag::attr_expected_rparen, AttrName, isModifier);
1857
+ // Pass through the switch without diagnosing anything.
1858
+ return AttrOptionSwitch<R>(None, P, Loc, " " , isModifier);
1859
+ }
1860
+
1861
+ AttrRange = SourceRange (Loc, P.PreviousLoc );
1862
+ return AttrOptionSwitch<R>(parsedName, P, Loc, AttrName, isModifier);
1863
+ }
1864
+
1738
1865
bool Parser::parseNewDeclAttribute (DeclAttributes &Attributes, SourceLoc AtLoc,
1739
1866
DeclAttrKind DK, bool isFromClangAttribute) {
1740
1867
// Ok, it is a valid attribute, eat it, and then process it.
@@ -1814,114 +1941,49 @@ bool Parser::parseNewDeclAttribute(DeclAttributes &Attributes, SourceLoc AtLoc,
1814
1941
#include " swift/AST/Attr.def"
1815
1942
1816
1943
case DAK_Effects: {
1817
- if (!consumeIf (tok::l_paren)) {
1818
- diagnose (Loc, diag::attr_expected_lparen, AttrName,
1819
- DeclAttribute::isDeclModifier (DK)); return false ;
1820
- }
1821
-
1822
- if (Tok.isNot (tok::identifier)) {
1823
- diagnose (Loc, diag::effects_attribute_expect_option, AttrName);
1824
- return false ;
1825
- }
1826
-
1827
- EffectsKind kind;
1828
- if (Tok.getText () == " readonly" )
1829
- kind = EffectsKind::ReadOnly;
1830
- else if (Tok.getText () == " readnone" )
1831
- kind = EffectsKind::ReadNone;
1832
- else if (Tok.getText () == " readwrite" )
1833
- kind = EffectsKind::ReadWrite;
1834
- else if (Tok.getText () == " releasenone" )
1835
- kind = EffectsKind::ReleaseNone;
1836
- else {
1837
- diagnose (Loc, diag::attr_unknown_option,
1838
- Tok.getText (), AttrName);
1839
- return false ;
1840
- }
1841
- AttrRange = SourceRange (Loc, Tok.getRange ().getStart ());
1842
- consumeToken (tok::identifier);
1843
-
1844
- if (!consumeIf (tok::r_paren)) {
1845
- diagnose (Loc, diag::attr_expected_rparen, AttrName,
1846
- DeclAttribute::isDeclModifier (DK));
1944
+ auto kind = parseSingleAttrOption<EffectsKind>
1945
+ (*this , Loc, AttrRange, AttrName, DK)
1946
+ .when (" readonly" , EffectsKind::ReadOnly)
1947
+ .when (" readnone" , EffectsKind::ReadNone)
1948
+ .when (" readwrite" , EffectsKind::ReadWrite)
1949
+ .when (" releasenone" , EffectsKind::ReleaseNone)
1950
+ .diagnoseWhenOmitted ();
1951
+ if (!kind)
1847
1952
return false ;
1848
- }
1849
1953
1850
1954
if (!DiscardAttribute)
1851
- Attributes.add (new (Context) EffectsAttr (AtLoc, AttrRange, kind));
1955
+ Attributes.add (new (Context) EffectsAttr (AtLoc, AttrRange, *kind));
1956
+
1852
1957
break ;
1853
1958
}
1854
1959
1855
1960
case DAK_Inline: {
1856
- if (!consumeIf (tok::l_paren)) {
1857
- diagnose (Loc, diag::attr_expected_lparen, AttrName,
1858
- DeclAttribute::isDeclModifier (DK));
1961
+ auto kind = parseSingleAttrOption<InlineKind>
1962
+ (*this , Loc, AttrRange, AttrName, DK)
1963
+ .when (" never" , InlineKind::Never)
1964
+ .when (" __always" , InlineKind::Always)
1965
+ .diagnoseWhenOmitted ();
1966
+ if (!kind)
1859
1967
return false ;
1860
- }
1861
-
1862
- if (Tok.isNot (tok::identifier)) {
1863
- diagnose (Loc, diag::attr_expected_option_such_as, AttrName, " none" );
1864
- return false ;
1865
- }
1866
-
1867
- InlineKind kind;
1868
- if (Tok.getText () == " never" )
1869
- kind = InlineKind::Never;
1870
- else if (Tok.getText () == " __always" )
1871
- kind = InlineKind::Always;
1872
- else {
1873
- diagnose (Loc, diag::attr_unknown_option, Tok.getText (), AttrName);
1874
- return false ;
1875
- }
1876
- consumeToken (tok::identifier);
1877
- AttrRange = SourceRange (Loc, Tok.getRange ().getStart ());
1878
-
1879
- if (!consumeIf (tok::r_paren)) {
1880
- diagnose (Loc, diag::attr_expected_rparen, AttrName,
1881
- DeclAttribute::isDeclModifier (DK));
1882
- return false ;
1883
- }
1884
1968
1885
1969
if (!DiscardAttribute)
1886
- Attributes.add (new (Context) InlineAttr (AtLoc, AttrRange, kind));
1970
+ Attributes.add (new (Context) InlineAttr (AtLoc, AttrRange, * kind));
1887
1971
1888
1972
break ;
1889
1973
}
1890
1974
1891
1975
case DAK_Optimize: {
1892
- if (!consumeIf (tok::l_paren)) {
1893
- diagnose (Loc, diag::attr_expected_lparen, AttrName,
1894
- DeclAttribute::isDeclModifier (DK));
1976
+ auto optMode = parseSingleAttrOption<OptimizationMode>
1977
+ (*this , Loc, AttrRange, AttrName, DK)
1978
+ .when (" speed" , OptimizationMode::ForSpeed)
1979
+ .when (" size" , OptimizationMode::ForSize)
1980
+ .when (" none" , OptimizationMode::NoOptimization)
1981
+ .diagnoseWhenOmitted ();
1982
+ if (!optMode)
1895
1983
return false ;
1896
- }
1897
-
1898
- if (Tok.isNot (tok::identifier)) {
1899
- diagnose (Loc, diag::attr_expected_option_such_as, AttrName, " speed" );
1900
- return false ;
1901
- }
1902
-
1903
- OptimizationMode optMode = OptimizationMode::NotSet;
1904
- if (Tok.getText () == " none" )
1905
- optMode = OptimizationMode::NoOptimization;
1906
- else if (Tok.getText () == " speed" )
1907
- optMode = OptimizationMode::ForSpeed;
1908
- else if (Tok.getText () == " size" )
1909
- optMode = OptimizationMode::ForSize;
1910
- else {
1911
- diagnose (Loc, diag::attr_unknown_option, Tok.getText (), AttrName);
1912
- return false ;
1913
- }
1914
- consumeToken (tok::identifier);
1915
- AttrRange = SourceRange (Loc, Tok.getRange ().getStart ());
1916
-
1917
- if (!consumeIf (tok::r_paren)) {
1918
- diagnose (Loc, diag::attr_expected_rparen, AttrName,
1919
- DeclAttribute::isDeclModifier (DK));
1920
- return false ;
1921
- }
1922
1984
1923
1985
if (!DiscardAttribute)
1924
- Attributes.add (new (Context) OptimizeAttr (AtLoc, AttrRange, optMode));
1986
+ Attributes.add (new (Context) OptimizeAttr (AtLoc, AttrRange, * optMode));
1925
1987
1926
1988
break ;
1927
1989
}
@@ -1930,30 +1992,25 @@ bool Parser::parseNewDeclAttribute(DeclAttributes &Attributes, SourceLoc AtLoc,
1930
1992
// Handle weak/unowned/unowned(unsafe).
1931
1993
auto Kind = AttrName == " weak" ? ReferenceOwnership::Weak
1932
1994
: ReferenceOwnership::Unowned;
1933
- SourceLoc EndLoc = Loc;
1934
1995
1935
- if (Kind == ReferenceOwnership::Unowned && Tok. is (tok::l_paren) ) {
1996
+ if (Kind == ReferenceOwnership::Unowned) {
1936
1997
// Parse an optional specifier after unowned.
1937
- SourceLoc lp = consumeToken (tok::l_paren);
1938
- if (Tok.is (tok::identifier) && Tok.getText () == " safe" ) {
1939
- consumeToken ();
1940
- } else if (Tok.is (tok::identifier) && Tok.getText () == " unsafe" ) {
1941
- consumeToken ();
1942
- Kind = ReferenceOwnership::Unmanaged;
1943
- } else {
1944
- diagnose (Tok, diag::attr_unowned_invalid_specifier);
1945
- consumeIf (tok::identifier);
1946
- }
1947
-
1948
- SourceLoc rp;
1949
- parseMatchingToken (tok::r_paren, rp, diag::attr_unowned_expected_rparen,
1950
- lp);
1951
- EndLoc = rp;
1998
+ Kind = parseSingleAttrOption<ReferenceOwnership>
1999
+ (*this , Loc, AttrRange, AttrName, DK)
2000
+ .when (" unsafe" , ReferenceOwnership::Unmanaged)
2001
+ .when (" safe" , ReferenceOwnership::Unowned)
2002
+ .whenOmitted (ReferenceOwnership::Unowned)
2003
+ // Recover from errors by going back to Unowned.
2004
+ .getValueOr (ReferenceOwnership::Unowned);
2005
+ }
2006
+ else {
2007
+ AttrRange = SourceRange (Loc);
1952
2008
}
1953
2009
1954
2010
if (!DiscardAttribute)
1955
2011
Attributes.add (
1956
- new (Context) ReferenceOwnershipAttr (SourceRange (Loc, EndLoc), Kind));
2012
+ new (Context) ReferenceOwnershipAttr (AttrRange, Kind));
2013
+
1957
2014
break ;
1958
2015
}
1959
2016
0 commit comments