diff options
author | Saar Raz <saar@raz.email> | 2020-01-25 22:54:27 +0200 |
---|---|---|
committer | Saar Raz <saar@raz.email> | 2020-01-25 23:10:40 +0200 |
commit | c21e178bf22b6b46f087e6aab02a34d11dd98432 (patch) | |
tree | da17ffa2315dc6dac7a64d5727e9536771e7a34d /clang/lib/Sema | |
parent | 0df13627c6a4006de39e5f01d81a338793b0e82b (diff) | |
download | bcm5719-llvm-c21e178bf22b6b46f087e6aab02a34d11dd98432.tar.gz bcm5719-llvm-c21e178bf22b6b46f087e6aab02a34d11dd98432.zip |
[Concepts] Transform constraints of non-template functions to ConstantEvaluated
We would previously try to evaluate atomic constraints of non-template functions as-is,
and since they are now unevaluated at first, this would cause incorrect evaluation (bugs #44657, #44656).
Substitute into atomic constraints of non-template functions as we would atomic constraints
of template functions, in order to rebuild the expressions in a constant-evaluated context.
(cherry picked from commit 713562f54858f10bf8998ee21ff2c7e7bad0d177)
Diffstat (limited to 'clang/lib/Sema')
-rwxr-xr-x | clang/lib/Sema/SemaConcept.cpp | 58 | ||||
-rw-r--r-- | clang/lib/Sema/SemaExpr.cpp | 3 | ||||
-rw-r--r-- | clang/lib/Sema/SemaExprCXX.cpp | 3 | ||||
-rw-r--r-- | clang/lib/Sema/SemaOverload.cpp | 20 | ||||
-rw-r--r-- | clang/lib/Sema/SemaTemplateInstantiate.cpp | 17 |
5 files changed, 57 insertions, 44 deletions
diff --git a/clang/lib/Sema/SemaConcept.cpp b/clang/lib/Sema/SemaConcept.cpp index 81601b09ce0..e5c0fa28c11 100755 --- a/clang/lib/Sema/SemaConcept.cpp +++ b/clang/lib/Sema/SemaConcept.cpp @@ -167,9 +167,8 @@ calculateConstraintSatisfaction(Sema &S, const Expr *ConstraintExpr, return false; } -template <typename TemplateDeclT> static bool calculateConstraintSatisfaction( - Sema &S, TemplateDeclT *Template, ArrayRef<TemplateArgument> TemplateArgs, + Sema &S, const NamedDecl *Template, ArrayRef<TemplateArgument> TemplateArgs, SourceLocation TemplateNameLoc, MultiLevelTemplateArgumentList &MLTAL, const Expr *ConstraintExpr, ConstraintSatisfaction &Satisfaction) { return calculateConstraintSatisfaction( @@ -182,8 +181,9 @@ static bool calculateConstraintSatisfaction( { TemplateDeductionInfo Info(TemplateNameLoc); Sema::InstantiatingTemplate Inst(S, AtomicExpr->getBeginLoc(), - Sema::InstantiatingTemplate::ConstraintSubstitution{}, Template, - Info, AtomicExpr->getSourceRange()); + Sema::InstantiatingTemplate::ConstraintSubstitution{}, + const_cast<NamedDecl *>(Template), Info, + AtomicExpr->getSourceRange()); if (Inst.isInvalid()) return ExprError(); // We do not want error diagnostics escaping here. @@ -230,8 +230,7 @@ static bool calculateConstraintSatisfaction( }); } -template<typename TemplateDeclT> -static bool CheckConstraintSatisfaction(Sema &S, TemplateDeclT *Template, +static bool CheckConstraintSatisfaction(Sema &S, const NamedDecl *Template, ArrayRef<const Expr *> ConstraintExprs, ArrayRef<TemplateArgument> TemplateArgs, SourceRange TemplateIDRange, @@ -249,8 +248,8 @@ static bool CheckConstraintSatisfaction(Sema &S, TemplateDeclT *Template, } Sema::InstantiatingTemplate Inst(S, TemplateIDRange.getBegin(), - Sema::InstantiatingTemplate::ConstraintsCheck{}, Template, TemplateArgs, - TemplateIDRange); + Sema::InstantiatingTemplate::ConstraintsCheck{}, + const_cast<NamedDecl *>(Template), TemplateArgs, TemplateIDRange); if (Inst.isInvalid()) return true; @@ -273,7 +272,7 @@ static bool CheckConstraintSatisfaction(Sema &S, TemplateDeclT *Template, } bool Sema::CheckConstraintSatisfaction( - NamedDecl *Template, ArrayRef<const Expr *> ConstraintExprs, + const NamedDecl *Template, ArrayRef<const Expr *> ConstraintExprs, ArrayRef<TemplateArgument> TemplateArgs, SourceRange TemplateIDRange, ConstraintSatisfaction &OutSatisfaction) { if (ConstraintExprs.empty()) { @@ -284,7 +283,8 @@ bool Sema::CheckConstraintSatisfaction( llvm::FoldingSetNodeID ID; void *InsertPos; ConstraintSatisfaction *Satisfaction = nullptr; - if (LangOpts.ConceptSatisfactionCaching) { + bool ShouldCache = LangOpts.ConceptSatisfactionCaching && Template; + if (ShouldCache) { ConstraintSatisfaction::Profile(ID, Context, Template, TemplateArgs); Satisfaction = SatisfactionCache.FindNodeOrInsertPos(ID, InsertPos); if (Satisfaction) { @@ -295,27 +295,15 @@ bool Sema::CheckConstraintSatisfaction( } else { Satisfaction = &OutSatisfaction; } - bool Failed; - if (auto *T = dyn_cast<TemplateDecl>(Template)) - Failed = ::CheckConstraintSatisfaction(*this, T, ConstraintExprs, - TemplateArgs, TemplateIDRange, - *Satisfaction); - else if (auto *P = - dyn_cast<ClassTemplatePartialSpecializationDecl>(Template)) - Failed = ::CheckConstraintSatisfaction(*this, P, ConstraintExprs, - TemplateArgs, TemplateIDRange, - *Satisfaction); - else - Failed = ::CheckConstraintSatisfaction( - *this, cast<VarTemplatePartialSpecializationDecl>(Template), - ConstraintExprs, TemplateArgs, TemplateIDRange, *Satisfaction); - if (Failed) { - if (LangOpts.ConceptSatisfactionCaching) + if (::CheckConstraintSatisfaction(*this, Template, ConstraintExprs, + TemplateArgs, TemplateIDRange, + *Satisfaction)) { + if (ShouldCache) delete Satisfaction; return true; } - if (LangOpts.ConceptSatisfactionCaching) { + if (ShouldCache) { // We cannot use InsertNode here because CheckConstraintSatisfaction might // have invalidated it. SatisfactionCache.InsertNode(Satisfaction); @@ -333,6 +321,22 @@ bool Sema::CheckConstraintSatisfaction(const Expr *ConstraintExpr, }); } +bool Sema::CheckFunctionConstraints(const FunctionDecl *FD, + ConstraintSatisfaction &Satisfaction, + SourceLocation UsageLoc) { + const Expr *RC = FD->getTrailingRequiresClause(); + assert(!RC->isInstantiationDependent() && + "CheckFunctionConstraints can only be used with functions with " + "non-dependent constraints"); + // We substitute with empty arguments in order to rebuild the atomic + // constraint in a constant-evaluated context. + // FIXME: Should this be a dedicated TreeTransform? + return CheckConstraintSatisfaction( + FD, {RC}, /*TemplateArgs=*/{}, + SourceRange(UsageLoc.isValid() ? UsageLoc : FD->getLocation()), + Satisfaction); +} + bool Sema::EnsureTemplateArgumentListConstraints( TemplateDecl *TD, ArrayRef<TemplateArgument> TemplateArgs, SourceRange TemplateIDRange) { diff --git a/clang/lib/Sema/SemaExpr.cpp b/clang/lib/Sema/SemaExpr.cpp index ea4b93ee6a5..4f777e7b981 100644 --- a/clang/lib/Sema/SemaExpr.cpp +++ b/clang/lib/Sema/SemaExpr.cpp @@ -335,7 +335,8 @@ bool Sema::DiagnoseUseOfDecl(NamedDecl *D, ArrayRef<SourceLocation> Locs, if (FunctionDecl *FD = dyn_cast<FunctionDecl>(D)) { if (Expr *RC = FD->getTrailingRequiresClause()) { ConstraintSatisfaction Satisfaction; - bool Failed = CheckConstraintSatisfaction(RC, Satisfaction); + bool Failed = CheckConstraintSatisfaction(FD, {RC}, /*TemplateArgs=*/{}, + SourceRange(Loc), Satisfaction); if (Failed) // A diagnostic will have already been generated (non-constant // constraint expression, for example) diff --git a/clang/lib/Sema/SemaExprCXX.cpp b/clang/lib/Sema/SemaExprCXX.cpp index 192c237b6c1..98af7fb73ec 100644 --- a/clang/lib/Sema/SemaExprCXX.cpp +++ b/clang/lib/Sema/SemaExprCXX.cpp @@ -8487,7 +8487,8 @@ concepts::NestedRequirement * Sema::BuildNestedRequirement(Expr *Constraint) { ConstraintSatisfaction Satisfaction; if (!Constraint->isInstantiationDependent() && - CheckConstraintSatisfaction(Constraint, Satisfaction)) + CheckConstraintSatisfaction(nullptr, {Constraint}, /*TemplateArgs=*/{}, + Constraint->getSourceRange(), Satisfaction)) return nullptr; return new (Context) concepts::NestedRequirement(Context, Constraint, Satisfaction); diff --git a/clang/lib/Sema/SemaOverload.cpp b/clang/lib/Sema/SemaOverload.cpp index 0fd932fac97..9f4996b5463 100644 --- a/clang/lib/Sema/SemaOverload.cpp +++ b/clang/lib/Sema/SemaOverload.cpp @@ -6291,9 +6291,9 @@ void Sema::AddOverloadCandidate( return; } - if (Expr *RequiresClause = Function->getTrailingRequiresClause()) { + if (Function->getTrailingRequiresClause()) { ConstraintSatisfaction Satisfaction; - if (CheckConstraintSatisfaction(RequiresClause, Satisfaction) || + if (CheckFunctionConstraints(Function, Satisfaction) || !Satisfaction.IsSatisfied) { Candidate.Viable = false; Candidate.FailureKind = ovl_fail_constraints_not_satisfied; @@ -6808,9 +6808,9 @@ Sema::AddMethodCandidate(CXXMethodDecl *Method, DeclAccessPair FoundDecl, return; } - if (Expr *RequiresClause = Method->getTrailingRequiresClause()) { + if (Method->getTrailingRequiresClause()) { ConstraintSatisfaction Satisfaction; - if (CheckConstraintSatisfaction(RequiresClause, Satisfaction) || + if (CheckFunctionConstraints(Method, Satisfaction) || !Satisfaction.IsSatisfied) { Candidate.Viable = false; Candidate.FailureKind = ovl_fail_constraints_not_satisfied; @@ -7204,10 +7204,9 @@ void Sema::AddConversionCandidate( return; } - Expr *RequiresClause = Conversion->getTrailingRequiresClause(); - if (RequiresClause) { + if (Conversion->getTrailingRequiresClause()) { ConstraintSatisfaction Satisfaction; - if (CheckConstraintSatisfaction(RequiresClause, Satisfaction) || + if (CheckFunctionConstraints(Conversion, Satisfaction) || !Satisfaction.IsSatisfied) { Candidate.Viable = false; Candidate.FailureKind = ovl_fail_constraints_not_satisfied; @@ -9947,9 +9946,9 @@ static bool checkAddressOfFunctionIsAvailable(Sema &S, const FunctionDecl *FD, return false; } - if (const Expr *RC = FD->getTrailingRequiresClause()) { + if (FD->getTrailingRequiresClause()) { ConstraintSatisfaction Satisfaction; - if (S.CheckConstraintSatisfaction(RC, Satisfaction)) + if (S.CheckFunctionConstraints(FD, Satisfaction, Loc)) return false; if (!Satisfaction.IsSatisfied) { if (Complain) { @@ -10974,8 +10973,7 @@ static void NoteFunctionCandidate(Sema &S, OverloadCandidate *Cand, << (unsigned)FnKindPair.first << (unsigned)ocs_non_template << FnDesc /* Ignored */; ConstraintSatisfaction Satisfaction; - if (S.CheckConstraintSatisfaction(Fn->getTrailingRequiresClause(), - Satisfaction)) + if (S.CheckFunctionConstraints(Fn, Satisfaction)) break; S.DiagnoseUnsatisfiedConstraint(Satisfaction); } diff --git a/clang/lib/Sema/SemaTemplateInstantiate.cpp b/clang/lib/Sema/SemaTemplateInstantiate.cpp index 39bc28d6230..26dc5d92f23 100644 --- a/clang/lib/Sema/SemaTemplateInstantiate.cpp +++ b/clang/lib/Sema/SemaTemplateInstantiate.cpp @@ -763,21 +763,30 @@ void Sema::PrintInstantiationStack() { case CodeSynthesisContext::ConstraintsCheck: { unsigned DiagID = 0; + if (!Active->Entity) { + Diags.Report(Active->PointOfInstantiation, + diag::note_nested_requirement_here) + << Active->InstantiationRange; + break; + } if (isa<ConceptDecl>(Active->Entity)) DiagID = diag::note_concept_specialization_here; else if (isa<TemplateDecl>(Active->Entity)) DiagID = diag::note_checking_constraints_for_template_id_here; else if (isa<VarTemplatePartialSpecializationDecl>(Active->Entity)) DiagID = diag::note_checking_constraints_for_var_spec_id_here; - else { - assert(isa<ClassTemplatePartialSpecializationDecl>(Active->Entity)); + else if (isa<ClassTemplatePartialSpecializationDecl>(Active->Entity)) DiagID = diag::note_checking_constraints_for_class_spec_id_here; + else { + assert(isa<FunctionDecl>(Active->Entity)); + DiagID = diag::note_checking_constraints_for_function_here; } SmallVector<char, 128> TemplateArgsStr; llvm::raw_svector_ostream OS(TemplateArgsStr); cast<NamedDecl>(Active->Entity)->printName(OS); - printTemplateArgumentList(OS, Active->template_arguments(), - getPrintingPolicy()); + if (!isa<FunctionDecl>(Active->Entity)) + printTemplateArgumentList(OS, Active->template_arguments(), + getPrintingPolicy()); Diags.Report(Active->PointOfInstantiation, DiagID) << OS.str() << Active->InstantiationRange; break; |