================
@@ -4244,6 +4230,163 @@ void Parser::ParseTrailingRequiresClause(Declarator &D)
{
}
}
+std::optional<Parser::ContractSpecifierKind>
+Parser::getContractSpecifierKind() {
+ if (!getLangOpts().CPlusPlus || Tok.isNot(tok::identifier))
+ return std::nullopt;
+
+ if (!Ident_pre) {
+ Ident_pre = &PP.getIdentifierTable().get("pre");
+ Ident_post = &PP.getIdentifierTable().get("post");
+ }
+
+ const IdentifierInfo *II = Tok.getIdentifierInfo();
+ if (II == Ident_pre)
+ return ContractSpecifierKind::Pre;
+ if (II == Ident_post)
+ return ContractSpecifierKind::Post;
+ return std::nullopt;
+}
+
+void Parser::ParseContractSpecifiers(Declarator &D) {
+ assert(getContractSpecifierKind() && "expected a contract specifier");
+
+ if (!getLangOpts().CPlusPlus26)
+ Diag(Tok, diag::err_contracts_require_cxx26);
+ else if (!getLangOpts().Contracts)
+ Diag(Tok, diag::err_contracts_disabled);
+
+ const bool IsFunction = D.isDeclarationOfFunction() &&
+ (D.isFunctionDeclarationContext() ||
+ D.getContext() == DeclaratorContext::LambdaExpr);
+ if (!IsFunction)
+ Diag(Tok, diag::err_contract_specifier_not_function);
+
+ while (std::optional<ContractSpecifierKind> Kind =
+ getContractSpecifierKind()) {
+ const bool IsPost = *Kind == ContractSpecifierKind::Post;
+ ConsumeToken();
+
+ ParsedAttributes Attrs(AttrFactory);
+ MaybeParseCXX11Attributes(Attrs);
+
+ BalancedDelimiterTracker T(*this, tok::l_paren);
+ if (T.expectAndConsume(diag::err_expected_lparen_after,
+ IsPost ? "post" : "pre"))
+ return;
+
+ // !IsFunction is diagnosed before, avoid confusing diagnostics.
+ if (!IsFunction) {
+ T.skipToEnd();
+ continue;
+ }
+
+ // FIXME: We should accept attribute for the result binding, e.g.,
+ // post(r [[attr]] : expr).
+ IdentifierInfo *ResultName = nullptr;
+ SourceLocation ResultNameLoc;
+ std::optional<ParseScope> ResultNameScope;
+ if (IsPost && Tok.is(tok::identifier) && NextToken().is(tok::colon)) {
+ ResultName = Tok.getIdentifierInfo();
+ ResultNameLoc = ConsumeToken();
+ ConsumeToken();
+ }
+
+ // A function contract specifier in a member-specification is a
+ // complete-class context. Cache its predicate so that name lookup and
+ // semantic analysis happen after the enclosing class is complete.
+ if (D.getContext() == DeclaratorContext::Member) {
+ auto PredicateTokens = std::make_unique<CachedTokens>();
+ ConsumeAndStoreUntil(tok::r_paren, *PredicateTokens,
+ /*StopAtSemi=*/false,
+ /*ConsumeFinalToken=*/false);
+ if (PredicateTokens->empty())
+ Diag(Tok, diag::err_expected_expression);
+ T.consumeClose();
+
+ D.addLateParsedContractSpecifier(
----------------
yronglin wrote:
This seems a regression, This seems only worked for syntactic function
declarators the following code should be rejected, but clang accept it and
doesn't check the predicate:
```cpp
using Fn = void();
struct S {
Fn f pre(true +); // error: expected expression, because `true +` is an
invalid expression
};
```
https://github.com/llvm/llvm-project/pull/221139
_______________________________________________
cfe-commits mailing list
[email protected]
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits