diff options
Diffstat (limited to 'clang/lib/Sema')
-rw-r--r--[-rwxr-xr-x] | clang/lib/Sema/SemaConcept.cpp | 360 | ||||
-rw-r--r--[-rwxr-xr-x] | clang/lib/Sema/SemaTemplate.cpp | 30 | ||||
-rw-r--r-- | clang/lib/Sema/SemaTemplateDeduction.cpp | 231 | ||||
-rw-r--r-- | clang/lib/Sema/SemaTemplateInstantiate.cpp | 42 | ||||
-rw-r--r--[-rwxr-xr-x] | clang/lib/Sema/SemaTemplateInstantiateDecl.cpp | 5 |
5 files changed, 49 insertions, 619 deletions
diff --git a/clang/lib/Sema/SemaConcept.cpp b/clang/lib/Sema/SemaConcept.cpp index 63b8e06a7ae..f917d9c7e5a 100755..100644 --- a/clang/lib/Sema/SemaConcept.cpp +++ b/clang/lib/Sema/SemaConcept.cpp @@ -17,7 +17,6 @@ #include "clang/Sema/TemplateDeduction.h" #include "clang/Sema/Template.h" #include "clang/AST/ExprCXX.h" -#include "clang/AST/RecursiveASTVisitor.h" #include "llvm/ADT/DenseMap.h" #include "llvm/ADT/PointerUnion.h" using namespace clang; @@ -415,363 +414,4 @@ void Sema::DiagnoseUnsatisfiedConstraint( diagnoseUnsatisfiedConstraintExpr(*this, Pair.first, Pair.second, First); First = false; } -} - -namespace { -struct AtomicConstraint { - const Expr *ConstraintExpr; - llvm::Optional<llvm::SmallVector<TemplateArgumentLoc, 3>> ParameterMapping; - - AtomicConstraint(Sema &S, const Expr *ConstraintExpr) : - ConstraintExpr(ConstraintExpr) { }; - - bool hasMatchingParameterMapping(ASTContext &C, - const AtomicConstraint &Other) const { - if (!ParameterMapping != !Other.ParameterMapping) - return false; - if (!ParameterMapping) - return true; - if (ParameterMapping->size() != Other.ParameterMapping->size()) - return false; - - for (unsigned I = 0, S = ParameterMapping->size(); I < S; ++I) - if (!C.getCanonicalTemplateArgument((*ParameterMapping)[I].getArgument()) - .structurallyEquals(C.getCanonicalTemplateArgument( - (*Other.ParameterMapping)[I].getArgument()))) - return false; - return true; - } - - bool subsumes(ASTContext &C, const AtomicConstraint &Other) const { - // C++ [temp.constr.order] p2 - // - an atomic constraint A subsumes another atomic constraint B - // if and only if the A and B are identical [...] - // - // C++ [temp.constr.atomic] p2 - // Two atomic constraints are identical if they are formed from the - // same expression and the targets of the parameter mappings are - // equivalent according to the rules for expressions [...] - - // We do not actually substitute the parameter mappings into the - // constraint expressions, therefore the constraint expressions are - // the originals, and comparing them will suffice. - if (ConstraintExpr != Other.ConstraintExpr) - return false; - - // Check that the parameter lists are identical - return hasMatchingParameterMapping(C, Other); - } -}; - -/// \brief A normalized constraint, as defined in C++ [temp.constr.normal], is -/// either an atomic constraint, a conjunction of normalized constraints or a -/// disjunction of normalized constraints. -struct NormalizedConstraint { - enum CompoundConstraintKind { CCK_Conjunction, CCK_Disjunction }; - - using CompoundConstraint = llvm::PointerIntPair< - std::pair<NormalizedConstraint, NormalizedConstraint> *, 1, - CompoundConstraintKind>; - - llvm::PointerUnion<AtomicConstraint *, CompoundConstraint> Constraint; - - NormalizedConstraint(AtomicConstraint *C): Constraint{C} { }; - NormalizedConstraint(ASTContext &C, NormalizedConstraint LHS, - NormalizedConstraint RHS, CompoundConstraintKind Kind) - : Constraint{CompoundConstraint{ - new (C) std::pair<NormalizedConstraint, NormalizedConstraint>{LHS, - RHS}, - Kind}} { }; - - CompoundConstraintKind getCompoundKind() const { - assert(!isAtomic() && "getCompoundKind called on atomic constraint."); - return Constraint.get<CompoundConstraint>().getInt(); - } - - bool isAtomic() const { return Constraint.is<AtomicConstraint *>(); } - - NormalizedConstraint &getLHS() const { - assert(!isAtomic() && "getLHS called on atomic constraint."); - return Constraint.get<CompoundConstraint>().getPointer()->first; - } - - NormalizedConstraint &getRHS() const { - assert(!isAtomic() && "getRHS called on atomic constraint."); - return Constraint.get<CompoundConstraint>().getPointer()->second; - } - - AtomicConstraint *getAtomicConstraint() const { - assert(isAtomic() && - "getAtomicConstraint called on non-atomic constraint."); - return Constraint.get<AtomicConstraint *>(); - } - - static llvm::Optional<NormalizedConstraint> - fromConstraintExprs(Sema &S, NamedDecl *D, ArrayRef<const Expr *> E) { - assert(E.size() != 0); - auto First = fromConstraintExpr(S, D, E[0]); - if (E.size() == 1) - return First; - auto Second = fromConstraintExpr(S, D, E[1]); - if (!Second) - return llvm::Optional<NormalizedConstraint>{}; - llvm::Optional<NormalizedConstraint> Conjunction; - Conjunction.emplace(S.Context, std::move(*First), std::move(*Second), - CCK_Conjunction); - for (unsigned I = 2; I < E.size(); ++I) { - auto Next = fromConstraintExpr(S, D, E[I]); - if (!Next) - return llvm::Optional<NormalizedConstraint>{}; - NormalizedConstraint NewConjunction(S.Context, std::move(*Conjunction), - std::move(*Next), CCK_Conjunction); - *Conjunction = std::move(NewConjunction); - } - return Conjunction; - } - -private: - static llvm::Optional<NormalizedConstraint> fromConstraintExpr(Sema &S, - NamedDecl *D, - const Expr *E); -}; - -static bool substituteParameterMappings(Sema &S, NormalizedConstraint &N, - ConceptDecl *Concept, ArrayRef<TemplateArgument> TemplateArgs, - const ASTTemplateArgumentListInfo *ArgsAsWritten) { - if (!N.isAtomic()) { - if (substituteParameterMappings(S, N.getLHS(), Concept, TemplateArgs, - ArgsAsWritten)) - return true; - return substituteParameterMappings(S, N.getRHS(), Concept, TemplateArgs, - ArgsAsWritten); - } - TemplateParameterList *TemplateParams = Concept->getTemplateParameters(); - - AtomicConstraint &Atomic = *N.getAtomicConstraint(); - TemplateArgumentListInfo SubstArgs; - MultiLevelTemplateArgumentList MLTAL; - MLTAL.addOuterTemplateArguments(TemplateArgs); - if (!Atomic.ParameterMapping) { - llvm::SmallBitVector OccurringIndices; - S.MarkUsedTemplateParameters(Atomic.ConstraintExpr, /*OnlyDeduced=*/false, - /*Depth=*/0, OccurringIndices); - Atomic.ParameterMapping.emplace(); - Atomic.ParameterMapping->reserve(OccurringIndices.size()); - for (unsigned I = 0, C = TemplateParams->size(); I != C; ++I) - if (I < OccurringIndices.size() && OccurringIndices[I]) - Atomic.ParameterMapping->push_back( - S.getIdentityTemplateArgumentLoc(TemplateParams->begin()[I], - // Here we assume we do not support things like - // template<typename A, typename B> - // concept C = ...; - // - // template<typename... Ts> requires C<Ts...> - // struct S { }; - // The above currently yields a diagnostic. - // We still might have default arguments for concept parameters. - ArgsAsWritten->NumTemplateArgs > I ? - ArgsAsWritten->arguments()[I].getLocation() : - SourceLocation())); - } - Sema::InstantiatingTemplate Inst( - S, ArgsAsWritten->arguments().front().getSourceRange().getBegin(), - Sema::InstantiatingTemplate::ParameterMappingSubstitution{}, Concept, - SourceRange(ArgsAsWritten->arguments()[0].getSourceRange().getBegin(), - ArgsAsWritten->arguments().back().getSourceRange().getEnd())); - if (S.SubstTemplateArguments(*Atomic.ParameterMapping, MLTAL, SubstArgs)) - return true; - std::copy(SubstArgs.arguments().begin(), SubstArgs.arguments().end(), - N.getAtomicConstraint()->ParameterMapping->begin()); - return false; -} - -llvm::Optional<NormalizedConstraint> -NormalizedConstraint::fromConstraintExpr(Sema &S, NamedDecl *D, const Expr *E) { - assert(E != nullptr); - - // C++ [temp.constr.normal]p1.1 - // [...] - // - The normal form of an expression (E) is the normal form of E. - // [...] - E = E->IgnoreParenImpCasts(); - if (auto *BO = dyn_cast<const BinaryOperator>(E)) { - if (BO->getOpcode() == BO_LAnd || BO->getOpcode() == BO_LOr) { - auto LHS = fromConstraintExpr(S, D, BO->getLHS()); - if (!LHS) - return None; - auto RHS = fromConstraintExpr(S, D, BO->getRHS()); - if (!RHS) - return None; - - return NormalizedConstraint( - S.Context, *LHS, *RHS, - BO->getOpcode() == BO_LAnd ? CCK_Conjunction : CCK_Disjunction); - } - } else if (auto *CSE = dyn_cast<const ConceptSpecializationExpr>(E)) { - Optional<NormalizedConstraint> SubNF; - { - Sema::InstantiatingTemplate Inst( - S, CSE->getExprLoc(), - Sema::InstantiatingTemplate::ConstraintNormalization{}, D, - CSE->getSourceRange()); - // C++ [temp.constr.normal]p1.1 - // [...] - // The normal form of an id-expression of the form C<A1, A2, ..., AN>, - // where C names a concept, is the normal form of the - // constraint-expression of C, after substituting A1, A2, ..., AN for C’s - // respective template parameters in the parameter mappings in each atomic - // constraint. If any such substitution results in an invalid type or - // expression, the program is ill-formed; no diagnostic is required. - // [...] - SubNF = fromConstraintExpr(S, CSE->getNamedConcept(), - CSE->getNamedConcept()->getConstraintExpr()); - if (!SubNF) - return None; - } - - if (substituteParameterMappings( - S, *SubNF, CSE->getNamedConcept(), - CSE->getTemplateArguments(), CSE->getTemplateArgsAsWritten())) - return None; - - return SubNF; - } - return NormalizedConstraint{new (S.Context) AtomicConstraint(S, E)}; -} - -} // namespace - -using NormalForm = - llvm::SmallVector<llvm::SmallVector<AtomicConstraint *, 2>, 4>; - -static NormalForm makeCNF(const NormalizedConstraint &Normalized) { - if (Normalized.isAtomic()) - return {{Normalized.getAtomicConstraint()}}; - - NormalForm LCNF = makeCNF(Normalized.getLHS()); - NormalForm RCNF = makeCNF(Normalized.getRHS()); - if (Normalized.getCompoundKind() == NormalizedConstraint::CCK_Conjunction) { - LCNF.reserve(LCNF.size() + RCNF.size()); - while (!RCNF.empty()) - LCNF.push_back(RCNF.pop_back_val()); - return LCNF; - } - - // Disjunction - NormalForm Res; - Res.reserve(LCNF.size() * RCNF.size()); - for (auto &LDisjunction : LCNF) - for (auto &RDisjunction : RCNF) { - NormalForm::value_type Combined; - Combined.reserve(LDisjunction.size() + RDisjunction.size()); - std::copy(LDisjunction.begin(), LDisjunction.end(), - std::back_inserter(Combined)); - std::copy(RDisjunction.begin(), RDisjunction.end(), - std::back_inserter(Combined)); - Res.emplace_back(Combined); - } - return Res; -} - -static NormalForm makeDNF(const NormalizedConstraint &Normalized) { - if (Normalized.isAtomic()) - return {{Normalized.getAtomicConstraint()}}; - - NormalForm LDNF = makeDNF(Normalized.getLHS()); - NormalForm RDNF = makeDNF(Normalized.getRHS()); - if (Normalized.getCompoundKind() == NormalizedConstraint::CCK_Disjunction) { - LDNF.reserve(LDNF.size() + RDNF.size()); - while (!RDNF.empty()) - LDNF.push_back(RDNF.pop_back_val()); - return LDNF; - } - - // Conjunction - NormalForm Res; - Res.reserve(LDNF.size() * RDNF.size()); - for (auto &LConjunction : LDNF) { - for (auto &RConjunction : RDNF) { - NormalForm::value_type Combined; - Combined.reserve(LConjunction.size() + RConjunction.size()); - std::copy(LConjunction.begin(), LConjunction.end(), - std::back_inserter(Combined)); - std::copy(RConjunction.begin(), RConjunction.end(), - std::back_inserter(Combined)); - Res.emplace_back(Combined); - } - } - return Res; -} - -static bool subsumes(Sema &S, NamedDecl *DP, ArrayRef<const Expr *> P, - NamedDecl *DQ, ArrayRef<const Expr *> Q, bool &Subsumes) { - // C++ [temp.constr.order] p2 - // In order to determine if a constraint P subsumes a constraint Q, P is - // transformed into disjunctive normal form, and Q is transformed into - // conjunctive normal form. [...] - auto PNormalized = NormalizedConstraint::fromConstraintExprs(S, DP, P); - if (!PNormalized) - return true; - const NormalForm PDNF = makeDNF(*PNormalized); - - auto QNormalized = NormalizedConstraint::fromConstraintExprs(S, DQ, Q); - if (!QNormalized) - return true; - const NormalForm QCNF = makeCNF(*QNormalized); - - // C++ [temp.constr.order] p2 - // Then, P subsumes Q if and only if, for every disjunctive clause Pi in the - // disjunctive normal form of P, Pi subsumes every conjunctive clause Qj in - // the conjuctive normal form of Q, where [...] - for (const auto &Pi : PDNF) { - for (const auto &Qj : QCNF) { - // C++ [temp.constr.order] p2 - // - [...] a disjunctive clause Pi subsumes a conjunctive clause Qj if - // and only if there exists an atomic constraint Pia in Pi for which - // there exists an atomic constraint, Qjb, in Qj such that Pia - // subsumes Qjb. - bool Found = false; - for (const AtomicConstraint *Pia : Pi) { - for (const AtomicConstraint *Qjb : Qj) { - if (Pia->subsumes(S.Context, *Qjb)) { - Found = true; - break; - } - } - if (Found) - break; - } - if (!Found) { - Subsumes = false; - return false; - } - } - } - Subsumes = true; - return false; -} - -bool Sema::IsAtLeastAsConstrained(NamedDecl *D1, ArrayRef<const Expr *> AC1, - NamedDecl *D2, ArrayRef<const Expr *> AC2, - bool &Result) { - if (AC1.empty()) { - Result = AC2.empty(); - return false; - } - if (AC2.empty()) { - // TD1 has associated constraints and TD2 does not. - Result = true; - return false; - } - - std::pair<NamedDecl *, NamedDecl *> Key{D1, D2}; - auto CacheEntry = SubsumptionCache.find(Key); - if (CacheEntry != SubsumptionCache.end()) { - Result = CacheEntry->second; - return false; - } - if (subsumes(*this, D1, AC1, D2, AC2, Result)) - return true; - SubsumptionCache.try_emplace(Key, Result); - return false; }
\ No newline at end of file diff --git a/clang/lib/Sema/SemaTemplate.cpp b/clang/lib/Sema/SemaTemplate.cpp index ade8a5a6ac1..699895568b7 100755..100644 --- a/clang/lib/Sema/SemaTemplate.cpp +++ b/clang/lib/Sema/SemaTemplate.cpp @@ -1120,11 +1120,11 @@ NamedDecl *Sema::ActOnNonTypeTemplateParameter(Scope *S, Declarator &D, // Check that we have valid decl-specifiers specified. auto CheckValidDeclSpecifiers = [this, &D] { // C++ [temp.param] - // p1 + // p1 // template-parameter: // ... // parameter-declaration - // p2 + // p2 // ... A storage class shall not be specified in a template-parameter // declaration. // [dcl.typedef]p1: @@ -3900,9 +3900,7 @@ DeclResult Sema::ActOnVarTemplateSpecialization( } if (isSameAsPrimaryTemplate(VarTemplate->getTemplateParameters(), - Converted) && - (!Context.getLangOpts().ConceptsTS || - !TemplateParams->hasAssociatedConstraints())) { + Converted)) { // C++ [temp.class.spec]p9b3: // // -- The argument list of the specialization shall not be identical @@ -3921,8 +3919,8 @@ DeclResult Sema::ActOnVarTemplateSpecialization( VarTemplateSpecializationDecl *PrevDecl = nullptr; if (IsPartialSpecialization) - PrevDecl = VarTemplate->findPartialSpecialization(Converted, TemplateParams, - InsertPos); + // FIXME: Template parameter list matters too + PrevDecl = VarTemplate->findPartialSpecialization(Converted, InsertPos); else PrevDecl = VarTemplate->findSpecialization(Converted, InsertPos); @@ -5275,16 +5273,12 @@ bool Sema::CheckTemplateArgumentList( bool PackExpansionIntoNonPack = NewArgs[ArgIdx].getArgument().isPackExpansion() && (!(*Param)->isTemplateParameterPack() || getExpandedPackSize(*Param)); - if (PackExpansionIntoNonPack && (isa<TypeAliasTemplateDecl>(Template) || - isa<ConceptDecl>(Template))) { + if (PackExpansionIntoNonPack && isa<TypeAliasTemplateDecl>(Template)) { // Core issue 1430: we have a pack expansion as an argument to an // alias template, and it's not part of a parameter pack. This // can't be canonicalized, so reject it now. - // As for concepts - we cannot normalize constraints where this - // situation exists. Diag(NewArgs[ArgIdx].getLocation(), - diag::err_template_expansion_into_fixed_list) - << (isa<ConceptDecl>(Template) ? 1 : 0) + diag::err_alias_template_expansion_into_fixed_list) << NewArgs[ArgIdx].getSourceRange(); Diag((*Param)->getLocation(), diag::note_template_param_here); return true; @@ -7118,7 +7112,6 @@ static bool MatchTemplateParameterKind(Sema &S, NamedDecl *New, NamedDecl *Old, bool Complain, Sema::TemplateParameterListEqualKind Kind, SourceLocation TemplateArgLoc) { - // TODO: Concepts: Check constrained-parameter constraints here. // Check the actual kind (type, non-type, template). if (Old->getKind() != New->getKind()) { if (Complain) { @@ -7820,9 +7813,8 @@ DeclResult Sema::ActOnClassTemplateSpecialization( ClassTemplateSpecializationDecl *PrevDecl = nullptr; if (isPartialSpecialization) - PrevDecl = ClassTemplate->findPartialSpecialization(Converted, - TemplateParams, - InsertPos); + // FIXME: Template parameter list matters, too + PrevDecl = ClassTemplate->findPartialSpecialization(Converted, InsertPos); else PrevDecl = ClassTemplate->findSpecialization(Converted, InsertPos); @@ -7846,9 +7838,7 @@ DeclResult Sema::ActOnClassTemplateSpecialization( Converted); if (Context.hasSameType(CanonType, - ClassTemplate->getInjectedClassNameSpecialization()) && - (!Context.getLangOpts().ConceptsTS || - !TemplateParams->hasAssociatedConstraints())) { + ClassTemplate->getInjectedClassNameSpecialization())) { // C++ [temp.class.spec]p9b3: // // -- The argument list of the specialization shall not be identical diff --git a/clang/lib/Sema/SemaTemplateDeduction.cpp b/clang/lib/Sema/SemaTemplateDeduction.cpp index df4f6f647b2..327447746c3 100644 --- a/clang/lib/Sema/SemaTemplateDeduction.cpp +++ b/clang/lib/Sema/SemaTemplateDeduction.cpp @@ -24,7 +24,6 @@ #include "clang/AST/Expr.h" #include "clang/AST/ExprCXX.h" #include "clang/AST/NestedNameSpecifier.h" -#include "clang/AST/RecursiveASTVisitor.h" #include "clang/AST/TemplateBase.h" #include "clang/AST/TemplateName.h" #include "clang/AST/Type.h" @@ -2502,30 +2501,6 @@ Sema::getTrivialTemplateArgumentLoc(const TemplateArgument &Arg, llvm_unreachable("Invalid TemplateArgument Kind!"); } -TemplateArgumentLoc -Sema::getIdentityTemplateArgumentLoc(Decl *TemplateParm, - SourceLocation Location) { - if (auto *TTP = dyn_cast<TemplateTypeParmDecl>(TemplateParm)) - return getTrivialTemplateArgumentLoc( - TemplateArgument( - Context.getTemplateTypeParmType(TTP->getDepth(), TTP->getIndex(), - TTP->isParameterPack(), TTP)), - QualType(), Location.isValid() ? Location : TTP->getLocation()); - else if (auto *TTP = dyn_cast<TemplateTemplateParmDecl>(TemplateParm)) - return getTrivialTemplateArgumentLoc(TemplateArgument(TemplateName(TTP)), - QualType(), - Location.isValid() ? Location : - TTP->getLocation()); - auto *NTTP = cast<NonTypeTemplateParmDecl>(TemplateParm); - CXXScopeSpec SS; - DeclarationNameInfo Info(NTTP->getDeclName(), - Location.isValid() ? Location : NTTP->getLocation()); - Expr *E = BuildDeclarationNameExpr(SS, Info, NTTP).get(); - return getTrivialTemplateArgumentLoc(TemplateArgument(E), NTTP->getType(), - Location.isValid() ? Location : - NTTP->getLocation()); -} - /// Convert the given deduced template argument and add it to the set of /// fully-converted template arguments. static bool @@ -2616,6 +2591,23 @@ ConvertDeducedTemplateArgument(Sema &S, NamedDecl *Param, return ConvertArg(Arg, 0); } +template<typename TemplateDeclT> +static Sema::TemplateDeductionResult +CheckDeducedArgumentConstraints(Sema& S, TemplateDeclT *Template, + ArrayRef<TemplateArgument> DeducedArgs, + TemplateDeductionInfo &Info) { + llvm::SmallVector<const Expr *, 3> AssociatedConstraints; + Template->getAssociatedConstraints(AssociatedConstraints); + if (S.CheckConstraintSatisfaction(Template, AssociatedConstraints, + DeducedArgs, Info.getLocation(), + Info.AssociatedConstraintsSatisfaction) || + !Info.AssociatedConstraintsSatisfaction.IsSatisfied) { + Info.reset(TemplateArgumentList::CreateCopy(S.Context, DeducedArgs)); + return Sema::TDK_ConstraintsNotSatisfied; + } + return Sema::TDK_Success; +} + // FIXME: This should not be a template, but // ClassTemplatePartialSpecializationDecl sadly does not derive from // TemplateDecl. @@ -2713,6 +2705,10 @@ static Sema::TemplateDeductionResult ConvertDeducedTemplateArguments( // If we get here, we successfully used the default template argument. } + if (Sema::TemplateDeductionResult Result + = CheckDeducedArgumentConstraints(S, Template, Builder, Info)) + return Result; + return Sema::TDK_Success; } @@ -2734,23 +2730,6 @@ struct IsPartialSpecialization<VarTemplatePartialSpecializationDecl> { static constexpr bool value = true; }; -template<typename TemplateDeclT> -static Sema::TemplateDeductionResult -CheckDeducedArgumentConstraints(Sema& S, TemplateDeclT *Template, - ArrayRef<TemplateArgument> DeducedArgs, - TemplateDeductionInfo& Info) { - llvm::SmallVector<const Expr *, 3> AssociatedConstraints; - Template->getAssociatedConstraints(AssociatedConstraints); - if (S.CheckConstraintSatisfaction(Template, AssociatedConstraints, - DeducedArgs, Info.getLocation(), - Info.AssociatedConstraintsSatisfaction) || - !Info.AssociatedConstraintsSatisfaction.IsSatisfied) { - Info.reset(TemplateArgumentList::CreateCopy(S.Context, DeducedArgs)); - return Sema::TDK_ConstraintsNotSatisfied; - } - return Sema::TDK_Success; -} - /// Complete template argument deduction for a partial specialization. template <typename T> static typename std::enable_if<IsPartialSpecialization<T>::value, @@ -2832,9 +2811,6 @@ FinishTemplateArgumentDeduction( if (Trap.hasErrorOccurred()) return Sema::TDK_SubstitutionFailure; - if (auto Result = CheckDeducedArgumentConstraints(S, Partial, Builder, Info)) - return Result; - return Sema::TDK_Success; } @@ -2877,10 +2853,6 @@ static Sema::TemplateDeductionResult FinishTemplateArgumentDeduction( if (Trap.hasErrorOccurred()) return Sema::TDK_SubstitutionFailure; - if (auto Result = CheckDeducedArgumentConstraints(S, Template, Builder, - Info)) - return Result; - return Sema::TDK_Success; } @@ -3392,11 +3364,6 @@ Sema::TemplateDeductionResult Sema::FinishTemplateArgumentDeduction( PartialOverloading)) return Result; - if (TemplateDeductionResult Result - = CheckDeducedArgumentConstraints(*this, FunctionTemplate, Builder, - Info)) - return Result; - // C++ [temp.deduct.call]p10: [DR1391] // If deduction succeeds for all parameters that contain // template-parameters that participate in template argument deduction, @@ -4962,21 +4929,6 @@ Sema::getMoreSpecializedTemplate(FunctionTemplateDecl *FT1, TemplatePartialOrderingContext TPOC, unsigned NumCallArguments1, unsigned NumCallArguments2) { - - auto JudgeByConstraints = [&] () -> FunctionTemplateDecl * { - llvm::SmallVector<const Expr *, 3> AC1, AC2; - FT1->getAssociatedConstraints(AC1); - FT2->getAssociatedConstraints(AC2); - bool AtLeastAsConstrained1, AtLeastAsConstrained2; - if (IsAtLeastAsConstrained(FT1, AC1, FT2, AC2, AtLeastAsConstrained1)) - return nullptr; - if (IsAtLeastAsConstrained(FT2, AC2, FT1, AC1, AtLeastAsConstrained2)) - return nullptr; - if (AtLeastAsConstrained1 == AtLeastAsConstrained2) - return nullptr; - return AtLeastAsConstrained1 ? FT1 : FT2; - }; - bool Better1 = isAtLeastAsSpecializedAs(*this, Loc, FT1, FT2, TPOC, NumCallArguments1); bool Better2 = isAtLeastAsSpecializedAs(*this, Loc, FT2, FT1, TPOC, @@ -4986,7 +4938,7 @@ Sema::getMoreSpecializedTemplate(FunctionTemplateDecl *FT1, return Better1 ? FT1 : FT2; if (!Better1 && !Better2) // Neither is better than the other - return JudgeByConstraints(); + return nullptr; // FIXME: This mimics what GCC implements, but doesn't match up with the // proposed resolution for core issue 692. This area needs to be sorted out, @@ -4996,7 +4948,7 @@ Sema::getMoreSpecializedTemplate(FunctionTemplateDecl *FT1, if (Variadic1 != Variadic2) return Variadic1? FT2 : FT1; - return JudgeByConstraints(); + return nullptr; } /// Determine if the two templates are equivalent. @@ -5121,6 +5073,7 @@ template<typename TemplateLikeDecl> static bool isAtLeastAsSpecializedAs(Sema &S, QualType T1, QualType T2, TemplateLikeDecl *P2, TemplateDeductionInfo &Info) { + // TODO: Concepts: Regard constraints // C++ [temp.class.order]p1: // For two class template partial specializations, the first is at least as // specialized as the second if, given the following rewrite to two @@ -5191,21 +5144,8 @@ Sema::getMoreSpecializedPartialSpecialization( bool Better1 = isAtLeastAsSpecializedAs(*this, PT1, PT2, PS2, Info); bool Better2 = isAtLeastAsSpecializedAs(*this, PT2, PT1, PS1, Info); - if (!Better1 && !Better2) - return nullptr; - if (Better1 && Better2) { - llvm::SmallVector<const Expr *, 3> AC1, AC2; - PS1->getAssociatedConstraints(AC1); - PS2->getAssociatedConstraints(AC2); - bool AtLeastAsConstrained1, AtLeastAsConstrained2; - if (IsAtLeastAsConstrained(PS1, AC1, PS2, AC2, AtLeastAsConstrained1)) - return nullptr; - if (IsAtLeastAsConstrained(PS2, AC2, PS1, AC1, AtLeastAsConstrained2)) - return nullptr; - if (AtLeastAsConstrained1 == AtLeastAsConstrained2) - return nullptr; - return AtLeastAsConstrained1 ? PS1 : PS2; - } + if (Better1 == Better2) + return nullptr; return Better1 ? PS1 : PS2; } @@ -5217,22 +5157,11 @@ bool Sema::isMoreSpecializedThanPrimary( QualType PartialT = Spec->getInjectedSpecializationType(); if (!isAtLeastAsSpecializedAs(*this, PartialT, PrimaryT, Primary, Info)) return false; - if (!isAtLeastAsSpecializedAs(*this, PrimaryT, PartialT, Spec, Info)) - return true; - Info.clearSFINAEDiagnostic(); - llvm::SmallVector<const Expr *, 3> PrimaryAC, SpecAC; - Primary->getAssociatedConstraints(PrimaryAC); - Spec->getAssociatedConstraints(SpecAC); - bool AtLeastAsConstrainedPrimary, AtLeastAsConstrainedSpec; - if (IsAtLeastAsConstrained(Spec, SpecAC, Primary, PrimaryAC, - AtLeastAsConstrainedSpec)) - return false; - if (!AtLeastAsConstrainedSpec) - return false; - if (IsAtLeastAsConstrained(Primary, PrimaryAC, Spec, SpecAC, - AtLeastAsConstrainedPrimary)) + if (isAtLeastAsSpecializedAs(*this, PrimaryT, PartialT, Spec, Info)) { + Info.clearSFINAEDiagnostic(); return false; - return !AtLeastAsConstrainedPrimary; + } + return true; } VarTemplatePartialSpecializationDecl * @@ -5255,22 +5184,8 @@ Sema::getMoreSpecializedPartialSpecialization( bool Better1 = isAtLeastAsSpecializedAs(*this, PT1, PT2, PS2, Info); bool Better2 = isAtLeastAsSpecializedAs(*this, PT2, PT1, PS1, Info); - if (!Better1 && !Better2) + if (Better1 == Better2) return nullptr; - if (Better1 && Better2) { - llvm::SmallVector<const Expr *, 3> AC1, AC2; - PS1->getAssociatedConstraints(AC1); - PS2->getAssociatedConstraints(AC2); - bool AtLeastAsConstrained1, AtLeastAsConstrained2; - if (IsAtLeastAsConstrained(PS1, AC1, PS2, AC2, AtLeastAsConstrained1)) - return nullptr; - if (IsAtLeastAsConstrained(PS2, AC2, PS1, AC1, AtLeastAsConstrained2)) - return nullptr; - if (AtLeastAsConstrained1 == AtLeastAsConstrained2) { - return nullptr; - } - return AtLeastAsConstrained1 ? PS1 : PS2; - } return Better1 ? PS1 : PS2; } @@ -5290,25 +5205,13 @@ bool Sema::isMoreSpecializedThanPrimary( CanonTemplate, PrimaryArgs); QualType PartialT = Context.getTemplateSpecializationType( CanonTemplate, Spec->getTemplateArgs().asArray()); - if (!isAtLeastAsSpecializedAs(*this, PartialT, PrimaryT, Primary, Info)) return false; - if (!isAtLeastAsSpecializedAs(*this, PrimaryT, PartialT, Spec, Info)) - return true; - Info.clearSFINAEDiagnostic(); - llvm::SmallVector<const Expr *, 3> PrimaryAC, SpecAC; - Primary->getAssociatedConstraints(PrimaryAC); - Spec->getAssociatedConstraints(SpecAC); - bool AtLeastAsConstrainedPrimary, AtLeastAsConstrainedSpec; - if (IsAtLeastAsConstrained(Spec, SpecAC, Primary, PrimaryAC, - AtLeastAsConstrainedSpec)) - return false; - if (!AtLeastAsConstrainedSpec) + if (isAtLeastAsSpecializedAs(*this, PrimaryT, PartialT, Spec, Info)) { + Info.clearSFINAEDiagnostic(); return false; - if (IsAtLeastAsConstrained(Primary, PrimaryAC, Spec, SpecAC, - AtLeastAsConstrainedPrimary)) - return false; - return !AtLeastAsConstrainedPrimary; + } + return true; } bool Sema::isTemplateTemplateParameterAtLeastAsSpecializedAs( @@ -5374,49 +5277,6 @@ bool Sema::isTemplateTemplateParameterAtLeastAsSpecializedAs( return isAtLeastAsSpecializedAs(*this, PType, AType, AArg, Info); } -struct OccurringTemplateParameterFinder : - RecursiveASTVisitor<OccurringTemplateParameterFinder> { - llvm::SmallBitVector &OccurringIndices; - - OccurringTemplateParameterFinder(llvm::SmallBitVector &OccurringIndices) - : OccurringIndices(OccurringIndices) { } - - bool VisitTemplateTypeParmType(TemplateTypeParmType *T) { - assert(T->getDepth() == 0 && "This assumes that we allow concepts at " - "namespace scope only"); - noteParameter(T->getIndex()); - return true; - } - - bool TraverseTemplateName(TemplateName Template) { - if (auto *TTP = - dyn_cast<TemplateTemplateParmDecl>(Template.getAsTemplateDecl())) { - assert(TTP->getDepth() == 0 && "This assumes that we allow concepts at " - "namespace scope only"); - noteParameter(TTP->getIndex()); - } - RecursiveASTVisitor<OccurringTemplateParameterFinder>:: - TraverseTemplateName(Template); - return true; - } - - bool VisitDeclRefExpr(DeclRefExpr *E) { - if (auto *NTTP = dyn_cast<NonTypeTemplateParmDecl>(E->getDecl())) { - assert(NTTP->getDepth() == 0 && "This assumes that we allow concepts at " - "namespace scope only"); - noteParameter(NTTP->getIndex()); - } - return true; - } - -protected: - void noteParameter(unsigned Index) { - if (OccurringIndices.size() >= Index) - OccurringIndices.resize(Index + 1, false); - OccurringIndices.set(Index); - } -}; - /// Mark the template parameters that are used by the given /// expression. static void @@ -5425,11 +5285,6 @@ MarkUsedTemplateParameters(ASTContext &Ctx, bool OnlyDeduced, unsigned Depth, llvm::SmallBitVector &Used) { - if (!OnlyDeduced) { - OccurringTemplateParameterFinder(Used).TraverseStmt(const_cast<Expr *>(E)); - return; - } - // We can deduce from a pack expansion. if (const PackExpansionExpr *Expansion = dyn_cast<PackExpansionExpr>(E)) E = Expansion->getPattern(); @@ -5448,6 +5303,8 @@ MarkUsedTemplateParameters(ASTContext &Ctx, break; } + // FIXME: if !OnlyDeduced, we have to walk the whole subexpression to + // find other occurrences of template parameters. const DeclRefExpr *DRE = dyn_cast<DeclRefExpr>(E); if (!DRE) return; @@ -5827,20 +5684,6 @@ MarkUsedTemplateParameters(ASTContext &Ctx, } } -/// Mark which template parameters are used in a given expression. -/// -/// \param E the expression from which template parameters will be deduced. -/// -/// \param Used a bit vector whose elements will be set to \c true -/// to indicate when the corresponding template parameter will be -/// deduced. -void -Sema::MarkUsedTemplateParameters(const Expr *E, bool OnlyDeduced, - unsigned Depth, - llvm::SmallBitVector &Used) { - ::MarkUsedTemplateParameters(Context, E, OnlyDeduced, Depth, Used); -} - /// Mark which template parameters can be deduced from a given /// template argument list. /// diff --git a/clang/lib/Sema/SemaTemplateInstantiate.cpp b/clang/lib/Sema/SemaTemplateInstantiate.cpp index 770c07d41b1..6db8eb3e5ed 100644 --- a/clang/lib/Sema/SemaTemplateInstantiate.cpp +++ b/clang/lib/Sema/SemaTemplateInstantiate.cpp @@ -207,8 +207,6 @@ bool Sema::CodeSynthesisContext::isInstantiationRecord() const { case DefiningSynthesizedFunction: case ExceptionSpecEvaluation: case ConstraintSubstitution: - case ParameterMappingSubstitution: - case ConstraintNormalization: case RewritingOperatorAsSpaceship: return false; @@ -382,22 +380,6 @@ Sema::InstantiatingTemplate::InstantiatingTemplate( PointOfInstantiation, InstantiationRange, Template, nullptr, {}, &DeductionInfo) {} -Sema::InstantiatingTemplate::InstantiatingTemplate( - Sema &SemaRef, SourceLocation PointOfInstantiation, - ConstraintNormalization, NamedDecl *Template, - SourceRange InstantiationRange) - : InstantiatingTemplate( - SemaRef, CodeSynthesisContext::ConstraintNormalization, - PointOfInstantiation, InstantiationRange, Template) {} - -Sema::InstantiatingTemplate::InstantiatingTemplate( - Sema &SemaRef, SourceLocation PointOfInstantiation, - ParameterMappingSubstitution, NamedDecl *Template, - SourceRange InstantiationRange) - : InstantiatingTemplate( - SemaRef, CodeSynthesisContext::ParameterMappingSubstitution, - PointOfInstantiation, InstantiationRange, Template) {} - void Sema::pushCodeSynthesisContext(CodeSynthesisContext Ctx) { Ctx.SavedInNonInstantiationSFINAEContext = InNonInstantiationSFINAEContext; InNonInstantiationSFINAEContext = false; @@ -751,17 +733,6 @@ void Sema::PrintInstantiationStack() { diag::note_constraint_substitution_here) << Active->InstantiationRange; break; - case CodeSynthesisContext::ConstraintNormalization: - Diags.Report(Active->PointOfInstantiation, - diag::note_constraint_normalization_here) - << cast<NamedDecl>(Active->Entity)->getName() - << Active->InstantiationRange; - break; - case CodeSynthesisContext::ParameterMappingSubstitution: - Diags.Report(Active->PointOfInstantiation, - diag::note_parameter_mapping_substitution_here) - << Active->InstantiationRange; - break; } } } @@ -786,8 +757,6 @@ Optional<TemplateDeductionInfo *> Sema::isSFINAEContext() const { case CodeSynthesisContext::DefaultFunctionArgumentInstantiation: case CodeSynthesisContext::ExceptionSpecInstantiation: case CodeSynthesisContext::ConstraintsCheck: - case CodeSynthesisContext::ParameterMappingSubstitution: - case CodeSynthesisContext::ConstraintNormalization: // This is a template instantiation, so there is no SFINAE. return None; @@ -2957,17 +2926,6 @@ Sema::SubstStmt(Stmt *S, const MultiLevelTemplateArgumentList &TemplateArgs) { return Instantiator.TransformStmt(S); } -bool Sema::SubstTemplateArguments( - ArrayRef<TemplateArgumentLoc> Args, - const MultiLevelTemplateArgumentList &TemplateArgs, - TemplateArgumentListInfo &Out) { - TemplateInstantiator Instantiator(*this, TemplateArgs, - SourceLocation(), - DeclarationName()); - return Instantiator.TransformTemplateArguments(Args.begin(), Args.end(), - Out); -} - ExprResult Sema::SubstExpr(Expr *E, const MultiLevelTemplateArgumentList &TemplateArgs) { if (!E) diff --git a/clang/lib/Sema/SemaTemplateInstantiateDecl.cpp b/clang/lib/Sema/SemaTemplateInstantiateDecl.cpp index a8fc77fff7d..0bff0747df3 100755..100644 --- a/clang/lib/Sema/SemaTemplateInstantiateDecl.cpp +++ b/clang/lib/Sema/SemaTemplateInstantiateDecl.cpp @@ -3706,8 +3706,7 @@ TemplateDeclInstantiator::InstantiateClassTemplatePartialSpecialization( // in the member template's set of class template partial specializations. void *InsertPos = nullptr; ClassTemplateSpecializationDecl *PrevDecl - = ClassTemplate->findPartialSpecialization(Converted, InstParams, - InsertPos); + = ClassTemplate->findPartialSpecialization(Converted, InsertPos); // Build the canonical type that describes the converted template // arguments of the class template partial specialization. @@ -3831,7 +3830,7 @@ TemplateDeclInstantiator::InstantiateVarTemplatePartialSpecialization( // in the member template's set of variable template partial specializations. void *InsertPos = nullptr; VarTemplateSpecializationDecl *PrevDecl = - VarTemplate->findPartialSpecialization(Converted, InstParams, InsertPos); + VarTemplate->findPartialSpecialization(Converted, InsertPos); // Build the canonical type that describes the converted template // arguments of the variable template partial specialization. |