[clang] fb94369 - PR47025, PR47043: Diagnose unexpanded parameter packs in concept
Richard Smith via cfe-commits
cfe-commits at lists.llvm.org
Fri Aug 7 18:19:52 PDT 2020
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>);
+}
More information about the cfe-commits
mailing list