declarations and requires-expressions.
"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<
/// 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.
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.
///
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;
}
return nullptr;
}
+ if (DiagnoseUnexpandedParameterPack(ConstraintExpr))
+ return nullptr;
+
ConceptDecl *NewDecl = ConceptDecl::Create(Context, DC, NameLoc, Name,
TemplateParameterLists.front(),
ConstraintExpr);
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:
--- /dev/null
+// 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>);
+}