[clang] 95d94a6 - Revert "Re-apply "Deferred Concept Instantiation Implementation"""
Erich Keane via cfe-commits
cfe-commits at lists.llvm.org
Fri Aug 19 12:49:42 PDT 2022
Author: Erich Keane
Date: 2022-08-19T12:47:34-07:00
New Revision: 95d94a67755620c0a2871ac6f056ca8e9731d5e9
URL: https://github.com/llvm/llvm-project/commit/95d94a67755620c0a2871ac6f056ca8e9731d5e9
DIFF: https://github.com/llvm/llvm-project/commit/95d94a67755620c0a2871ac6f056ca8e9731d5e9.diff
LOG: Revert "Re-apply "Deferred Concept Instantiation Implementation"""
This reverts commit d483730d8c3fa2e0d4192b2f3c61c761b124e6ad.
This allegedly breaks a significant part of facebooks internal build.
Reverting while we wait for them to provide a reproducer of this from
@wlei.
Added:
Modified:
clang/docs/ReleaseNotes.rst
clang/include/clang/Sema/Sema.h
clang/include/clang/Sema/Template.h
clang/lib/Sema/SemaConcept.cpp
clang/lib/Sema/SemaExpr.cpp
clang/lib/Sema/SemaOverload.cpp
clang/lib/Sema/SemaTemplate.cpp
clang/lib/Sema/SemaTemplateDeduction.cpp
clang/lib/Sema/SemaTemplateInstantiate.cpp
clang/lib/Sema/SemaTemplateInstantiateDecl.cpp
clang/lib/Sema/TreeTransform.h
clang/test/CXX/temp/temp.constr/temp.constr.constr/non-function-templates.cpp
clang/test/CXX/temp/temp.constr/temp.constr.order/class-template-partial-specializations.cpp
clang/test/CXX/temp/temp.constr/temp.constr.order/var-template-partial-specializations.cpp
clang/test/SemaTemplate/concepts.cpp
clang/test/SemaTemplate/instantiate-requires-clause.cpp
Removed:
clang/test/SemaTemplate/concepts-friends.cpp
clang/test/SemaTemplate/deferred-concept-inst.cpp
clang/test/SemaTemplate/trailing-return-short-circuit.cpp
################################################################################
diff --git a/clang/docs/ReleaseNotes.rst b/clang/docs/ReleaseNotes.rst
index e313f006b514..ee9c463bb346 100644
--- a/clang/docs/ReleaseNotes.rst
+++ b/clang/docs/ReleaseNotes.rst
@@ -149,10 +149,6 @@ C++ Language Changes in Clang
C++20 Feature Support
^^^^^^^^^^^^^^^^^^^^^
-- Clang now correctly delays the instantiation of function constraints until
- the time of checking, which should now allow the libstdc++ ranges implementation
- to work for at least trivial examples. This fixes
- `Issue 44178 <https://github.com/llvm/llvm-project/issues/44178>`_.
- Support capturing structured bindings in lambdas
(`P1091R3 <https://wg21.link/p1091r3>`_ and `P1381R1 <https://wg21.link/P1381R1>`).
diff --git a/clang/include/clang/Sema/Sema.h b/clang/include/clang/Sema/Sema.h
index 51e526a62274..28a47a2eea8b 100644
--- a/clang/include/clang/Sema/Sema.h
+++ b/clang/include/clang/Sema/Sema.h
@@ -3637,16 +3637,6 @@ class Sema final {
bool ConsiderCudaAttrs = true,
bool ConsiderRequiresClauses = true);
- // Calculates whether the expression Constraint depends on an enclosing
- // template, for the purposes of [temp.friend] p9.
- // TemplateDepth is the 'depth' of the friend function, which is used to
- // compare whether a declaration reference is referring to a containing
- // template, or just the current friend function. A 'lower' TemplateDepth in
- // the AST refers to a 'containing' template. As the constraint is
- // uninstantiated, this is relative to the 'top' of the TU.
- bool ConstraintExpressionDependsOnEnclosingTemplate(unsigned TemplateDepth,
- const Expr *Constraint);
-
enum class AllowedExplicit {
/// Allow no explicit functions to be used.
None,
@@ -7119,21 +7109,6 @@ class Sema final {
LocalInstantiationScope &Scope,
const MultiLevelTemplateArgumentList &TemplateArgs);
- /// used by SetupConstraintCheckingTemplateArgumentsAndScope to recursively(in
- /// the case of lambdas) set up the LocalInstantiationScope of the current
- /// function.
- bool SetupConstraintScope(
- FunctionDecl *FD, llvm::Optional<ArrayRef<TemplateArgument>> TemplateArgs,
- MultiLevelTemplateArgumentList MLTAL, LocalInstantiationScope &Scope);
-
- /// Used during constraint checking, sets up the constraint template arguemnt
- /// lists, and calls SetupConstraintScope to set up the
- /// LocalInstantiationScope to have the proper set of ParVarDecls configured.
- llvm::Optional<MultiLevelTemplateArgumentList>
- SetupConstraintCheckingTemplateArgumentsAndScope(
- FunctionDecl *FD, llvm::Optional<ArrayRef<TemplateArgument>> TemplateArgs,
- LocalInstantiationScope &Scope);
-
public:
const NormalizedConstraint *
getNormalizedAssociatedConstraints(
@@ -7176,39 +7151,6 @@ class Sema final {
bool CheckConstraintSatisfaction(
const NamedDecl *Template, ArrayRef<const Expr *> ConstraintExprs,
const MultiLevelTemplateArgumentList &TemplateArgLists,
- SourceRange TemplateIDRange, ConstraintSatisfaction &Satisfaction) {
- llvm::SmallVector<Expr *, 4> Converted;
- return CheckConstraintSatisfaction(Template, ConstraintExprs, Converted,
- TemplateArgLists, TemplateIDRange,
- Satisfaction);
- }
-
- /// \brief Check whether the given list of constraint expressions are
- /// satisfied (as if in a 'conjunction') given template arguments.
- /// Additionally, takes an empty list of Expressions which is populated with
- /// the instantiated versions of the ConstraintExprs.
- /// \param Template the template-like entity that triggered the constraints
- /// check (either a concept or a constrained entity).
- /// \param ConstraintExprs a list of constraint expressions, treated as if
- /// they were 'AND'ed together.
- /// \param ConvertedConstraints a out parameter that will get populated with
- /// the instantiated version of the ConstraintExprs if we successfully checked
- /// satisfaction.
- /// \param TemplateArgList the multi-level list of template arguments to
- /// substitute into the constraint expression. This should be relative to the
- /// top-level (hence multi-level), since we need to instantiate fully at the
- /// time of checking.
- /// \param TemplateIDRange The source range of the template id that
- /// caused the constraints check.
- /// \param Satisfaction if true is returned, will contain details of the
- /// satisfaction, with enough information to diagnose an unsatisfied
- /// expression.
- /// \returns true if an error occurred and satisfaction could not be checked,
- /// false otherwise.
- bool CheckConstraintSatisfaction(
- const NamedDecl *Template, ArrayRef<const Expr *> ConstraintExprs,
- llvm::SmallVectorImpl<Expr *> &ConvertedConstraints,
- const MultiLevelTemplateArgumentList &TemplateArgList,
SourceRange TemplateIDRange, ConstraintSatisfaction &Satisfaction);
/// \brief Check whether the given non-dependent constraint expression is
@@ -7228,8 +7170,8 @@ class Sema final {
/// \returns true if an error occurred, false otherwise.
bool CheckFunctionConstraints(const FunctionDecl *FD,
ConstraintSatisfaction &Satisfaction,
- SourceLocation UsageLoc = SourceLocation(),
- bool ForOverloadResolution = false);
+ SourceLocation UsageLoc = SourceLocation());
+
/// \brief Ensure that the given template arguments satisfy the constraints
/// associated with the given template, emitting a diagnostic if they do not.
@@ -8985,8 +8927,7 @@ class Sema final {
MultiLevelTemplateArgumentList getTemplateInstantiationArgs(
const NamedDecl *D, const TemplateArgumentList *Innermost = nullptr,
- bool RelativeToPrimary = false, const FunctionDecl *Pattern = nullptr,
- bool LookBeyondLambda = false, bool IncludeContainingStruct = false);
+ bool RelativeToPrimary = false, const FunctionDecl *Pattern = nullptr);
/// A context in which code is being synthesized (where a source location
/// alone is not sufficient to identify the context). This covers template
@@ -9694,21 +9635,23 @@ class Sema final {
const MultiLevelTemplateArgumentList &TemplateArgs,
SourceLocation Loc, DeclarationName Entity);
- TypeSourceInfo *SubstFunctionDeclType(
- TypeSourceInfo *T, const MultiLevelTemplateArgumentList &TemplateArgs,
- SourceLocation Loc, DeclarationName Entity, CXXRecordDecl *ThisContext,
- Qualifiers ThisTypeQuals, bool EvaluateConstraints = true);
+ TypeSourceInfo *SubstFunctionDeclType(TypeSourceInfo *T,
+ const MultiLevelTemplateArgumentList &TemplateArgs,
+ SourceLocation Loc,
+ DeclarationName Entity,
+ CXXRecordDecl *ThisContext,
+ Qualifiers ThisTypeQuals);
void SubstExceptionSpec(FunctionDecl *New, const FunctionProtoType *Proto,
const MultiLevelTemplateArgumentList &Args);
bool SubstExceptionSpec(SourceLocation Loc,
FunctionProtoType::ExceptionSpecInfo &ESI,
SmallVectorImpl<QualType> &ExceptionStorage,
const MultiLevelTemplateArgumentList &Args);
- ParmVarDecl *
- SubstParmVarDecl(ParmVarDecl *D,
- const MultiLevelTemplateArgumentList &TemplateArgs,
- int indexAdjustment, Optional<unsigned> NumExpansions,
- bool ExpectParameterPack, bool EvaluateConstraints = true);
+ ParmVarDecl *SubstParmVarDecl(ParmVarDecl *D,
+ const MultiLevelTemplateArgumentList &TemplateArgs,
+ int indexAdjustment,
+ Optional<unsigned> NumExpansions,
+ bool ExpectParameterPack);
bool SubstParmTypes(SourceLocation Loc, ArrayRef<ParmVarDecl *> Params,
const FunctionProtoType::ExtParameterInfo *ExtParamInfos,
const MultiLevelTemplateArgumentList &TemplateArgs,
@@ -9718,25 +9661,6 @@ class Sema final {
ExprResult SubstExpr(Expr *E,
const MultiLevelTemplateArgumentList &TemplateArgs);
- // A RAII type used by the TemplateDeclInstantiator and TemplateInstantiator
- // to disable constraint evaluation, then restore the state.
- template <typename InstTy> struct ConstraintEvalRAII {
- InstTy &TI;
- bool OldValue;
-
- ConstraintEvalRAII(InstTy &TI)
- : TI(TI), OldValue(TI.getEvaluateConstraints()) {
- TI.setEvaluateConstraints(false);
- }
- ~ConstraintEvalRAII() { TI.setEvaluateConstraints(OldValue); }
- };
-
- // Unlike the above, this evaluates constraints, which should only happen at
- // 'constraint checking' time.
- ExprResult
- SubstConstraintExpr(Expr *E,
- const MultiLevelTemplateArgumentList &TemplateArgs);
-
/// Substitute the given template arguments into a list of
/// expressions, expanding pack expansions if required.
///
@@ -9766,6 +9690,7 @@ class Sema final {
const MultiLevelTemplateArgumentList &TemplateArgs,
TemplateArgumentListInfo &Outputs);
+
Decl *SubstDecl(Decl *D, DeclContext *Owner,
const MultiLevelTemplateArgumentList &TemplateArgs);
@@ -9856,8 +9781,7 @@ class Sema final {
const MultiLevelTemplateArgumentList &TemplateArgs);
bool SubstTypeConstraint(TemplateTypeParmDecl *Inst, const TypeConstraint *TC,
- const MultiLevelTemplateArgumentList &TemplateArgs,
- bool EvaluateConstraint);
+ const MultiLevelTemplateArgumentList &TemplateArgs);
bool InstantiateDefaultArgument(SourceLocation CallLoc, FunctionDecl *FD,
ParmVarDecl *Param);
diff --git a/clang/include/clang/Sema/Template.h b/clang/include/clang/Sema/Template.h
index 2630853d1438..8df92b7000f3 100644
--- a/clang/include/clang/Sema/Template.h
+++ b/clang/include/clang/Sema/Template.h
@@ -503,7 +503,6 @@ enum class TemplateSubstitutionKind : char {
const MultiLevelTemplateArgumentList &TemplateArgs;
Sema::LateInstantiatedAttrVec* LateAttrs = nullptr;
LocalInstantiationScope *StartingScope = nullptr;
- bool EvaluateConstraints = true;
/// A list of out-of-line class template partial
/// specializations that will need to be instantiated after the
@@ -527,13 +526,6 @@ enum class TemplateSubstitutionKind : char {
SubstIndex(SemaRef, SemaRef.ArgumentPackSubstitutionIndex),
Owner(Owner), TemplateArgs(TemplateArgs) {}
- void setEvaluateConstraints(bool B) {
- EvaluateConstraints = B;
- }
- bool getEvaluateConstraints() {
- return EvaluateConstraints;
- }
-
// Define all the decl visitors using DeclNodes.inc
#define DECL(DERIVED, BASE) \
Decl *Visit ## DERIVED ## Decl(DERIVED ## Decl *D);
diff --git a/clang/lib/Sema/SemaConcept.cpp b/clang/lib/Sema/SemaConcept.cpp
index 240c656b953f..7545b7974ce4 100644
--- a/clang/lib/Sema/SemaConcept.cpp
+++ b/clang/lib/Sema/SemaConcept.cpp
@@ -18,7 +18,6 @@
#include "clang/Sema/Template.h"
#include "clang/Sema/Overload.h"
#include "clang/Sema/Initialization.h"
-#include "clang/AST/ASTLambda.h"
#include "clang/AST/ExprConcepts.h"
#include "clang/AST/RecursiveASTVisitor.h"
#include "clang/Basic/OperatorPrecedence.h"
@@ -31,7 +30,6 @@ using namespace sema;
namespace {
class LogicalBinOp {
- SourceLocation Loc;
OverloadedOperatorKind Op = OO_None;
const Expr *LHS = nullptr;
const Expr *RHS = nullptr;
@@ -42,14 +40,12 @@ class LogicalBinOp {
Op = BinaryOperator::getOverloadedOperator(BO->getOpcode());
LHS = BO->getLHS();
RHS = BO->getRHS();
- Loc = BO->getExprLoc();
} else if (auto *OO = dyn_cast<CXXOperatorCallExpr>(E)) {
// If OO is not || or && it might not have exactly 2 arguments.
if (OO->getNumArgs() == 2) {
Op = OO->getOperator();
LHS = OO->getArg(0);
RHS = OO->getArg(1);
- Loc = OO->getOperatorLoc();
}
}
}
@@ -60,26 +56,6 @@ class LogicalBinOp {
const Expr *getLHS() const { return LHS; }
const Expr *getRHS() const { return RHS; }
-
- ExprResult recreateBinOp(Sema &SemaRef, ExprResult LHS) const {
- return recreateBinOp(SemaRef, LHS, const_cast<Expr *>(getRHS()));
- }
-
- ExprResult recreateBinOp(Sema &SemaRef, ExprResult LHS,
- ExprResult RHS) const {
- assert((isAnd() || isOr()) && "Not the right kind of op?");
- assert((!LHS.isInvalid() && !RHS.isInvalid()) && "not good expressions?");
-
- if (!LHS.isUsable() || !RHS.isUsable())
- return ExprEmpty();
-
- // We should just be able to 'normalize' these to the builtin Binary
- // Operator, since that is how they are evaluated in constriant checks.
- return BinaryOperator::Create(SemaRef.Context, LHS.get(), RHS.get(),
- BinaryOperator::getOverloadedOpcode(Op),
- SemaRef.Context.BoolTy, VK_PRValue,
- OK_Ordinary, Loc, FPOptionsOverride{});
- }
};
}
@@ -146,18 +122,16 @@ bool Sema::CheckConstraintExpression(const Expr *ConstraintExpression,
}
template <typename AtomicEvaluator>
-static ExprResult
+static bool
calculateConstraintSatisfaction(Sema &S, const Expr *ConstraintExpr,
ConstraintSatisfaction &Satisfaction,
AtomicEvaluator &&Evaluator) {
ConstraintExpr = ConstraintExpr->IgnoreParenImpCasts();
if (LogicalBinOp BO = ConstraintExpr) {
- ExprResult LHSRes = calculateConstraintSatisfaction(
- S, BO.getLHS(), Satisfaction, Evaluator);
-
- if (LHSRes.isInvalid())
- return ExprError();
+ if (calculateConstraintSatisfaction(S, BO.getLHS(), Satisfaction,
+ Evaluator))
+ return true;
bool IsLHSSatisfied = Satisfaction.IsSatisfied;
@@ -168,7 +142,7 @@ calculateConstraintSatisfaction(Sema &S, const Expr *ConstraintExpr,
// is checked. If that is satisfied, the disjunction is satisfied.
// Otherwise, the disjunction is satisfied if and only if the second
// operand is satisfied.
- return BO.recreateBinOp(S, LHSRes);
+ return false;
if (BO.isAnd() && !IsLHSSatisfied)
// [temp.constr.op] p2
@@ -177,21 +151,12 @@ calculateConstraintSatisfaction(Sema &S, const Expr *ConstraintExpr,
// is checked. If that is not satisfied, the conjunction is not
// satisfied. Otherwise, the conjunction is satisfied if and only if
// the second operand is satisfied.
- return BO.recreateBinOp(S, LHSRes);
-
- ExprResult RHSRes = calculateConstraintSatisfaction(
- S, BO.getRHS(), Satisfaction, std::forward<AtomicEvaluator>(Evaluator));
- if (RHSRes.isInvalid())
- return ExprError();
-
- return BO.recreateBinOp(S, LHSRes, RHSRes);
- }
+ return false;
- if (auto *C = dyn_cast<ExprWithCleanups>(ConstraintExpr)) {
- // These aren't evaluated, so we don't care about cleanups, so we can just
- // evaluate these as if the cleanups didn't exist.
return calculateConstraintSatisfaction(
- S, C->getSubExpr(), Satisfaction,
+ S, BO.getRHS(), Satisfaction, std::forward<AtomicEvaluator>(Evaluator));
+ } else if (auto *C = dyn_cast<ExprWithCleanups>(ConstraintExpr)) {
+ return calculateConstraintSatisfaction(S, C->getSubExpr(), Satisfaction,
std::forward<AtomicEvaluator>(Evaluator));
}
@@ -199,11 +164,11 @@ calculateConstraintSatisfaction(Sema &S, const Expr *ConstraintExpr,
ExprResult SubstitutedAtomicExpr = Evaluator(ConstraintExpr);
if (SubstitutedAtomicExpr.isInvalid())
- return ExprError();
+ return true;
if (!SubstitutedAtomicExpr.isUsable())
// Evaluator has decided satisfaction without yielding an expression.
- return ExprEmpty();
+ return false;
EnterExpressionEvaluationContext ConstantEvaluated(
S, Sema::ExpressionEvaluationContext::ConstantEvaluated);
@@ -220,7 +185,7 @@ calculateConstraintSatisfaction(Sema &S, const Expr *ConstraintExpr,
<< SubstitutedAtomicExpr.get()->getSourceRange();
for (const PartialDiagnosticAt &PDiag : EvaluationDiags)
S.Diag(PDiag.first, PDiag.second);
- return ExprError();
+ return true;
}
assert(EvalResult.Val.isInt() &&
@@ -230,10 +195,10 @@ calculateConstraintSatisfaction(Sema &S, const Expr *ConstraintExpr,
Satisfaction.Details.emplace_back(ConstraintExpr,
SubstitutedAtomicExpr.get());
- return SubstitutedAtomicExpr;
+ return false;
}
-static ExprResult calculateConstraintSatisfaction(
+static bool calculateConstraintSatisfaction(
Sema &S, const NamedDecl *Template, SourceLocation TemplateNameLoc,
const MultiLevelTemplateArgumentList &MLTAL, const Expr *ConstraintExpr,
ConstraintSatisfaction &Satisfaction) {
@@ -254,8 +219,8 @@ static ExprResult calculateConstraintSatisfaction(
return ExprError();
// We do not want error diagnostics escaping here.
Sema::SFINAETrap Trap(S);
- SubstitutedExpression =
- S.SubstConstraintExpr(const_cast<Expr *>(AtomicExpr), MLTAL);
+ SubstitutedExpression = S.SubstExpr(const_cast<Expr *>(AtomicExpr),
+ MLTAL);
// Substitution might have stripped off a contextual conversion to
// bool if this is the operand of an '&&' or '||'. For example, we
// might lose an lvalue-to-rvalue conversion here. If so, put it back
@@ -305,7 +270,6 @@ static ExprResult calculateConstraintSatisfaction(
static bool CheckConstraintSatisfaction(
Sema &S, const NamedDecl *Template, ArrayRef<const Expr *> ConstraintExprs,
- llvm::SmallVectorImpl<Expr *> &Converted,
const MultiLevelTemplateArgumentList &TemplateArgsLists,
SourceRange TemplateIDRange, ConstraintSatisfaction &Satisfaction) {
if (ConstraintExprs.empty()) {
@@ -330,30 +294,22 @@ static bool CheckConstraintSatisfaction(
return true;
for (const Expr *ConstraintExpr : ConstraintExprs) {
- ExprResult Res = calculateConstraintSatisfaction(
- S, Template, TemplateIDRange.getBegin(), TemplateArgsLists,
- ConstraintExpr, Satisfaction);
- if (Res.isInvalid())
+ if (calculateConstraintSatisfaction(S, Template, TemplateIDRange.getBegin(),
+ TemplateArgsLists, ConstraintExpr,
+ Satisfaction))
return true;
-
- Converted.push_back(Res.get());
- if (!Satisfaction.IsSatisfied) {
- // Backfill the 'converted' list with nulls so we can keep the Converted
- // and unconverted lists in sync.
- Converted.append(ConstraintExprs.size() - Converted.size(), nullptr);
+ if (!Satisfaction.IsSatisfied)
// [temp.constr.op] p2
- // [...] To determine if a conjunction is satisfied, the satisfaction
- // of the first operand is checked. If that is not satisfied, the
- // conjunction is not satisfied. [...]
+ // [...] To determine if a conjunction is satisfied, the satisfaction
+ // of the first operand is checked. If that is not satisfied, the
+ // conjunction is not satisfied. [...]
return false;
- }
}
return false;
}
bool Sema::CheckConstraintSatisfaction(
const NamedDecl *Template, ArrayRef<const Expr *> ConstraintExprs,
- llvm::SmallVectorImpl<Expr *> &ConvertedConstraints,
const MultiLevelTemplateArgumentList &TemplateArgsLists,
SourceRange TemplateIDRange, ConstraintSatisfaction &OutSatisfaction) {
if (ConstraintExprs.empty()) {
@@ -361,9 +317,9 @@ bool Sema::CheckConstraintSatisfaction(
return false;
}
if (!Template) {
- return ::CheckConstraintSatisfaction(
- *this, nullptr, ConstraintExprs, ConvertedConstraints,
- TemplateArgsLists, TemplateIDRange, OutSatisfaction);
+ return ::CheckConstraintSatisfaction(*this, nullptr, ConstraintExprs,
+ TemplateArgsLists, TemplateIDRange,
+ OutSatisfaction);
}
// A list of the template argument list flattened in a predictible manner for
@@ -384,8 +340,8 @@ bool Sema::CheckConstraintSatisfaction(
auto Satisfaction =
std::make_unique<ConstraintSatisfaction>(Template, FlattenedArgs);
if (::CheckConstraintSatisfaction(*this, Template, ConstraintExprs,
- ConvertedConstraints, TemplateArgsLists,
- TemplateIDRange, *Satisfaction)) {
+ TemplateArgsLists, TemplateIDRange,
+ *Satisfaction)) {
return true;
}
OutSatisfaction = *Satisfaction;
@@ -399,120 +355,21 @@ bool Sema::CheckConstraintSatisfaction(
bool Sema::CheckConstraintSatisfaction(const Expr *ConstraintExpr,
ConstraintSatisfaction &Satisfaction) {
return calculateConstraintSatisfaction(
- *this, ConstraintExpr, Satisfaction,
- [this](const Expr *AtomicExpr) -> ExprResult {
- // We only do this to immitate lvalue-to-rvalue conversion.
- return PerformContextuallyConvertToBool(
- const_cast<Expr *>(AtomicExpr));
- })
- .isInvalid();
-}
-
-bool Sema::SetupConstraintScope(
- FunctionDecl *FD, llvm::Optional<ArrayRef<TemplateArgument>> TemplateArgs,
- MultiLevelTemplateArgumentList MLTAL, LocalInstantiationScope &Scope) {
- if (FD->isTemplateInstantiation() && FD->getPrimaryTemplate()) {
- FunctionTemplateDecl *PrimaryTemplate = FD->getPrimaryTemplate();
- InstantiatingTemplate Inst(
- *this, FD->getPointOfInstantiation(),
- Sema::InstantiatingTemplate::ConstraintsCheck{}, PrimaryTemplate,
- TemplateArgs ? *TemplateArgs : ArrayRef<TemplateArgument>{},
- SourceRange());
- if (Inst.isInvalid())
- return true;
-
- // addInstantiatedParametersToScope creates a map of 'uninstantiated' to
- // 'instantiated' parameters and adds it to the context. For the case where
- // this function is a template being instantiated NOW, we also need to add
- // the list of current template arguments to the list so that they also can
- // be picked out of the map.
- if (auto *SpecArgs = FD->getTemplateSpecializationArgs()) {
- MultiLevelTemplateArgumentList JustTemplArgs(*SpecArgs);
- if (addInstantiatedParametersToScope(
- FD, PrimaryTemplate->getTemplatedDecl(), Scope, JustTemplArgs))
- return true;
- }
-
- // If this is a member function, make sure we get the parameters that
- // reference the original primary template.
- if (const auto *FromMemTempl =
- PrimaryTemplate->getInstantiatedFromMemberTemplate()) {
- if (addInstantiatedParametersToScope(FD, FromMemTempl->getTemplatedDecl(),
- Scope, MLTAL))
- return true;
- }
-
- return false;
- }
-
- if (FD->getTemplatedKind() == FunctionDecl::TK_MemberSpecialization ||
- FD->getTemplatedKind() == FunctionDecl::TK_DependentNonTemplate) {
- FunctionDecl *InstantiatedFrom =
- FD->getTemplatedKind() == FunctionDecl::TK_MemberSpecialization
- ? FD->getInstantiatedFromMemberFunction()
- : FD->getInstantiatedFromDecl();
-
- InstantiatingTemplate Inst(
- *this, FD->getPointOfInstantiation(),
- Sema::InstantiatingTemplate::ConstraintsCheck{}, InstantiatedFrom,
- TemplateArgs ? *TemplateArgs : ArrayRef<TemplateArgument>{},
- SourceRange());
- if (Inst.isInvalid())
- return true;
-
- // Case where this was not a template, but instantiated as a
- // child-function.
- if (addInstantiatedParametersToScope(FD, InstantiatedFrom, Scope, MLTAL))
- return true;
- }
-
- return false;
-}
-
-// This function collects all of the template arguments for the purposes of
-// constraint-instantiation and checking.
-llvm::Optional<MultiLevelTemplateArgumentList>
-Sema::SetupConstraintCheckingTemplateArgumentsAndScope(
- FunctionDecl *FD, llvm::Optional<ArrayRef<TemplateArgument>> TemplateArgs,
- LocalInstantiationScope &Scope) {
- MultiLevelTemplateArgumentList MLTAL;
-
- // Collect the list of template arguments relative to the 'primary' template.
- // We need the entire list, since the constraint is completely uninstantiated
- // at this point.
- MLTAL = getTemplateInstantiationArgs(FD, nullptr, /*RelativeToPrimary*/ true,
- /*Pattern*/ nullptr,
- /*LookBeyondLambda*/ true);
- if (SetupConstraintScope(FD, TemplateArgs, MLTAL, Scope))
- return {};
-
- return MLTAL;
+ *this, ConstraintExpr, Satisfaction,
+ [this](const Expr *AtomicExpr) -> ExprResult {
+ // We only do this to immitate lvalue-to-rvalue conversion.
+ return PerformContextuallyConvertToBool(const_cast<Expr *>(AtomicExpr));
+ });
}
bool Sema::CheckFunctionConstraints(const FunctionDecl *FD,
ConstraintSatisfaction &Satisfaction,
- SourceLocation UsageLoc,
- bool ForOverloadResolution) {
- // Don't check constraints if the function is dependent. Also don't check if
- // this is a function template specialization, as the call to
- // CheckinstantiatedFunctionTemplateConstraints after this will check it
- // better.
- if (FD->isDependentContext() ||
- FD->getTemplatedKind() ==
- FunctionDecl::TK_FunctionTemplateSpecialization) {
+ SourceLocation UsageLoc) {
+ const Expr *RC = FD->getTrailingRequiresClause();
+ if (RC->isInstantiationDependent()) {
Satisfaction.IsSatisfied = true;
return false;
}
-
- ContextRAII SavedContext{
- *this, cast<DeclContext>(
- const_cast<FunctionDecl *>(FD)->getNonClosureContext())};
- LocalInstantiationScope Scope(*this, !ForOverloadResolution ||
- isLambdaCallOperator(FD));
- llvm::Optional<MultiLevelTemplateArgumentList> MLTAL =
- SetupConstraintCheckingTemplateArgumentsAndScope(
- const_cast<FunctionDecl *>(FD), {}, Scope);
-
Qualifiers ThisQuals;
CXXRecordDecl *Record = nullptr;
if (auto *Method = dyn_cast<CXXMethodDecl>(FD)) {
@@ -523,23 +380,10 @@ bool Sema::CheckFunctionConstraints(const FunctionDecl *FD,
// We substitute with empty arguments in order to rebuild the atomic
// constraint in a constant-evaluated context.
// FIXME: Should this be a dedicated TreeTransform?
- const Expr *RC = FD->getTrailingRequiresClause();
- llvm::SmallVector<Expr *, 1> Converted;
-
- if (CheckConstraintSatisfaction(
- FD, {RC}, Converted, *MLTAL,
- SourceRange(UsageLoc.isValid() ? UsageLoc : FD->getLocation()),
- Satisfaction))
- return true;
-
- // FIXME: we need to do this for the function constraints for
- // comparison of constraints to work, but do we also need to do it for
- // CheckInstantiatedFunctionConstraints? That one is more
diff icult, but we
- // seem to always just pick up the constraints from the primary template.
- assert(Converted.size() <= 1 && "Got more expressions converted?");
- if (!Converted.empty() && Converted[0] != nullptr)
- const_cast<FunctionDecl *>(FD)->setTrailingRequiresClause(Converted[0]);
- return false;
+ return CheckConstraintSatisfaction(
+ FD, {RC}, /*TemplateArgs=*/{},
+ SourceRange(UsageLoc.isValid() ? UsageLoc : FD->getLocation()),
+ Satisfaction);
}
bool Sema::EnsureTemplateArgumentListConstraints(
@@ -588,14 +432,26 @@ bool Sema::CheckInstantiatedFunctionTemplateConstraints(
// PushDeclContext because we don't have a scope.
Sema::ContextRAII savedContext(*this, Decl);
LocalInstantiationScope Scope(*this);
-
- Optional<MultiLevelTemplateArgumentList> MLTAL =
- SetupConstraintCheckingTemplateArgumentsAndScope(Decl, TemplateArgs,
- Scope);
-
- if (!MLTAL)
- return true;
-
+ MultiLevelTemplateArgumentList MLTAL;
+ // FIXME: This will be replaced with some logic to get all the template
+ // arguments when we switch to deferred template instantiation.
+ MLTAL.addOuterTemplateArguments(TemplateArgs);
+
+ // If this is not an explicit specialization - we need to get the instantiated
+ // version of the template arguments and add them to scope for the
+ // substitution.
+ if (Decl->isTemplateInstantiation()) {
+ InstantiatingTemplate Inst(*this, Decl->getPointOfInstantiation(),
+ InstantiatingTemplate::ConstraintsCheck{}, Decl->getPrimaryTemplate(),
+ TemplateArgs, SourceRange());
+ if (Inst.isInvalid())
+ return true;
+ MultiLevelTemplateArgumentList MLTAL(
+ *Decl->getTemplateSpecializationArgs());
+ if (addInstantiatedParametersToScope(
+ Decl, Decl->getPrimaryTemplate()->getTemplatedDecl(), Scope, MLTAL))
+ return true;
+ }
Qualifiers ThisQuals;
CXXRecordDecl *Record = nullptr;
if (auto *Method = dyn_cast<CXXMethodDecl>(Decl)) {
@@ -603,8 +459,7 @@ bool Sema::CheckInstantiatedFunctionTemplateConstraints(
Record = Method->getParent();
}
CXXThisScopeRAII ThisScope(*this, Record, ThisQuals, Record != nullptr);
- llvm::SmallVector<Expr *, 1> Converted;
- return CheckConstraintSatisfaction(Template, TemplateAC, Converted, *MLTAL,
+ return CheckConstraintSatisfaction(Template, TemplateAC, MLTAL,
PointOfInstantiation, Satisfaction);
}
@@ -879,22 +734,22 @@ Sema::getNormalizedAssociatedConstraints(
return CacheEntry->second;
}
-static bool
-substituteParameterMappings(Sema &S, NormalizedConstraint &N,
- ConceptDecl *Concept,
- const MultiLevelTemplateArgumentList &MLTAL,
- const ASTTemplateArgumentListInfo *ArgsAsWritten) {
+static bool substituteParameterMappings(Sema &S, NormalizedConstraint &N,
+ ConceptDecl *Concept, ArrayRef<TemplateArgument> TemplateArgs,
+ const ASTTemplateArgumentListInfo *ArgsAsWritten) {
if (!N.isAtomic()) {
- if (substituteParameterMappings(S, N.getLHS(), Concept, MLTAL,
+ if (substituteParameterMappings(S, N.getLHS(), Concept, TemplateArgs,
ArgsAsWritten))
return true;
- return substituteParameterMappings(S, N.getRHS(), Concept, MLTAL,
+ return substituteParameterMappings(S, N.getRHS(), Concept, TemplateArgs,
ArgsAsWritten);
}
TemplateParameterList *TemplateParams = Concept->getTemplateParameters();
AtomicConstraint &Atomic = *N.getAtomicConstraint();
TemplateArgumentListInfo SubstArgs;
+ MultiLevelTemplateArgumentList MLTAL;
+ MLTAL.addOuterTemplateArguments(TemplateArgs);
if (!Atomic.ParameterMapping) {
llvm::SmallBitVector OccurringIndices(TemplateParams->size());
S.MarkUsedTemplateParameters(Atomic.ConstraintExpr, /*OnlyDeduced=*/false,
@@ -935,20 +790,6 @@ substituteParameterMappings(Sema &S, NormalizedConstraint &N,
return false;
}
-static bool substituteParameterMappings(Sema &S, NormalizedConstraint &N,
- const ConceptSpecializationExpr *CSE) {
- TemplateArgumentList TAL{TemplateArgumentList::OnStack,
- CSE->getTemplateArguments()};
- MultiLevelTemplateArgumentList MLTAL =
- S.getTemplateInstantiationArgs(CSE->getNamedConcept(), &TAL,
- /*RelativeToPrimary*/ true,
- /*Pattern*/ nullptr,
- /*LookBeyondLambda*/ true);
-
- return substituteParameterMappings(S, N, CSE->getNamedConcept(), MLTAL,
- CSE->getTemplateArgsAsWritten());
-}
-
Optional<NormalizedConstraint>
NormalizedConstraint::fromConstraintExprs(Sema &S, NamedDecl *D,
ArrayRef<const Expr *> E) {
@@ -1011,7 +852,9 @@ NormalizedConstraint::fromConstraintExpr(Sema &S, NamedDecl *D, const Expr *E) {
Optional<NormalizedConstraint> New;
New.emplace(S.Context, *SubNF);
- if (substituteParameterMappings(S, *New, CSE))
+ if (substituteParameterMappings(
+ S, *New, CSE->getNamedConcept(),
+ CSE->getTemplateArguments(), CSE->getTemplateArgsAsWritten()))
return None;
return New;
diff --git a/clang/lib/Sema/SemaExpr.cpp b/clang/lib/Sema/SemaExpr.cpp
index 377bfaa5f177..59918464148c 100644
--- a/clang/lib/Sema/SemaExpr.cpp
+++ b/clang/lib/Sema/SemaExpr.cpp
@@ -283,8 +283,7 @@ bool Sema::DiagnoseUseOfDecl(NamedDecl *D, ArrayRef<SourceLocation> Locs,
// definition.
if (FD->getTrailingRequiresClause()) {
ConstraintSatisfaction Satisfaction;
- if (CheckFunctionConstraints(FD, Satisfaction, Loc,
- /*ForOverloadResolution*/ true))
+ if (CheckFunctionConstraints(FD, Satisfaction, Loc))
// A diagnostic will have already been generated (non-constant
// constraint expression, for example)
return true;
diff --git a/clang/lib/Sema/SemaOverload.cpp b/clang/lib/Sema/SemaOverload.cpp
index 623bd288e502..91e308d0d0fe 100644
--- a/clang/lib/Sema/SemaOverload.cpp
+++ b/clang/lib/Sema/SemaOverload.cpp
@@ -992,78 +992,6 @@ static bool checkArgPlaceholdersForOverload(Sema &S, MultiExprArg Args,
return false;
}
-// Figure out the to-translation-unit depth for this function declaration for
-// the purpose of seeing if they
diff er by constraints. This isn't the same as
-// getTemplateDepth, because it includes already instantiated parents.
-static unsigned CalculateTemplateDepthForConstraints(Sema &S,
- FunctionDecl *FD) {
- MultiLevelTemplateArgumentList MLTAL =
- S.getTemplateInstantiationArgs(FD, nullptr, /*RelativeToPrimary*/ true,
- /*Pattern*/ nullptr,
- /*LookBeyondLambda*/ true);
- return MLTAL.getNumSubstitutedLevels();
-}
-
-// Friend definitions can appear identical but be
diff erent declarations based
-// on the last sentence of the rule below (others included for clarification):
-// C++20 [temp.friend] p9: A non-template friend declaration
-// with a requires-clause shall be a definition. A friend function template
-// with a constraint that depends on a template parameter from an enclosing
-// template shall be a definition. Such a constrained friend function or
-// function template declaration does not declare the same function or function
-// template as a declaration in any other scope.
-static bool FriendsDifferByConstraints(Sema &S, DeclContext *CurContext,
- FunctionDecl *Old, FunctionDecl *New,
- Scope *Scope) {
- // If these aren't friends, than they aren't friends that
diff ere by
- // constraints.
- if (!Old->getFriendObjectKind() || !New->getFriendObjectKind())
- return false;
-
- // If the the two functions share lexical declaration context, they are not in
- // separate instantations, and thus in the same scope.
- if (New->getLexicalDeclContext() == Old->getLexicalDeclContext())
- return false;
-
- if (!Old->getDescribedFunctionTemplate()) {
- assert(!New->getDescribedFunctionTemplate() &&
- "How would these be the same if they aren't both templates?");
-
- // If these friends don't have constraints, they aren't constrained, and
- // thus don't fall under temp.friend p9. Else the simple presence of a
- // constraint makes them unique.
- return Old->getTrailingRequiresClause();
- }
-
- SmallVector<const Expr *, 3> OldAC;
- Old->getDescribedFunctionTemplate()->getAssociatedConstraints(OldAC);
-
-#ifndef NDEBUG
- SmallVector<const Expr *, 3> NewAC;
- New->getDescribedFunctionTemplate()->getAssociatedConstraints(NewAC);
- assert(OldAC.size() == NewAC.size() &&
- "Difference should have been noticed earlier if sizes of constraints "
- "aren't the same");
-#endif
- // If there are no constraints, these are not constrained friend function or
- // friend function templates.
- if (OldAC.size() == 0)
- return false;
-
- unsigned OldTemplateDepth = CalculateTemplateDepthForConstraints(S, Old);
-
- // At this point, if the constrained function template declaration depends on
- // a template parameter from an enclosing template, they are not the same
- // function. Since these were deemed identical before we got here, we only
- // have to look into 1 side to see if they refer to a containing template.
- for (const Expr *Constraint : OldAC)
- if (S.ConstraintExpressionDependsOnEnclosingTemplate(OldTemplateDepth,
- Constraint))
- return true;
-
- return false;
-}
-
/// Determine whether the given New declaration is an overload of the
/// declarations in Old. This routine returns Ovl_Match or Ovl_NonFunction if
/// New and Old cannot be overloaded, e.g., if New has the same signature as
@@ -1140,15 +1068,6 @@ Sema::CheckOverload(Scope *S, FunctionDecl *New, const LookupResult &Old,
!shouldLinkPossiblyHiddenDecl(*I, New))
continue;
- // C++20 [temp.friend] p9: A non-template friend declaration with a
- // requires-clause shall be a definition. A friend function template
- // with a constraint that depends on a template parameter from an
- // enclosing template shall be a definition. Such a constrained friend
- // function or function template declaration does not declare the same
- // function or function template as a declaration in any other scope.
- if (FriendsDifferByConstraints(*this, CurContext, OldF, New, S))
- continue;
-
Match = *I;
return Ovl_Match;
}
@@ -6596,8 +6515,7 @@ void Sema::AddOverloadCandidate(
if (Function->getTrailingRequiresClause()) {
ConstraintSatisfaction Satisfaction;
- if (CheckFunctionConstraints(Function, Satisfaction, /*Loc*/ {},
- /*ForOverloadResolution*/ true) ||
+ if (CheckFunctionConstraints(Function, Satisfaction) ||
!Satisfaction.IsSatisfied) {
Candidate.Viable = false;
Candidate.FailureKind = ovl_fail_constraints_not_satisfied;
@@ -7103,8 +7021,7 @@ Sema::AddMethodCandidate(CXXMethodDecl *Method, DeclAccessPair FoundDecl,
if (Method->getTrailingRequiresClause()) {
ConstraintSatisfaction Satisfaction;
- if (CheckFunctionConstraints(Method, Satisfaction, /*Loc*/ {},
- /*ForOverloadResolution*/ true) ||
+ if (CheckFunctionConstraints(Method, Satisfaction) ||
!Satisfaction.IsSatisfied) {
Candidate.Viable = false;
Candidate.FailureKind = ovl_fail_constraints_not_satisfied;
diff --git a/clang/lib/Sema/SemaTemplate.cpp b/clang/lib/Sema/SemaTemplate.cpp
index 6bc1a35ee946..1d9c36477192 100644
--- a/clang/lib/Sema/SemaTemplate.cpp
+++ b/clang/lib/Sema/SemaTemplate.cpp
@@ -1686,59 +1686,6 @@ NamedDecl *Sema::ActOnTemplateTemplateParameter(Scope* S,
return Param;
}
-namespace {
-class ConstraintRefersToContainingTemplateChecker
- : public TreeTransform<ConstraintRefersToContainingTemplateChecker> {
- bool Result = false;
- unsigned TemplateDepth = 0;
-
-public:
- using inherited = TreeTransform<ConstraintRefersToContainingTemplateChecker>;
-
- ConstraintRefersToContainingTemplateChecker(Sema &SemaRef,
- unsigned TemplateDepth)
- : inherited(SemaRef), TemplateDepth(TemplateDepth) {}
- bool getResult() const { return Result; }
-
- // This should be the only template parm type that we have to deal with.
- // SubstTempalteTypeParmPack, SubstNonTypeTemplateParmPack, and
- // FunctionParmPackExpr are all partially substituted, which cannot happen
- // with concepts at this point in translation.
- QualType TransformTemplateTypeParmType(TypeLocBuilder &TLB,
- TemplateTypeParmTypeLoc TL) {
- assert(TL.getDecl()->getDepth() <= TemplateDepth &&
- "Nothing should reference a value below the actual template depth, "
- "depth is likely wrong");
- if (TL.getDecl()->getDepth() != TemplateDepth)
- Result = true;
- return inherited::TransformTemplateTypeParmType(TLB, TL);
- }
-
- Decl *TransformDecl(SourceLocation Loc, Decl *D) {
- // FIXME : This is possibly an incomplete list, but it is unclear what other
- // Decl kinds could be used to refer to the template parameters. This is a
- // best guess so far based on examples currently available, but the
- // unreachable should catch future instances/cases.
- if (auto *TD = dyn_cast<TypedefNameDecl>(D))
- TransformType(TD->getUnderlyingType());
- else if (auto *VD = dyn_cast<ValueDecl>(D))
- TransformType(VD->getType());
- else if (auto *TD = dyn_cast<TemplateDecl>(D))
- TransformTemplateParameterList(TD->getTemplateParameters());
- else
- llvm_unreachable("Don't know how to handle this declaration type yet");
- return D;
- }
-};
-} // namespace
-
-bool Sema::ConstraintExpressionDependsOnEnclosingTemplate(
- unsigned TemplateDepth, const Expr *Constraint) {
- ConstraintRefersToContainingTemplateChecker Checker(*this, TemplateDepth);
- Checker.TransformExpr(const_cast<Expr *>(Constraint));
- return Checker.getResult();
-}
-
/// ActOnTemplateParameterList - Builds a TemplateParameterList, optionally
/// constrained by RequiresClause, that contains the template parameters in
/// Params.
@@ -2340,8 +2287,7 @@ struct ConvertConstructorToDeductionGuideTransform {
TTP->isExpandedParameterPack() ?
llvm::Optional<unsigned>(TTP->getNumExpansionParameters()) : None);
if (const auto *TC = TTP->getTypeConstraint())
- SemaRef.SubstTypeConstraint(NewTTP, TC, Args,
- /*EvaluateConstraint*/ true);
+ SemaRef.SubstTypeConstraint(NewTTP, TC, Args);
if (TTP->hasDefaultArgument()) {
TypeSourceInfo *InstantiatedDefaultArg =
SemaRef.SubstType(TTP->getDefaultArgumentInfo(), Args,
@@ -6027,12 +5973,10 @@ bool Sema::CheckTemplateArgumentList(
TemplateArgs = std::move(NewArgs);
if (!PartialTemplateArgs) {
- TemplateArgumentList StackTemplateArgs(TemplateArgumentList::OnStack,
- Converted);
- MultiLevelTemplateArgumentList MLTAL = getTemplateInstantiationArgs(
- Template, &StackTemplateArgs, /*RelativeToPrimary*/ true,
- /*Pattern*/ nullptr,
- /*LookBeyondLambda*/ true, /*IncludeContainingStruct*/ true);
+ // FIXME: This will be changed a bit once deferred concept instantiation is
+ // implemented.
+ MultiLevelTemplateArgumentList MLTAL;
+ MLTAL.addOuterTemplateArguments(Converted);
if (EnsureTemplateArgumentListConstraints(
Template, MLTAL,
SourceRange(TemplateLoc, TemplateArgs.getRAngleLoc()))) {
@@ -7569,9 +7513,7 @@ bool Sema::CheckTemplateTemplateArgument(TemplateTemplateParmDecl *Param,
// are not considered.
if (ParamsAC.empty())
return false;
-
Template->getAssociatedConstraints(TemplateAC);
-
bool IsParamAtLeastAsConstrained;
if (IsAtLeastAsConstrained(Param, ParamsAC, Template, TemplateAC,
IsParamAtLeastAsConstrained))
diff --git a/clang/lib/Sema/SemaTemplateDeduction.cpp b/clang/lib/Sema/SemaTemplateDeduction.cpp
index bddf2c0f6966..99119bcb2e4e 100644
--- a/clang/lib/Sema/SemaTemplateDeduction.cpp
+++ b/clang/lib/Sema/SemaTemplateDeduction.cpp
@@ -2827,20 +2827,6 @@ template<>
struct IsPartialSpecialization<VarTemplatePartialSpecializationDecl> {
static constexpr bool value = true;
};
-template <typename TemplateDeclT>
-static bool DeducedArgsNeedReplacement(TemplateDeclT *Template) {
- return false;
-}
-template <>
-bool DeducedArgsNeedReplacement<VarTemplatePartialSpecializationDecl>(
- VarTemplatePartialSpecializationDecl *Spec) {
- return !Spec->isClassScopeExplicitSpecialization();
-}
-template <>
-bool DeducedArgsNeedReplacement<ClassTemplatePartialSpecializationDecl>(
- ClassTemplatePartialSpecializationDecl *Spec) {
- return !Spec->isClassScopeExplicitSpecialization();
-}
template<typename TemplateDeclT>
static Sema::TemplateDeductionResult
@@ -2849,25 +2835,13 @@ CheckDeducedArgumentConstraints(Sema& S, TemplateDeclT *Template,
TemplateDeductionInfo& Info) {
llvm::SmallVector<const Expr *, 3> AssociatedConstraints;
Template->getAssociatedConstraints(AssociatedConstraints);
+ // FIXME: This will change quite a bit once deferred concept instantiation is
+ // implemented.
MultiLevelTemplateArgumentList MLTAL;
+ MLTAL.addOuterTemplateArguments(DeducedArgs);
- bool NeedsReplacement = DeducedArgsNeedReplacement(Template);
- TemplateArgumentList DeducedTAL{TemplateArgumentList::OnStack, DeducedArgs};
-
- MLTAL = S.getTemplateInstantiationArgs(
- Template, /*InnerMost*/ NeedsReplacement ? nullptr : &DeducedTAL,
- /*RelativeToPrimary*/ true, /*Pattern*/
- nullptr, /*LookBeyondLambda*/ true);
-
- // getTemplateInstantiationArgs picks up the non-deduced version of the
- // template args when this is a variable template partial specialization and
- // not class-scope explicit specialization, so replace with Deduced Args
- // instead of adding to inner-most.
- if (NeedsReplacement)
- MLTAL.replaceInnermostTemplateArguments(DeducedArgs);
-
- if (S.CheckConstraintSatisfaction(Template, AssociatedConstraints, MLTAL,
- Info.getLocation(),
+ if (S.CheckConstraintSatisfaction(Template, AssociatedConstraints,
+ MLTAL, Info.getLocation(),
Info.AssociatedConstraintsSatisfaction) ||
!Info.AssociatedConstraintsSatisfaction.IsSatisfied) {
Info.reset(TemplateArgumentList::CreateCopy(S.Context, DeducedArgs));
diff --git a/clang/lib/Sema/SemaTemplateInstantiate.cpp b/clang/lib/Sema/SemaTemplateInstantiate.cpp
index 44c714c59217..1dd4baf90182 100644
--- a/clang/lib/Sema/SemaTemplateInstantiate.cpp
+++ b/clang/lib/Sema/SemaTemplateInstantiate.cpp
@@ -57,18 +57,9 @@ using namespace sema;
/// instantiating the definition of the given declaration, \p D. This is
/// used to determine the proper set of template instantiation arguments for
/// friend function template specializations.
-///
-/// \param LookBeyondLambda Indicates that this collection of arguments should
-/// continue looking when it encounters a lambda generic call operator.
-///
-/// \param IncludeContainingStructArgs Indicates that this collection of
-/// arguments should include arguments for any class template that this
-/// declaration is included inside of.
-
MultiLevelTemplateArgumentList Sema::getTemplateInstantiationArgs(
const NamedDecl *D, const TemplateArgumentList *Innermost,
- bool RelativeToPrimary, const FunctionDecl *Pattern, bool LookBeyondLambda,
- bool IncludeContainingStructArgs) {
+ bool RelativeToPrimary, const FunctionDecl *Pattern) {
// Accumulate the set of template argument lists in this structure.
MultiLevelTemplateArgumentList Result;
@@ -164,13 +155,11 @@ MultiLevelTemplateArgumentList Sema::getTemplateInstantiationArgs(
break;
// If this function is a generic lambda specialization, we are done.
- if (!LookBeyondLambda &&
- isGenericLambdaCallOperatorOrStaticInvokerSpecialization(Function))
+ if (isGenericLambdaCallOperatorOrStaticInvokerSpecialization(Function))
break;
} else if (Function->getDescribedFunctionTemplate()) {
- assert((IncludeContainingStructArgs ||
- Result.getNumSubstitutedLevels() == 0) &&
+ assert(Result.getNumSubstitutedLevels() == 0 &&
"Outer template not instantiated?");
}
@@ -187,18 +176,10 @@ MultiLevelTemplateArgumentList Sema::getTemplateInstantiationArgs(
}
} else if (const auto *Rec = dyn_cast<CXXRecordDecl>(Ctx)) {
if (ClassTemplateDecl *ClassTemplate = Rec->getDescribedClassTemplate()) {
- assert((IncludeContainingStructArgs ||
- Result.getNumSubstitutedLevels() == 0) &&
+ assert(Result.getNumSubstitutedLevels() == 0 &&
"Outer template not instantiated?");
if (ClassTemplate->isMemberSpecialization())
break;
- if (IncludeContainingStructArgs) {
- QualType RecordType = Context.getTypeDeclType(Rec);
- QualType Injected = cast<InjectedClassNameType>(RecordType)
- ->getInjectedSpecializationType();
- const auto *InjectedType = cast<TemplateSpecializationType>(Injected);
- Result.addOuterTemplateArguments(InjectedType->template_arguments());
- }
}
}
@@ -949,23 +930,16 @@ namespace {
const MultiLevelTemplateArgumentList &TemplateArgs;
SourceLocation Loc;
DeclarationName Entity;
- bool EvaluateConstraints = true;
public:
typedef TreeTransform<TemplateInstantiator> inherited;
TemplateInstantiator(Sema &SemaRef,
const MultiLevelTemplateArgumentList &TemplateArgs,
- SourceLocation Loc, DeclarationName Entity)
- : inherited(SemaRef), TemplateArgs(TemplateArgs), Loc(Loc),
- Entity(Entity) {}
-
- void setEvaluateConstraints(bool B) {
- EvaluateConstraints = B;
- }
- bool getEvaluateConstraints() {
- return EvaluateConstraints;
- }
+ SourceLocation Loc,
+ DeclarationName Entity)
+ : inherited(SemaRef), TemplateArgs(TemplateArgs), Loc(Loc),
+ Entity(Entity) { }
/// Determine whether the given type \p T has already been
/// transformed.
@@ -1172,9 +1146,7 @@ namespace {
ExprResult TransformLambdaExpr(LambdaExpr *E) {
LocalInstantiationScope Scope(SemaRef, /*CombineWithOuterScope=*/true);
- Sema::ConstraintEvalRAII<TemplateInstantiator> RAII(*this);
- ExprResult Res = inherited::TransformLambdaExpr(E);
- return Res;
+ return inherited::TransformLambdaExpr(E);
}
ExprResult TransformRequiresExpr(RequiresExpr *E) {
@@ -1219,7 +1191,6 @@ namespace {
DeclContext *Owner = OrigTPL->getParam(0)->getDeclContext();
TemplateDeclInstantiator DeclInstantiator(getSema(),
/* DeclContext *Owner */ Owner, TemplateArgs);
- DeclInstantiator.setEvaluateConstraints(EvaluateConstraints);
return DeclInstantiator.SubstTemplateParams(OrigTPL);
}
@@ -1795,9 +1766,9 @@ TemplateInstantiator::TransformFunctionTypeParam(ParmVarDecl *OldParm,
int indexAdjustment,
Optional<unsigned> NumExpansions,
bool ExpectParameterPack) {
- auto NewParm = SemaRef.SubstParmVarDecl(
- OldParm, TemplateArgs, indexAdjustment, NumExpansions,
- ExpectParameterPack, EvaluateConstraints);
+ auto NewParm =
+ SemaRef.SubstParmVarDecl(OldParm, TemplateArgs, indexAdjustment,
+ NumExpansions, ExpectParameterPack);
if (NewParm && SemaRef.getLangOpts().OpenCL)
SemaRef.deduceOpenCLAddressSpace(NewParm);
return NewParm;
@@ -2015,7 +1986,8 @@ TemplateInstantiator::TransformExprRequirement(concepts::ExprRequirement *Req) {
Req, Info, OrigTPL->getSourceRange());
if (TPLInst.isInvalid())
return nullptr;
- TemplateParameterList *TPL = TransformTemplateParameterList(OrigTPL);
+ TemplateParameterList *TPL =
+ TransformTemplateParameterList(OrigTPL);
if (!TPL)
TransRetReq.emplace(createSubstDiag(SemaRef, Info,
[&] (llvm::raw_ostream& OS) {
@@ -2225,8 +2197,7 @@ TypeSourceInfo *Sema::SubstFunctionDeclType(TypeSourceInfo *T,
SourceLocation Loc,
DeclarationName Entity,
CXXRecordDecl *ThisContext,
- Qualifiers ThisTypeQuals,
- bool EvaluateConstraints) {
+ Qualifiers ThisTypeQuals) {
assert(!CodeSynthesisContexts.empty() &&
"Cannot perform an instantiation without some context on the "
"instantiation stack");
@@ -2235,7 +2206,6 @@ TypeSourceInfo *Sema::SubstFunctionDeclType(TypeSourceInfo *T,
return T;
TemplateInstantiator Instantiator(*this, Args, Loc, Entity);
- Instantiator.setEvaluateConstraints(EvaluateConstraints);
TypeLocBuilder TLB;
@@ -2380,19 +2350,9 @@ namespace {
bool Sema::SubstTypeConstraint(
TemplateTypeParmDecl *Inst, const TypeConstraint *TC,
- const MultiLevelTemplateArgumentList &TemplateArgs,
- bool EvaluateConstraints) {
+ const MultiLevelTemplateArgumentList &TemplateArgs) {
const ASTTemplateArgumentListInfo *TemplArgInfo =
TC->getTemplateArgsAsWritten();
-
- if (!EvaluateConstraints) {
- Inst->setTypeConstraint(TC->getNestedNameSpecifierLoc(),
- TC->getConceptNameInfo(), TC->getNamedConcept(),
- TC->getNamedConcept(), TemplArgInfo,
- TC->getImmediatelyDeclaredConstraint());
- return false;
- }
-
TemplateArgumentListInfo InstArgs;
if (TemplArgInfo) {
@@ -2411,11 +2371,11 @@ bool Sema::SubstTypeConstraint(
: SourceLocation());
}
-ParmVarDecl *
-Sema::SubstParmVarDecl(ParmVarDecl *OldParm,
- const MultiLevelTemplateArgumentList &TemplateArgs,
- int indexAdjustment, Optional<unsigned> NumExpansions,
- bool ExpectParameterPack, bool EvaluateConstraint) {
+ParmVarDecl *Sema::SubstParmVarDecl(ParmVarDecl *OldParm,
+ const MultiLevelTemplateArgumentList &TemplateArgs,
+ int indexAdjustment,
+ Optional<unsigned> NumExpansions,
+ bool ExpectParameterPack) {
TypeSourceInfo *OldDI = OldParm->getTypeSourceInfo();
TypeSourceInfo *NewDI = nullptr;
@@ -2473,7 +2433,9 @@ Sema::SubstParmVarDecl(ParmVarDecl *OldParm,
// template's described function, but we might also get here later.
// Make sure we do not instantiate the TypeConstraint more than once.
if (Inst && !Inst->getTypeConstraint()) {
- if (SubstTypeConstraint(Inst, TC, TemplateArgs, EvaluateConstraint))
+ // TODO: Concepts: do not instantiate the constraint (delayed constraint
+ // substitution)
+ if (SubstTypeConstraint(Inst, TC, TemplateArgs))
return nullptr;
}
}
@@ -3560,9 +3522,11 @@ bool Sema::SubstTemplateArguments(
ArrayRef<TemplateArgumentLoc> Args,
const MultiLevelTemplateArgumentList &TemplateArgs,
TemplateArgumentListInfo &Out) {
- TemplateInstantiator Instantiator(*this, TemplateArgs, SourceLocation(),
+ TemplateInstantiator Instantiator(*this, TemplateArgs,
+ SourceLocation(),
DeclarationName());
- return Instantiator.TransformTemplateArguments(Args.begin(), Args.end(), Out);
+ return Instantiator.TransformTemplateArguments(Args.begin(), Args.end(),
+ Out);
}
ExprResult
@@ -3576,23 +3540,11 @@ Sema::SubstExpr(Expr *E, const MultiLevelTemplateArgumentList &TemplateArgs) {
return Instantiator.TransformExpr(E);
}
-ExprResult
-Sema::SubstConstraintExpr(Expr *E,
- const MultiLevelTemplateArgumentList &TemplateArgs) {
- if (!E)
- return E;
-
- // This is where we need to make sure we 'know' constraint checking needs to
- // happen.
- TemplateInstantiator Instantiator(*this, TemplateArgs, SourceLocation(),
- DeclarationName());
- return Instantiator.TransformExpr(E);
-}
-
ExprResult Sema::SubstInitializer(Expr *Init,
const MultiLevelTemplateArgumentList &TemplateArgs,
bool CXXDirectInit) {
- TemplateInstantiator Instantiator(*this, TemplateArgs, SourceLocation(),
+ TemplateInstantiator Instantiator(*this, TemplateArgs,
+ SourceLocation(),
DeclarationName());
return Instantiator.TransformInitializer(Init, CXXDirectInit);
}
diff --git a/clang/lib/Sema/SemaTemplateInstantiateDecl.cpp b/clang/lib/Sema/SemaTemplateInstantiateDecl.cpp
index 7c43aa79ea14..140844ca4e81 100644
--- a/clang/lib/Sema/SemaTemplateInstantiateDecl.cpp
+++ b/clang/lib/Sema/SemaTemplateInstantiateDecl.cpp
@@ -1823,7 +1823,6 @@ TemplateDeclInstantiator::VisitFunctionTemplateDecl(FunctionTemplateDecl *D) {
// merged with the local instantiation scope for the function template
// itself.
LocalInstantiationScope Scope(SemaRef);
- Sema::ConstraintEvalRAII<TemplateDeclInstantiator> RAII(*this);
TemplateParameterList *TempParams = D->getTemplateParameters();
TemplateParameterList *InstParams = SubstTemplateParams(TempParams);
@@ -2063,7 +2062,19 @@ Decl *TemplateDeclInstantiator::VisitFunctionDecl(
return nullptr;
}
+ // FIXME: Concepts: Do not substitute into constraint expressions
Expr *TrailingRequiresClause = D->getTrailingRequiresClause();
+ if (TrailingRequiresClause) {
+ EnterExpressionEvaluationContext ConstantEvaluated(
+ SemaRef, Sema::ExpressionEvaluationContext::Unevaluated);
+ ExprResult SubstRC = SemaRef.SubstExpr(TrailingRequiresClause,
+ TemplateArgs);
+ if (SubstRC.isInvalid())
+ return nullptr;
+ TrailingRequiresClause = SubstRC.get();
+ if (!SemaRef.CheckConstraintExpression(TrailingRequiresClause))
+ return nullptr;
+ }
// If we're instantiating a local function declaration, put the result
// in the enclosing namespace; otherwise we need to find the instantiated
@@ -2414,6 +2425,23 @@ Decl *TemplateDeclInstantiator::VisitCXXMethodDecl(
return nullptr;
}
+ // FIXME: Concepts: Do not substitute into constraint expressions
+ Expr *TrailingRequiresClause = D->getTrailingRequiresClause();
+ if (TrailingRequiresClause) {
+ EnterExpressionEvaluationContext ConstantEvaluated(
+ SemaRef, Sema::ExpressionEvaluationContext::Unevaluated);
+ auto *ThisContext = dyn_cast_or_null<CXXRecordDecl>(Owner);
+ Sema::CXXThisScopeRAII ThisScope(SemaRef, ThisContext,
+ D->getMethodQualifiers(), ThisContext);
+ ExprResult SubstRC = SemaRef.SubstExpr(TrailingRequiresClause,
+ TemplateArgs);
+ if (SubstRC.isInvalid())
+ return nullptr;
+ TrailingRequiresClause = SubstRC.get();
+ if (!SemaRef.CheckConstraintExpression(TrailingRequiresClause))
+ return nullptr;
+ }
+
DeclContext *DC = Owner;
if (isFriend) {
if (QualifierLoc) {
@@ -2431,9 +2459,6 @@ Decl *TemplateDeclInstantiator::VisitCXXMethodDecl(
if (!DC) return nullptr;
}
- CXXRecordDecl *Record = cast<CXXRecordDecl>(DC);
- Expr *TrailingRequiresClause = D->getTrailingRequiresClause();
-
DeclarationNameInfo NameInfo
= SemaRef.SubstDeclarationNameInfo(D->getNameInfo(), TemplateArgs);
@@ -2441,6 +2466,7 @@ Decl *TemplateDeclInstantiator::VisitCXXMethodDecl(
adjustForRewrite(FunctionRewriteKind, D, T, TInfo, NameInfo);
// Build the instantiated method declaration.
+ CXXRecordDecl *Record = cast<CXXRecordDecl>(DC);
CXXMethodDecl *Method = nullptr;
SourceLocation StartLoc = D->getInnerLocStart();
@@ -2745,11 +2771,13 @@ Decl *TemplateDeclInstantiator::VisitTemplateTypeParmDecl(
Inst->setImplicit(D->isImplicit());
if (auto *TC = D->getTypeConstraint()) {
if (!D->isImplicit()) {
- // Invented template parameter type constraints will be instantiated
- // with the corresponding auto-typed parameter as it might reference
- // other parameters.
- if (SemaRef.SubstTypeConstraint(Inst, TC, TemplateArgs,
- EvaluateConstraints))
+ // Invented template parameter type constraints will be instantiated with
+ // the corresponding auto-typed parameter as it might reference other
+ // parameters.
+
+ // TODO: Concepts: do not instantiate the constraint (delayed constraint
+ // substitution)
+ if (SemaRef.SubstTypeConstraint(Inst, TC, TemplateArgs))
return nullptr;
}
}
@@ -3993,7 +4021,18 @@ TemplateDeclInstantiator::SubstTemplateParams(TemplateParameterList *L) {
if (Invalid)
return nullptr;
- Expr *InstRequiresClause = L->getRequiresClause();
+ // FIXME: Concepts: Substitution into requires clause should only happen when
+ // checking satisfaction.
+ Expr *InstRequiresClause = nullptr;
+ if (Expr *E = L->getRequiresClause()) {
+ EnterExpressionEvaluationContext ConstantEvaluated(
+ SemaRef, Sema::ExpressionEvaluationContext::Unevaluated);
+ ExprResult Res = SemaRef.SubstExpr(E, TemplateArgs);
+ if (Res.isInvalid() || !Res.isUsable()) {
+ return nullptr;
+ }
+ InstRequiresClause = Res.get();
+ }
TemplateParameterList *InstL
= TemplateParameterList::Create(SemaRef.Context, L->getTemplateLoc(),
@@ -4287,9 +4326,11 @@ TemplateDeclInstantiator::SubstFunctionType(FunctionDecl *D,
ThisTypeQuals = Method->getMethodQualifiers();
}
- TypeSourceInfo *NewTInfo = SemaRef.SubstFunctionDeclType(
- OldTInfo, TemplateArgs, D->getTypeSpecStartLoc(), D->getDeclName(),
- ThisContext, ThisTypeQuals, EvaluateConstraints);
+ TypeSourceInfo *NewTInfo
+ = SemaRef.SubstFunctionDeclType(OldTInfo, TemplateArgs,
+ D->getTypeSpecStartLoc(),
+ D->getDeclName(),
+ ThisContext, ThisTypeQuals);
if (!NewTInfo)
return nullptr;
diff --git a/clang/lib/Sema/TreeTransform.h b/clang/lib/Sema/TreeTransform.h
index db9fa77d3937..142e00a73ddb 100644
--- a/clang/lib/Sema/TreeTransform.h
+++ b/clang/lib/Sema/TreeTransform.h
@@ -13081,6 +13081,13 @@ TreeTransform<Derived>::TransformLambdaExpr(LambdaExpr *E) {
NewCallOpType);
}
+ // Transform the trailing requires clause
+ ExprResult NewTrailingRequiresClause;
+ if (Expr *TRC = E->getCallOperator()->getTrailingRequiresClause())
+ // FIXME: Concepts: Substitution into requires clause should only happen
+ // when checking satisfaction.
+ NewTrailingRequiresClause = getDerived().TransformExpr(TRC);
+
// Create the local class that will describe the lambda.
// FIXME: DependencyKind below is wrong when substituting inside a templated
@@ -13115,7 +13122,7 @@ TreeTransform<Derived>::TransformLambdaExpr(LambdaExpr *E) {
E->getCallOperator()->getEndLoc(),
NewCallOpTSI->getTypeLoc().castAs<FunctionProtoTypeLoc>().getParams(),
E->getCallOperator()->getConstexprKind(),
- E->getCallOperator()->getTrailingRequiresClause());
+ NewTrailingRequiresClause.get());
LSI->CallOperator = NewCallOperator;
diff --git a/clang/test/CXX/temp/temp.constr/temp.constr.constr/non-function-templates.cpp b/clang/test/CXX/temp/temp.constr/temp.constr.constr/non-function-templates.cpp
index 15e00e4481e7..dd6bfe8011dd 100644
--- a/clang/test/CXX/temp/temp.constr/temp.constr.constr/non-function-templates.cpp
+++ b/clang/test/CXX/temp/temp.constr/temp.constr.constr/non-function-templates.cpp
@@ -90,24 +90,3 @@ struct D { };
static_assert(C<int>{}); // expected-note{{while checking constraint satisfaction for template 'C<int>' required here}}
static_assert(D<int>{}); // expected-note{{while checking constraint satisfaction for template 'D<int>' required here}}
-
-// Test the delayed instantiation, the 'foo' implementation shouldn't cause the
-// constraint failure(or crash!) until the use to create 'y'.
-namespace DelayedInst {
-template <unsigned I>
-struct AAA {
- template <typename T>
- requires(sizeof(T) == I) // expected-note {{because 'sizeof(int) == 5U' (4 == 5) evaluated to false}}
- struct B {
- static constexpr int a = 0;
- };
-
- static constexpr auto foo() {
- return B<int>::a; // expected-error{{constraints not satisfied for class template 'B' [with T = int]}}
- }
-};
-
-constexpr auto x = AAA<4>::foo();
-constexpr auto y = AAA<5>::foo(); // expected-note {{in instantiation of member function 'DelayedInst::AAA<5>::foo' requested here}}
-
-} // namespace DelayedInst
diff --git a/clang/test/CXX/temp/temp.constr/temp.constr.order/class-template-partial-specializations.cpp b/clang/test/CXX/temp/temp.constr/temp.constr.order/class-template-partial-specializations.cpp
index 7772eecc69be..ceb5af87b8f0 100644
--- a/clang/test/CXX/temp/temp.constr/temp.constr.order/class-template-partial-specializations.cpp
+++ b/clang/test/CXX/temp/temp.constr/temp.constr.order/class-template-partial-specializations.cpp
@@ -52,30 +52,6 @@ static_assert(F<unsigned>::value == 2);
static_assert(F<char[10]>::value == 3);
static_assert(F<char>::value == 1);
-template <unsigned I>
-struct S {
- template <typename T>
- struct F {
- enum { value = 1 };
- };
-
- template <typename T>
- requires C1<T> && C2<T>
- struct F<T> {
- enum { value = 2 };
- };
-
- template <typename T>
- requires C1<T> || C2<T>
- struct F<T> {
- enum { value = 3 };
- };
-};
-
-static_assert(S<1>::F<unsigned>::value == 2);
-static_assert(S<1>::F<char[10]>::value == 3);
-static_assert(S<1>::F<char>::value == 1);
-
// Make sure atomic constraints subsume each other only if their parameter
// mappings are identical.
diff --git a/clang/test/CXX/temp/temp.constr/temp.constr.order/var-template-partial-specializations.cpp b/clang/test/CXX/temp/temp.constr/temp.constr.order/var-template-partial-specializations.cpp
index 972a4fd0c5c8..98bfaead773a 100644
--- a/clang/test/CXX/temp/temp.constr/temp.constr.order/var-template-partial-specializations.cpp
+++ b/clang/test/CXX/temp/temp.constr/temp.constr.order/var-template-partial-specializations.cpp
@@ -51,20 +51,5 @@ static_assert(f<unsigned> == 2);
static_assert(f<char[10]> == 3);
static_assert(f<char> == 1);
-template <int I>
-struct S {
- template <typename T>
- static constexpr int f = 1;
-
- template <typename T>
- requires C1<T> && C2<T>
- static constexpr int f<T> = 2;
-
- template <typename T>
- requires C1<T> || C2<T>
- static constexpr int f<T> = 3;
-};
-
-static_assert(S<1>::f<unsigned> == 2);
-static_assert(S<1>::f<char[10]> == 3);
-static_assert(S<1>::f<char> == 1);
+
+
diff --git a/clang/test/SemaTemplate/concepts-friends.cpp b/clang/test/SemaTemplate/concepts-friends.cpp
deleted file mode 100644
index 650376732339..000000000000
--- a/clang/test/SemaTemplate/concepts-friends.cpp
+++ /dev/null
@@ -1,371 +0,0 @@
-// RUN: %clang_cc1 -std=c++20 -fsyntax-only -verify %s
-
-template <typename T>
-concept constraint = false;
-namespace temp_friend_9 {
-// A non-template friend declaration with a requires-clause shall be a
-// definition. ...Such a constrained friend function ... does not declare the
-// same function or function template as a declaration in any other scope.
-template <typename T>
-struct NonTemplateFriend {
- friend void foo()
- requires true
- {}
-};
-
-// A friend function template with a constraint that depends on a template
-// parameter from an enclosing template shall be a definition. Such a ...
-// function template declaration does not declare the same function or
-// function template as a declaration in any other scope.
-template <typename T>
-struct TemplateFromEnclosing {
- template <typename U>
- friend void foo()
- requires constraint<T>
- {}
-
- T variable;
- template <typename U>
- friend void foo2()
- requires constraint<decltype(variable)>
- {}
-
- template <typename U>
- friend void foo3(T parmvar)
- requires constraint<decltype(parmvar)>
- {}
-
- template <typename U>
- friend void foo4()
- requires requires(T &req) { (void)req; }
- {}
-
- using Alias = T;
- template <typename U>
- friend void foo5()
- requires constraint<Alias>
- {}
-
- // All of these refer to a parent, so these are not duplicate definitions.
- struct ChildOfEnclosing {
- template <typename U>
- friend void foo6()
- requires constraint<T>
- {}
- template <typename U>
- friend void foo7()
- requires constraint<decltype(variable)>
- {}
- template <typename U>
- friend void foo8(T parmvar)
- requires constraint<decltype(parmvar)>
- {}
- // This is NOT a duplicate since it itself is not a template.
- friend void foo9()
- requires true
- {}
- };
- template <typename T2>
- struct TemplChildOfEnclosing {
- template <typename U>
- friend void foo10()
- requires constraint<T>
- {}
- };
-};
-
-// Doesn't meet either of the requirements in the above as they don't refer to
-// an enclosing scope.
-template <typename T>
-struct Redefinition {
- template <typename U>
- friend void foo() // #REDEF
- requires constraint<U>
- {}
-
- struct ChildOfRedef {
- template <typename U>
- friend void foo2() // #REDEF2
- requires constraint<U>
- {}
- };
- template <typename T2>
- struct ChildOfRedef2 {
- template <typename U>
- friend void foo3() // #REDEF3
- requires constraint<U>
- {}
- };
-};
-
-void bar() {
- NonTemplateFriend<int> S1;
- NonTemplateFriend<float> S2;
- TemplateFromEnclosing<int> S3;
- TemplateFromEnclosing<int>::ChildOfEnclosing S3b;
- TemplateFromEnclosing<float> S4;
- TemplateFromEnclosing<float>::ChildOfEnclosing S4b;
- Redefinition<int> S5;
- Redefinition<float> S6;
- // expected-error@#REDEF {{redefinition of 'foo'}}
- // expected-note at -2{{in instantiation of template class }}
- // expected-note@#REDEF {{previous definition is here}}
- Redefinition<int>::ChildOfRedef S7;
- Redefinition<float>::ChildOfRedef S8;
- // expected-error@#REDEF2 {{redefinition of 'foo2'}}
- // expected-note at -2{{in instantiation of member class }}
- // expected-note@#REDEF2 {{previous definition is here}}
-
- Redefinition<int>::ChildOfRedef2<int> S9;
- Redefinition<float>::ChildOfRedef2<float> S10;
- // expected-error@#REDEF3 {{redefinition of 'foo3'}}
- // expected-note at -2{{in instantiation of template class }}
- // expected-note@#REDEF3 {{previous definition is here}}
-}
-} // namespace temp_friend_9
-
-namespace SameScopeRedefs {
-template <typename T>
-struct NonTemplateFriend {
- friend void foo() // #NTF1
- requires true
- {}
- friend void foo() // #NTF2
- requires true
- {}
-};
-
-template <typename T>
-struct TemplateFromEnclosing {
- template <typename U>
- friend void foo() // #TFE1
- requires constraint<T>
- {}
- template <typename U>
- friend void foo() // #TFE2
- requires constraint<T>
- {}
-};
-// Same as above, but doesn't require an instantiation pair to cause.
-template <typename T>
-struct Redefinition {
- template <typename U>
- friend void foo() // #RD1
- requires constraint<U>
- {}
- template <typename U>
- friend void foo() // #RD2
- requires constraint<U>
- {}
-};
-void bar() {
- NonTemplateFriend<int> S1;
- // expected-error@#NTF2 {{redefinition of 'foo'}}
- // expected-note at -2{{in instantiation of template class}}
- // expected-note@#NTF1 {{previous definition is here}}
-
- TemplateFromEnclosing<int> S2;
- // expected-error@#TFE2 {{redefinition of 'foo'}}
- // expected-note at -2{{in instantiation of template class}}
- // expected-note@#TFE1 {{previous definition is here}}
-
- Redefinition<int> S3;
- // expected-error@#RD2 {{redefinition of 'foo'}}
- // expected-note at -2{{in instantiation of template class}}
- // expected-note@#RD1 {{previous definition is here}}
-}
-} // namespace SameScopeRedefs
-
-namespace LibCXXOperatorRedef {
-template <typename T, typename U> struct is_same {
- static constexpr bool value = false;
-};
-template <typename T> struct is_same<T, T> {
- static constexpr bool value = false;
-};
-
-template <typename T, typename U>
-concept same_as = is_same<T, U>::value;
-
-// An issue found from libcxx when trying to commit the deferred concepts patch.
-// This caused an error of 'redefinition of funcN'.
-template <class _Tp> struct __range_adaptor_closure {
- template <typename _View, typename _Closure>
- requires same_as<_Tp, _Closure>
- friend constexpr decltype(auto) R1func1(_View &&__view,
- _Closure &&__closure){};
- template <typename _View, typename _Closure>
- friend constexpr decltype(auto) R1func2(_View &&__view,
- _Closure &&__closure)
- requires same_as<_Tp, _Closure>
- {};
- template <same_as<_Tp> _View, typename _Closure>
- friend constexpr decltype(auto) R1func3(_View &&__view,
- _Closure &&__closure){};
-};
-
-struct A : __range_adaptor_closure<A> {};
-struct B : __range_adaptor_closure<B> {};
-
-// These three fail because after the 1st pass of instantiation, they are still
-// identical.
-template <class _Tp> struct __range_adaptor_closure2 {
- template <typename _View, typename _Closure>
- requires same_as<_View, _Closure>
- friend constexpr decltype(auto) R2func1(_View &&__view, // #FUNC1
- _Closure &&__closure){};
- template <typename _View, typename _Closure>
- friend constexpr decltype(auto) R2func2(_View &&__view, // #FUNC2
- _Closure &&__closure)
- requires same_as<_View, _Closure>
- {};
- template <typename _View, same_as<_View> _Closure>
- friend constexpr decltype(auto) R2func3(_View &&__view, // #FUNC3
- _Closure &&__closure){};
-};
-
-struct A2 : __range_adaptor_closure2<A2> {};
-struct B2 : __range_adaptor_closure2<B2> {};
-// expected-error@#FUNC1{{redefinition of 'R2func1'}}
-// expected-note at -2{{in instantiation of template class}}
-// expected-note@#FUNC1{{previous definition is here}}
-// expected-error@#FUNC2{{redefinition of 'R2func2'}}
-// expected-note@#FUNC2{{previous definition is here}}
-// expected-error@#FUNC3{{redefinition of 'R2func3'}}
-// expected-note@#FUNC3{{previous definition is here}}
-
-// These three are fine, they all depend on the parent template parameter, so
-// are
diff erent despite ::type not being valid.
-template <class _Tp> struct __range_adaptor_closure3 {
- template <typename _View, typename _Closure>
- requires same_as<typename _Tp::type, _Closure>
- friend constexpr decltype(auto) R3func1(_View &&__view,
- _Closure &&__closure){};
- template <typename _View, typename _Closure>
- friend constexpr decltype(auto) R3func2(_View &&__view,
- _Closure &&__closure)
- requires same_as<typename _Tp::type, _Closure>
- {};
- template <same_as<typename _Tp::type> _View, typename _Closure>
- friend constexpr decltype(auto) R3func3(_View &&__view,
- _Closure &&__closure){};
-};
-
-struct A3 : __range_adaptor_closure3<A3> {};
-struct B3 : __range_adaptor_closure3<B3> {};
-
-template <class _Tp> struct __range_adaptor_closure4 {
- template <typename _View, typename _Closure>
- requires same_as<_Tp, _View>
- // expected-note at +1{{previous definition is here}}
- void foo1(_View &&, _Closure &&) {}
- template <typename _View, typename _Closure>
- requires same_as<_Tp, _View>
- // expected-error at +1{{class member cannot be redeclared}}
- void foo1(_View &&, _Closure &&) {}
-
- template <typename _View, typename _Closure>
- // expected-note at +1{{previous definition is here}}
- void foo2(_View &&, _Closure &&)
- requires same_as<_Tp, _View>
- {}
- template <typename _View, typename _Closure>
- // expected-error at +1{{class member cannot be redeclared}}
- void foo2(_View &&, _Closure &&)
- requires same_as<_Tp, _View>
- {}
-
- template <same_as<_Tp> _View, typename _Closure>
- // expected-note at +1{{previous definition is here}}
- void foo3(_View &&, _Closure &&) {}
- template <same_as<_Tp> _View, typename _Closure>
- // expected-error at +1{{class member cannot be redeclared}}
- void foo3(_View &&, _Closure &&) {}
-};
-
-// Requires instantiation to fail, so no errors here.
-template <class _Tp> struct __range_adaptor_closure5 {
- template <same_as<_Tp> U>
- friend void foo() {}
- template <same_as<_Tp> U>
- friend void foo() {}
-};
-
-template <class _Tp> struct __range_adaptor_closure6 {
- template <same_as<_Tp> U>
- friend void foo() {} // #RAC6FOO1
- template <same_as<_Tp> U>
- friend void foo() {} // #RAC6FOO2
-};
-struct A6 : __range_adaptor_closure6<A6> {};
-// expected-error@#RAC6FOO2{{redefinition of 'foo'}}
-// expected-note at -2{{in instantiation of template class}}
-// expected-note@#RAC6FOO1{{previous definition is here}}
-
-template <class T> struct S1 {
- template <typename U>
- friend void dupe() {} // #S1DUPE
-
- template <typename U>
- requires same_as<U, U>
- friend void dupe2() {} // #S1DUPE2
-};
-template <class T> struct S2 {
- template <typename U>
- friend void dupe() {} // #S2DUPE
-
- template <typename U>
- requires same_as<U, U>
- friend void dupe2() {} // #S2DUPE2
-};
-
-template <class T> struct S3 {
- template <typename U>
- requires same_as<T, U>
- friend void dupe() {}
-};
-template <class T> struct S4 {
- template <typename U>
- requires same_as<T, U>
- friend void dupe() {}
-};
-
-// Same as S3 and S4, but aren't instantiated with the same T.
-template <class T> struct S5 {
- template <typename U>
- requires same_as<T, U>
- friend void not_dupe() {}
-};
-template <class T> struct S6 {
- template <typename U>
- requires same_as<T, U>
- friend void not_dupe() {}
-};
-
-template <class T> struct S7 {
- void not_dupe()
- requires same_as<T, T>
- {}
-};
-
-void useS() {
- S1<int> s1;
- S2<double> s2;
- // expected-error@#S2DUPE{{redefinition}}
- // expected-note at -2{{in instantiation of template class}}
- // expected-note@#S1DUPE{{previous definition is here}}
- // expected-error@#S2DUPE2{{redefinition}}
- // expected-note@#S1DUPE2{{previous definition is here}}
-
- // OK, they have
diff erent 'scopes'.
- S3<int> s3;
- S4<int> s4;
-
- // OK, because only instantiated with
diff erent T.
- S5<int> s5;
- S6<double> s6;
-
- S7<int> s7;
-}
-
-} // namespace LibCXXOperatorRedef
diff --git a/clang/test/SemaTemplate/concepts.cpp b/clang/test/SemaTemplate/concepts.cpp
index 836ab6f5e0dc..23c79421bb6f 100644
--- a/clang/test/SemaTemplate/concepts.cpp
+++ b/clang/test/SemaTemplate/concepts.cpp
@@ -256,387 +256,3 @@ C auto **j1 = g(); // expected-error {{deduced type 'int' does not satisfy 'C'
C auto **&j2 = g(); // expected-error {{deduced type 'int' does not satisfy 'C'}}
C auto **&&j3 = g(); // expected-error {{deduced type 'int' does not satisfy 'C'}}
}
-
-namespace SubConstraintChecks {
-template <typename T>
-concept TrueConstraint = true;
-template <typename T>
-concept FalseConstraint = false;
-
-template <typename T, typename... Us>
-class ContainsConstrainedFuncTrue {
-public:
- template <typename V, TrueConstraint Constrained>
- static void func(V &&, Constrained &&C);
-};
-template <typename T, typename... Us>
-class ContainsConstrainedFuncFalse {
-public:
- template <typename V, FalseConstraint Constrained>
- static void func(V &&, Constrained &&C);
-};
-
-template <typename... Us>
-concept TrueConstraint2 =
- requires(float &&t) {
- ContainsConstrainedFuncTrue<float, Us...>::func(5, 0.0);
- };
-template <typename... Us>
-concept FalseConstraint2 =
- requires(float &&t) {
- ContainsConstrainedFuncFalse<float, Us...>::func(5, 0.0); // #FC2_CONSTR
- };
-
-template <typename T>
-void useTrue(int F)
- requires TrueConstraint2<int>
-{}
-
-template <typename T>
-void useFalse(int F) // #USE_FALSE
- requires FalseConstraint2<int> // #USE_FALSE_CONSTR
-{}
-
-// Should only diagnose 'false' once instantiated.
-void UseUse() {
- useTrue<int>(5);
- useFalse<int>(5);
- // expected-error at -1{{no matching function for call to 'useFalse'}}
- // expected-note@#USE_FALSE{{constraints not satisfied}}
- // expected-note@#USE_FALSE_CONSTR{{because 'int' does not satisfy 'FalseConstraint2'}}
- // expected-note@#FC2_CONSTR {{would be invalid: no matching function for call to 'func'}}
-}
-} // namespace SubConstraintChecks
-
-namespace DeducedTemplateArgs {
-template <typename Itr> struct ItrTraits {
- template <typename PtrItr> struct Ptr {
- };
- template <typename PtrItr>
- requires requires { typename PtrItr::pointer; }
- struct Ptr<PtrItr> {
- using type = typename Itr::pointer;
- };
- using pointer = typename Ptr<Itr>::type; // #TRAITS_PTR
-};
-
-struct complete_itr {
- using pointer = int;
-};
-
-template <typename T> class Complete {
- using ItrType = ItrTraits<complete_itr>;
- ItrType begin() noexcept { return ItrType(); }
-};
-
-// This version doesn't have 'pointer', so error confirms we are in the first
-// verison of 'Ptr'.
-struct not_complete_itr {
-};
-
-template <typename T> class NotComplete {
- using ItrType = ItrTraits<not_complete_itr>;
- ItrType begin() noexcept { return ItrType(); }
- // expected-error@#TRAITS_PTR{{no type named 'type' in }}
- // expected-note at -2{{in instantiation of template class }}
-};
-} // namespace DeducedTemplateArgs
-
-namespace DeferredInstantiationInstScope {
-template <typename T>
-struct remove_ref {
- using type = T;
-};
-template <typename T>
-struct remove_ref<T &> {
- using type = T;
-};
-template <typename T>
-struct remove_ref<T &&> {
- using type = T;
-};
-
-template <typename T>
-constexpr bool IsInt = PR54443::is_same<typename remove_ref<T>::type,
- int>::value;
-
-template <typename U>
-void SingleDepthReferencesTop(U &&u) {
- struct lc {
- void operator()() // #SDRT_OP
- requires IsInt<decltype(u)> // #SDRT_REQ
- {}
- };
- lc lv;
- lv(); // #SDRT_CALL
-}
-
-template <typename U>
-void SingleDepthReferencesTopNotCalled(U &&u) {
- struct lc {
- void operator()()
- requires IsInt<typename decltype(u)::FOO>
- {}
- };
- lc lv;
-}
-
-template <typename U>
-void SingleDepthReferencesTopCalled(U &&u) {
- struct lc {
- void operator()() // #CALLOP
- requires IsInt<typename decltype(u)::FOO> // #CONSTR
- {}
- };
- lc lv;
- lv();
- // expected-error at -1{{no matching function for call to object of type 'lc'}}
- // expected-note@#SDRTC{{in instantiation of function template}}
- // expected-note@#CALLOP{{constraints not satisfied}}
- // expected-note@#CONSTR{{substituted constraint expression is ill-formed}}
-}
-
-template <typename U>
-void SingleDepthReferencesTopLambda(U &&u) {
- []()
- requires IsInt<decltype(u)>
- {}();
-}
-
-template <typename U>
-void DoubleDepthReferencesTop(U &&u) {
- struct lc { // #DDRT_STRCT
- void operator()() {
- struct lc2 {
- void operator()() // #DDRT_OP
- requires IsInt<decltype(u)> // #DDRT_REQ
- {}
- };
- lc2 lv2;
- lv2(); // #DDRT_CALL
- }
- };
- lc lv;
- lv();
-}
-
-template <typename U>
-void DoubleDepthReferencesTopLambda(U &&u) {
- []() { []()
- requires IsInt<decltype(u)>
- {}(); }();
-}
-
-template <typename U>
-void DoubleDepthReferencesAll(U &&u) {
- struct lc { // #DDRA_STRCT
- void operator()(U &&u2) {
- struct lc2 {
- void operator()(U &&u3) // #DDRA_OP
- requires IsInt<decltype(u)> && // #DDRA_REQ
- IsInt<decltype(u2)> && IsInt<decltype(u3)>
- {}
- };
- lc2 lv2;
- lv2(u2); // #DDRA_CALL
- }
- };
- lc lv;
- lv(u);
-}
-
-template <typename U>
-void DoubleDepthReferencesAllLambda(U &&u) {
- [](U &&u2) {
- [](U && u3)
- requires IsInt<decltype(u)> &&
- IsInt<decltype(u2)> && IsInt<decltype(u3)>
- {}(u2);
- }(u);
-}
-
-template <typename U>
-struct CausesFriendConstraint {
- template <typename V>
- friend void FriendFunc(CausesFriendConstraint, V) // #FF_DECL
- requires IsInt<U> &&
- IsInt<V> // #FF_REQ
- {}
-};
-// FIXME: Re-enable this test when constraints are allowed to refer to captures.
-// template<typename T>
-// void ChecksCapture(T x) {
-// [y = x]() requires(IsInt<decltype(y)>){}();
-// }
-
-template <typename T>
-void ChecksLocalVar(T x) {
- T Local;
- []()
- requires(IsInt<decltype(Local)>)
- {}();
-}
-
-template <typename T>
-void LocalStructMemberVar(T x) {
- struct S {
- T local;
- void foo()
- requires(IsInt<decltype(local)>) // #LSMV_REQ
- {}
- } s;
- s.foo(); // #LSMV_CALL
-};
-
-template <typename T>
-struct ChecksMemberVar {
- T t;
- void foo()
- requires(IsInt<decltype(t)>) // #CMV_FOO
- {}
- template <typename U>
- void foo2() // #CMV_FOO2
- requires(IsInt<decltype(t)>) // #CMV_FOO2_REQ
- {}
-};
-
-void test_dependent() {
- int v = 0;
- float will_fail;
- SingleDepthReferencesTop(v);
- SingleDepthReferencesTop(will_fail);
- // expected-error@#SDRT_CALL{{no matching function for call to object of type 'lc'}}
- // expected-note at -2{{in instantiation of function template specialization}}
- // expected-note@#SDRT_OP{{candidate function not viable}}
- // expected-note@#SDRT_REQ{{'IsInt<decltype(u)>' evaluated to false}}
-
- SingleDepthReferencesTopNotCalled(v);
- // Won't error unless we try to call it.
- SingleDepthReferencesTopNotCalled(will_fail);
- SingleDepthReferencesTopCalled(v); // #SDRTC
- SingleDepthReferencesTopLambda(v);
- // FIXME: This should error on constraint failure! (Lambda!)
- SingleDepthReferencesTopLambda(will_fail);
- DoubleDepthReferencesTop(v);
- DoubleDepthReferencesTop(will_fail);
- // expected-error@#DDRT_CALL{{no matching function for call to object of type 'lc2'}}
- // expected-note at -2{{in instantiation of function template specialization}}
- // expected-note@#DDRT_STRCT{{in instantiation of member function}}
- // expected-note@#DDRT_OP{{candidate function not viable}}
- // expected-note@#DDRT_REQ{{'IsInt<decltype(u)>' evaluated to false}}
-
- DoubleDepthReferencesTopLambda(v);
- // FIXME: This should error on constraint failure! (Lambda!)
- DoubleDepthReferencesTopLambda(will_fail);
- DoubleDepthReferencesAll(v);
- DoubleDepthReferencesAll(will_fail);
- // expected-error@#DDRA_CALL{{no matching function for call to object of type 'lc2'}}
- // expected-note at -2{{in instantiation of function template specialization}}
- // expected-note@#DDRA_STRCT{{in instantiation of member function}}
- // expected-note@#DDRA_OP{{candidate function not viable}}
- // expected-note@#DDRA_REQ{{'IsInt<decltype(u)>' evaluated to false}}
-
- DoubleDepthReferencesAllLambda(v);
- // FIXME: This should error on constraint failure! (Lambda!)
- DoubleDepthReferencesAllLambda(will_fail);
-
- CausesFriendConstraint<int> CFC;
- FriendFunc(CFC, 1);
- FriendFunc(CFC, 1.0);
- // expected-error at -1{{no matching function for call to 'FriendFunc'}}
- // expected-note@#FF_DECL{{constraints not satisfied}}
- // expected-note@#FF_REQ{{because 'IsInt<double>' evaluated to false}}
-
- // FIXME: Re-enable this test when constraints are allowed to refer to captures.
- // ChecksCapture(v);
-
- ChecksLocalVar(v);
- // FIXME: This should error on constraint failure! (Lambda!)
- ChecksLocalVar(will_fail);
-
- LocalStructMemberVar(v);
- LocalStructMemberVar(will_fail);
- // expected-error@#LSMV_CALL{{invalid reference to function 'foo'}}
- // expected-note at -2{{in instantiation of function template specialization}}
- // expected-note@#LSMV_REQ{{because 'IsInt<decltype(this->local)>' evaluated to false}}
-
- ChecksMemberVar<int> CMV;
- CMV.foo();
- CMV.foo2<int>();
-
- ChecksMemberVar<float> CMV2;
- CMV2.foo();
- // expected-error at -1{{invalid reference to function 'foo'}}
- // expected-note@#CMV_FOO{{because 'IsInt<decltype(this->t)>' evaluated to false}}
- CMV2.foo2<float>();
- // expected-error at -1{{no matching member function for call to 'foo2'}}
- // expected-note@#CMV_FOO2{{constraints not satisfied}}
- // expected-note@#CMV_FOO2_REQ{{because 'IsInt<decltype(this->t)>' evaluated to false}}
-}
-} // namespace DeferredInstantiationInstScope
-
-// Ane example of evaluating a concept at two
diff erent depths in the same
-// evaluation. No diagnostic is expected.
-namespace SameConceptDifferentDepth {
-template <class _Ip>
-concept sentinel_for =
- requires(_Ip __i) {
- __i++;
- };
-
-template <class _Ip>
-concept bidirectional_iterator =
- sentinel_for<_Ip>;
-
-template <class _Iter>
-class move_iterator {
-public:
- auto operator++(int)
- requires sentinel_for<_Iter>{}
-};
-
-static_assert(bidirectional_iterator<move_iterator<int>>);
-} // namespace SameConceptDifferentDepth
-
-namespace VarInit {
-template <class _Tp>
-concept __can_reference = true;
-
-template <class _Iter>
-class common_iterator {
-public:
- common_iterator() {
- constexpr auto x = requires(_Iter & __i) { { __i } -> __can_reference; };
- }
-};
-
-void test() {
- auto commonIter1 = common_iterator<int>();
-}
-} // namespace VarInit
-
-
-namespace InlineFriendOperator {
-template <typename T>
-concept C = true;
-template <class _Iter>
-class counted_iterator {
- _Iter I;
-public:
- constexpr counted_iterator() = default;
- friend constexpr auto operator+( // expected-note {{candidate function not viable}}
- int __n, const counted_iterator &__x)
- requires C<decltype(I)>
- {
- return __x + __n; // expected-error{{invalid operands to binary expression}}
- }
-};
-
-constexpr bool test() {
- counted_iterator<int> iter;
- auto x = 2 + iter; // expected-note{{in instantiation of member function 'InlineFriendOperator::operator+'}}
-
- return true;
-}
-} // namespace InlineFriendOperator
-
diff --git a/clang/test/SemaTemplate/deferred-concept-inst.cpp b/clang/test/SemaTemplate/deferred-concept-inst.cpp
deleted file mode 100644
index dd9a4086a42e..000000000000
--- a/clang/test/SemaTemplate/deferred-concept-inst.cpp
+++ /dev/null
@@ -1,23 +0,0 @@
-// RUN: %clang_cc1 -std=c++2a -x c++ %s -verify -fsyntax-only -Wno-unused-value
-// expected-no-diagnostics
-
-namespace GithubBug44178 {
-template <typename D>
-struct CRTP {
- void call_foo()
- requires requires(D &v) { v.foo(); }
- {
- static_cast<D *>(this)->foo();
- }
-};
-
-struct Test : public CRTP<Test> {
- void foo() {}
-};
-
-int main() {
- Test t;
- t.call_foo();
- return 0;
-}
-} // namespace GithubBug44178
diff --git a/clang/test/SemaTemplate/instantiate-requires-clause.cpp b/clang/test/SemaTemplate/instantiate-requires-clause.cpp
index 3f438d8885a2..73dd20d27d22 100644
--- a/clang/test/SemaTemplate/instantiate-requires-clause.cpp
+++ b/clang/test/SemaTemplate/instantiate-requires-clause.cpp
@@ -1,4 +1,4 @@
-// RUN: %clang_cc1 -std=c++2a -x c++ %s -Wno-unused-value -verify
+// RUN: %clang_cc1 -std=c++2a -x c++ %s -verify
template <typename... Args> requires ((sizeof(Args) == 1), ...)
// expected-note at -1 {{because '(sizeof(int) == 1) , (sizeof(char) == 1) , (sizeof(int) == 1)' evaluated to false}}
@@ -40,20 +40,6 @@ struct S {
static_assert(S<void>::f(1));
-// Similar to the 'S' test, but tries to use 'U' in the requires clause.
-template <typename T2>
-struct S1 {
- // expected-note at +3 {{candidate template ignored: constraints not satisfied [with U = int]}}
- // expected-note at +3 {{because substituted constraint expression is ill-formed: type 'int' cannot be used prior to '::' because it has no members}}
- template <typename U>
- static constexpr auto f(U const index)
- requires(U::foo)
- { return true; }
-};
-
-// expected-error at +1 {{no matching function for call to 'f'}}
-static_assert(S1<void>::f(1));
-
constexpr auto value = 0;
template<typename T>
diff --git a/clang/test/SemaTemplate/trailing-return-short-circuit.cpp b/clang/test/SemaTemplate/trailing-return-short-circuit.cpp
deleted file mode 100644
index 0d1c9b52b0e8..000000000000
--- a/clang/test/SemaTemplate/trailing-return-short-circuit.cpp
+++ /dev/null
@@ -1,62 +0,0 @@
-// RUN: %clang_cc1 -std=c++20 -verify %s
-
-template <class T>
- requires(sizeof(T) > 2) || T::value // #FOO_REQ
-void Foo(T){}; // #FOO
-
-template <class T>
-void TrailingReturn(T) // #TRAILING
- requires(sizeof(T) > 2) || // #TRAILING_REQ
- T::value // #TRAILING_REQ_VAL
-{};
-template <bool B>
-struct HasValue {
- static constexpr bool value = B;
-};
-static_assert(sizeof(HasValue<true>) <= 2);
-
-template <bool B>
-struct HasValueLarge {
- static constexpr bool value = B;
- int I;
-};
-static_assert(sizeof(HasValueLarge<true>) > 2);
-
-void usage() {
- // Passes the 1st check, short-circuit so the 2nd ::value is not evaluated.
- Foo(1.0);
- TrailingReturn(1.0);
-
- // Fails the 1st check, but has a ::value, so the check happens correctly.
- Foo(HasValue<true>{});
- TrailingReturn(HasValue<true>{});
-
- // Passes the 1st check, but would have passed the 2nd one.
- Foo(HasValueLarge<true>{});
- TrailingReturn(HasValueLarge<true>{});
-
- // Fails the 1st check, fails 2nd because there is no ::value.
- Foo(true);
- // expected-error at -1{{no matching function for call to 'Foo'}}
- // expected-note@#FOO{{candidate template ignored: constraints not satisfied [with T = bool]}}
- // expected-note@#FOO_REQ{{because 'sizeof(_Bool) > 2' (1 > 2) evaluated to false}}
- // expected-note@#FOO_REQ{{because substituted constraint expression is ill-formed: type 'bool' cannot be used prior to '::' because it has no members}}
-
- TrailingReturn(true);
- // expected-error at -1{{no matching function for call to 'TrailingReturn'}}
- // expected-note@#TRAILING{{candidate template ignored: constraints not satisfied [with T = bool]}}
- // expected-note@#TRAILING_REQ{{because 'sizeof(_Bool) > 2' (1 > 2) evaluated to false}}
- // expected-note@#TRAILING_REQ_VAL{{because substituted constraint expression is ill-formed: type 'bool' cannot be used prior to '::' because it has no members}}
-
- // Fails the 1st check, fails 2nd because ::value is false.
- Foo(HasValue<false>{});
- // expected-error at -1 {{no matching function for call to 'Foo'}}
- // expected-note@#FOO{{candidate template ignored: constraints not satisfied [with T = HasValue<false>]}}
- // expected-note@#FOO_REQ{{because 'sizeof(HasValue<false>) > 2' (1 > 2) evaluated to false}}
- // expected-note@#FOO_REQ{{and 'HasValue<false>::value' evaluated to false}}
- TrailingReturn(HasValue<false>{});
- // expected-error at -1 {{no matching function for call to 'TrailingReturn'}}
- // expected-note@#TRAILING{{candidate template ignored: constraints not satisfied [with T = HasValue<false>]}}
- // expected-note@#TRAILING_REQ{{because 'sizeof(HasValue<false>) > 2' (1 > 2) evaluated to false}}
- // expected-note@#TRAILING_REQ_VAL{{and 'HasValue<false>::value' evaluated to false}}
-}
More information about the cfe-commits
mailing list