Author: Richard Smith Date: 2020-08-07T18:19:39-07:00 New Revision: fb943696cbc695b28d7deabf8ee0d1b1a6cc605a
URL: https://github.com/llvm/llvm-project/commit/fb943696cbc695b28d7deabf8ee0d1b1a6cc605a DIFF: https://github.com/llvm/llvm-project/commit/fb943696cbc695b28d7deabf8ee0d1b1a6cc605a.diff LOG: PR47025, PR47043: Diagnose unexpanded parameter packs in concept declarations and requires-expressions. Added: clang/test/SemaTemplate/concepts.cpp Modified: clang/include/clang/Basic/DiagnosticSemaKinds.td clang/include/clang/Sema/Sema.h clang/lib/Sema/SemaExprCXX.cpp clang/lib/Sema/SemaTemplate.cpp clang/lib/Sema/SemaTemplateVariadic.cpp Removed: ################################################################################ diff --git a/clang/include/clang/Basic/DiagnosticSemaKinds.td b/clang/include/clang/Basic/DiagnosticSemaKinds.td index 7185a4d6cab0..659f1d6df39e 100644 --- a/clang/include/clang/Basic/DiagnosticSemaKinds.td +++ b/clang/include/clang/Basic/DiagnosticSemaKinds.td @@ -5046,8 +5046,8 @@ def err_unexpanded_parameter_pack : Error< "size|static assertion|fixed underlying type|enumerator value|" "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}0 " - "contains%plural{0: an|:}1 unexpanded parameter pack" + "__if_exists name|__if_not_exists name|lambda|block|type constraint|" + "requirement}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 b88e5578c114..09e4c6743efc 100644 --- a/clang/include/clang/Sema/Sema.h +++ b/clang/include/clang/Sema/Sema.h @@ -7760,11 +7760,14 @@ class Sema final { /// Lambda expression. UPPC_Lambda, - /// Block expression, + /// Block expression. UPPC_Block, - /// A type constraint, - UPPC_TypeConstraint + /// A type constraint. + UPPC_TypeConstraint, + + // A requirement in a requires-expression. + UPPC_Requirement, }; /// Diagnose unexpanded parameter packs. @@ -7803,6 +7806,15 @@ class Sema final { bool DiagnoseUnexpandedParameterPack(Expr *E, UnexpandedParameterPackContext UPPC = UPPC_Expression); + /// If the given requirees-expression contains an unexpanded reference to one + /// of its own parameter packs, diagnose the error. + /// + /// \param RE The requiress-expression that is being checked for unexpanded + /// parameter packs. + /// + /// \returns true if an error occurred, false otherwise. + bool DiagnoseUnexpandedParameterPackInRequiresExpr(RequiresExpr *RE); + /// If the given nested-name-specifier contains an unexpanded /// parameter pack, diagnose the error. /// diff --git a/clang/lib/Sema/SemaExprCXX.cpp b/clang/lib/Sema/SemaExprCXX.cpp index fe5ba6a5e87f..335ee95715d0 100644 --- a/clang/lib/Sema/SemaExprCXX.cpp +++ b/clang/lib/Sema/SemaExprCXX.cpp @@ -8650,6 +8650,9 @@ Sema::ActOnRequiresExpr(SourceLocation RequiresKWLoc, ArrayRef<ParmVarDecl *> LocalParameters, ArrayRef<concepts::Requirement *> Requirements, SourceLocation ClosingBraceLoc) { - return RequiresExpr::Create(Context, RequiresKWLoc, Body, LocalParameters, - Requirements, ClosingBraceLoc); + auto *RE = RequiresExpr::Create(Context, RequiresKWLoc, Body, LocalParameters, + Requirements, ClosingBraceLoc); + if (DiagnoseUnexpandedParameterPackInRequiresExpr(RE)) + return ExprError(); + return RE; } diff --git a/clang/lib/Sema/SemaTemplate.cpp b/clang/lib/Sema/SemaTemplate.cpp index 5d037e58de51..d63d307b9ab7 100644 --- a/clang/lib/Sema/SemaTemplate.cpp +++ b/clang/lib/Sema/SemaTemplate.cpp @@ -8476,6 +8476,9 @@ Decl *Sema::ActOnConceptDefinition(Scope *S, return nullptr; } + if (DiagnoseUnexpandedParameterPack(ConstraintExpr)) + return nullptr; + ConceptDecl *NewDecl = ConceptDecl::Create(Context, DC, NameLoc, Name, TemplateParameterLists.front(), ConstraintExpr); diff --git a/clang/lib/Sema/SemaTemplateVariadic.cpp b/clang/lib/Sema/SemaTemplateVariadic.cpp index c95d67b7c732..623d808b59f6 100644 --- a/clang/lib/Sema/SemaTemplateVariadic.cpp +++ b/clang/lib/Sema/SemaTemplateVariadic.cpp @@ -408,6 +408,29 @@ bool Sema::DiagnoseUnexpandedParameterPack(Expr *E, return DiagnoseUnexpandedParameterPacks(E->getBeginLoc(), UPPC, Unexpanded); } +bool Sema::DiagnoseUnexpandedParameterPackInRequiresExpr(RequiresExpr *RE) { + if (!RE->containsUnexpandedParameterPack()) + return false; + + SmallVector<UnexpandedParameterPack, 2> Unexpanded; + CollectUnexpandedParameterPacksVisitor(Unexpanded).TraverseStmt(RE); + assert(!Unexpanded.empty() && "Unable to find unexpanded parameter packs"); + + // We only care about unexpanded references to the RequiresExpr's own + // parameter packs. + auto Parms = RE->getLocalParameters(); + llvm::SmallPtrSet<NamedDecl*, 8> ParmSet(Parms.begin(), Parms.end()); + SmallVector<UnexpandedParameterPack, 2> UnexpandedParms; + for (auto Parm : Unexpanded) + if (ParmSet.contains(Parm.first.dyn_cast<NamedDecl*>())) + UnexpandedParms.push_back(Parm); + if (UnexpandedParms.empty()) + return false; + + return DiagnoseUnexpandedParameterPacks(RE->getBeginLoc(), UPPC_Requirement, + UnexpandedParms); +} + bool Sema::DiagnoseUnexpandedParameterPack(const CXXScopeSpec &SS, UnexpandedParameterPackContext UPPC) { // C++0x [temp.variadic]p5: diff --git a/clang/test/SemaTemplate/concepts.cpp b/clang/test/SemaTemplate/concepts.cpp new file mode 100644 index 000000000000..db154a9a0f5b --- /dev/null +++ b/clang/test/SemaTemplate/concepts.cpp @@ -0,0 +1,25 @@ +// RUN: %clang_cc1 -std=c++20 -verify %s + +namespace PR47043 { + template<typename T> concept True = true; + template<typename ...T> concept AllTrue1 = True<T>; // expected-error {{expression contains unexpanded parameter pack 'T'}} + template<typename ...T> concept AllTrue2 = (True<T> && ...); + static_assert(AllTrue2<int, float, char>); +} + +namespace PR47025 { + template<typename ...T> concept AllAddable1 = requires(T ...t) { (void(t + 1), ...); }; + template<typename ...T> concept AllAddable2 = (requires(T ...t) { (t + 1); } && ...); // expected-error {{requirement contains unexpanded parameter pack 't'}} + template<typename ...T> concept AllAddable3 = (requires(T t) { (t + 1); } && ...); + template<typename ...T> concept AllAddable4 = requires(T t) { (t + 1); }; // expected-error {{expression contains unexpanded parameter pack 'T'}} + template<typename ...T> concept AllAddable5 = requires(T t) { (void(t + 1), ...); }; // expected-error {{does not contain any unexpanded}} + template<typename ...T> concept AllAddable6 = (requires { (T() + 1); } && ...); + template<typename ...T> concept AllAddable7 = requires { (T() + 1); }; // expected-error {{expression contains unexpanded parameter pack 'T'}} + + static_assert(AllAddable1<int, float>); + static_assert(AllAddable3<int, float>); + static_assert(AllAddable6<int, float>); + static_assert(!AllAddable1<int, void>); + static_assert(!AllAddable3<int, void>); + static_assert(!AllAddable6<int, void>); +} _______________________________________________ cfe-commits mailing list cfe-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits