[llvm-branch-commits] [clang] be162f4 - PR45699: Fix crash if an unexpanded parameter pack appears in a
Richard Smith via llvm-branch-commits
llvm-branch-commits at lists.llvm.org
Thu Dec 3 15:30:29 PST 2020
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();
+ }
+}
More information about the llvm-branch-commits
mailing list