[clang] 0c31da4 - Revert "Deferred Concept Instantiation Implementation"
Erich Keane via cfe-commits
cfe-commits at lists.llvm.org
Mon May 2 06:27:40 PDT 2022
Author: Erich Keane
Date: 2022-05-02T06:25:38-07:00
New Revision: 0c31da48389754822dc3eecc4723160c295b9ab2
URL: https://github.com/llvm/llvm-project/commit/0c31da48389754822dc3eecc4723160c295b9ab2
DIFF: https://github.com/llvm/llvm-project/commit/0c31da48389754822dc3eecc4723160c295b9ab2.diff
LOG: Revert "Deferred Concept Instantiation Implementation"
This reverts commit 4b6c2cd647e9e5a147954886338f97ffb6a1bcfb.
The patch caused numerous ARM 32 bit build failures, since we added a
5th item to the PointerUnion, and went over the 2-bits available in the
32 bit pointers.
Added:
Modified:
clang/docs/ReleaseNotes.rst
clang/include/clang/AST/Decl.h
clang/include/clang/AST/DeclBase.h
clang/include/clang/Sema/Sema.h
clang/include/clang/Sema/Template.h
clang/lib/AST/ASTImporter.cpp
clang/lib/AST/Decl.cpp
clang/lib/AST/DeclBase.cpp
clang/lib/ExtractAPI/ExtractAPIConsumer.cpp
clang/lib/Sema/SemaConcept.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/lib/Serialization/ASTReaderDecl.cpp
clang/lib/Serialization/ASTWriterDecl.cpp
clang/test/CXX/temp/temp.constr/temp.constr.constr/non-function-templates.cpp
clang/test/SemaTemplate/concepts.cpp
clang/test/SemaTemplate/instantiate-requires-clause.cpp
Removed:
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 839a7035a94fd..91944e0b11ef0 100644
--- a/clang/docs/ReleaseNotes.rst
+++ b/clang/docs/ReleaseNotes.rst
@@ -275,10 +275,6 @@ C++20 Feature Support
`Issue 54578 <https://github.com/llvm/llvm-project/issues/54578>`_.
- Implemented `__builtin_source_location()` which enables library support for std::source_location.
-- 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>`_.
- The mangling scheme for C++20 modules has incompatibly changed. The
initial mangling was discovered not to be reversible, and the weak
diff --git a/clang/include/clang/AST/Decl.h b/clang/include/clang/AST/Decl.h
index 6de480dbfe1ad..c2133f4e79a15 100644
--- a/clang/include/clang/AST/Decl.h
+++ b/clang/include/clang/AST/Decl.h
@@ -1890,9 +1890,7 @@ class FunctionDecl : public DeclaratorDecl,
TK_FunctionTemplateSpecialization,
// A function template specialization that hasn't yet been resolved to a
// particular specialized function template.
- TK_DependentFunctionTemplateSpecialization,
- // A non templated function which is in a dependent scope.
- TK_DependentNonTemplate
+ TK_DependentFunctionTemplateSpecialization
};
/// Stashed information about a defaulted function definition whose body has
@@ -1941,21 +1939,20 @@ class FunctionDecl : public DeclaratorDecl,
/// The template or declaration that this declaration
/// describes or was instantiated from, respectively.
///
- /// For non-templates this value will be NULL, unless this non-template
- /// function declaration was declared directly inside of a function template,
- /// in which case this will have a pointer to a FunctionDecl. For function
- /// declarations that describe a function template, this will be a pointer to
- /// a FunctionTemplateDecl. For member functions of class template
- /// specializations, this will be a MemberSpecializationInfo pointer
- /// containing information about the specialization. For function template
- /// specializations, this will be a FunctionTemplateSpecializationInfo, which
- /// contains information about the template being specialized and the template
- /// arguments involved in that specialization.
- llvm::PointerUnion<FunctionDecl *, FunctionTemplateDecl *,
+ /// For non-templates, this value will be NULL. For function
+ /// declarations that describe a function template, this will be a
+ /// pointer to a FunctionTemplateDecl. For member functions
+ /// of class template specializations, this will be a MemberSpecializationInfo
+ /// pointer containing information about the specialization.
+ /// For function template specializations, this will be a
+ /// FunctionTemplateSpecializationInfo, which contains information about
+ /// the template being specialized and the template arguments involved in
+ /// that specialization.
+ llvm::PointerUnion<FunctionTemplateDecl *,
MemberSpecializationInfo *,
FunctionTemplateSpecializationInfo *,
DependentFunctionTemplateSpecializationInfo *>
- TemplateOrSpecialization;
+ TemplateOrSpecialization;
/// Provides source/type location info for the declaration name embedded in
/// the DeclaratorDecl base class.
@@ -2691,11 +2688,6 @@ class FunctionDecl : public DeclaratorDecl,
setInstantiationOfMemberFunction(getASTContext(), FD, TSK);
}
- /// Specify that this function declaration was instantiated from FunctionDecl
- /// FD. This is only used if this is a function declaration declared locally
- /// inside of a function template.
- void setInstantiatedFromDecl(FunctionDecl *FD);
-
/// Retrieves the function template that is described by this
/// function declaration.
///
@@ -2710,8 +2702,6 @@ class FunctionDecl : public DeclaratorDecl,
/// FunctionTemplateDecl from a FunctionDecl.
FunctionTemplateDecl *getDescribedFunctionTemplate() const;
- FunctionDecl *getInstantiatedFromDecl() const;
-
void setDescribedFunctionTemplate(FunctionTemplateDecl *Template);
/// Determine whether this function is a function template
diff --git a/clang/include/clang/AST/DeclBase.h b/clang/include/clang/AST/DeclBase.h
index 54cecade3a709..a4a44e0b30e64 100644
--- a/clang/include/clang/AST/DeclBase.h
+++ b/clang/include/clang/AST/DeclBase.h
@@ -906,14 +906,6 @@ class alignas(8) Decl {
const_cast<const Decl*>(this)->getParentFunctionOrMethod());
}
- /// Does the same thing as getParentFunctionOrMethod, except starts with the
- /// lexical declaration context instead.
- const DeclContext *getLexicalParentFunctionOrMethod() const;
- DeclContext *getLexicalParentFunctionOrMethod() {
- return const_cast<DeclContext *>(
- const_cast<const Decl *>(this)->getLexicalParentFunctionOrMethod());
- }
-
/// Retrieves the "canonical" declaration of the given declaration.
virtual Decl *getCanonicalDecl() { return this; }
const Decl *getCanonicalDecl() const {
diff --git a/clang/include/clang/Sema/Sema.h b/clang/include/clang/Sema/Sema.h
index d62607f74aad5..114725498c982 100644
--- a/clang/include/clang/Sema/Sema.h
+++ b/clang/include/clang/Sema/Sema.h
@@ -6989,34 +6989,7 @@ 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);
-
- // Keep track of whether we are evaluating a constraint.
- unsigned ConstraintEvaluationDepth = 0;
-
- class ConstraintEvalRAII {
- Sema &S;
-
- public:
- ConstraintEvalRAII(Sema &S) : S(S) { ++S.ConstraintEvaluationDepth; }
- ~ConstraintEvalRAII() { --S.ConstraintEvaluationDepth; }
- };
-
public:
- bool IsEvaluatingAConstraint() { return ConstraintEvaluationDepth > 0; }
const NormalizedConstraint *
getNormalizedAssociatedConstraints(
NamedDecl *ConstrainedDecl, ArrayRef<const Expr *> AssociatedConstraints);
@@ -7046,42 +7019,8 @@ class Sema final {
/// check (either a concept or a constrained entity).
/// \param ConstraintExprs a list of constraint expressions, treated as if
/// they were 'AND'ed together.
- /// \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,
- const MultiLevelTemplateArgumentList &TemplateArgList,
- SourceRange TemplateIDRange, ConstraintSatisfaction &Satisfaction) {
- llvm::SmallVector<Expr *, 4> Converted;
- return CheckConstraintSatisfaction(Template, ConstraintExprs, Converted,
- TemplateArgList, 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 TemplateArgs the list of template arguments to substitute into the
+ /// constraint expression.
/// \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
@@ -7091,8 +7030,7 @@ class Sema final {
/// false otherwise.
bool CheckConstraintSatisfaction(
const NamedDecl *Template, ArrayRef<const Expr *> ConstraintExprs,
- llvm::SmallVectorImpl<Expr *> &ConvertedConstraints,
- const MultiLevelTemplateArgumentList &TemplateArgList,
+ ArrayRef<TemplateArgument> TemplateArgs,
SourceRange TemplateIDRange, ConstraintSatisfaction &Satisfaction);
/// \brief Check whether the given non-dependent constraint expression is
@@ -7128,9 +7066,9 @@ class Sema final {
///
/// \returns true if the constrains are not satisfied or could not be checked
/// for satisfaction, false if the constraints are satisfied.
- bool EnsureTemplateArgumentListConstraints(
- TemplateDecl *Template, MultiLevelTemplateArgumentList TemplateArgs,
- SourceRange TemplateIDRange);
+ bool EnsureTemplateArgumentListConstraints(TemplateDecl *Template,
+ ArrayRef<TemplateArgument> TemplateArgs,
+ SourceRange TemplateIDRange);
/// \brief Emit diagnostics explaining why a constraint expression was deemed
/// unsatisfied.
@@ -8864,8 +8802,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
@@ -9586,11 +9523,6 @@ class Sema final {
ExtParameterInfoBuilder &ParamInfos);
ExprResult SubstExpr(Expr *E,
const MultiLevelTemplateArgumentList &TemplateArgs);
- // 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.
diff --git a/clang/include/clang/Sema/Template.h b/clang/include/clang/Sema/Template.h
index c8179dd9d15b6..540d2c9aa87e7 100644
--- a/clang/include/clang/Sema/Template.h
+++ b/clang/include/clang/Sema/Template.h
@@ -75,9 +75,6 @@ enum class TemplateSubstitutionKind : char {
class MultiLevelTemplateArgumentList {
/// The template argument list at a certain template depth
using ArgList = ArrayRef<TemplateArgument>;
- using ArgListsIterator = SmallVector<ArgList, 4>::reverse_iterator;
- using ConstArgListsIterator =
- SmallVector<ArgList, 4>::const_reverse_iterator;
/// The template argument lists, stored from the innermost template
/// argument list (first) to the outermost template argument list (last).
@@ -124,12 +121,6 @@ enum class TemplateSubstitutionKind : char {
return TemplateArgumentLists.size();
}
- /// Determine the number of substituted args at 'Depth'.
- unsigned getNumSubstitutedArgs(unsigned Depth) const {
- assert(NumRetainedOuterLevels <= Depth && Depth < getNumLevels());
- return TemplateArgumentLists[getNumLevels() - Depth - 1].size();
- }
-
unsigned getNumRetainedOuterLevels() const {
return NumRetainedOuterLevels;
}
@@ -167,14 +158,6 @@ enum class TemplateSubstitutionKind : char {
return !(*this)(Depth, Index).isNull();
}
- bool isAnyArgInstantiationDependent() const {
- for (ArgList List : TemplateArgumentLists)
- for (const TemplateArgument &TA : List)
- if (TA.isInstantiationDependent())
- return true;
- return false;
- }
-
/// Clear out a specific template argument.
void setArgument(unsigned Depth, unsigned Index,
TemplateArgument Arg) {
@@ -214,16 +197,6 @@ enum class TemplateSubstitutionKind : char {
const ArgList &getInnermost() const {
return TemplateArgumentLists.front();
}
-
- /// Retrieve the outermost template argument list.
- const ArgList &getOutermost() const { return TemplateArgumentLists.back(); }
-
- ArgListsIterator begin() { return TemplateArgumentLists.rbegin(); }
- ConstArgListsIterator begin() const {
- return TemplateArgumentLists.rbegin();
- }
- ArgListsIterator end() { return TemplateArgumentLists.rend(); }
- ConstArgListsIterator end() const { return TemplateArgumentLists.rend(); }
};
/// The context in which partial ordering of function templates occurs.
diff --git a/clang/lib/AST/ASTImporter.cpp b/clang/lib/AST/ASTImporter.cpp
index be77d68ca7a56..e2294088908c5 100644
--- a/clang/lib/AST/ASTImporter.cpp
+++ b/clang/lib/AST/ASTImporter.cpp
@@ -3109,11 +3109,6 @@ Error ASTNodeImporter::ImportTemplateInformation(
case FunctionDecl::TK_FunctionTemplate:
return Error::success();
- case FunctionDecl::TK_DependentNonTemplate:
- if (Expected<FunctionDecl *> InstFDOrErr =
- import(FromFD->getInstantiatedFromDecl()))
- ToFD->setInstantiatedFromDecl(*InstFDOrErr);
- return Error::success();
case FunctionDecl::TK_MemberSpecialization: {
TemplateSpecializationKind TSK = FromFD->getTemplateSpecializationKind();
diff --git a/clang/lib/AST/Decl.cpp b/clang/lib/AST/Decl.cpp
index 5180f62021d43..911479bee5ff9 100644
--- a/clang/lib/AST/Decl.cpp
+++ b/clang/lib/AST/Decl.cpp
@@ -3729,8 +3729,6 @@ const IdentifierInfo *FunctionDecl::getLiteralIdentifier() const {
FunctionDecl::TemplatedKind FunctionDecl::getTemplatedKind() const {
if (TemplateOrSpecialization.isNull())
return TK_NonTemplate;
- if (TemplateOrSpecialization.is<FunctionDecl *>())
- return TK_DependentNonTemplate;
if (TemplateOrSpecialization.is<FunctionTemplateDecl *>())
return TK_FunctionTemplate;
if (TemplateOrSpecialization.is<MemberSpecializationInfo *>())
@@ -3782,16 +3780,6 @@ void FunctionDecl::setDescribedFunctionTemplate(FunctionTemplateDecl *Template)
TemplateOrSpecialization = Template;
}
-void FunctionDecl::setInstantiatedFromDecl(FunctionDecl *FD) {
- assert(TemplateOrSpecialization.isNull() &&
- "function is already a specialization");
- TemplateOrSpecialization = FD;
-}
-
-FunctionDecl *FunctionDecl::getInstantiatedFromDecl() const {
- return TemplateOrSpecialization.dyn_cast<FunctionDecl *>();
-}
-
bool FunctionDecl::isImplicitlyInstantiable() const {
// If the function is invalid, it can't be implicitly instantiated.
if (isInvalidDecl())
diff --git a/clang/lib/AST/DeclBase.cpp b/clang/lib/AST/DeclBase.cpp
index d666d6b10a2e3..d5ad636810544 100644
--- a/clang/lib/AST/DeclBase.cpp
+++ b/clang/lib/AST/DeclBase.cpp
@@ -293,16 +293,6 @@ const DeclContext *Decl::getParentFunctionOrMethod() const {
return nullptr;
}
-const DeclContext *Decl::getLexicalParentFunctionOrMethod() const {
- for (const DeclContext *DC = getLexicalDeclContext();
- DC && !DC->isTranslationUnit() && !DC->isNamespace();
- DC = DC->getParent())
- if (DC->isFunctionOrMethod())
- return DC;
-
- return nullptr;
-}
-
//===----------------------------------------------------------------------===//
// PrettyStackTraceDecl Implementation
//===----------------------------------------------------------------------===//
diff --git a/clang/lib/ExtractAPI/ExtractAPIConsumer.cpp b/clang/lib/ExtractAPI/ExtractAPIConsumer.cpp
index e13ad1e8beaac..b1de2674b622b 100644
--- a/clang/lib/ExtractAPI/ExtractAPIConsumer.cpp
+++ b/clang/lib/ExtractAPI/ExtractAPIConsumer.cpp
@@ -161,7 +161,6 @@ class ExtractAPIVisitor : public RecursiveASTVisitor<ExtractAPIVisitor> {
// Skip templated functions.
switch (Decl->getTemplatedKind()) {
case FunctionDecl::TK_NonTemplate:
- case FunctionDecl::TK_DependentNonTemplate:
break;
case FunctionDecl::TK_MemberSpecialization:
case FunctionDecl::TK_FunctionTemplateSpecialization:
diff --git a/clang/lib/Sema/SemaConcept.cpp b/clang/lib/Sema/SemaConcept.cpp
index 3471cc383c9cd..449f9eb33f47b 100644
--- a/clang/lib/Sema/SemaConcept.cpp
+++ b/clang/lib/Sema/SemaConcept.cpp
@@ -30,7 +30,6 @@ using namespace sema;
namespace {
class LogicalBinOp {
- SourceLocation Loc;
OverloadedOperatorKind Op = OO_None;
const Expr *LHS = nullptr;
const Expr *RHS = nullptr;
@@ -41,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();
}
}
}
@@ -59,25 +56,6 @@ class LogicalBinOp {
const Expr *getLHS() const { return LHS; }
const Expr *getRHS() const { return RHS; }
-
- ExprResult recreateBinOp(Sema &SemaRef, ExprResult LHS) {
- return recreateBinOp(SemaRef, LHS, const_cast<Expr *>(getRHS()));
- }
-
- ExprResult recreateBinOp(Sema &SemaRef, ExprResult LHS, ExprResult RHS) {
- 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{});
- }
};
}
@@ -144,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;
@@ -166,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 LHSRes.isUsable() ? BO.recreateBinOp(S, LHSRes) : ExprEmpty();
+ return false;
if (BO.isAnd() && !IsLHSSatisfied)
// [temp.constr.op] p2
@@ -175,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 LHSRes.isUsable() ? BO.recreateBinOp(S, LHSRes) : ExprEmpty();
+ return false;
- ExprResult RHSRes = calculateConstraintSatisfaction(
+ return calculateConstraintSatisfaction(
S, BO.getRHS(), Satisfaction, std::forward<AtomicEvaluator>(Evaluator));
- if (RHSRes.isInvalid())
- return ExprError();
-
- if (!LHSRes.isUsable() || !RHSRes.isUsable())
- return ExprEmpty();
- return BO.recreateBinOp(S, LHSRes, RHSRes);
} else 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,
+ return calculateConstraintSatisfaction(S, C->getSubExpr(), Satisfaction,
std::forward<AtomicEvaluator>(Evaluator));
}
@@ -197,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);
@@ -218,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() &&
@@ -228,13 +195,13 @@ calculateConstraintSatisfaction(Sema &S, const Expr *ConstraintExpr,
Satisfaction.Details.emplace_back(ConstraintExpr,
SubstitutedAtomicExpr.get());
- return SubstitutedAtomicExpr;
+ return false;
}
-static ExprResult calculateConstraintSatisfaction(
- Sema &S, const NamedDecl *Template, SourceLocation TemplateNameLoc,
- const MultiLevelTemplateArgumentList &MLTAL, const Expr *ConstraintExpr,
- ConstraintSatisfaction &Satisfaction) {
+static bool calculateConstraintSatisfaction(
+ Sema &S, const NamedDecl *Template, ArrayRef<TemplateArgument> TemplateArgs,
+ SourceLocation TemplateNameLoc, MultiLevelTemplateArgumentList &MLTAL,
+ const Expr *ConstraintExpr, ConstraintSatisfaction &Satisfaction) {
return calculateConstraintSatisfaction(
S, ConstraintExpr, Satisfaction, [&](const Expr *AtomicExpr) {
EnterExpressionEvaluationContext ConstantEvaluated(
@@ -252,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
@@ -301,92 +268,74 @@ static ExprResult calculateConstraintSatisfaction(
});
}
-static bool CheckConstraintSatisfaction(
- Sema &S, const NamedDecl *Template, ArrayRef<const Expr *> ConstraintExprs,
- llvm::SmallVectorImpl<Expr *> &Converted,
- const MultiLevelTemplateArgumentList &TemplateArgsList,
- SourceRange TemplateIDRange, ConstraintSatisfaction &Satisfaction) {
+static bool CheckConstraintSatisfaction(Sema &S, const NamedDecl *Template,
+ ArrayRef<const Expr *> ConstraintExprs,
+ ArrayRef<TemplateArgument> TemplateArgs,
+ SourceRange TemplateIDRange,
+ ConstraintSatisfaction &Satisfaction) {
if (ConstraintExprs.empty()) {
Satisfaction.IsSatisfied = true;
return false;
}
- if (TemplateArgsList.isAnyArgInstantiationDependent()) {
- // No need to check satisfaction for dependent constraint expressions.
- Satisfaction.IsSatisfied = true;
- return false;
- }
-
- ArrayRef<TemplateArgument> TemplateArgs =
- TemplateArgsList.getNumSubstitutedLevels() > 0
- ? TemplateArgsList.getOutermost()
- : ArrayRef<TemplateArgument>{};
+ for (auto& Arg : TemplateArgs)
+ if (Arg.isInstantiationDependent()) {
+ // No need to check satisfaction for dependent constraint expressions.
+ Satisfaction.IsSatisfied = true;
+ return false;
+ }
- Sema::InstantiatingTemplate Inst(
- S, TemplateIDRange.getBegin(),
+ Sema::InstantiatingTemplate Inst(S, TemplateIDRange.getBegin(),
Sema::InstantiatingTemplate::ConstraintsCheck{},
const_cast<NamedDecl *>(Template), TemplateArgs, TemplateIDRange);
if (Inst.isInvalid())
return true;
+ MultiLevelTemplateArgumentList MLTAL;
+ MLTAL.addOuterTemplateArguments(TemplateArgs);
+
for (const Expr *ConstraintExpr : ConstraintExprs) {
- ExprResult Res = calculateConstraintSatisfaction(
- S, Template, TemplateIDRange.getBegin(), TemplateArgsList,
- ConstraintExpr, Satisfaction);
- if (Res.isInvalid())
+ if (calculateConstraintSatisfaction(S, Template, TemplateArgs,
+ TemplateIDRange.getBegin(), MLTAL,
+ 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 &TemplateArgsList,
- SourceRange TemplateIDRange, ConstraintSatisfaction &OutSatisfaction) {
+ ArrayRef<TemplateArgument> TemplateArgs, SourceRange TemplateIDRange,
+ ConstraintSatisfaction &OutSatisfaction) {
if (ConstraintExprs.empty()) {
OutSatisfaction.IsSatisfied = true;
return false;
}
- // A list of the template argument list flattened in a predictible manner for
- // the purposes of caching. The ConstraintSatisfaction type is in AST so it
- // has no access to the MultiLevelTemplateArgumentList, so this has to happen
- // here.
- llvm::SmallVector<TemplateArgument, 4> FlattenedArgs;
- for (ArrayRef<TemplateArgument> List : TemplateArgsList)
- FlattenedArgs.insert(FlattenedArgs.end(), List.begin(), List.end());
-
llvm::FoldingSetNodeID ID;
void *InsertPos;
ConstraintSatisfaction *Satisfaction = nullptr;
bool ShouldCache = LangOpts.ConceptSatisfactionCaching && Template;
if (ShouldCache) {
- ConstraintSatisfaction::Profile(ID, Context, Template, FlattenedArgs);
+ ConstraintSatisfaction::Profile(ID, Context, Template, TemplateArgs);
Satisfaction = SatisfactionCache.FindNodeOrInsertPos(ID, InsertPos);
if (Satisfaction) {
OutSatisfaction = *Satisfaction;
return false;
}
- Satisfaction = new ConstraintSatisfaction(Template, FlattenedArgs);
+ Satisfaction = new ConstraintSatisfaction(Template, TemplateArgs);
} else {
Satisfaction = &OutSatisfaction;
}
if (::CheckConstraintSatisfaction(*this, Template, ConstraintExprs,
- ConvertedConstraints, TemplateArgsList,
- TemplateIDRange, *Satisfaction)) {
+ TemplateArgs, TemplateIDRange,
+ *Satisfaction)) {
if (ShouldCache)
delete Satisfaction;
return true;
@@ -404,111 +353,20 @@ bool Sema::CheckConstraintSatisfaction(
bool Sema::CheckConstraintSatisfaction(const Expr *ConstraintExpr,
ConstraintSatisfaction &Satisfaction) {
return calculateConstraintSatisfaction(
- *this, ConstraintExpr, Satisfaction,
- [](const Expr *AtomicExpr) -> ExprResult {
- return ExprResult(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;
- }
- } else 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,
+ [](const Expr *AtomicExpr) -> ExprResult {
+ return ExprResult(const_cast<Expr *>(AtomicExpr));
+ });
}
bool Sema::CheckFunctionConstraints(const FunctionDecl *FD,
ConstraintSatisfaction &Satisfaction,
SourceLocation UsageLoc) {
- // 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) {
+ 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, true);
- llvm::Optional<MultiLevelTemplateArgumentList> MLTAL =
- SetupConstraintCheckingTemplateArgumentsAndScope(
- const_cast<FunctionDecl *>(FD), {}, Scope);
-
Qualifiers ThisQuals;
CXXRecordDecl *Record = nullptr;
if (auto *Method = dyn_cast<CXXMethodDecl>(FD)) {
@@ -519,27 +377,14 @@ 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(
- TemplateDecl *TD, MultiLevelTemplateArgumentList TemplateArgs,
+ TemplateDecl *TD, ArrayRef<TemplateArgument> TemplateArgs,
SourceRange TemplateIDRange) {
ConstraintSatisfaction Satisfaction;
llvm::SmallVector<const Expr *, 3> AssociatedConstraints;
@@ -552,8 +397,7 @@ bool Sema::EnsureTemplateArgumentListConstraints(
SmallString<128> TemplateArgString;
TemplateArgString = " ";
TemplateArgString += getTemplateArgumentBindingsText(
- TD->getTemplateParameters(), TemplateArgs.getInnermost().data(),
- TemplateArgs.getInnermost().size());
+ TD->getTemplateParameters(), TemplateArgs.data(), TemplateArgs.size());
Diag(TemplateIDRange.getBegin(),
diag::err_template_arg_list_constraints_not_satisfied)
@@ -585,13 +429,21 @@ bool Sema::CheckInstantiatedFunctionTemplateConstraints(
Sema::ContextRAII savedContext(*this, Decl);
LocalInstantiationScope Scope(*this);
- Optional<MultiLevelTemplateArgumentList> MLTAL =
- SetupConstraintCheckingTemplateArgumentsAndScope(Decl, TemplateArgs,
- Scope);
-
- if (!MLTAL)
- return true;
-
+ // 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)) {
@@ -599,8 +451,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, TemplateArgs,
PointOfInstantiation, Satisfaction);
}
diff --git a/clang/lib/Sema/SemaTemplate.cpp b/clang/lib/Sema/SemaTemplate.cpp
index 34e1352de2c53..4a42969c34d3f 100644
--- a/clang/lib/Sema/SemaTemplate.cpp
+++ b/clang/lib/Sema/SemaTemplate.cpp
@@ -4702,11 +4702,9 @@ Sema::CheckConceptTemplateId(const CXXScopeSpec &SS,
bool AreArgsDependent =
TemplateSpecializationType::anyDependentTemplateArguments(*TemplateArgs,
Converted);
- MultiLevelTemplateArgumentList MLTAL;
- MLTAL.addOuterTemplateArguments(Converted);
if (!AreArgsDependent &&
CheckConstraintSatisfaction(
- NamedConcept, {NamedConcept->getConstraintExpr()}, MLTAL,
+ NamedConcept, {NamedConcept->getConstraintExpr()}, Converted,
SourceRange(SS.isSet() ? SS.getBeginLoc() : ConceptNameInfo.getLoc(),
TemplateArgs->getRAngleLoc()),
Satisfaction))
@@ -5566,7 +5564,6 @@ bool Sema::CheckTemplateArgument(NamedDecl *Param,
if (Inst.isInvalid())
return true;
- ConstraintEvalRAII EvalRAII(*this);
TemplateArgumentList TemplateArgs(TemplateArgumentList::OnStack, Converted);
Params = SubstTemplateParams(Params, CurContext,
MultiLevelTemplateArgumentList(TemplateArgs));
@@ -5924,20 +5921,13 @@ bool Sema::CheckTemplateArgumentList(
if (UpdateArgsWithConversions)
TemplateArgs = std::move(NewArgs);
- if (!PartialTemplateArgs) {
- TemplateArgumentList StackTemplateArgs(TemplateArgumentList::OnStack,
- Converted);
- MultiLevelTemplateArgumentList MLTAL = getTemplateInstantiationArgs(
- Template, &StackTemplateArgs, /*RelativeToPrimary*/ true,
- /*Pattern*/ nullptr,
- /*LookBeyondLambda*/ true, /*IncludeContainingStruct*/ true);
- if (EnsureTemplateArgumentListConstraints(
- Template, MLTAL,
- SourceRange(TemplateLoc, TemplateArgs.getRAngleLoc()))) {
- if (ConstraintsNotSatisfied)
- *ConstraintsNotSatisfied = true;
- return true;
- }
+ if (!PartialTemplateArgs &&
+ EnsureTemplateArgumentListConstraints(
+ Template, Converted, SourceRange(TemplateLoc,
+ TemplateArgs.getRAngleLoc()))) {
+ if (ConstraintsNotSatisfied)
+ *ConstraintsNotSatisfied = true;
+ return true;
}
return false;
@@ -7467,9 +7457,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 4fa1395b62b71..0662dd7602236 100644
--- a/clang/lib/Sema/SemaTemplateDeduction.cpp
+++ b/clang/lib/Sema/SemaTemplateDeduction.cpp
@@ -2791,10 +2791,8 @@ CheckDeducedArgumentConstraints(Sema& S, TemplateDeclT *Template,
TemplateDeductionInfo& Info) {
llvm::SmallVector<const Expr *, 3> AssociatedConstraints;
Template->getAssociatedConstraints(AssociatedConstraints);
- MultiLevelTemplateArgumentList MLTAL;
- MLTAL.addOuterTemplateArguments(DeducedArgs);
- if (S.CheckConstraintSatisfaction(Template, AssociatedConstraints, MLTAL,
- Info.getLocation(),
+ if (S.CheckConstraintSatisfaction(Template, AssociatedConstraints,
+ DeducedArgs, Info.getLocation(),
Info.AssociatedConstraintsSatisfaction) ||
!Info.AssociatedConstraintsSatisfaction.IsSatisfied) {
Info.reset(TemplateArgumentList::CreateCopy(S.Context, DeducedArgs));
@@ -4574,11 +4572,8 @@ CheckDeducedPlaceholderConstraints(Sema &S, const AutoType &Type,
if (S.CheckTemplateArgumentList(Concept, SourceLocation(), TemplateArgs,
/*PartialTemplateArgs=*/false, Converted))
return Sema::DAR_FailedAlreadyDiagnosed;
-
- MultiLevelTemplateArgumentList MLTAL;
- MLTAL.addOuterTemplateArguments(Converted);
if (S.CheckConstraintSatisfaction(Concept, {Concept->getConstraintExpr()},
- MLTAL, TypeLoc.getLocalSourceRange(),
+ Converted, TypeLoc.getLocalSourceRange(),
Satisfaction))
return Sema::DAR_FailedAlreadyDiagnosed;
if (!Satisfaction.IsSatisfied) {
diff --git a/clang/lib/Sema/SemaTemplateInstantiate.cpp b/clang/lib/Sema/SemaTemplateInstantiate.cpp
index 4001b3554771c..1143023bb5baa 100644
--- a/clang/lib/Sema/SemaTemplateInstantiate.cpp
+++ b/clang/lib/Sema/SemaTemplateInstantiate.cpp
@@ -55,18 +55,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;
@@ -162,13 +153,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?");
}
@@ -185,18 +174,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());
- }
}
}
@@ -2323,18 +2304,6 @@ bool Sema::SubstTypeConstraint(
const MultiLevelTemplateArgumentList &TemplateArgs) {
const ASTTemplateArgumentListInfo *TemplArgInfo =
TC->getTemplateArgsAsWritten();
-
- // If we're not checking a constraint, we shouldn't be instantiating the type
- // constraint, so we should just create a copy of the previous one.
- // TODO: ERICH: Should this be RebuildExprInCurrentInstantiation here?
- if (!IsEvaluatingAConstraint()) {
- Inst->setTypeConstraint(TC->getNestedNameSpecifierLoc(),
- TC->getConceptNameInfo(), TC->getNamedConcept(),
- TC->getNamedConcept(), TemplArgInfo,
- TC->getImmediatelyDeclaredConstraint());
- return false;
- }
-
TemplateArgumentListInfo InstArgs;
if (TemplArgInfo) {
@@ -3519,14 +3488,6 @@ Sema::SubstExpr(Expr *E, const MultiLevelTemplateArgumentList &TemplateArgs) {
return Instantiator.TransformExpr(E);
}
-ExprResult
-Sema::SubstConstraintExpr(Expr *E,
- const MultiLevelTemplateArgumentList &TemplateArgs) {
-
- ConstraintEvalRAII EvalRAII(*this);
- return SubstExpr(E, TemplateArgs);
-}
-
ExprResult Sema::SubstInitializer(Expr *Init,
const MultiLevelTemplateArgumentList &TemplateArgs,
bool CXXDirectInit) {
diff --git a/clang/lib/Sema/SemaTemplateInstantiateDecl.cpp b/clang/lib/Sema/SemaTemplateInstantiateDecl.cpp
index e3460d5d4cb25..77c5677b65c87 100644
--- a/clang/lib/Sema/SemaTemplateInstantiateDecl.cpp
+++ b/clang/lib/Sema/SemaTemplateInstantiateDecl.cpp
@@ -2062,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
@@ -2170,11 +2182,6 @@ Decl *TemplateDeclInstantiator::VisitFunctionDecl(
// definition. We don't want non-template functions to be marked as being
// template instantiations.
Function->setInstantiationOfMemberFunction(D, TSK_ImplicitInstantiation);
- } else if (!isFriend) {
- // If this is not a function template, and this is not a friend (that is,
- // this is a locally declared function), save the instantiation relationship
- // for the purposes of constraint instantiation.
- Function->setInstantiatedFromDecl(D);
}
if (isFriend) {
@@ -2413,6 +2420,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) {
@@ -2430,9 +2454,6 @@ Decl *TemplateDeclInstantiator::VisitCXXMethodDecl(
if (!DC) return nullptr;
}
- CXXRecordDecl *Record = cast<CXXRecordDecl>(DC);
- Expr *TrailingRequiresClause = D->getTrailingRequiresClause();
-
DeclarationNameInfo NameInfo
= SemaRef.SubstDeclarationNameInfo(D->getNameInfo(), TemplateArgs);
@@ -2440,6 +2461,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();
@@ -2746,6 +2768,9 @@ Decl *TemplateDeclInstantiator::VisitTemplateTypeParmDecl(
// 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;
}
@@ -3988,7 +4013,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(),
diff --git a/clang/lib/Sema/TreeTransform.h b/clang/lib/Sema/TreeTransform.h
index 2717e4abf5b84..aef757efc9e71 100644
--- a/clang/lib/Sema/TreeTransform.h
+++ b/clang/lib/Sema/TreeTransform.h
@@ -12997,6 +12997,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
@@ -13031,7 +13038,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/lib/Serialization/ASTReaderDecl.cpp b/clang/lib/Serialization/ASTReaderDecl.cpp
index 4b9c83b9d1f91..86a9c7733069e 100644
--- a/clang/lib/Serialization/ASTReaderDecl.cpp
+++ b/clang/lib/Serialization/ASTReaderDecl.cpp
@@ -941,10 +941,6 @@ void ASTDeclReader::VisitFunctionDecl(FunctionDecl *FD) {
case FunctionDecl::TK_NonTemplate:
mergeRedeclarable(FD, Redecl);
break;
- case FunctionDecl::TK_DependentNonTemplate:
- mergeRedeclarable(FD, Redecl);
- FD->setInstantiatedFromDecl(readDeclAs<FunctionDecl>());
- break;
case FunctionDecl::TK_FunctionTemplate:
// Merged when we merge the template.
FD->setDescribedFunctionTemplate(readDeclAs<FunctionTemplateDecl>());
diff --git a/clang/lib/Serialization/ASTWriterDecl.cpp b/clang/lib/Serialization/ASTWriterDecl.cpp
index 49401c1d5e4b8..3666d5a6daab8 100644
--- a/clang/lib/Serialization/ASTWriterDecl.cpp
+++ b/clang/lib/Serialization/ASTWriterDecl.cpp
@@ -585,9 +585,6 @@ void ASTDeclWriter::VisitFunctionDecl(FunctionDecl *D) {
switch (D->getTemplatedKind()) {
case FunctionDecl::TK_NonTemplate:
break;
- case FunctionDecl::TK_DependentNonTemplate:
- Record.AddDeclRef(D->getInstantiatedFromDecl());
- break;
case FunctionDecl::TK_FunctionTemplate:
Record.AddDeclRef(D->getDescribedFunctionTemplate());
break;
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 15e00e4481e75..dd6bfe8011ddf 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/SemaTemplate/concepts.cpp b/clang/test/SemaTemplate/concepts.cpp
index 3a3ea2be126ec..23c79421bb6f8 100644
--- a/clang/test/SemaTemplate/concepts.cpp
+++ b/clang/test/SemaTemplate/concepts.cpp
@@ -256,249 +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 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>
-void HasInnerFunc(U &&u) {
- void InnerFunc(U && u2)
- requires IsInt<decltype(u)> && // #INNERFUNC_REQ
- IsInt<decltype(u2)>;
- InnerFunc(u); // #INNERFUNC_CALL
-}
-
-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);
- HasInnerFunc(v);
- HasInnerFunc(will_fail);
- // expected-error@#INNERFUNC_CALL{{invalid reference to function 'InnerFunc': constraints not satisfied}}
- // expected-note at -2{{in instantiation of function template specialization}}
- // expected-note@#INNERFUNC_REQ{{'IsInt<decltype(u)>' evaluated to false}}
-
- 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
diff --git a/clang/test/SemaTemplate/deferred-concept-inst.cpp b/clang/test/SemaTemplate/deferred-concept-inst.cpp
deleted file mode 100644
index 00e8845c3ecbb..0000000000000
--- a/clang/test/SemaTemplate/deferred-concept-inst.cpp
+++ /dev/null
@@ -1,23 +0,0 @@
-// RUN: %clang_cc1 -std=c++2a -x c++ %s -verify -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 3f438d8885a20..73dd20d27d226 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 0d1c9b52b0e85..0000000000000
--- 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