forked from OSchip/llvm-project
Revert "Deferred Concept Instantiation Implementation"
This reverts commit 4b6c2cd647
.
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.
This commit is contained in:
parent
2e8a506142
commit
0c31da4838
|
@ -275,10 +275,6 @@ C++20 Feature Support
|
||||||
`Issue 54578 <https://github.com/llvm/llvm-project/issues/54578>`_.
|
`Issue 54578 <https://github.com/llvm/llvm-project/issues/54578>`_.
|
||||||
|
|
||||||
- Implemented `__builtin_source_location()` which enables library support for std::source_location.
|
- 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
|
- The mangling scheme for C++20 modules has incompatibly changed. The
|
||||||
initial mangling was discovered not to be reversible, and the weak
|
initial mangling was discovered not to be reversible, and the weak
|
||||||
|
|
|
@ -1890,9 +1890,7 @@ public:
|
||||||
TK_FunctionTemplateSpecialization,
|
TK_FunctionTemplateSpecialization,
|
||||||
// A function template specialization that hasn't yet been resolved to a
|
// A function template specialization that hasn't yet been resolved to a
|
||||||
// particular specialized function template.
|
// particular specialized function template.
|
||||||
TK_DependentFunctionTemplateSpecialization,
|
TK_DependentFunctionTemplateSpecialization
|
||||||
// A non templated function which is in a dependent scope.
|
|
||||||
TK_DependentNonTemplate
|
|
||||||
};
|
};
|
||||||
|
|
||||||
/// Stashed information about a defaulted function definition whose body has
|
/// Stashed information about a defaulted function definition whose body has
|
||||||
|
@ -1941,17 +1939,16 @@ private:
|
||||||
/// The template or declaration that this declaration
|
/// The template or declaration that this declaration
|
||||||
/// describes or was instantiated from, respectively.
|
/// describes or was instantiated from, respectively.
|
||||||
///
|
///
|
||||||
/// For non-templates this value will be NULL, unless this non-template
|
/// For non-templates, this value will be NULL. For function
|
||||||
/// function declaration was declared directly inside of a function template,
|
/// declarations that describe a function template, this will be a
|
||||||
/// in which case this will have a pointer to a FunctionDecl. For function
|
/// pointer to a FunctionTemplateDecl. For member functions
|
||||||
/// declarations that describe a function template, this will be a pointer to
|
/// of class template specializations, this will be a MemberSpecializationInfo
|
||||||
/// a FunctionTemplateDecl. For member functions of class template
|
/// pointer containing information about the specialization.
|
||||||
/// specializations, this will be a MemberSpecializationInfo pointer
|
/// For function template specializations, this will be a
|
||||||
/// containing information about the specialization. For function template
|
/// FunctionTemplateSpecializationInfo, which contains information about
|
||||||
/// specializations, this will be a FunctionTemplateSpecializationInfo, which
|
/// the template being specialized and the template arguments involved in
|
||||||
/// contains information about the template being specialized and the template
|
/// that specialization.
|
||||||
/// arguments involved in that specialization.
|
llvm::PointerUnion<FunctionTemplateDecl *,
|
||||||
llvm::PointerUnion<FunctionDecl *, FunctionTemplateDecl *,
|
|
||||||
MemberSpecializationInfo *,
|
MemberSpecializationInfo *,
|
||||||
FunctionTemplateSpecializationInfo *,
|
FunctionTemplateSpecializationInfo *,
|
||||||
DependentFunctionTemplateSpecializationInfo *>
|
DependentFunctionTemplateSpecializationInfo *>
|
||||||
|
@ -2691,11 +2688,6 @@ public:
|
||||||
setInstantiationOfMemberFunction(getASTContext(), FD, TSK);
|
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
|
/// Retrieves the function template that is described by this
|
||||||
/// function declaration.
|
/// function declaration.
|
||||||
///
|
///
|
||||||
|
@ -2710,8 +2702,6 @@ public:
|
||||||
/// FunctionTemplateDecl from a FunctionDecl.
|
/// FunctionTemplateDecl from a FunctionDecl.
|
||||||
FunctionTemplateDecl *getDescribedFunctionTemplate() const;
|
FunctionTemplateDecl *getDescribedFunctionTemplate() const;
|
||||||
|
|
||||||
FunctionDecl *getInstantiatedFromDecl() const;
|
|
||||||
|
|
||||||
void setDescribedFunctionTemplate(FunctionTemplateDecl *Template);
|
void setDescribedFunctionTemplate(FunctionTemplateDecl *Template);
|
||||||
|
|
||||||
/// Determine whether this function is a function template
|
/// Determine whether this function is a function template
|
||||||
|
|
|
@ -906,14 +906,6 @@ public:
|
||||||
const_cast<const Decl*>(this)->getParentFunctionOrMethod());
|
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.
|
/// Retrieves the "canonical" declaration of the given declaration.
|
||||||
virtual Decl *getCanonicalDecl() { return this; }
|
virtual Decl *getCanonicalDecl() { return this; }
|
||||||
const Decl *getCanonicalDecl() const {
|
const Decl *getCanonicalDecl() const {
|
||||||
|
|
|
@ -6989,34 +6989,7 @@ private:
|
||||||
LocalInstantiationScope &Scope,
|
LocalInstantiationScope &Scope,
|
||||||
const MultiLevelTemplateArgumentList &TemplateArgs);
|
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:
|
public:
|
||||||
ConstraintEvalRAII(Sema &S) : S(S) { ++S.ConstraintEvaluationDepth; }
|
|
||||||
~ConstraintEvalRAII() { --S.ConstraintEvaluationDepth; }
|
|
||||||
};
|
|
||||||
|
|
||||||
public:
|
|
||||||
bool IsEvaluatingAConstraint() { return ConstraintEvaluationDepth > 0; }
|
|
||||||
const NormalizedConstraint *
|
const NormalizedConstraint *
|
||||||
getNormalizedAssociatedConstraints(
|
getNormalizedAssociatedConstraints(
|
||||||
NamedDecl *ConstrainedDecl, ArrayRef<const Expr *> AssociatedConstraints);
|
NamedDecl *ConstrainedDecl, ArrayRef<const Expr *> AssociatedConstraints);
|
||||||
|
@ -7046,10 +7019,8 @@ public:
|
||||||
/// check (either a concept or a constrained entity).
|
/// check (either a concept or a constrained entity).
|
||||||
/// \param ConstraintExprs a list of constraint expressions, treated as if
|
/// \param ConstraintExprs a list of constraint expressions, treated as if
|
||||||
/// they were 'AND'ed together.
|
/// they were 'AND'ed together.
|
||||||
/// \param TemplateArgList the multi-level list of template arguments to
|
/// \param TemplateArgs the list of template arguments to substitute into the
|
||||||
/// substitute into the constraint expression. This should be relative to the
|
/// constraint expression.
|
||||||
/// 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
|
/// \param TemplateIDRange The source range of the template id that
|
||||||
/// caused the constraints check.
|
/// caused the constraints check.
|
||||||
/// \param Satisfaction if true is returned, will contain details of the
|
/// \param Satisfaction if true is returned, will contain details of the
|
||||||
|
@ -7059,40 +7030,7 @@ public:
|
||||||
/// false otherwise.
|
/// false otherwise.
|
||||||
bool CheckConstraintSatisfaction(
|
bool CheckConstraintSatisfaction(
|
||||||
const NamedDecl *Template, ArrayRef<const Expr *> ConstraintExprs,
|
const NamedDecl *Template, ArrayRef<const Expr *> ConstraintExprs,
|
||||||
const MultiLevelTemplateArgumentList &TemplateArgList,
|
ArrayRef<TemplateArgument> TemplateArgs,
|
||||||
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 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);
|
SourceRange TemplateIDRange, ConstraintSatisfaction &Satisfaction);
|
||||||
|
|
||||||
/// \brief Check whether the given non-dependent constraint expression is
|
/// \brief Check whether the given non-dependent constraint expression is
|
||||||
|
@ -7128,8 +7066,8 @@ public:
|
||||||
///
|
///
|
||||||
/// \returns true if the constrains are not satisfied or could not be checked
|
/// \returns true if the constrains are not satisfied or could not be checked
|
||||||
/// for satisfaction, false if the constraints are satisfied.
|
/// for satisfaction, false if the constraints are satisfied.
|
||||||
bool EnsureTemplateArgumentListConstraints(
|
bool EnsureTemplateArgumentListConstraints(TemplateDecl *Template,
|
||||||
TemplateDecl *Template, MultiLevelTemplateArgumentList TemplateArgs,
|
ArrayRef<TemplateArgument> TemplateArgs,
|
||||||
SourceRange TemplateIDRange);
|
SourceRange TemplateIDRange);
|
||||||
|
|
||||||
/// \brief Emit diagnostics explaining why a constraint expression was deemed
|
/// \brief Emit diagnostics explaining why a constraint expression was deemed
|
||||||
|
@ -8864,8 +8802,7 @@ public:
|
||||||
|
|
||||||
MultiLevelTemplateArgumentList getTemplateInstantiationArgs(
|
MultiLevelTemplateArgumentList getTemplateInstantiationArgs(
|
||||||
const NamedDecl *D, const TemplateArgumentList *Innermost = nullptr,
|
const NamedDecl *D, const TemplateArgumentList *Innermost = nullptr,
|
||||||
bool RelativeToPrimary = false, const FunctionDecl *Pattern = nullptr,
|
bool RelativeToPrimary = false, const FunctionDecl *Pattern = nullptr);
|
||||||
bool LookBeyondLambda = false, bool IncludeContainingStruct = false);
|
|
||||||
|
|
||||||
/// A context in which code is being synthesized (where a source location
|
/// A context in which code is being synthesized (where a source location
|
||||||
/// alone is not sufficient to identify the context). This covers template
|
/// alone is not sufficient to identify the context). This covers template
|
||||||
|
@ -9586,11 +9523,6 @@ public:
|
||||||
ExtParameterInfoBuilder &ParamInfos);
|
ExtParameterInfoBuilder &ParamInfos);
|
||||||
ExprResult SubstExpr(Expr *E,
|
ExprResult SubstExpr(Expr *E,
|
||||||
const MultiLevelTemplateArgumentList &TemplateArgs);
|
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
|
/// Substitute the given template arguments into a list of
|
||||||
/// expressions, expanding pack expansions if required.
|
/// expressions, expanding pack expansions if required.
|
||||||
|
|
|
@ -75,9 +75,6 @@ enum class TemplateSubstitutionKind : char {
|
||||||
class MultiLevelTemplateArgumentList {
|
class MultiLevelTemplateArgumentList {
|
||||||
/// The template argument list at a certain template depth
|
/// The template argument list at a certain template depth
|
||||||
using ArgList = ArrayRef<TemplateArgument>;
|
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
|
/// The template argument lists, stored from the innermost template
|
||||||
/// argument list (first) to the outermost template argument list (last).
|
/// argument list (first) to the outermost template argument list (last).
|
||||||
|
@ -124,12 +121,6 @@ enum class TemplateSubstitutionKind : char {
|
||||||
return TemplateArgumentLists.size();
|
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 {
|
unsigned getNumRetainedOuterLevels() const {
|
||||||
return NumRetainedOuterLevels;
|
return NumRetainedOuterLevels;
|
||||||
}
|
}
|
||||||
|
@ -167,14 +158,6 @@ enum class TemplateSubstitutionKind : char {
|
||||||
return !(*this)(Depth, Index).isNull();
|
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.
|
/// Clear out a specific template argument.
|
||||||
void setArgument(unsigned Depth, unsigned Index,
|
void setArgument(unsigned Depth, unsigned Index,
|
||||||
TemplateArgument Arg) {
|
TemplateArgument Arg) {
|
||||||
|
@ -214,16 +197,6 @@ enum class TemplateSubstitutionKind : char {
|
||||||
const ArgList &getInnermost() const {
|
const ArgList &getInnermost() const {
|
||||||
return TemplateArgumentLists.front();
|
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.
|
/// The context in which partial ordering of function templates occurs.
|
||||||
|
|
|
@ -3109,11 +3109,6 @@ Error ASTNodeImporter::ImportTemplateInformation(
|
||||||
case FunctionDecl::TK_FunctionTemplate:
|
case FunctionDecl::TK_FunctionTemplate:
|
||||||
return Error::success();
|
return Error::success();
|
||||||
|
|
||||||
case FunctionDecl::TK_DependentNonTemplate:
|
|
||||||
if (Expected<FunctionDecl *> InstFDOrErr =
|
|
||||||
import(FromFD->getInstantiatedFromDecl()))
|
|
||||||
ToFD->setInstantiatedFromDecl(*InstFDOrErr);
|
|
||||||
return Error::success();
|
|
||||||
case FunctionDecl::TK_MemberSpecialization: {
|
case FunctionDecl::TK_MemberSpecialization: {
|
||||||
TemplateSpecializationKind TSK = FromFD->getTemplateSpecializationKind();
|
TemplateSpecializationKind TSK = FromFD->getTemplateSpecializationKind();
|
||||||
|
|
||||||
|
|
|
@ -3729,8 +3729,6 @@ const IdentifierInfo *FunctionDecl::getLiteralIdentifier() const {
|
||||||
FunctionDecl::TemplatedKind FunctionDecl::getTemplatedKind() const {
|
FunctionDecl::TemplatedKind FunctionDecl::getTemplatedKind() const {
|
||||||
if (TemplateOrSpecialization.isNull())
|
if (TemplateOrSpecialization.isNull())
|
||||||
return TK_NonTemplate;
|
return TK_NonTemplate;
|
||||||
if (TemplateOrSpecialization.is<FunctionDecl *>())
|
|
||||||
return TK_DependentNonTemplate;
|
|
||||||
if (TemplateOrSpecialization.is<FunctionTemplateDecl *>())
|
if (TemplateOrSpecialization.is<FunctionTemplateDecl *>())
|
||||||
return TK_FunctionTemplate;
|
return TK_FunctionTemplate;
|
||||||
if (TemplateOrSpecialization.is<MemberSpecializationInfo *>())
|
if (TemplateOrSpecialization.is<MemberSpecializationInfo *>())
|
||||||
|
@ -3782,16 +3780,6 @@ void FunctionDecl::setDescribedFunctionTemplate(FunctionTemplateDecl *Template)
|
||||||
TemplateOrSpecialization = 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 {
|
bool FunctionDecl::isImplicitlyInstantiable() const {
|
||||||
// If the function is invalid, it can't be implicitly instantiated.
|
// If the function is invalid, it can't be implicitly instantiated.
|
||||||
if (isInvalidDecl())
|
if (isInvalidDecl())
|
||||||
|
|
|
@ -293,16 +293,6 @@ const DeclContext *Decl::getParentFunctionOrMethod() const {
|
||||||
return nullptr;
|
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
|
// PrettyStackTraceDecl Implementation
|
||||||
//===----------------------------------------------------------------------===//
|
//===----------------------------------------------------------------------===//
|
||||||
|
|
|
@ -161,7 +161,6 @@ public:
|
||||||
// Skip templated functions.
|
// Skip templated functions.
|
||||||
switch (Decl->getTemplatedKind()) {
|
switch (Decl->getTemplatedKind()) {
|
||||||
case FunctionDecl::TK_NonTemplate:
|
case FunctionDecl::TK_NonTemplate:
|
||||||
case FunctionDecl::TK_DependentNonTemplate:
|
|
||||||
break;
|
break;
|
||||||
case FunctionDecl::TK_MemberSpecialization:
|
case FunctionDecl::TK_MemberSpecialization:
|
||||||
case FunctionDecl::TK_FunctionTemplateSpecialization:
|
case FunctionDecl::TK_FunctionTemplateSpecialization:
|
||||||
|
|
|
@ -30,7 +30,6 @@ using namespace sema;
|
||||||
|
|
||||||
namespace {
|
namespace {
|
||||||
class LogicalBinOp {
|
class LogicalBinOp {
|
||||||
SourceLocation Loc;
|
|
||||||
OverloadedOperatorKind Op = OO_None;
|
OverloadedOperatorKind Op = OO_None;
|
||||||
const Expr *LHS = nullptr;
|
const Expr *LHS = nullptr;
|
||||||
const Expr *RHS = nullptr;
|
const Expr *RHS = nullptr;
|
||||||
|
@ -41,14 +40,12 @@ public:
|
||||||
Op = BinaryOperator::getOverloadedOperator(BO->getOpcode());
|
Op = BinaryOperator::getOverloadedOperator(BO->getOpcode());
|
||||||
LHS = BO->getLHS();
|
LHS = BO->getLHS();
|
||||||
RHS = BO->getRHS();
|
RHS = BO->getRHS();
|
||||||
Loc = BO->getExprLoc();
|
|
||||||
} else if (auto *OO = dyn_cast<CXXOperatorCallExpr>(E)) {
|
} else if (auto *OO = dyn_cast<CXXOperatorCallExpr>(E)) {
|
||||||
// If OO is not || or && it might not have exactly 2 arguments.
|
// If OO is not || or && it might not have exactly 2 arguments.
|
||||||
if (OO->getNumArgs() == 2) {
|
if (OO->getNumArgs() == 2) {
|
||||||
Op = OO->getOperator();
|
Op = OO->getOperator();
|
||||||
LHS = OO->getArg(0);
|
LHS = OO->getArg(0);
|
||||||
RHS = OO->getArg(1);
|
RHS = OO->getArg(1);
|
||||||
Loc = OO->getOperatorLoc();
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -59,25 +56,6 @@ public:
|
||||||
|
|
||||||
const Expr *getLHS() const { return LHS; }
|
const Expr *getLHS() const { return LHS; }
|
||||||
const Expr *getRHS() const { return RHS; }
|
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>
|
template <typename AtomicEvaluator>
|
||||||
static ExprResult
|
static bool
|
||||||
calculateConstraintSatisfaction(Sema &S, const Expr *ConstraintExpr,
|
calculateConstraintSatisfaction(Sema &S, const Expr *ConstraintExpr,
|
||||||
ConstraintSatisfaction &Satisfaction,
|
ConstraintSatisfaction &Satisfaction,
|
||||||
AtomicEvaluator &&Evaluator) {
|
AtomicEvaluator &&Evaluator) {
|
||||||
ConstraintExpr = ConstraintExpr->IgnoreParenImpCasts();
|
ConstraintExpr = ConstraintExpr->IgnoreParenImpCasts();
|
||||||
|
|
||||||
if (LogicalBinOp BO = ConstraintExpr) {
|
if (LogicalBinOp BO = ConstraintExpr) {
|
||||||
ExprResult LHSRes = calculateConstraintSatisfaction(
|
if (calculateConstraintSatisfaction(S, BO.getLHS(), Satisfaction,
|
||||||
S, BO.getLHS(), Satisfaction, Evaluator);
|
Evaluator))
|
||||||
|
return true;
|
||||||
if (LHSRes.isInvalid())
|
|
||||||
return ExprError();
|
|
||||||
|
|
||||||
bool IsLHSSatisfied = Satisfaction.IsSatisfied;
|
bool IsLHSSatisfied = Satisfaction.IsSatisfied;
|
||||||
|
|
||||||
|
@ -166,7 +142,7 @@ calculateConstraintSatisfaction(Sema &S, const Expr *ConstraintExpr,
|
||||||
// is checked. If that is satisfied, the disjunction is satisfied.
|
// is checked. If that is satisfied, the disjunction is satisfied.
|
||||||
// Otherwise, the disjunction is satisfied if and only if the second
|
// Otherwise, the disjunction is satisfied if and only if the second
|
||||||
// operand is satisfied.
|
// operand is satisfied.
|
||||||
return LHSRes.isUsable() ? BO.recreateBinOp(S, LHSRes) : ExprEmpty();
|
return false;
|
||||||
|
|
||||||
if (BO.isAnd() && !IsLHSSatisfied)
|
if (BO.isAnd() && !IsLHSSatisfied)
|
||||||
// [temp.constr.op] p2
|
// [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
|
// is checked. If that is not satisfied, the conjunction is not
|
||||||
// satisfied. Otherwise, the conjunction is satisfied if and only if
|
// satisfied. Otherwise, the conjunction is satisfied if and only if
|
||||||
// the second operand is satisfied.
|
// the second operand is satisfied.
|
||||||
return LHSRes.isUsable() ? BO.recreateBinOp(S, LHSRes) : ExprEmpty();
|
return false;
|
||||||
|
|
||||||
ExprResult RHSRes = 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(
|
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));
|
std::forward<AtomicEvaluator>(Evaluator));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -197,11 +164,11 @@ calculateConstraintSatisfaction(Sema &S, const Expr *ConstraintExpr,
|
||||||
ExprResult SubstitutedAtomicExpr = Evaluator(ConstraintExpr);
|
ExprResult SubstitutedAtomicExpr = Evaluator(ConstraintExpr);
|
||||||
|
|
||||||
if (SubstitutedAtomicExpr.isInvalid())
|
if (SubstitutedAtomicExpr.isInvalid())
|
||||||
return ExprError();
|
return true;
|
||||||
|
|
||||||
if (!SubstitutedAtomicExpr.isUsable())
|
if (!SubstitutedAtomicExpr.isUsable())
|
||||||
// Evaluator has decided satisfaction without yielding an expression.
|
// Evaluator has decided satisfaction without yielding an expression.
|
||||||
return ExprEmpty();
|
return false;
|
||||||
|
|
||||||
EnterExpressionEvaluationContext ConstantEvaluated(
|
EnterExpressionEvaluationContext ConstantEvaluated(
|
||||||
S, Sema::ExpressionEvaluationContext::ConstantEvaluated);
|
S, Sema::ExpressionEvaluationContext::ConstantEvaluated);
|
||||||
|
@ -218,7 +185,7 @@ calculateConstraintSatisfaction(Sema &S, const Expr *ConstraintExpr,
|
||||||
<< SubstitutedAtomicExpr.get()->getSourceRange();
|
<< SubstitutedAtomicExpr.get()->getSourceRange();
|
||||||
for (const PartialDiagnosticAt &PDiag : EvaluationDiags)
|
for (const PartialDiagnosticAt &PDiag : EvaluationDiags)
|
||||||
S.Diag(PDiag.first, PDiag.second);
|
S.Diag(PDiag.first, PDiag.second);
|
||||||
return ExprError();
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
assert(EvalResult.Val.isInt() &&
|
assert(EvalResult.Val.isInt() &&
|
||||||
|
@ -228,13 +195,13 @@ calculateConstraintSatisfaction(Sema &S, const Expr *ConstraintExpr,
|
||||||
Satisfaction.Details.emplace_back(ConstraintExpr,
|
Satisfaction.Details.emplace_back(ConstraintExpr,
|
||||||
SubstitutedAtomicExpr.get());
|
SubstitutedAtomicExpr.get());
|
||||||
|
|
||||||
return SubstitutedAtomicExpr;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
static ExprResult calculateConstraintSatisfaction(
|
static bool calculateConstraintSatisfaction(
|
||||||
Sema &S, const NamedDecl *Template, SourceLocation TemplateNameLoc,
|
Sema &S, const NamedDecl *Template, ArrayRef<TemplateArgument> TemplateArgs,
|
||||||
const MultiLevelTemplateArgumentList &MLTAL, const Expr *ConstraintExpr,
|
SourceLocation TemplateNameLoc, MultiLevelTemplateArgumentList &MLTAL,
|
||||||
ConstraintSatisfaction &Satisfaction) {
|
const Expr *ConstraintExpr, ConstraintSatisfaction &Satisfaction) {
|
||||||
return calculateConstraintSatisfaction(
|
return calculateConstraintSatisfaction(
|
||||||
S, ConstraintExpr, Satisfaction, [&](const Expr *AtomicExpr) {
|
S, ConstraintExpr, Satisfaction, [&](const Expr *AtomicExpr) {
|
||||||
EnterExpressionEvaluationContext ConstantEvaluated(
|
EnterExpressionEvaluationContext ConstantEvaluated(
|
||||||
|
@ -252,8 +219,8 @@ static ExprResult calculateConstraintSatisfaction(
|
||||||
return ExprError();
|
return ExprError();
|
||||||
// We do not want error diagnostics escaping here.
|
// We do not want error diagnostics escaping here.
|
||||||
Sema::SFINAETrap Trap(S);
|
Sema::SFINAETrap Trap(S);
|
||||||
SubstitutedExpression =
|
SubstitutedExpression = S.SubstExpr(const_cast<Expr *>(AtomicExpr),
|
||||||
S.SubstConstraintExpr(const_cast<Expr *>(AtomicExpr), MLTAL);
|
MLTAL);
|
||||||
// Substitution might have stripped off a contextual conversion to
|
// Substitution might have stripped off a contextual conversion to
|
||||||
// bool if this is the operand of an '&&' or '||'. For example, we
|
// 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
|
// might lose an lvalue-to-rvalue conversion here. If so, put it back
|
||||||
|
@ -301,92 +268,74 @@ static ExprResult calculateConstraintSatisfaction(
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
static bool CheckConstraintSatisfaction(
|
static bool CheckConstraintSatisfaction(Sema &S, const NamedDecl *Template,
|
||||||
Sema &S, const NamedDecl *Template, ArrayRef<const Expr *> ConstraintExprs,
|
ArrayRef<const Expr *> ConstraintExprs,
|
||||||
llvm::SmallVectorImpl<Expr *> &Converted,
|
ArrayRef<TemplateArgument> TemplateArgs,
|
||||||
const MultiLevelTemplateArgumentList &TemplateArgsList,
|
SourceRange TemplateIDRange,
|
||||||
SourceRange TemplateIDRange, ConstraintSatisfaction &Satisfaction) {
|
ConstraintSatisfaction &Satisfaction) {
|
||||||
if (ConstraintExprs.empty()) {
|
if (ConstraintExprs.empty()) {
|
||||||
Satisfaction.IsSatisfied = true;
|
Satisfaction.IsSatisfied = true;
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (TemplateArgsList.isAnyArgInstantiationDependent()) {
|
for (auto& Arg : TemplateArgs)
|
||||||
|
if (Arg.isInstantiationDependent()) {
|
||||||
// No need to check satisfaction for dependent constraint expressions.
|
// No need to check satisfaction for dependent constraint expressions.
|
||||||
Satisfaction.IsSatisfied = true;
|
Satisfaction.IsSatisfied = true;
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
ArrayRef<TemplateArgument> TemplateArgs =
|
Sema::InstantiatingTemplate Inst(S, TemplateIDRange.getBegin(),
|
||||||
TemplateArgsList.getNumSubstitutedLevels() > 0
|
|
||||||
? TemplateArgsList.getOutermost()
|
|
||||||
: ArrayRef<TemplateArgument>{};
|
|
||||||
|
|
||||||
Sema::InstantiatingTemplate Inst(
|
|
||||||
S, TemplateIDRange.getBegin(),
|
|
||||||
Sema::InstantiatingTemplate::ConstraintsCheck{},
|
Sema::InstantiatingTemplate::ConstraintsCheck{},
|
||||||
const_cast<NamedDecl *>(Template), TemplateArgs, TemplateIDRange);
|
const_cast<NamedDecl *>(Template), TemplateArgs, TemplateIDRange);
|
||||||
if (Inst.isInvalid())
|
if (Inst.isInvalid())
|
||||||
return true;
|
return true;
|
||||||
|
|
||||||
for (const Expr *ConstraintExpr : ConstraintExprs) {
|
MultiLevelTemplateArgumentList MLTAL;
|
||||||
ExprResult Res = calculateConstraintSatisfaction(
|
MLTAL.addOuterTemplateArguments(TemplateArgs);
|
||||||
S, Template, TemplateIDRange.getBegin(), TemplateArgsList,
|
|
||||||
ConstraintExpr, Satisfaction);
|
|
||||||
if (Res.isInvalid())
|
|
||||||
return true;
|
|
||||||
|
|
||||||
Converted.push_back(Res.get());
|
for (const Expr *ConstraintExpr : ConstraintExprs) {
|
||||||
if (!Satisfaction.IsSatisfied) {
|
if (calculateConstraintSatisfaction(S, Template, TemplateArgs,
|
||||||
// Backfill the 'converted' list with nulls so we can keep the Converted
|
TemplateIDRange.getBegin(), MLTAL,
|
||||||
// and unconverted lists in sync.
|
ConstraintExpr, Satisfaction))
|
||||||
Converted.append(ConstraintExprs.size() - Converted.size(), nullptr);
|
return true;
|
||||||
|
if (!Satisfaction.IsSatisfied)
|
||||||
// [temp.constr.op] p2
|
// [temp.constr.op] p2
|
||||||
// [...] To determine if a conjunction is satisfied, the satisfaction
|
// [...] To determine if a conjunction is satisfied, the satisfaction
|
||||||
// of the first operand is checked. If that is not satisfied, the
|
// of the first operand is checked. If that is not satisfied, the
|
||||||
// conjunction is not satisfied. [...]
|
// conjunction is not satisfied. [...]
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
}
|
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool Sema::CheckConstraintSatisfaction(
|
bool Sema::CheckConstraintSatisfaction(
|
||||||
const NamedDecl *Template, ArrayRef<const Expr *> ConstraintExprs,
|
const NamedDecl *Template, ArrayRef<const Expr *> ConstraintExprs,
|
||||||
llvm::SmallVectorImpl<Expr *> &ConvertedConstraints,
|
ArrayRef<TemplateArgument> TemplateArgs, SourceRange TemplateIDRange,
|
||||||
const MultiLevelTemplateArgumentList &TemplateArgsList,
|
ConstraintSatisfaction &OutSatisfaction) {
|
||||||
SourceRange TemplateIDRange, ConstraintSatisfaction &OutSatisfaction) {
|
|
||||||
if (ConstraintExprs.empty()) {
|
if (ConstraintExprs.empty()) {
|
||||||
OutSatisfaction.IsSatisfied = true;
|
OutSatisfaction.IsSatisfied = true;
|
||||||
return false;
|
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;
|
llvm::FoldingSetNodeID ID;
|
||||||
void *InsertPos;
|
void *InsertPos;
|
||||||
ConstraintSatisfaction *Satisfaction = nullptr;
|
ConstraintSatisfaction *Satisfaction = nullptr;
|
||||||
bool ShouldCache = LangOpts.ConceptSatisfactionCaching && Template;
|
bool ShouldCache = LangOpts.ConceptSatisfactionCaching && Template;
|
||||||
if (ShouldCache) {
|
if (ShouldCache) {
|
||||||
ConstraintSatisfaction::Profile(ID, Context, Template, FlattenedArgs);
|
ConstraintSatisfaction::Profile(ID, Context, Template, TemplateArgs);
|
||||||
Satisfaction = SatisfactionCache.FindNodeOrInsertPos(ID, InsertPos);
|
Satisfaction = SatisfactionCache.FindNodeOrInsertPos(ID, InsertPos);
|
||||||
if (Satisfaction) {
|
if (Satisfaction) {
|
||||||
OutSatisfaction = *Satisfaction;
|
OutSatisfaction = *Satisfaction;
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
Satisfaction = new ConstraintSatisfaction(Template, FlattenedArgs);
|
Satisfaction = new ConstraintSatisfaction(Template, TemplateArgs);
|
||||||
} else {
|
} else {
|
||||||
Satisfaction = &OutSatisfaction;
|
Satisfaction = &OutSatisfaction;
|
||||||
}
|
}
|
||||||
if (::CheckConstraintSatisfaction(*this, Template, ConstraintExprs,
|
if (::CheckConstraintSatisfaction(*this, Template, ConstraintExprs,
|
||||||
ConvertedConstraints, TemplateArgsList,
|
TemplateArgs, TemplateIDRange,
|
||||||
TemplateIDRange, *Satisfaction)) {
|
*Satisfaction)) {
|
||||||
if (ShouldCache)
|
if (ShouldCache)
|
||||||
delete Satisfaction;
|
delete Satisfaction;
|
||||||
return true;
|
return true;
|
||||||
|
@ -407,108 +356,17 @@ bool Sema::CheckConstraintSatisfaction(const Expr *ConstraintExpr,
|
||||||
*this, ConstraintExpr, Satisfaction,
|
*this, ConstraintExpr, Satisfaction,
|
||||||
[](const Expr *AtomicExpr) -> ExprResult {
|
[](const Expr *AtomicExpr) -> ExprResult {
|
||||||
return ExprResult(const_cast<Expr *>(AtomicExpr));
|
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;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
bool Sema::CheckFunctionConstraints(const FunctionDecl *FD,
|
bool Sema::CheckFunctionConstraints(const FunctionDecl *FD,
|
||||||
ConstraintSatisfaction &Satisfaction,
|
ConstraintSatisfaction &Satisfaction,
|
||||||
SourceLocation UsageLoc) {
|
SourceLocation UsageLoc) {
|
||||||
// Don't check constraints if the function is dependent. Also don't check if
|
const Expr *RC = FD->getTrailingRequiresClause();
|
||||||
// this is a function template specialization, as the call to
|
if (RC->isInstantiationDependent()) {
|
||||||
// CheckinstantiatedFunctionTemplateConstraints after this will check it
|
|
||||||
// better.
|
|
||||||
if (FD->isDependentContext() ||
|
|
||||||
FD->getTemplatedKind() ==
|
|
||||||
FunctionDecl::TK_FunctionTemplateSpecialization) {
|
|
||||||
Satisfaction.IsSatisfied = true;
|
Satisfaction.IsSatisfied = true;
|
||||||
return false;
|
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;
|
Qualifiers ThisQuals;
|
||||||
CXXRecordDecl *Record = nullptr;
|
CXXRecordDecl *Record = nullptr;
|
||||||
if (auto *Method = dyn_cast<CXXMethodDecl>(FD)) {
|
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
|
// We substitute with empty arguments in order to rebuild the atomic
|
||||||
// constraint in a constant-evaluated context.
|
// constraint in a constant-evaluated context.
|
||||||
// FIXME: Should this be a dedicated TreeTransform?
|
// FIXME: Should this be a dedicated TreeTransform?
|
||||||
const Expr *RC = FD->getTrailingRequiresClause();
|
return CheckConstraintSatisfaction(
|
||||||
llvm::SmallVector<Expr *, 1> Converted;
|
FD, {RC}, /*TemplateArgs=*/{},
|
||||||
|
|
||||||
if (CheckConstraintSatisfaction(
|
|
||||||
FD, {RC}, Converted, *MLTAL,
|
|
||||||
SourceRange(UsageLoc.isValid() ? UsageLoc : FD->getLocation()),
|
SourceRange(UsageLoc.isValid() ? UsageLoc : FD->getLocation()),
|
||||||
Satisfaction))
|
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 difficult, 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;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
bool Sema::EnsureTemplateArgumentListConstraints(
|
bool Sema::EnsureTemplateArgumentListConstraints(
|
||||||
TemplateDecl *TD, MultiLevelTemplateArgumentList TemplateArgs,
|
TemplateDecl *TD, ArrayRef<TemplateArgument> TemplateArgs,
|
||||||
SourceRange TemplateIDRange) {
|
SourceRange TemplateIDRange) {
|
||||||
ConstraintSatisfaction Satisfaction;
|
ConstraintSatisfaction Satisfaction;
|
||||||
llvm::SmallVector<const Expr *, 3> AssociatedConstraints;
|
llvm::SmallVector<const Expr *, 3> AssociatedConstraints;
|
||||||
|
@ -552,8 +397,7 @@ bool Sema::EnsureTemplateArgumentListConstraints(
|
||||||
SmallString<128> TemplateArgString;
|
SmallString<128> TemplateArgString;
|
||||||
TemplateArgString = " ";
|
TemplateArgString = " ";
|
||||||
TemplateArgString += getTemplateArgumentBindingsText(
|
TemplateArgString += getTemplateArgumentBindingsText(
|
||||||
TD->getTemplateParameters(), TemplateArgs.getInnermost().data(),
|
TD->getTemplateParameters(), TemplateArgs.data(), TemplateArgs.size());
|
||||||
TemplateArgs.getInnermost().size());
|
|
||||||
|
|
||||||
Diag(TemplateIDRange.getBegin(),
|
Diag(TemplateIDRange.getBegin(),
|
||||||
diag::err_template_arg_list_constraints_not_satisfied)
|
diag::err_template_arg_list_constraints_not_satisfied)
|
||||||
|
@ -585,13 +429,21 @@ bool Sema::CheckInstantiatedFunctionTemplateConstraints(
|
||||||
Sema::ContextRAII savedContext(*this, Decl);
|
Sema::ContextRAII savedContext(*this, Decl);
|
||||||
LocalInstantiationScope Scope(*this);
|
LocalInstantiationScope Scope(*this);
|
||||||
|
|
||||||
Optional<MultiLevelTemplateArgumentList> MLTAL =
|
// If this is not an explicit specialization - we need to get the instantiated
|
||||||
SetupConstraintCheckingTemplateArgumentsAndScope(Decl, TemplateArgs,
|
// version of the template arguments and add them to scope for the
|
||||||
Scope);
|
// substitution.
|
||||||
|
if (Decl->isTemplateInstantiation()) {
|
||||||
if (!MLTAL)
|
InstantiatingTemplate Inst(*this, Decl->getPointOfInstantiation(),
|
||||||
|
InstantiatingTemplate::ConstraintsCheck{}, Decl->getPrimaryTemplate(),
|
||||||
|
TemplateArgs, SourceRange());
|
||||||
|
if (Inst.isInvalid())
|
||||||
return true;
|
return true;
|
||||||
|
MultiLevelTemplateArgumentList MLTAL(
|
||||||
|
*Decl->getTemplateSpecializationArgs());
|
||||||
|
if (addInstantiatedParametersToScope(
|
||||||
|
Decl, Decl->getPrimaryTemplate()->getTemplatedDecl(), Scope, MLTAL))
|
||||||
|
return true;
|
||||||
|
}
|
||||||
Qualifiers ThisQuals;
|
Qualifiers ThisQuals;
|
||||||
CXXRecordDecl *Record = nullptr;
|
CXXRecordDecl *Record = nullptr;
|
||||||
if (auto *Method = dyn_cast<CXXMethodDecl>(Decl)) {
|
if (auto *Method = dyn_cast<CXXMethodDecl>(Decl)) {
|
||||||
|
@ -599,8 +451,7 @@ bool Sema::CheckInstantiatedFunctionTemplateConstraints(
|
||||||
Record = Method->getParent();
|
Record = Method->getParent();
|
||||||
}
|
}
|
||||||
CXXThisScopeRAII ThisScope(*this, Record, ThisQuals, Record != nullptr);
|
CXXThisScopeRAII ThisScope(*this, Record, ThisQuals, Record != nullptr);
|
||||||
llvm::SmallVector<Expr *, 1> Converted;
|
return CheckConstraintSatisfaction(Template, TemplateAC, TemplateArgs,
|
||||||
return CheckConstraintSatisfaction(Template, TemplateAC, Converted, *MLTAL,
|
|
||||||
PointOfInstantiation, Satisfaction);
|
PointOfInstantiation, Satisfaction);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -4702,11 +4702,9 @@ Sema::CheckConceptTemplateId(const CXXScopeSpec &SS,
|
||||||
bool AreArgsDependent =
|
bool AreArgsDependent =
|
||||||
TemplateSpecializationType::anyDependentTemplateArguments(*TemplateArgs,
|
TemplateSpecializationType::anyDependentTemplateArguments(*TemplateArgs,
|
||||||
Converted);
|
Converted);
|
||||||
MultiLevelTemplateArgumentList MLTAL;
|
|
||||||
MLTAL.addOuterTemplateArguments(Converted);
|
|
||||||
if (!AreArgsDependent &&
|
if (!AreArgsDependent &&
|
||||||
CheckConstraintSatisfaction(
|
CheckConstraintSatisfaction(
|
||||||
NamedConcept, {NamedConcept->getConstraintExpr()}, MLTAL,
|
NamedConcept, {NamedConcept->getConstraintExpr()}, Converted,
|
||||||
SourceRange(SS.isSet() ? SS.getBeginLoc() : ConceptNameInfo.getLoc(),
|
SourceRange(SS.isSet() ? SS.getBeginLoc() : ConceptNameInfo.getLoc(),
|
||||||
TemplateArgs->getRAngleLoc()),
|
TemplateArgs->getRAngleLoc()),
|
||||||
Satisfaction))
|
Satisfaction))
|
||||||
|
@ -5566,7 +5564,6 @@ bool Sema::CheckTemplateArgument(NamedDecl *Param,
|
||||||
if (Inst.isInvalid())
|
if (Inst.isInvalid())
|
||||||
return true;
|
return true;
|
||||||
|
|
||||||
ConstraintEvalRAII EvalRAII(*this);
|
|
||||||
TemplateArgumentList TemplateArgs(TemplateArgumentList::OnStack, Converted);
|
TemplateArgumentList TemplateArgs(TemplateArgumentList::OnStack, Converted);
|
||||||
Params = SubstTemplateParams(Params, CurContext,
|
Params = SubstTemplateParams(Params, CurContext,
|
||||||
MultiLevelTemplateArgumentList(TemplateArgs));
|
MultiLevelTemplateArgumentList(TemplateArgs));
|
||||||
|
@ -5924,21 +5921,14 @@ bool Sema::CheckTemplateArgumentList(
|
||||||
if (UpdateArgsWithConversions)
|
if (UpdateArgsWithConversions)
|
||||||
TemplateArgs = std::move(NewArgs);
|
TemplateArgs = std::move(NewArgs);
|
||||||
|
|
||||||
if (!PartialTemplateArgs) {
|
if (!PartialTemplateArgs &&
|
||||||
TemplateArgumentList StackTemplateArgs(TemplateArgumentList::OnStack,
|
EnsureTemplateArgumentListConstraints(
|
||||||
Converted);
|
Template, Converted, SourceRange(TemplateLoc,
|
||||||
MultiLevelTemplateArgumentList MLTAL = getTemplateInstantiationArgs(
|
TemplateArgs.getRAngleLoc()))) {
|
||||||
Template, &StackTemplateArgs, /*RelativeToPrimary*/ true,
|
|
||||||
/*Pattern*/ nullptr,
|
|
||||||
/*LookBeyondLambda*/ true, /*IncludeContainingStruct*/ true);
|
|
||||||
if (EnsureTemplateArgumentListConstraints(
|
|
||||||
Template, MLTAL,
|
|
||||||
SourceRange(TemplateLoc, TemplateArgs.getRAngleLoc()))) {
|
|
||||||
if (ConstraintsNotSatisfied)
|
if (ConstraintsNotSatisfied)
|
||||||
*ConstraintsNotSatisfied = true;
|
*ConstraintsNotSatisfied = true;
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
@ -7467,9 +7457,7 @@ bool Sema::CheckTemplateTemplateArgument(TemplateTemplateParmDecl *Param,
|
||||||
// are not considered.
|
// are not considered.
|
||||||
if (ParamsAC.empty())
|
if (ParamsAC.empty())
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
Template->getAssociatedConstraints(TemplateAC);
|
Template->getAssociatedConstraints(TemplateAC);
|
||||||
|
|
||||||
bool IsParamAtLeastAsConstrained;
|
bool IsParamAtLeastAsConstrained;
|
||||||
if (IsAtLeastAsConstrained(Param, ParamsAC, Template, TemplateAC,
|
if (IsAtLeastAsConstrained(Param, ParamsAC, Template, TemplateAC,
|
||||||
IsParamAtLeastAsConstrained))
|
IsParamAtLeastAsConstrained))
|
||||||
|
|
|
@ -2791,10 +2791,8 @@ CheckDeducedArgumentConstraints(Sema& S, TemplateDeclT *Template,
|
||||||
TemplateDeductionInfo& Info) {
|
TemplateDeductionInfo& Info) {
|
||||||
llvm::SmallVector<const Expr *, 3> AssociatedConstraints;
|
llvm::SmallVector<const Expr *, 3> AssociatedConstraints;
|
||||||
Template->getAssociatedConstraints(AssociatedConstraints);
|
Template->getAssociatedConstraints(AssociatedConstraints);
|
||||||
MultiLevelTemplateArgumentList MLTAL;
|
if (S.CheckConstraintSatisfaction(Template, AssociatedConstraints,
|
||||||
MLTAL.addOuterTemplateArguments(DeducedArgs);
|
DeducedArgs, Info.getLocation(),
|
||||||
if (S.CheckConstraintSatisfaction(Template, AssociatedConstraints, MLTAL,
|
|
||||||
Info.getLocation(),
|
|
||||||
Info.AssociatedConstraintsSatisfaction) ||
|
Info.AssociatedConstraintsSatisfaction) ||
|
||||||
!Info.AssociatedConstraintsSatisfaction.IsSatisfied) {
|
!Info.AssociatedConstraintsSatisfaction.IsSatisfied) {
|
||||||
Info.reset(TemplateArgumentList::CreateCopy(S.Context, DeducedArgs));
|
Info.reset(TemplateArgumentList::CreateCopy(S.Context, DeducedArgs));
|
||||||
|
@ -4574,11 +4572,8 @@ CheckDeducedPlaceholderConstraints(Sema &S, const AutoType &Type,
|
||||||
if (S.CheckTemplateArgumentList(Concept, SourceLocation(), TemplateArgs,
|
if (S.CheckTemplateArgumentList(Concept, SourceLocation(), TemplateArgs,
|
||||||
/*PartialTemplateArgs=*/false, Converted))
|
/*PartialTemplateArgs=*/false, Converted))
|
||||||
return Sema::DAR_FailedAlreadyDiagnosed;
|
return Sema::DAR_FailedAlreadyDiagnosed;
|
||||||
|
|
||||||
MultiLevelTemplateArgumentList MLTAL;
|
|
||||||
MLTAL.addOuterTemplateArguments(Converted);
|
|
||||||
if (S.CheckConstraintSatisfaction(Concept, {Concept->getConstraintExpr()},
|
if (S.CheckConstraintSatisfaction(Concept, {Concept->getConstraintExpr()},
|
||||||
MLTAL, TypeLoc.getLocalSourceRange(),
|
Converted, TypeLoc.getLocalSourceRange(),
|
||||||
Satisfaction))
|
Satisfaction))
|
||||||
return Sema::DAR_FailedAlreadyDiagnosed;
|
return Sema::DAR_FailedAlreadyDiagnosed;
|
||||||
if (!Satisfaction.IsSatisfied) {
|
if (!Satisfaction.IsSatisfied) {
|
||||||
|
|
|
@ -55,18 +55,9 @@ using namespace sema;
|
||||||
/// instantiating the definition of the given declaration, \p D. This is
|
/// instantiating the definition of the given declaration, \p D. This is
|
||||||
/// used to determine the proper set of template instantiation arguments for
|
/// used to determine the proper set of template instantiation arguments for
|
||||||
/// friend function template specializations.
|
/// 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(
|
MultiLevelTemplateArgumentList Sema::getTemplateInstantiationArgs(
|
||||||
const NamedDecl *D, const TemplateArgumentList *Innermost,
|
const NamedDecl *D, const TemplateArgumentList *Innermost,
|
||||||
bool RelativeToPrimary, const FunctionDecl *Pattern, bool LookBeyondLambda,
|
bool RelativeToPrimary, const FunctionDecl *Pattern) {
|
||||||
bool IncludeContainingStructArgs) {
|
|
||||||
// Accumulate the set of template argument lists in this structure.
|
// Accumulate the set of template argument lists in this structure.
|
||||||
MultiLevelTemplateArgumentList Result;
|
MultiLevelTemplateArgumentList Result;
|
||||||
|
|
||||||
|
@ -162,13 +153,11 @@ MultiLevelTemplateArgumentList Sema::getTemplateInstantiationArgs(
|
||||||
break;
|
break;
|
||||||
|
|
||||||
// If this function is a generic lambda specialization, we are done.
|
// If this function is a generic lambda specialization, we are done.
|
||||||
if (!LookBeyondLambda &&
|
if (isGenericLambdaCallOperatorOrStaticInvokerSpecialization(Function))
|
||||||
isGenericLambdaCallOperatorOrStaticInvokerSpecialization(Function))
|
|
||||||
break;
|
break;
|
||||||
|
|
||||||
} else if (Function->getDescribedFunctionTemplate()) {
|
} else if (Function->getDescribedFunctionTemplate()) {
|
||||||
assert((IncludeContainingStructArgs ||
|
assert(Result.getNumSubstitutedLevels() == 0 &&
|
||||||
Result.getNumSubstitutedLevels() == 0) &&
|
|
||||||
"Outer template not instantiated?");
|
"Outer template not instantiated?");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -185,18 +174,10 @@ MultiLevelTemplateArgumentList Sema::getTemplateInstantiationArgs(
|
||||||
}
|
}
|
||||||
} else if (const auto *Rec = dyn_cast<CXXRecordDecl>(Ctx)) {
|
} else if (const auto *Rec = dyn_cast<CXXRecordDecl>(Ctx)) {
|
||||||
if (ClassTemplateDecl *ClassTemplate = Rec->getDescribedClassTemplate()) {
|
if (ClassTemplateDecl *ClassTemplate = Rec->getDescribedClassTemplate()) {
|
||||||
assert((IncludeContainingStructArgs ||
|
assert(Result.getNumSubstitutedLevels() == 0 &&
|
||||||
Result.getNumSubstitutedLevels() == 0) &&
|
|
||||||
"Outer template not instantiated?");
|
"Outer template not instantiated?");
|
||||||
if (ClassTemplate->isMemberSpecialization())
|
if (ClassTemplate->isMemberSpecialization())
|
||||||
break;
|
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 MultiLevelTemplateArgumentList &TemplateArgs) {
|
||||||
const ASTTemplateArgumentListInfo *TemplArgInfo =
|
const ASTTemplateArgumentListInfo *TemplArgInfo =
|
||||||
TC->getTemplateArgsAsWritten();
|
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;
|
TemplateArgumentListInfo InstArgs;
|
||||||
|
|
||||||
if (TemplArgInfo) {
|
if (TemplArgInfo) {
|
||||||
|
@ -3519,14 +3488,6 @@ Sema::SubstExpr(Expr *E, const MultiLevelTemplateArgumentList &TemplateArgs) {
|
||||||
return Instantiator.TransformExpr(E);
|
return Instantiator.TransformExpr(E);
|
||||||
}
|
}
|
||||||
|
|
||||||
ExprResult
|
|
||||||
Sema::SubstConstraintExpr(Expr *E,
|
|
||||||
const MultiLevelTemplateArgumentList &TemplateArgs) {
|
|
||||||
|
|
||||||
ConstraintEvalRAII EvalRAII(*this);
|
|
||||||
return SubstExpr(E, TemplateArgs);
|
|
||||||
}
|
|
||||||
|
|
||||||
ExprResult Sema::SubstInitializer(Expr *Init,
|
ExprResult Sema::SubstInitializer(Expr *Init,
|
||||||
const MultiLevelTemplateArgumentList &TemplateArgs,
|
const MultiLevelTemplateArgumentList &TemplateArgs,
|
||||||
bool CXXDirectInit) {
|
bool CXXDirectInit) {
|
||||||
|
|
|
@ -2062,7 +2062,19 @@ Decl *TemplateDeclInstantiator::VisitFunctionDecl(
|
||||||
return nullptr;
|
return nullptr;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// FIXME: Concepts: Do not substitute into constraint expressions
|
||||||
Expr *TrailingRequiresClause = D->getTrailingRequiresClause();
|
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
|
// If we're instantiating a local function declaration, put the result
|
||||||
// in the enclosing namespace; otherwise we need to find the instantiated
|
// 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
|
// definition. We don't want non-template functions to be marked as being
|
||||||
// template instantiations.
|
// template instantiations.
|
||||||
Function->setInstantiationOfMemberFunction(D, TSK_ImplicitInstantiation);
|
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) {
|
if (isFriend) {
|
||||||
|
@ -2413,6 +2420,23 @@ Decl *TemplateDeclInstantiator::VisitCXXMethodDecl(
|
||||||
return nullptr;
|
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;
|
DeclContext *DC = Owner;
|
||||||
if (isFriend) {
|
if (isFriend) {
|
||||||
if (QualifierLoc) {
|
if (QualifierLoc) {
|
||||||
|
@ -2430,9 +2454,6 @@ Decl *TemplateDeclInstantiator::VisitCXXMethodDecl(
|
||||||
if (!DC) return nullptr;
|
if (!DC) return nullptr;
|
||||||
}
|
}
|
||||||
|
|
||||||
CXXRecordDecl *Record = cast<CXXRecordDecl>(DC);
|
|
||||||
Expr *TrailingRequiresClause = D->getTrailingRequiresClause();
|
|
||||||
|
|
||||||
DeclarationNameInfo NameInfo
|
DeclarationNameInfo NameInfo
|
||||||
= SemaRef.SubstDeclarationNameInfo(D->getNameInfo(), TemplateArgs);
|
= SemaRef.SubstDeclarationNameInfo(D->getNameInfo(), TemplateArgs);
|
||||||
|
|
||||||
|
@ -2440,6 +2461,7 @@ Decl *TemplateDeclInstantiator::VisitCXXMethodDecl(
|
||||||
adjustForRewrite(FunctionRewriteKind, D, T, TInfo, NameInfo);
|
adjustForRewrite(FunctionRewriteKind, D, T, TInfo, NameInfo);
|
||||||
|
|
||||||
// Build the instantiated method declaration.
|
// Build the instantiated method declaration.
|
||||||
|
CXXRecordDecl *Record = cast<CXXRecordDecl>(DC);
|
||||||
CXXMethodDecl *Method = nullptr;
|
CXXMethodDecl *Method = nullptr;
|
||||||
|
|
||||||
SourceLocation StartLoc = D->getInnerLocStart();
|
SourceLocation StartLoc = D->getInnerLocStart();
|
||||||
|
@ -2746,6 +2768,9 @@ Decl *TemplateDeclInstantiator::VisitTemplateTypeParmDecl(
|
||||||
// Invented template parameter type constraints will be instantiated with
|
// Invented template parameter type constraints will be instantiated with
|
||||||
// the corresponding auto-typed parameter as it might reference other
|
// the corresponding auto-typed parameter as it might reference other
|
||||||
// parameters.
|
// parameters.
|
||||||
|
|
||||||
|
// TODO: Concepts: do not instantiate the constraint (delayed constraint
|
||||||
|
// substitution)
|
||||||
if (SemaRef.SubstTypeConstraint(Inst, TC, TemplateArgs))
|
if (SemaRef.SubstTypeConstraint(Inst, TC, TemplateArgs))
|
||||||
return nullptr;
|
return nullptr;
|
||||||
}
|
}
|
||||||
|
@ -3988,7 +4013,18 @@ TemplateDeclInstantiator::SubstTemplateParams(TemplateParameterList *L) {
|
||||||
if (Invalid)
|
if (Invalid)
|
||||||
return nullptr;
|
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 *InstL
|
||||||
= TemplateParameterList::Create(SemaRef.Context, L->getTemplateLoc(),
|
= TemplateParameterList::Create(SemaRef.Context, L->getTemplateLoc(),
|
||||||
|
|
|
@ -12997,6 +12997,13 @@ TreeTransform<Derived>::TransformLambdaExpr(LambdaExpr *E) {
|
||||||
NewCallOpType);
|
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.
|
// Create the local class that will describe the lambda.
|
||||||
|
|
||||||
// FIXME: DependencyKind below is wrong when substituting inside a templated
|
// FIXME: DependencyKind below is wrong when substituting inside a templated
|
||||||
|
@ -13031,7 +13038,7 @@ TreeTransform<Derived>::TransformLambdaExpr(LambdaExpr *E) {
|
||||||
E->getCallOperator()->getEndLoc(),
|
E->getCallOperator()->getEndLoc(),
|
||||||
NewCallOpTSI->getTypeLoc().castAs<FunctionProtoTypeLoc>().getParams(),
|
NewCallOpTSI->getTypeLoc().castAs<FunctionProtoTypeLoc>().getParams(),
|
||||||
E->getCallOperator()->getConstexprKind(),
|
E->getCallOperator()->getConstexprKind(),
|
||||||
E->getCallOperator()->getTrailingRequiresClause());
|
NewTrailingRequiresClause.get());
|
||||||
|
|
||||||
LSI->CallOperator = NewCallOperator;
|
LSI->CallOperator = NewCallOperator;
|
||||||
|
|
||||||
|
|
|
@ -941,10 +941,6 @@ void ASTDeclReader::VisitFunctionDecl(FunctionDecl *FD) {
|
||||||
case FunctionDecl::TK_NonTemplate:
|
case FunctionDecl::TK_NonTemplate:
|
||||||
mergeRedeclarable(FD, Redecl);
|
mergeRedeclarable(FD, Redecl);
|
||||||
break;
|
break;
|
||||||
case FunctionDecl::TK_DependentNonTemplate:
|
|
||||||
mergeRedeclarable(FD, Redecl);
|
|
||||||
FD->setInstantiatedFromDecl(readDeclAs<FunctionDecl>());
|
|
||||||
break;
|
|
||||||
case FunctionDecl::TK_FunctionTemplate:
|
case FunctionDecl::TK_FunctionTemplate:
|
||||||
// Merged when we merge the template.
|
// Merged when we merge the template.
|
||||||
FD->setDescribedFunctionTemplate(readDeclAs<FunctionTemplateDecl>());
|
FD->setDescribedFunctionTemplate(readDeclAs<FunctionTemplateDecl>());
|
||||||
|
|
|
@ -585,9 +585,6 @@ void ASTDeclWriter::VisitFunctionDecl(FunctionDecl *D) {
|
||||||
switch (D->getTemplatedKind()) {
|
switch (D->getTemplatedKind()) {
|
||||||
case FunctionDecl::TK_NonTemplate:
|
case FunctionDecl::TK_NonTemplate:
|
||||||
break;
|
break;
|
||||||
case FunctionDecl::TK_DependentNonTemplate:
|
|
||||||
Record.AddDeclRef(D->getInstantiatedFromDecl());
|
|
||||||
break;
|
|
||||||
case FunctionDecl::TK_FunctionTemplate:
|
case FunctionDecl::TK_FunctionTemplate:
|
||||||
Record.AddDeclRef(D->getDescribedFunctionTemplate());
|
Record.AddDeclRef(D->getDescribedFunctionTemplate());
|
||||||
break;
|
break;
|
||||||
|
|
|
@ -90,24 +90,3 @@ struct D { };
|
||||||
|
|
||||||
static_assert(C<int>{}); // expected-note{{while checking constraint satisfaction for template 'C<int>' required here}}
|
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}}
|
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
|
|
||||||
|
|
|
@ -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 **&j2 = g(); // expected-error {{deduced type 'int' does not satisfy 'C'}}
|
||||||
C auto **&&j3 = 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@-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@-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@-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@-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@-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@-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@-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@-1{{invalid reference to function 'foo'}}
|
|
||||||
// expected-note@#CMV_FOO{{because 'IsInt<decltype(this->t)>' evaluated to false}}
|
|
||||||
CMV2.foo2<float>();
|
|
||||||
// expected-error@-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
|
|
||||||
|
|
|
@ -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
|
|
|
@ -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), ...)
|
template <typename... Args> requires ((sizeof(Args) == 1), ...)
|
||||||
// expected-note@-1 {{because '(sizeof(int) == 1) , (sizeof(char) == 1) , (sizeof(int) == 1)' evaluated to false}}
|
// expected-note@-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));
|
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@+3 {{candidate template ignored: constraints not satisfied [with U = int]}}
|
|
||||||
// expected-note@+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@+1 {{no matching function for call to 'f'}}
|
|
||||||
static_assert(S1<void>::f(1));
|
|
||||||
|
|
||||||
constexpr auto value = 0;
|
constexpr auto value = 0;
|
||||||
|
|
||||||
template<typename T>
|
template<typename T>
|
||||||
|
|
|
@ -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@-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@-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@-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@-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}}
|
|
||||||
}
|
|
Loading…
Reference in New Issue