diff options
Diffstat (limited to 'clang')
18 files changed, 102 insertions, 1021 deletions
diff --git a/clang/include/clang/AST/DeclTemplate.h b/clang/include/clang/AST/DeclTemplate.h index 8b2c271fbf2..3bebba5b9c1 100755..100644 --- a/clang/include/clang/AST/DeclTemplate.h +++ b/clang/include/clang/AST/DeclTemplate.h @@ -793,10 +793,9 @@ protected: void loadLazySpecializationsImpl() const; - template <class EntryType, typename ...ProfileArguments> - typename SpecEntryTraits<EntryType>::DeclType* + template <class EntryType> typename SpecEntryTraits<EntryType>::DeclType* findSpecializationImpl(llvm::FoldingSetVector<EntryType> &Specs, - void *&InsertPos, ProfileArguments &&...ProfileArgs); + ArrayRef<TemplateArgument> Args, void *&InsertPos); template <class Derived, class EntryType> void addSpecializationImpl(llvm::FoldingSetVector<EntryType> &Specs, @@ -2057,14 +2056,7 @@ public: ->getInjectedSpecializationType(); } - void Profile(llvm::FoldingSetNodeID &ID) const { - Profile(ID, getTemplateArgs().asArray(), getTemplateParameters(), - getASTContext()); - } - - static void - Profile(llvm::FoldingSetNodeID &ID, ArrayRef<TemplateArgument> TemplateArgs, - TemplateParameterList *TPL, ASTContext &Context); + // FIXME: Add Profile support! static bool classof(const Decl *D) { return classofKind(D->getKind()); } @@ -2188,8 +2180,7 @@ public: /// Return the partial specialization with the provided arguments if it /// exists, otherwise return the insertion point. ClassTemplatePartialSpecializationDecl * - findPartialSpecialization(ArrayRef<TemplateArgument> Args, - TemplateParameterList *TPL, void *&InsertPos); + findPartialSpecialization(ArrayRef<TemplateArgument> Args, void *&InsertPos); /// Insert the specified partial specialization knowing that it is not /// already in. InsertPos must be obtained from findPartialSpecialization. @@ -2889,15 +2880,6 @@ public: return First->InstantiatedFromMember.setInt(true); } - void Profile(llvm::FoldingSetNodeID &ID) const { - Profile(ID, getTemplateArgs().asArray(), getTemplateParameters(), - getASTContext()); - } - - static void - Profile(llvm::FoldingSetNodeID &ID, ArrayRef<TemplateArgument> TemplateArgs, - TemplateParameterList *TPL, ASTContext &Context); - static bool classof(const Decl *D) { return classofKind(D->getKind()); } static bool classofKind(Kind K) { @@ -3016,8 +2998,7 @@ public: /// Return the partial specialization with the provided arguments if it /// exists, otherwise return the insertion point. VarTemplatePartialSpecializationDecl * - findPartialSpecialization(ArrayRef<TemplateArgument> Args, - TemplateParameterList *TPL, void *&InsertPos); + findPartialSpecialization(ArrayRef<TemplateArgument> Args, void *&InsertPos); /// Insert the specified partial specialization knowing that it is not /// already in. InsertPos must be obtained from findPartialSpecialization. diff --git a/clang/include/clang/Basic/DiagnosticSemaKinds.td b/clang/include/clang/Basic/DiagnosticSemaKinds.td index 71f9a189a6a..c7b501b9bb2 100644 --- a/clang/include/clang/Basic/DiagnosticSemaKinds.td +++ b/clang/include/clang/Basic/DiagnosticSemaKinds.td @@ -2590,6 +2590,11 @@ def note_single_arg_concept_specialization_constraint_evaluated_to_false : Note< "%select{and |because }0%1 does not satisfy %2">; def note_atomic_constraint_evaluated_to_false_elaborated : Note< "%select{and |because }0'%1' (%2 %3 %4) evaluated to false">; +def err_could_not_normalize_ill_formed_constraint : Error< + "required expansion of concept specialization %0 failed, substituted " + "expression would be illegal">; +def note_could_not_normalize_ill_formed_constraint_reason : Note< + "because: %0">; def err_template_different_requires_clause : Error< "requires clause differs in template redeclaration">; @@ -4591,11 +4596,6 @@ def note_checking_constraints_for_class_spec_id_here : Note< "specialization '%0' required here">; def note_constraint_substitution_here : Note< "while substituting template arguments into constraint expression here">; -def note_constraint_normalization_here : Note< - "while calculating associated constraint of template '%0' here">; -def note_parameter_mapping_substitution_here : Note< - "while substituting into concept arguments here; substitution failures not " - "allowed in concept arguments">; def note_instantiation_contexts_suppressed : Note< "(skipping %0 context%s0 in backtrace; use -ftemplate-backtrace-limit=0 to " "see all)">; @@ -4759,9 +4759,8 @@ def note_template_declared_here : Note< "%select{function template|class template|variable template" "|type alias template|template template parameter}0 " "%1 declared here">; -def err_template_expansion_into_fixed_list : Error< - "pack expansion used as argument for non-pack parameter of %select{alias " - "template|concept}0">; +def err_alias_template_expansion_into_fixed_list : Error< + "pack expansion used as argument for non-pack parameter of alias template">; def note_parameter_type : Note< "parameter of type %0 is declared here">; diff --git a/clang/include/clang/Sema/Sema.h b/clang/include/clang/Sema/Sema.h index 07eba0306c9..abc414c62c6 100755..100644 --- a/clang/include/clang/Sema/Sema.h +++ b/clang/include/clang/Sema/Sema.h @@ -6171,25 +6171,6 @@ public: /// A diagnostic is emitted if it is not, and false is returned. bool CheckConstraintExpression(Expr *CE); -private: - /// \brief Caches pairs of template-like decls whose associated constraints - /// were checked for subsumption and whether or not the first's constraints - /// did in fact subsume the second's. - llvm::DenseMap<std::pair<NamedDecl *, NamedDecl *>, bool> SubsumptionCache; - -public: - /// \brief Check whether the given declaration's associated constraints are - /// at least as constrained than another declaration's according to the - /// partial ordering of constraints. - /// - /// \param Result If no error occurred, receives the result of true if D1 is - /// at least constrained than D2, and false otherwise. - /// - /// \returns true if an error occurred, false otherwise. - bool IsAtLeastAsConstrained(NamedDecl *D1, ArrayRef<const Expr *> AC1, - NamedDecl *D2, ArrayRef<const Expr *> AC2, - bool &Result); - /// \brief Check whether the given list of constraint expressions are /// satisfied (as if in a 'conjunction') given template arguments. /// \param ConstraintExprs a list of constraint expressions, treated as if @@ -6268,10 +6249,6 @@ public: void DiagnoseUnsatisfiedIllFormedConstraint(SourceLocation DiagnosticLocation, StringRef Diagnostic); - void - DiagnoseRedeclarationConstraintMismatch(const TemplateParameterList *Old, - const TemplateParameterList *New); - // ParseObjCStringLiteral - Parse Objective-C string literals. ExprResult ParseObjCStringLiteral(SourceLocation *AtLocs, ArrayRef<Expr *> Strings); @@ -6911,12 +6888,6 @@ public: QualType NTTPType, SourceLocation Loc); - /// Get a template argument mapping the given template parameter to itself, - /// e.g. for X in \c template<int X>, this would return an expression template - /// argument referencing X. - TemplateArgumentLoc getIdentityTemplateArgumentLoc(Decl *Param, - SourceLocation Location); - void translateTemplateArguments(const ASTTemplateArgsPtr &In, TemplateArgumentListInfo &Out); @@ -7815,9 +7786,6 @@ public: bool isTemplateTemplateParameterAtLeastAsSpecializedAs( TemplateParameterList *P, TemplateDecl *AArg, SourceLocation Loc); - void MarkUsedTemplateParameters(const Expr *E, bool OnlyDeduced, - unsigned Depth, llvm::SmallBitVector &Used); - void MarkUsedTemplateParameters(const TemplateArgumentList &TemplateArgs, bool OnlyDeduced, unsigned Depth, @@ -7911,13 +7879,6 @@ public: // We are substituting template arguments into a constraint expression. ConstraintSubstitution, - // We are normalizing a constraint expression. - ConstraintNormalization, - - // We are substituting into the parameter mapping of an atomic constraint - // during normalization. - ParameterMappingSubstitution, - /// We are rewriting a comparison operator in terms of an operator<=>. RewritingOperatorAsSpaceship, @@ -8199,19 +8160,6 @@ public: sema::TemplateDeductionInfo &DeductionInfo, SourceRange InstantiationRange); - struct ConstraintNormalization {}; - /// \brief Note that we are normalizing a constraint expression. - InstantiatingTemplate(Sema &SemaRef, SourceLocation PointOfInstantiation, - ConstraintNormalization, NamedDecl *Template, - SourceRange InstantiationRange); - - struct ParameterMappingSubstitution {}; - /// \brief Note that we are subtituting into the parameter mapping of an - /// atomic constraint during constraint normalization. - InstantiatingTemplate(Sema &SemaRef, SourceLocation PointOfInstantiation, - ParameterMappingSubstitution, NamedDecl *Template, - SourceRange InstantiationRange); - /// Note that we have finished instantiating this template. void Clear(); @@ -8545,12 +8493,6 @@ public: SubstTemplateParams(TemplateParameterList *Params, DeclContext *Owner, const MultiLevelTemplateArgumentList &TemplateArgs); - bool - SubstTemplateArguments(ArrayRef<TemplateArgumentLoc> Args, - const MultiLevelTemplateArgumentList &TemplateArgs, - TemplateArgumentListInfo &Outputs); - - Decl *SubstDecl(Decl *D, DeclContext *Owner, const MultiLevelTemplateArgumentList &TemplateArgs); diff --git a/clang/lib/AST/ASTImporter.cpp b/clang/lib/AST/ASTImporter.cpp index 20c1241613c..b75a689ec27 100644 --- a/clang/lib/AST/ASTImporter.cpp +++ b/clang/lib/AST/ASTImporter.cpp @@ -5278,25 +5278,16 @@ ExpectedDecl ASTNodeImporter::VisitClassTemplateSpecializationDecl( if (Error Err = ImportTemplateArguments( D->getTemplateArgs().data(), D->getTemplateArgs().size(), TemplateArgs)) return std::move(Err); - // Try to find an existing specialization with these template arguments and - // template parameter list. + + // Try to find an existing specialization with these template arguments. void *InsertPos = nullptr; ClassTemplateSpecializationDecl *PrevDecl = nullptr; ClassTemplatePartialSpecializationDecl *PartialSpec = dyn_cast<ClassTemplatePartialSpecializationDecl>(D); - - // Import template parameters. - TemplateParameterList *ToTPList = nullptr; - - if (PartialSpec) { - auto ToTPListOrErr = import(PartialSpec->getTemplateParameters()); - if (!ToTPListOrErr) - return ToTPListOrErr.takeError(); - ToTPList = *ToTPListOrErr; - PrevDecl = ClassTemplate->findPartialSpecialization(TemplateArgs, - *ToTPListOrErr, - InsertPos); - } else + if (PartialSpec) + PrevDecl = + ClassTemplate->findPartialSpecialization(TemplateArgs, InsertPos); + else PrevDecl = ClassTemplate->findSpecialization(TemplateArgs, InsertPos); if (PrevDecl) { @@ -5355,9 +5346,13 @@ ExpectedDecl ASTNodeImporter::VisitClassTemplateSpecializationDecl( return std::move(Err); CanonInjType = CanonInjType.getCanonicalType(); + auto ToTPListOrErr = import(PartialSpec->getTemplateParameters()); + if (!ToTPListOrErr) + return ToTPListOrErr.takeError(); + if (GetImportedOrCreateDecl<ClassTemplatePartialSpecializationDecl>( D2, D, Importer.getToContext(), D->getTagKind(), DC, - *BeginLocOrErr, *IdLocOrErr, ToTPList, ClassTemplate, + *BeginLocOrErr, *IdLocOrErr, *ToTPListOrErr, ClassTemplate, llvm::makeArrayRef(TemplateArgs.data(), TemplateArgs.size()), ToTAInfo, CanonInjType, cast_or_null<ClassTemplatePartialSpecializationDecl>(PrevDecl))) @@ -5365,11 +5360,10 @@ ExpectedDecl ASTNodeImporter::VisitClassTemplateSpecializationDecl( // Update InsertPos, because preceding import calls may have invalidated // it by adding new specializations. - auto *PartSpec2 = cast<ClassTemplatePartialSpecializationDecl>(D2); - if (!ClassTemplate->findPartialSpecialization(TemplateArgs, ToTPList, - InsertPos)) + if (!ClassTemplate->findPartialSpecialization(TemplateArgs, InsertPos)) // Add this partial specialization to the class template. - ClassTemplate->AddPartialSpecialization(PartSpec2, InsertPos); + ClassTemplate->AddPartialSpecialization( + cast<ClassTemplatePartialSpecializationDecl>(D2), InsertPos); } else { // Not a partial specialization. if (GetImportedOrCreateDecl( diff --git a/clang/lib/AST/DeclTemplate.cpp b/clang/lib/AST/DeclTemplate.cpp index 23734396b76..7e013c6c54d 100755..100644 --- a/clang/lib/AST/DeclTemplate.cpp +++ b/clang/lib/AST/DeclTemplate.cpp @@ -231,16 +231,15 @@ void RedeclarableTemplateDecl::loadLazySpecializationsImpl() const { } } -template<class EntryType, typename... ProfileArguments> +template<class EntryType> typename RedeclarableTemplateDecl::SpecEntryTraits<EntryType>::DeclType * RedeclarableTemplateDecl::findSpecializationImpl( - llvm::FoldingSetVector<EntryType> &Specs, void *&InsertPos, - ProfileArguments&&... ProfileArgs) { + llvm::FoldingSetVector<EntryType> &Specs, ArrayRef<TemplateArgument> Args, + void *&InsertPos) { using SETraits = SpecEntryTraits<EntryType>; llvm::FoldingSetNodeID ID; - EntryType::Profile(ID, std::forward<ProfileArguments>(ProfileArgs)..., - getASTContext()); + EntryType::Profile(ID, Args, getASTContext()); EntryType *Entry = Specs.FindNodeOrInsertPos(ID, InsertPos); return Entry ? SETraits::getDecl(Entry)->getMostRecentDecl() : nullptr; } @@ -255,8 +254,8 @@ void RedeclarableTemplateDecl::addSpecializationImpl( #ifndef NDEBUG void *CorrectInsertPos; assert(!findSpecializationImpl(Specializations, - CorrectInsertPos, - SETraits::getTemplateArgs(Entry)) && + SETraits::getTemplateArgs(Entry), + CorrectInsertPos) && InsertPos == CorrectInsertPos && "given incorrect InsertPos for specialization"); #endif @@ -313,7 +312,7 @@ FunctionTemplateDecl::getSpecializations() const { FunctionDecl * FunctionTemplateDecl::findSpecialization(ArrayRef<TemplateArgument> Args, void *&InsertPos) { - return findSpecializationImpl(getSpecializations(), InsertPos, Args); + return findSpecializationImpl(getSpecializations(), Args, InsertPos); } void FunctionTemplateDecl::addSpecialization( @@ -419,7 +418,7 @@ ClassTemplateDecl::newCommon(ASTContext &C) const { ClassTemplateSpecializationDecl * ClassTemplateDecl::findSpecialization(ArrayRef<TemplateArgument> Args, void *&InsertPos) { - return findSpecializationImpl(getSpecializations(), InsertPos, Args); + return findSpecializationImpl(getSpecializations(), Args, InsertPos); } void ClassTemplateDecl::AddSpecialization(ClassTemplateSpecializationDecl *D, @@ -428,48 +427,9 @@ void ClassTemplateDecl::AddSpecialization(ClassTemplateSpecializationDecl *D, } ClassTemplatePartialSpecializationDecl * -ClassTemplateDecl::findPartialSpecialization( - ArrayRef<TemplateArgument> Args, - TemplateParameterList *TPL, void *&InsertPos) { - return findSpecializationImpl(getPartialSpecializations(), InsertPos, Args, - TPL); -} - -static void ProfileTemplateParameterList(ASTContext &C, - llvm::FoldingSetNodeID &ID, const TemplateParameterList *TPL) { - const Expr *RC = TPL->getRequiresClause(); - ID.AddBoolean(RC != nullptr); - if (RC) - RC->Profile(ID, C, /*Canonical=*/true); - ID.AddInteger(TPL->size()); - for (NamedDecl *D : *TPL) { - if (const auto *NTTP = dyn_cast<NonTypeTemplateParmDecl>(D)) { - ID.AddInteger(0); - ID.AddBoolean(NTTP->isParameterPack()); - NTTP->getType().getCanonicalType().Profile(ID); - continue; - } - if (const auto *TTP = dyn_cast<TemplateTypeParmDecl>(D)) { - ID.AddInteger(1); - ID.AddBoolean(TTP->isParameterPack()); - // TODO: Concepts: profile type-constraints. - continue; - } - const auto *TTP = cast<TemplateTemplateParmDecl>(D); - ID.AddInteger(2); - ID.AddBoolean(TTP->isParameterPack()); - ProfileTemplateParameterList(C, ID, TTP->getTemplateParameters()); - } -} - -void -ClassTemplatePartialSpecializationDecl::Profile(llvm::FoldingSetNodeID &ID, - ArrayRef<TemplateArgument> TemplateArgs, TemplateParameterList *TPL, - ASTContext &Context) { - ID.AddInteger(TemplateArgs.size()); - for (const TemplateArgument &TemplateArg : TemplateArgs) - TemplateArg.Profile(ID, Context); - ProfileTemplateParameterList(Context, ID, TPL); +ClassTemplateDecl::findPartialSpecialization(ArrayRef<TemplateArgument> Args, + void *&InsertPos) { + return findSpecializationImpl(getPartialSpecializations(), Args, InsertPos); } void ClassTemplateDecl::AddPartialSpecialization( @@ -1075,7 +1035,7 @@ VarTemplateDecl::newCommon(ASTContext &C) const { VarTemplateSpecializationDecl * VarTemplateDecl::findSpecialization(ArrayRef<TemplateArgument> Args, void *&InsertPos) { - return findSpecializationImpl(getSpecializations(), InsertPos, Args); + return findSpecializationImpl(getSpecializations(), Args, InsertPos); } void VarTemplateDecl::AddSpecialization(VarTemplateSpecializationDecl *D, @@ -1085,19 +1045,8 @@ void VarTemplateDecl::AddSpecialization(VarTemplateSpecializationDecl *D, VarTemplatePartialSpecializationDecl * VarTemplateDecl::findPartialSpecialization(ArrayRef<TemplateArgument> Args, - TemplateParameterList *TPL, void *&InsertPos) { - return findSpecializationImpl(getPartialSpecializations(), InsertPos, Args, - TPL); -} - -void -VarTemplatePartialSpecializationDecl::Profile(llvm::FoldingSetNodeID &ID, - ArrayRef<TemplateArgument> TemplateArgs, TemplateParameterList *TPL, - ASTContext &Context) { - ID.AddInteger(TemplateArgs.size()); - for (const TemplateArgument &TemplateArg : TemplateArgs) - TemplateArg.Profile(ID, Context); - ProfileTemplateParameterList(Context, ID, TPL); + void *&InsertPos) { + return findSpecializationImpl(getPartialSpecializations(), Args, InsertPos); } void VarTemplateDecl::AddPartialSpecialization( diff --git a/clang/lib/Frontend/FrontendActions.cpp b/clang/lib/Frontend/FrontendActions.cpp index cbcaf2f96d5..aeea63ca323 100644 --- a/clang/lib/Frontend/FrontendActions.cpp +++ b/clang/lib/Frontend/FrontendActions.cpp @@ -425,10 +425,6 @@ private: return "ConstraintsCheck"; case CodeSynthesisContext::ConstraintSubstitution: return "ConstraintSubstitution"; - case CodeSynthesisContext::ConstraintNormalization: - return "ConstraintNormalization"; - case CodeSynthesisContext::ParameterMappingSubstitution: - return "ParameterMappingSubstitution"; } return ""; } 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. diff --git a/clang/lib/Serialization/ASTReaderDecl.cpp b/clang/lib/Serialization/ASTReaderDecl.cpp index 3351f76151e..0240984d75a 100644 --- a/clang/lib/Serialization/ASTReaderDecl.cpp +++ b/clang/lib/Serialization/ASTReaderDecl.cpp @@ -2176,14 +2176,12 @@ ASTDeclReader::VisitClassTemplateSpecializationDeclImpl( void ASTDeclReader::VisitClassTemplatePartialSpecializationDecl( ClassTemplatePartialSpecializationDecl *D) { - // We need to read the template params first because redeclarable is going to - // need them for profiling + RedeclarableResult Redecl = VisitClassTemplateSpecializationDeclImpl(D); + TemplateParameterList *Params = Record.readTemplateParameterList(); D->TemplateParams = Params; D->ArgsAsWritten = Record.readASTTemplateArgumentListInfo(); - RedeclarableResult Redecl = VisitClassTemplateSpecializationDeclImpl(D); - // These are read/set from/to the first declaration. if (ThisDeclID == Redecl.getFirstID()) { D->InstantiatedFromMember.setPointer( @@ -2281,12 +2279,12 @@ ASTDeclReader::VisitVarTemplateSpecializationDeclImpl( /// using Template(Partial)SpecializationDecl as input type. void ASTDeclReader::VisitVarTemplatePartialSpecializationDecl( VarTemplatePartialSpecializationDecl *D) { + RedeclarableResult Redecl = VisitVarTemplateSpecializationDeclImpl(D); + TemplateParameterList *Params = Record.readTemplateParameterList(); D->TemplateParams = Params; D->ArgsAsWritten = Record.readASTTemplateArgumentListInfo(); - RedeclarableResult Redecl = VisitVarTemplateSpecializationDeclImpl(D); - // These are read/set from/to the first declaration. if (ThisDeclID == Redecl.getFirstID()) { D->InstantiatedFromMember.setPointer( diff --git a/clang/lib/Serialization/ASTWriterDecl.cpp b/clang/lib/Serialization/ASTWriterDecl.cpp index 66f4db855a3..8931dc05fdd 100644 --- a/clang/lib/Serialization/ASTWriterDecl.cpp +++ b/clang/lib/Serialization/ASTWriterDecl.cpp @@ -1539,11 +1539,11 @@ void ASTDeclWriter::VisitClassTemplateSpecializationDecl( void ASTDeclWriter::VisitClassTemplatePartialSpecializationDecl( ClassTemplatePartialSpecializationDecl *D) { + VisitClassTemplateSpecializationDecl(D); + Record.AddTemplateParameterList(D->getTemplateParameters()); Record.AddASTTemplateArgumentListInfo(D->getTemplateArgsAsWritten()); - VisitClassTemplateSpecializationDecl(D); - // These are read/set from/to the first declaration. if (D->getPreviousDecl() == nullptr) { Record.AddDeclRef(D->getInstantiatedFromMember()); @@ -1599,11 +1599,11 @@ void ASTDeclWriter::VisitVarTemplateSpecializationDecl( void ASTDeclWriter::VisitVarTemplatePartialSpecializationDecl( VarTemplatePartialSpecializationDecl *D) { + VisitVarTemplateSpecializationDecl(D); + Record.AddTemplateParameterList(D->getTemplateParameters()); Record.AddASTTemplateArgumentListInfo(D->getTemplateArgsAsWritten()); - VisitVarTemplateSpecializationDecl(D); - // These are read/set from/to the first declaration. if (D->getPreviousDecl() == nullptr) { Record.AddDeclRef(D->getInstantiatedFromMember()); diff --git a/clang/test/CXX/expr/expr.prim/expr.prim.id/p3.cpp b/clang/test/CXX/expr/expr.prim/expr.prim.id/p3.cpp index fb3978240af..1e10d4550ce 100644 --- a/clang/test/CXX/expr/expr.prim/expr.prim.id/p3.cpp +++ b/clang/test/CXX/expr/expr.prim/expr.prim.id/p3.cpp @@ -75,8 +75,11 @@ static_assert(!IsTypePredicate<T1>); template<typename T, typename U, typename... Ts> concept OneOf = (Same<T, Ts> || ...); -static_assert(OneOf<int, long, int>); -static_assert(!OneOf<long, int, char, char>); +template<typename... X> +constexpr bool S = OneOf<X..., int, int>; + +static_assert(S<int, long, int>); +static_assert(!S<long, int, char, char>); namespace piecewise_substitution { template <typename T> @@ -175,11 +178,3 @@ template<typename T> concept AccessPrivate = T{}.f; static_assert(AccessPrivate<T4>); // expected-error@-1{{static_assert failed}} // expected-note@-2{{because 'T4' does not satisfy 'AccessPrivate'}} - -template<typename T, typename U> -// expected-note@-1{{template parameter is declared here}} -concept C8 = sizeof(T) > sizeof(U); - -template<typename... T> -constexpr bool B8 = C8<T...>; -// expected-error@-1{{pack expansion used as argument for non-pack parameter of concept}} diff --git a/clang/test/CXX/temp/temp.constr/temp.constr.normal/p1.cpp b/clang/test/CXX/temp/temp.constr/temp.constr.normal/p1.cpp deleted file mode 100644 index 387b75c4ef0..00000000000 --- a/clang/test/CXX/temp/temp.constr/temp.constr.normal/p1.cpp +++ /dev/null @@ -1,18 +0,0 @@ -// RUN: %clang_cc1 -std=c++2a -fconcepts-ts -x c++ -verify %s - -template<typename T> concept True = true; -template<typename T> concept Foo = True<T*>; -template<typename T> concept Bar = Foo<T&>; -template<typename T> requires Bar<T> struct S { }; -template<typename T> requires Bar<T> && true struct S<T> { }; - -template<typename T> concept True2 = sizeof(T) >= 0; -template<typename T> concept Foo2 = True2<T*>; -// expected-error@-1{{'type name' declared as a pointer to a reference of type 'type-parameter-0-0 &'}} -template<typename T> concept Bar2 = Foo2<T&>; -// expected-note@-1{{while substituting into concept arguments here; substitution failures not allowed in concept arguments}} -template<typename T> requires Bar2<T> struct S2 { }; -// expected-note@-1{{template is declared here}} -template<typename T> requires Bar2<T> && true struct S2<T> { }; -// expected-error@-1{{class template partial specialization is not more specialized than the primary template}} -// expected-note@-2{{while calculating associated constraint of template 'S2' here}} diff --git a/clang/test/CXX/temp/temp.constr/temp.constr.order/class-template-partial-specializations.cpp b/clang/test/CXX/temp/temp.constr/temp.constr.order/class-template-partial-specializations.cpp deleted file mode 100644 index 8c2f5526941..00000000000 --- a/clang/test/CXX/temp/temp.constr/temp.constr.order/class-template-partial-specializations.cpp +++ /dev/null @@ -1,50 +0,0 @@ -// RUN: %clang_cc1 -std=c++2a -fconcepts-ts -x c++ -verify %s - -template<typename T> requires sizeof(T) >= 4 -class A{}; // expected-note{{template is declared here}} - -template<typename T> requires sizeof(T) >= 4 && sizeof(T) <= 10 -class A<T>{}; // expected-error{{class template partial specialization is not more specialized than the primary template}} - -template<typename T> -concept C1 = sizeof(T) >= 4; - -template<typename T> requires C1<T> -class B{}; - -template<typename T> requires C1<T> && sizeof(T) <= 10 -class B<T>{}; - -template<typename T> -concept C2 = sizeof(T) > 1 && sizeof(T) <= 8; - -template<typename T> -class C{}; - -template<typename T> requires C1<T> -class C<T>{}; - -template<typename T> -class D{}; // expected-note{{previous definition is here}} - -template<typename T> -class D<T>{}; // expected-error{{class template partial specialization does not specialize any template argument; to define the primary template, remove the template argument list}} expected-error{{redefinition of 'D'}} - -template<typename T> requires C1<T> // expected-note{{previous template declaration is here}} -class E{}; - -template<typename T> // expected-error{{requires clause differs in template redeclaration}} -class E<T>{}; // expected-error{{class template partial specialization does not specialize any template argument; to define the primary template, remove the template argument list}} - -template<typename T> -struct F{ enum{ value = 1 }; }; - -template<typename T> requires C1<T> && C2<T> -struct F<T>{ enum{ value = 2 }; }; - -template<typename T> requires C1<T> || C2<T> -struct F<T>{ enum{ value = 3 }; }; - -static_assert(F<unsigned>::value == 2); -static_assert(F<char[10]>::value == 3); -static_assert(F<char>::value == 1); diff --git a/clang/test/CXX/temp/temp.constr/temp.constr.order/function-templates.cpp b/clang/test/CXX/temp/temp.constr/temp.constr.order/function-templates.cpp deleted file mode 100644 index d1b52182df4..00000000000 --- a/clang/test/CXX/temp/temp.constr/temp.constr.order/function-templates.cpp +++ /dev/null @@ -1,82 +0,0 @@ -// RUN: %clang_cc1 -std=c++2a -fconcepts-ts -x c++ -verify %s - -template<typename T> requires sizeof(T) >= 4 -bool a() { return false; } // expected-note {{candidate function [with T = unsigned int]}} - -template<typename T> requires sizeof(T) >= 4 && sizeof(T) <= 10 -bool a() { return true; } // expected-note {{candidate function [with T = unsigned int]}} - -bool av = a<unsigned>(); // expected-error {{call to 'a' is ambiguous}} - -template<typename T> -concept C1 = sizeof(T) >= 4; - -template<typename T> requires C1<T> -constexpr bool b() { return false; } - -template<typename T> requires C1<T> && sizeof(T) <= 10 -constexpr bool b() { return true; } - -static_assert(b<int>()); -static_assert(!b<int[10]>()); - -template<typename T> -concept C2 = sizeof(T) > 1 && sizeof(T) <= 8; - -template<typename T> -bool c() { return false; } - -template<typename T> requires C1<T> -bool c() { return true; } - -template<typename T> requires C1<T> -constexpr bool d() { return false; } - -template<typename T> -constexpr bool d() { return true; } - -static_assert(!d<int>()); - -template<typename T> -constexpr int e() { return 1; } - -template<typename T> requires C1<T> && C2<T> -constexpr int e() { return 2; } - -template<typename T> requires C1<T> || C2<T> -constexpr int e() { return 3; } - -static_assert(e<unsigned>() == 2); -static_assert(e<char[10]>() == 3); -static_assert(e<char>() == 1); - -template<class T, class U> -concept BiggerThan = sizeof(T) > sizeof(U); - -template<class T> -concept BiggerThanInt = BiggerThan<T, int>; - -template<class T, class U> requires BiggerThan<T, U> -void f() { } -// expected-note@-1 {{candidate function [with T = long long, U = int]}} - -template<class T, class U> requires BiggerThanInt<T> -void f() { } -// expected-note@-1 {{candidate function [with T = long long, U = int]}} - -static_assert(sizeof(f<long long, int>())); -// expected-error@-1 {{call to 'f' is ambiguous}} - -template<typename T> -concept C3 = true; - -template<typename T> -concept C4 = true && C3<T>; - -template<typename T> requires C3<void> -int g() { } - -template<typename T> requires C4<void> -int g() { } - -static_assert(sizeof(g<int>()));
\ No newline at end of file diff --git a/clang/test/CXX/temp/temp.constr/temp.constr.order/var-template-partial-specializations.cpp b/clang/test/CXX/temp/temp.constr/temp.constr.order/var-template-partial-specializations.cpp deleted file mode 100644 index b40c77e70a1..00000000000 --- a/clang/test/CXX/temp/temp.constr/temp.constr.order/var-template-partial-specializations.cpp +++ /dev/null @@ -1,53 +0,0 @@ -// RUN: %clang_cc1 -std=c++2a -fconcepts-ts -x c++ -verify %s - -template<typename T> requires sizeof(T) >= 4 -bool a = false; // expected-note{{template is declared here}} - -template<typename T> requires sizeof(T) >= 4 && sizeof(T) <= 10 -bool a<T> = true; // expected-error{{variable template partial specialization is not more specialized than the primary template}} - -template<typename T> -concept C1 = sizeof(T) >= 4; - -template<typename T> requires C1<T> -bool b = false; - -template<typename T> requires C1<T> && sizeof(T) <= 10 -bool b<T> = true; - -template<typename T> -concept C2 = sizeof(T) > 1 && sizeof(T) <= 8; - -template<typename T> -bool c = false; - -template<typename T> requires C1<T> -bool c<T> = true; - -template<typename T> -bool d = false; - -template<typename T> -bool d<T> = true; // expected-error{{variable template partial specialization does not specialize any template argument; to define the primary template, remove the template argument list}} - -template<typename T> requires C1<T> -bool e = false; - -template<typename T> -bool e<T> = true; // expected-error{{variable template partial specialization does not specialize any template argument; to define the primary template, remove the template argument list}} - -template<typename T> -constexpr int f = 1; - -template<typename T> requires C1<T> && C2<T> -constexpr int f<T> = 2; - -template<typename T> requires C1<T> || C2<T> -constexpr int f<T> = 3; - -static_assert(f<unsigned> == 2); -static_assert(f<char[10]> == 3); -static_assert(f<char> == 1); - - - |