Author: Richard Smith Date: 2020-12-03T15:26:06-08:00 New Revision: be162f4c0e8563c8de510121435281ae628c8654
URL: https://github.com/llvm/llvm-project/commit/be162f4c0e8563c8de510121435281ae628c8654 DIFF: https://github.com/llvm/llvm-project/commit/be162f4c0e8563c8de510121435281ae628c8654.diff LOG: PR45699: Fix crash if an unexpanded parameter pack appears in a requires-clause. Added: Modified: clang/include/clang/AST/ExprCXX.h clang/include/clang/AST/RecursiveASTVisitor.h clang/include/clang/Basic/DiagnosticSemaKinds.td clang/include/clang/Sema/Sema.h clang/lib/AST/ExprCXX.cpp clang/lib/Parse/ParseTemplate.cpp clang/lib/Sema/SemaDeclCXX.cpp clang/test/SemaTemplate/concepts.cpp Removed: ################################################################################ diff --git a/clang/include/clang/AST/ExprCXX.h b/clang/include/clang/AST/ExprCXX.h index 2f89b43267b6..1efa78fc4294 100644 --- a/clang/include/clang/AST/ExprCXX.h +++ b/clang/include/clang/AST/ExprCXX.h @@ -2029,6 +2029,9 @@ class LambdaExpr final : public Expr, /// invented by use of an auto parameter). ArrayRef<NamedDecl *> getExplicitTemplateParameters() const; + /// Get the trailing requires clause, if any. + Expr *getTrailingRequiresClause() const; + /// Whether this is a generic lambda. bool isGenericLambda() const { return getTemplateParameterList(); } diff --git a/clang/include/clang/AST/RecursiveASTVisitor.h b/clang/include/clang/AST/RecursiveASTVisitor.h index 0a36ec9ad687..612e60cf4df1 100644 --- a/clang/include/clang/AST/RecursiveASTVisitor.h +++ b/clang/include/clang/AST/RecursiveASTVisitor.h @@ -2503,17 +2503,12 @@ DEF_TRAVERSE_STMT(LambdaExpr, { TypeLoc TL = S->getCallOperator()->getTypeSourceInfo()->getTypeLoc(); FunctionProtoTypeLoc Proto = TL.getAsAdjusted<FunctionProtoTypeLoc>(); - for (Decl *D : S->getExplicitTemplateParameters()) { - // Visit explicit template parameters. - TRY_TO(TraverseDecl(D)); - } + TRY_TO(TraverseTemplateParameterListHelper(S->getTemplateParameterList())); if (S->hasExplicitParameters()) { // Visit parameters. for (unsigned I = 0, N = Proto.getNumParams(); I != N; ++I) TRY_TO(TraverseDecl(Proto.getParam(I))); } - if (S->hasExplicitResultType()) - TRY_TO(TraverseTypeLoc(Proto.getReturnLoc())); auto *T = Proto.getTypePtr(); for (const auto &E : T->exceptions()) @@ -2522,6 +2517,10 @@ DEF_TRAVERSE_STMT(LambdaExpr, { if (Expr *NE = T->getNoexceptExpr()) TRY_TO_TRAVERSE_OR_ENQUEUE_STMT(NE); + if (S->hasExplicitResultType()) + TRY_TO(TraverseTypeLoc(Proto.getReturnLoc())); + TRY_TO_TRAVERSE_OR_ENQUEUE_STMT(S->getTrailingRequiresClause()); + TRY_TO_TRAVERSE_OR_ENQUEUE_STMT(S->getBody()); } ShouldVisitChildren = false; diff --git a/clang/include/clang/Basic/DiagnosticSemaKinds.td b/clang/include/clang/Basic/DiagnosticSemaKinds.td index 44195cc9db45..23f374987c92 100644 --- a/clang/include/clang/Basic/DiagnosticSemaKinds.td +++ b/clang/include/clang/Basic/DiagnosticSemaKinds.td @@ -5158,7 +5158,8 @@ def err_unexpanded_parameter_pack : Error< "using declaration|friend declaration|qualifier|initializer|default argument|" "non-type template parameter type|exception type|partial specialization|" "__if_exists name|__if_not_exists name|lambda|block|type constraint|" - "requirement}0 contains%plural{0: an|:}1 unexpanded parameter pack" + "requirement|requires clause}0 " + "contains%plural{0: an|:}1 unexpanded parameter pack" "%plural{0:|1: %2|2:s %2 and %3|:s %2, %3, ...}1">; def err_pack_expansion_without_parameter_packs : Error< diff --git a/clang/include/clang/Sema/Sema.h b/clang/include/clang/Sema/Sema.h index 8b4a18ab11d6..fc19e04e6c5d 100644 --- a/clang/include/clang/Sema/Sema.h +++ b/clang/include/clang/Sema/Sema.h @@ -2674,6 +2674,7 @@ class Sema final { SkipBodyInfo *SkipBody = nullptr); void ActOnStartTrailingRequiresClause(Scope *S, Declarator &D); ExprResult ActOnFinishTrailingRequiresClause(ExprResult ConstraintExpr); + ExprResult ActOnRequiresClause(ExprResult ConstraintExpr); void ActOnStartOfObjCMethodDef(Scope *S, Decl *D); bool isObjCMethodDecl(Decl *D) { return D && isa<ObjCMethodDecl>(D); @@ -7927,6 +7928,9 @@ class Sema final { // A requirement in a requires-expression. UPPC_Requirement, + + // A requires-clause. + UPPC_RequiresClause, }; /// Diagnose unexpanded parameter packs. diff --git a/clang/lib/AST/ExprCXX.cpp b/clang/lib/AST/ExprCXX.cpp index b7f677051ea2..8dc9d4296e14 100644 --- a/clang/lib/AST/ExprCXX.cpp +++ b/clang/lib/AST/ExprCXX.cpp @@ -1271,6 +1271,10 @@ ArrayRef<NamedDecl *> LambdaExpr::getExplicitTemplateParameters() const { return Record->getLambdaExplicitTemplateParameters(); } +Expr *LambdaExpr::getTrailingRequiresClause() const { + return getCallOperator()->getTrailingRequiresClause(); +} + bool LambdaExpr::isMutable() const { return !getCallOperator()->isConst(); } LambdaExpr::child_range LambdaExpr::children() { diff --git a/clang/lib/Parse/ParseTemplate.cpp b/clang/lib/Parse/ParseTemplate.cpp index 09ffc422e813..828b9b2277ff 100644 --- a/clang/lib/Parse/ParseTemplate.cpp +++ b/clang/lib/Parse/ParseTemplate.cpp @@ -141,9 +141,8 @@ Decl *Parser::ParseTemplateDeclarationOrSpecialization( if (TryConsumeToken(tok::kw_requires)) { OptionalRequiresClauseConstraintER = - Actions.CorrectDelayedTyposInExpr( - ParseConstraintLogicalOrExpression( - /*IsTrailingRequiresClause=*/false)); + Actions.ActOnRequiresClause(ParseConstraintLogicalOrExpression( + /*IsTrailingRequiresClause=*/false)); if (!OptionalRequiresClauseConstraintER.isUsable()) { // Skip until the semi-colon or a '}'. SkipUntil(tok::r_brace, StopAtSemi | StopBeforeMatch); diff --git a/clang/lib/Sema/SemaDeclCXX.cpp b/clang/lib/Sema/SemaDeclCXX.cpp index 593f4a937c79..0df022f036f2 100644 --- a/clang/lib/Sema/SemaDeclCXX.cpp +++ b/clang/lib/Sema/SemaDeclCXX.cpp @@ -3932,9 +3932,22 @@ void Sema::ActOnStartTrailingRequiresClause(Scope *S, Declarator &D) { } ExprResult Sema::ActOnFinishTrailingRequiresClause(ExprResult ConstraintExpr) { + return ActOnRequiresClause(ConstraintExpr); +} + +ExprResult Sema::ActOnRequiresClause(ExprResult ConstraintExpr) { + if (ConstraintExpr.isInvalid()) + return ExprError(); + + ConstraintExpr = CorrectDelayedTyposInExpr(ConstraintExpr); if (ConstraintExpr.isInvalid()) return ExprError(); - return CorrectDelayedTyposInExpr(ConstraintExpr); + + if (DiagnoseUnexpandedParameterPack(ConstraintExpr.get(), + UPPC_RequiresClause)) + return ExprError(); + + return ConstraintExpr; } /// This is invoked after parsing an in-class initializer for a diff --git a/clang/test/SemaTemplate/concepts.cpp b/clang/test/SemaTemplate/concepts.cpp index db154a9a0f5b..d228ff07837d 100644 --- a/clang/test/SemaTemplate/concepts.cpp +++ b/clang/test/SemaTemplate/concepts.cpp @@ -23,3 +23,31 @@ namespace PR47025 { static_assert(!AllAddable3<int, void>); static_assert(!AllAddable6<int, void>); } + +namespace PR45699 { + template<class> concept C = true; // expected-note 2{{here}} + template<class ...Ts> void f1a() requires C<Ts>; // expected-error {{requires clause contains unexpanded parameter pack 'Ts'}} + template<class ...Ts> requires C<Ts> void f1b(); // expected-error {{requires clause contains unexpanded parameter pack 'Ts'}} + template<class ...Ts> void f2a() requires (C<Ts> && ...); + template<class ...Ts> requires (C<Ts> && ...) void f2b(); + template<class ...Ts> void f3a() requires C<Ts...>; // expected-error {{pack expansion used as argument for non-pack parameter of concept}} + template<class ...Ts> requires C<Ts...> void f3b(); // expected-error {{pack expansion used as argument for non-pack parameter of concept}} + template<class ...Ts> void f4() { + ([] () requires C<Ts> {} ()); // expected-error {{expression contains unexpanded parameter pack 'Ts'}} + ([]<int = 0> requires C<Ts> () {} ()); // FIXME: expected-error {{lambda requires '()' before 'requires' clause}} expected-error 0+{{}} + } + template<class ...Ts> void f5() { + ([] () requires C<Ts> {} (), ...); + ([]<int = 0> requires C<Ts> () {} (), ...); // FIXME: expected-error {{lambda requires '()' before 'requires' clause}} expected-error 0+{{}} + } + void g() { + f1a(); + f1b(); // FIXME: Bad error recovery. expected-error {{undeclared identifier}} + f2a(); + f2b(); + f3a(); + f3b(); // FIXME: Bad error recovery. expected-error {{undeclared identifier}} + f4(); + f5(); + } +} _______________________________________________ cfe-commits mailing list cfe-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits