@@ -1559,7 +1559,10 @@ Parser<ManagedTokenSource>::parse_function (AST::Visibility vis,
15591559{
15601560 location_t locus = lexer.peek_token ()->get_locus ();
15611561 // Get qualifiers for function if they exist
1562- AST::FunctionQualifiers qualifiers = parse_function_qualifiers ();
1562+ std::unique_ptr<AST::FunctionQualifiers> qualifiers
1563+ = parse_function_qualifiers ();
1564+ if (qualifiers == nullptr )
1565+ return nullptr ;
15631566
15641567 skip_token (FN_KW);
15651568
@@ -1636,7 +1639,7 @@ Parser<ManagedTokenSource>::parse_function (AST::Visibility vis,
16361639 }
16371640
16381641 return std::unique_ptr<AST::Function> (
1639- new AST::Function (std::move (function_name), std::move (qualifiers),
1642+ new AST::Function (std::move (function_name), std::move (* qualifiers),
16401643 std::move (generic_params), std::move (function_params),
16411644 std::move (return_type), std::move (where_clause),
16421645 std::move (body), std::move (vis),
@@ -1645,7 +1648,7 @@ Parser<ManagedTokenSource>::parse_function (AST::Visibility vis,
16451648
16461649// Parses function or method qualifiers (i.e. const, unsafe, and extern).
16471650template <typename ManagedTokenSource>
1648- AST::FunctionQualifiers
1651+ std::unique_ptr< AST::FunctionQualifiers>
16491652Parser<ManagedTokenSource>::parse_function_qualifiers ()
16501653{
16511654 Default default_status = Default::No;
@@ -1655,51 +1658,151 @@ Parser<ManagedTokenSource>::parse_function_qualifiers ()
16551658 bool has_extern = false ;
16561659 std::string abi;
16571660
1661+ // collect all qualifiers before checking the order to allow for a better
1662+ // error message
1663+ std::vector<TokenId> found_order;
1664+
16581665 const_TokenPtr t;
16591666 location_t locus = lexer.peek_token ()->get_locus ();
1660- // Check in order of default, const, async, unsafe, extern
1661- if (lexer.peek_token ()->get_id () == IDENTIFIER
1662- && lexer.peek_token ()->get_str () == Values::WeakKeywords::DEFAULT)
1663- {
1664- default_status = Default::Yes;
1665- lexer.skip_token ();
1666- }
16671667
1668- if (lexer.peek_token ()->get_id () == CONST)
1668+ // this will terminate on duplicates or the first non-qualifier token
1669+ while (true )
16691670 {
1670- lexer.skip_token ();
1671- const_status = Const::Yes;
1672- }
1671+ const TokenId token_id = lexer.peek_token ()->get_id ();
16731672
1674- if (lexer.peek_token ()->get_id () == ASYNC)
1675- {
1676- lexer.skip_token ();
1677- async_status = Async::Yes;
1678- }
1673+ if (std::find (found_order.cbegin (), found_order.cend (), token_id)
1674+ != found_order.cend ())
1675+ {
1676+ // qualifiers mustn't appear twice
1677+ Error error (lexer.peek_token ()->get_locus (),
1678+ " encountered duplicate function qualifier %qs" ,
1679+ lexer.peek_token ()->get_token_description ());
1680+ add_error (std::move (error));
16791681
1680- if (lexer.peek_token ()->get_id () == UNSAFE)
1681- {
1682- lexer.skip_token ();
1683- unsafe_status = Unsafety::Unsafe;
1684- }
1682+ return nullptr ;
1683+ }
16851684
1686- if (lexer.peek_token ()->get_id () == EXTERN_KW)
1687- {
1685+ switch (token_id)
1686+ {
1687+ default :
1688+ goto done;
1689+ case IDENTIFIER:
1690+ if (lexer.peek_token ()->get_str () != Values::WeakKeywords::DEFAULT)
1691+ {
1692+ // only "default" is valid in this context
1693+ goto done;
1694+ }
1695+ default_status = Default::Yes;
1696+ break ;
1697+ case CONST:
1698+ const_status = Const::Yes;
1699+ break ;
1700+ case ASYNC:
1701+ async_status = Async::Yes;
1702+ break ;
1703+ case UNSAFE:
1704+ unsafe_status = Unsafety::Unsafe;
1705+ break ;
1706+ case EXTERN_KW:
1707+ has_extern = true ;
1708+ // detect optional abi name
1709+ lexer.skip_token ();
1710+ const_TokenPtr next_tok = lexer.peek_token ();
1711+ if (next_tok->get_id () == STRING_LITERAL)
1712+ {
1713+ abi = next_tok->get_str ();
1714+ }
1715+ break ;
1716+ }
1717+ found_order.push_back (token_id);
16881718 lexer.skip_token ();
1689- has_extern = true ;
1719+ }
1720+ done:
16901721
1691- // detect optional abi name
1692- const_TokenPtr next_tok = lexer.peek_token ();
1693- if (next_tok->get_id () == STRING_LITERAL)
1722+ // Check in order of default, const, async, unsafe, extern
1723+ auto token_priority = [] (const TokenId id) {
1724+ switch (id)
1725+ {
1726+ default : // unreachable, but will cause an error
1727+ return 0 ;
1728+ case IDENTIFIER: // "default"; the only "weak" keyword considered here
1729+ return 1 ;
1730+ case CONST:
1731+ return 2 ;
1732+ case ASYNC:
1733+ return 3 ;
1734+ case UNSAFE:
1735+ return 4 ;
1736+ case EXTERN_KW:
1737+ return 5 ;
1738+ };
1739+ };
1740+
1741+ size_t last_priority = 0 ;
1742+ for (auto token_id : found_order)
1743+ {
1744+ const size_t priority = token_priority (token_id);
1745+ if (priority <= last_priority)
16941746 {
1695- lexer.skip_token ();
1696- abi = next_tok->get_str ();
1747+ auto qualifiers_to_str = [] (const std::vector<TokenId> &token_ids) {
1748+ std::string acc;
1749+
1750+ for (auto id : token_ids)
1751+ {
1752+ if (!acc.empty ())
1753+ acc += ' ' ;
1754+
1755+ if (id == IDENTIFIER)
1756+ acc += " default" ;
1757+ else
1758+ acc += token_id_keyword_string (id);
1759+ }
1760+
1761+ return acc;
1762+ };
1763+
1764+ std::vector<TokenId> expected_order
1765+ = {IDENTIFIER, CONST, ASYNC, UNSAFE, EXTERN_KW};
1766+
1767+ // we only keep the qualifiers actually used in the offending code
1768+ std::vector<TokenId>::const_iterator token_id
1769+ = expected_order.cbegin ();
1770+ while (token_id != expected_order.cend ())
1771+ {
1772+ if (std::find (found_order.cbegin (), found_order.cend (),
1773+ *token_id)
1774+ == found_order.cend ())
1775+ {
1776+ token_id = expected_order.erase (token_id);
1777+ }
1778+ else
1779+ {
1780+ ++token_id;
1781+ }
1782+ }
1783+
1784+ const std::string found_qualifiers = qualifiers_to_str (found_order);
1785+ const std::string expected_qualifiers
1786+ = qualifiers_to_str (expected_order);
1787+
1788+ location_t error_locus
1789+ = make_location (locus, locus, lexer.peek_token ()->get_locus ());
1790+ Error error (
1791+ error_locus,
1792+ " invalid order of function qualifiers; found %qs, expected %qs" ,
1793+ found_qualifiers.c_str (), expected_qualifiers.c_str ());
1794+ add_error (std::move (error));
1795+
1796+ return nullptr ;
16971797 }
1798+
1799+ last_priority = priority;
16981800 }
16991801
1700- return AST::FunctionQualifiers (locus, default_status, async_status,
1701- const_status, unsafe_status, has_extern,
1702- std::move (abi));
1802+ return std::unique_ptr<AST::FunctionQualifiers> (
1803+ new AST::FunctionQualifiers (locus, default_status, async_status,
1804+ const_status, unsafe_status, has_extern,
1805+ std::move (abi)));
17031806}
17041807
17051808// Parses generic (lifetime or type) params inside angle brackets (optional).
@@ -4276,7 +4379,10 @@ Parser<ManagedTokenSource>::parse_inherent_impl_function_or_method (
42764379{
42774380 location_t locus = lexer.peek_token ()->get_locus ();
42784381 // parse function or method qualifiers
4279- AST::FunctionQualifiers qualifiers = parse_function_qualifiers ();
4382+ std::unique_ptr<AST::FunctionQualifiers> qualifiers
4383+ = parse_function_qualifiers ();
4384+ if (qualifiers == nullptr )
4385+ return nullptr ;
42804386
42814387 skip_token (FN_KW);
42824388
@@ -4362,7 +4468,7 @@ Parser<ManagedTokenSource>::parse_inherent_impl_function_or_method (
43624468 }
43634469
43644470 return std::unique_ptr<AST::Function> (
4365- new AST::Function (std::move (ident), std::move (qualifiers),
4471+ new AST::Function (std::move (ident), std::move (* qualifiers),
43664472 std::move (generic_params), std::move (function_params),
43674473 std::move (return_type), std::move (where_clause),
43684474 std::move (body), std::move (vis),
@@ -4459,7 +4565,10 @@ Parser<ManagedTokenSource>::parse_trait_impl_function_or_method (
44594565 location_t locus = lexer.peek_token ()->get_locus ();
44604566
44614567 // parse function or method qualifiers
4462- AST::FunctionQualifiers qualifiers = parse_function_qualifiers ();
4568+ std::unique_ptr<AST::FunctionQualifiers> qualifiers
4569+ = parse_function_qualifiers ();
4570+ if (qualifiers == nullptr )
4571+ return nullptr ;
44634572
44644573 skip_token (FN_KW);
44654574
@@ -4590,7 +4699,7 @@ Parser<ManagedTokenSource>::parse_trait_impl_function_or_method (
45904699 }
45914700
45924701 return std::unique_ptr<AST::Function> (
4593- new AST::Function (std::move (ident), std::move (qualifiers),
4702+ new AST::Function (std::move (ident), std::move (* qualifiers),
45944703 std::move (generic_params), std::move (function_params),
45954704 std::move (return_type), std::move (where_clause),
45964705 std::move (body), std::move (vis),
@@ -6202,7 +6311,10 @@ Parser<ManagedTokenSource>::parse_bare_function_type (
62026311 // TODO: pass in for lifetime location as param
62036312 location_t best_try_locus = lexer.peek_token ()->get_locus ();
62046313
6205- AST::FunctionQualifiers qualifiers = parse_function_qualifiers ();
6314+ std::unique_ptr<AST::FunctionQualifiers> qualifiers
6315+ = parse_function_qualifiers ();
6316+ if (qualifiers == nullptr )
6317+ return nullptr ;
62066318
62076319 if (!skip_token (FN_KW))
62086320 return nullptr ;
@@ -6287,7 +6399,7 @@ Parser<ManagedTokenSource>::parse_bare_function_type (
62876399
62886400 return std::unique_ptr<AST::BareFunctionType> (
62896401 new AST::BareFunctionType (std::move (for_lifetimes),
6290- std::move (qualifiers), std::move (params),
6402+ std::move (* qualifiers), std::move (params),
62916403 is_variadic, std::move (variadic_attrs),
62926404 std::move (return_type), best_try_locus));
62936405}
0 commit comments