From 017abbb258618ed7aad4573f8940a67eb868027f Mon Sep 17 00:00:00 2001 From: Erich Keane Date: Mon, 9 May 2022 09:04:17 -0700 Subject: [PATCH] Revert ""Re-apply 4b6c2cd642 "Deferred Concept Instantiation Implementation""""" This reverts commit a425cac31e2e4cee8e14b7b9a99c8ba17c1ebb52. There is another libc++ test, that this time causes us to hit an assertion. Reverting, likely for a while this time. --- clang/docs/ReleaseNotes.rst | 9 +- clang/include/clang/AST/Decl.h | 36 +- clang/include/clang/AST/DeclBase.h | 8 - clang/include/clang/Sema/Sema.h | 82 +--- clang/include/clang/Sema/Template.h | 27 -- clang/lib/AST/ASTImporter.cpp | 5 - clang/lib/AST/Decl.cpp | 25 +- clang/lib/AST/DeclBase.cpp | 10 - clang/lib/ExtractAPI/ExtractAPIConsumer.cpp | 1 - clang/lib/Sema/SemaConcept.cpp | 303 ++++---------- clang/lib/Sema/SemaOverload.cpp | 90 ----- clang/lib/Sema/SemaTemplate.cpp | 28 +- clang/lib/Sema/SemaTemplateDeduction.cpp | 11 +- clang/lib/Sema/SemaTemplateInstantiate.cpp | 47 +-- clang/lib/Sema/SemaTemplateInstantiateDecl.cpp | 54 ++- clang/lib/Sema/TreeTransform.h | 9 +- clang/lib/Serialization/ASTReaderDecl.cpp | 4 - clang/lib/Serialization/ASTWriterDecl.cpp | 3 - .../temp.constr.constr/non-function-templates.cpp | 21 - clang/test/SemaTemplate/concepts.cpp | 444 --------------------- clang/test/SemaTemplate/deferred-concept-inst.cpp | 23 -- .../SemaTemplate/instantiate-requires-clause.cpp | 16 +- .../SemaTemplate/trailing-return-short-circuit.cpp | 62 --- 23 files changed, 173 insertions(+), 1145 deletions(-) delete mode 100644 clang/test/SemaTemplate/deferred-concept-inst.cpp delete mode 100644 clang/test/SemaTemplate/trailing-return-short-circuit.cpp diff --git a/clang/docs/ReleaseNotes.rst b/clang/docs/ReleaseNotes.rst index d4b38f3..ce9de524 100644 --- a/clang/docs/ReleaseNotes.rst +++ b/clang/docs/ReleaseNotes.rst @@ -329,11 +329,10 @@ C++20 Feature Support - No longer attempt to evaluate a consteval UDL function call at runtime when it is called through a template instantiation. This fixes `Issue 54578 `_. -- Implemented `__builtin_source_location()` which enables library support for std::source_location. -- Clang now correctly delays the instantiation of function constraints until - the time of checking, which should now allow the libstdc++ ranges implementation - to work for at least trivial examples. This fixes - `Issue 44178 `_. + +- Implemented ``__builtin_source_location()``, which enables library support + for ``std::source_location``. + - The mangling scheme for C++20 modules has incompatibly changed. The initial mangling was discovered not to be reversible, and the weak ownership design decision did not give the backwards compatibility diff --git a/clang/include/clang/AST/Decl.h b/clang/include/clang/AST/Decl.h index cc84e74..c2133f4 100644 --- a/clang/include/clang/AST/Decl.h +++ b/clang/include/clang/AST/Decl.h @@ -1890,9 +1890,7 @@ public: TK_FunctionTemplateSpecialization, // A function template specialization that hasn't yet been resolved to a // particular specialized function template. - TK_DependentFunctionTemplateSpecialization, - // A non templated function which is in a dependent scope. - TK_DependentNonTemplate + TK_DependentFunctionTemplateSpecialization }; /// Stashed information about a defaulted function definition whose body has @@ -1941,21 +1939,20 @@ private: /// The template or declaration that this declaration /// describes or was instantiated from, respectively. /// - /// For non-templates this value will be NULL, unless this non-template - /// function declaration was declared directly inside of a function template, - /// in which case this will have a pointer to a FunctionDecl, stored in the - /// NamedDecl. For function declarations that describe a function template, - /// this will be a pointer to a FunctionTemplateDecl, stored in the NamedDecl. - /// For member functions of class template specializations, this will be a - /// MemberSpecializationInfo pointer containing information about the - /// specialization. For function template specializations, this will be a - /// FunctionTemplateSpecializationInfo, which contains information about the - /// template being specialized and the template arguments involved in that - /// specialization. - llvm::PointerUnion - TemplateOrSpecialization; + TemplateOrSpecialization; /// Provides source/type location info for the declaration name embedded in /// the DeclaratorDecl base class. @@ -2691,11 +2688,6 @@ public: setInstantiationOfMemberFunction(getASTContext(), FD, TSK); } - /// Specify that this function declaration was instantiated from FunctionDecl - /// FD. This is only used if this is a function declaration declared locally - /// inside of a function template. - void setInstantiatedFromDecl(FunctionDecl *FD); - /// Retrieves the function template that is described by this /// function declaration. /// @@ -2710,8 +2702,6 @@ public: /// FunctionTemplateDecl from a FunctionDecl. FunctionTemplateDecl *getDescribedFunctionTemplate() const; - FunctionDecl *getInstantiatedFromDecl() const; - void setDescribedFunctionTemplate(FunctionTemplateDecl *Template); /// Determine whether this function is a function template diff --git a/clang/include/clang/AST/DeclBase.h b/clang/include/clang/AST/DeclBase.h index 54cecad..a4a44e0 100644 --- a/clang/include/clang/AST/DeclBase.h +++ b/clang/include/clang/AST/DeclBase.h @@ -906,14 +906,6 @@ public: const_cast(this)->getParentFunctionOrMethod()); } - /// Does the same thing as getParentFunctionOrMethod, except starts with the - /// lexical declaration context instead. - const DeclContext *getLexicalParentFunctionOrMethod() const; - DeclContext *getLexicalParentFunctionOrMethod() { - return const_cast( - const_cast(this)->getLexicalParentFunctionOrMethod()); - } - /// Retrieves the "canonical" declaration of the given declaration. virtual Decl *getCanonicalDecl() { return this; } const Decl *getCanonicalDecl() const { diff --git a/clang/include/clang/Sema/Sema.h b/clang/include/clang/Sema/Sema.h index 7bcf8c6..27603f0 100644 --- a/clang/include/clang/Sema/Sema.h +++ b/clang/include/clang/Sema/Sema.h @@ -6989,34 +6989,7 @@ private: LocalInstantiationScope &Scope, const MultiLevelTemplateArgumentList &TemplateArgs); - /// used by SetupConstraintCheckingTemplateArgumentsAndScope to recursively(in - /// the case of lambdas) set up the LocalInstantiationScope of the current - /// function. - bool SetupConstraintScope( - FunctionDecl *FD, llvm::Optional> TemplateArgs, - MultiLevelTemplateArgumentList MLTAL, LocalInstantiationScope &Scope); - - /// Used during constraint checking, sets up the constraint template arguemnt - /// lists, and calls SetupConstraintScope to set up the - /// LocalInstantiationScope to have the proper set of ParVarDecls configured. - llvm::Optional - SetupConstraintCheckingTemplateArgumentsAndScope( - FunctionDecl *FD, llvm::Optional> TemplateArgs, - LocalInstantiationScope &Scope); - - // Keep track of whether we are evaluating a constraint. - unsigned ConstraintEvaluationDepth = 0; - - class ConstraintEvalRAII { - Sema &S; - - public: - ConstraintEvalRAII(Sema &S) : S(S) { ++S.ConstraintEvaluationDepth; } - ~ConstraintEvalRAII() { --S.ConstraintEvaluationDepth; } - }; - public: - bool IsEvaluatingAConstraint() { return ConstraintEvaluationDepth > 0; } const NormalizedConstraint * getNormalizedAssociatedConstraints( NamedDecl *ConstrainedDecl, ArrayRef AssociatedConstraints); @@ -7046,42 +7019,8 @@ public: /// check (either a concept or a constrained entity). /// \param ConstraintExprs a list of constraint expressions, treated as if /// they were 'AND'ed together. - /// \param TemplateArgList the multi-level list of template arguments to - /// substitute into the constraint expression. This should be relative to the - /// top-level (hence multi-level), since we need to instantiate fully at the - /// time of checking. - /// \param TemplateIDRange The source range of the template id that - /// caused the constraints check. - /// \param Satisfaction if true is returned, will contain details of the - /// satisfaction, with enough information to diagnose an unsatisfied - /// expression. - /// \returns true if an error occurred and satisfaction could not be checked, - /// false otherwise. - bool CheckConstraintSatisfaction( - const NamedDecl *Template, ArrayRef ConstraintExprs, - const MultiLevelTemplateArgumentList &TemplateArgList, - SourceRange TemplateIDRange, ConstraintSatisfaction &Satisfaction) { - llvm::SmallVector Converted; - return CheckConstraintSatisfaction(Template, ConstraintExprs, Converted, - TemplateArgList, TemplateIDRange, - Satisfaction); - } - - /// \brief Check whether the given list of constraint expressions are - /// satisfied (as if in a 'conjunction') given template arguments. - /// Additionally, takes an empty list of Expressions which is populated with - /// the instantiated versions of the ConstraintExprs. - /// \param Template the template-like entity that triggered the constraints - /// check (either a concept or a constrained entity). - /// \param ConstraintExprs a list of constraint expressions, treated as if - /// they were 'AND'ed together. - /// \param ConvertedConstraints a out parameter that will get populated with - /// the instantiated version of the ConstraintExprs if we successfully checked - /// satisfaction. - /// \param TemplateArgList the multi-level list of template arguments to - /// substitute into the constraint expression. This should be relative to the - /// top-level (hence multi-level), since we need to instantiate fully at the - /// time of checking. + /// \param TemplateArgs the list of template arguments to substitute into the + /// constraint expression. /// \param TemplateIDRange The source range of the template id that /// caused the constraints check. /// \param Satisfaction if true is returned, will contain details of the @@ -7091,8 +7030,7 @@ public: /// false otherwise. bool CheckConstraintSatisfaction( const NamedDecl *Template, ArrayRef ConstraintExprs, - llvm::SmallVectorImpl &ConvertedConstraints, - const MultiLevelTemplateArgumentList &TemplateArgList, + ArrayRef TemplateArgs, SourceRange TemplateIDRange, ConstraintSatisfaction &Satisfaction); /// \brief Check whether the given non-dependent constraint expression is @@ -7128,9 +7066,9 @@ public: /// /// \returns true if the constrains are not satisfied or could not be checked /// for satisfaction, false if the constraints are satisfied. - bool EnsureTemplateArgumentListConstraints( - TemplateDecl *Template, MultiLevelTemplateArgumentList TemplateArgs, - SourceRange TemplateIDRange); + bool EnsureTemplateArgumentListConstraints(TemplateDecl *Template, + ArrayRef TemplateArgs, + SourceRange TemplateIDRange); /// \brief Emit diagnostics explaining why a constraint expression was deemed /// unsatisfied. @@ -8864,8 +8802,7 @@ public: MultiLevelTemplateArgumentList getTemplateInstantiationArgs( const NamedDecl *D, const TemplateArgumentList *Innermost = nullptr, - bool RelativeToPrimary = false, const FunctionDecl *Pattern = nullptr, - bool LookBeyondLambda = false, bool IncludeContainingStruct = false); + bool RelativeToPrimary = false, const FunctionDecl *Pattern = nullptr); /// A context in which code is being synthesized (where a source location /// alone is not sufficient to identify the context). This covers template @@ -9598,11 +9535,6 @@ public: ExtParameterInfoBuilder &ParamInfos); ExprResult SubstExpr(Expr *E, const MultiLevelTemplateArgumentList &TemplateArgs); - // Unlike the above, this evaluates constraints, which should only happen at - // 'constraint checking' time. - ExprResult - SubstConstraintExpr(Expr *E, - const MultiLevelTemplateArgumentList &TemplateArgs); /// Substitute the given template arguments into a list of /// expressions, expanding pack expansions if required. diff --git a/clang/include/clang/Sema/Template.h b/clang/include/clang/Sema/Template.h index c8179dd..540d2c9 100644 --- a/clang/include/clang/Sema/Template.h +++ b/clang/include/clang/Sema/Template.h @@ -75,9 +75,6 @@ enum class TemplateSubstitutionKind : char { class MultiLevelTemplateArgumentList { /// The template argument list at a certain template depth using ArgList = ArrayRef; - using ArgListsIterator = SmallVector::reverse_iterator; - using ConstArgListsIterator = - SmallVector::const_reverse_iterator; /// The template argument lists, stored from the innermost template /// argument list (first) to the outermost template argument list (last). @@ -124,12 +121,6 @@ enum class TemplateSubstitutionKind : char { return TemplateArgumentLists.size(); } - /// Determine the number of substituted args at 'Depth'. - unsigned getNumSubstitutedArgs(unsigned Depth) const { - assert(NumRetainedOuterLevels <= Depth && Depth < getNumLevels()); - return TemplateArgumentLists[getNumLevels() - Depth - 1].size(); - } - unsigned getNumRetainedOuterLevels() const { return NumRetainedOuterLevels; } @@ -167,14 +158,6 @@ enum class TemplateSubstitutionKind : char { return !(*this)(Depth, Index).isNull(); } - bool isAnyArgInstantiationDependent() const { - for (ArgList List : TemplateArgumentLists) - for (const TemplateArgument &TA : List) - if (TA.isInstantiationDependent()) - return true; - return false; - } - /// Clear out a specific template argument. void setArgument(unsigned Depth, unsigned Index, TemplateArgument Arg) { @@ -214,16 +197,6 @@ enum class TemplateSubstitutionKind : char { const ArgList &getInnermost() const { return TemplateArgumentLists.front(); } - - /// Retrieve the outermost template argument list. - const ArgList &getOutermost() const { return TemplateArgumentLists.back(); } - - ArgListsIterator begin() { return TemplateArgumentLists.rbegin(); } - ConstArgListsIterator begin() const { - return TemplateArgumentLists.rbegin(); - } - ArgListsIterator end() { return TemplateArgumentLists.rend(); } - ConstArgListsIterator end() const { return TemplateArgumentLists.rend(); } }; /// The context in which partial ordering of function templates occurs. diff --git a/clang/lib/AST/ASTImporter.cpp b/clang/lib/AST/ASTImporter.cpp index be77d68..e229408 100644 --- a/clang/lib/AST/ASTImporter.cpp +++ b/clang/lib/AST/ASTImporter.cpp @@ -3109,11 +3109,6 @@ Error ASTNodeImporter::ImportTemplateInformation( case FunctionDecl::TK_FunctionTemplate: return Error::success(); - case FunctionDecl::TK_DependentNonTemplate: - if (Expected InstFDOrErr = - import(FromFD->getInstantiatedFromDecl())) - ToFD->setInstantiatedFromDecl(*InstFDOrErr); - return Error::success(); case FunctionDecl::TK_MemberSpecialization: { TemplateSpecializationKind TSK = FromFD->getTemplateSpecializationKind(); diff --git a/clang/lib/AST/Decl.cpp b/clang/lib/AST/Decl.cpp index e6b949a..911479b 100644 --- a/clang/lib/AST/Decl.cpp +++ b/clang/lib/AST/Decl.cpp @@ -3729,12 +3729,8 @@ const IdentifierInfo *FunctionDecl::getLiteralIdentifier() const { FunctionDecl::TemplatedKind FunctionDecl::getTemplatedKind() const { if (TemplateOrSpecialization.isNull()) return TK_NonTemplate; - if (auto *ND = TemplateOrSpecialization.dyn_cast()) { - if (isa(ND)) - return TK_DependentNonTemplate; - assert(isa(ND) && "No other types it could be?"); + if (TemplateOrSpecialization.is()) return TK_FunctionTemplate; - } if (TemplateOrSpecialization.is()) return TK_MemberSpecialization; if (TemplateOrSpecialization.is()) @@ -3775,26 +3771,13 @@ FunctionDecl::setInstantiationOfMemberFunction(ASTContext &C, } FunctionTemplateDecl *FunctionDecl::getDescribedFunctionTemplate() const { - return dyn_cast_or_null( - TemplateOrSpecialization.dyn_cast()); + return TemplateOrSpecialization.dyn_cast(); } -void FunctionDecl::setDescribedFunctionTemplate( - FunctionTemplateDecl *Template) { +void FunctionDecl::setDescribedFunctionTemplate(FunctionTemplateDecl *Template) { assert(TemplateOrSpecialization.isNull() && "Member function is already a specialization"); - TemplateOrSpecialization = static_cast(Template); -} - -void FunctionDecl::setInstantiatedFromDecl(FunctionDecl *FD) { - assert(TemplateOrSpecialization.isNull() && - "function is already a specialization"); - TemplateOrSpecialization = static_cast(FD); -} - -FunctionDecl *FunctionDecl::getInstantiatedFromDecl() const { - return dyn_cast_or_null( - TemplateOrSpecialization.dyn_cast()); + TemplateOrSpecialization = Template; } bool FunctionDecl::isImplicitlyInstantiable() const { diff --git a/clang/lib/AST/DeclBase.cpp b/clang/lib/AST/DeclBase.cpp index d666d6b..d5ad636 100644 --- a/clang/lib/AST/DeclBase.cpp +++ b/clang/lib/AST/DeclBase.cpp @@ -293,16 +293,6 @@ const DeclContext *Decl::getParentFunctionOrMethod() const { return nullptr; } -const DeclContext *Decl::getLexicalParentFunctionOrMethod() const { - for (const DeclContext *DC = getLexicalDeclContext(); - DC && !DC->isTranslationUnit() && !DC->isNamespace(); - DC = DC->getParent()) - if (DC->isFunctionOrMethod()) - return DC; - - return nullptr; -} - //===----------------------------------------------------------------------===// // PrettyStackTraceDecl Implementation //===----------------------------------------------------------------------===// diff --git a/clang/lib/ExtractAPI/ExtractAPIConsumer.cpp b/clang/lib/ExtractAPI/ExtractAPIConsumer.cpp index 4975111..a7b0a1a 100644 --- a/clang/lib/ExtractAPI/ExtractAPIConsumer.cpp +++ b/clang/lib/ExtractAPI/ExtractAPIConsumer.cpp @@ -303,7 +303,6 @@ public: // Skip templated functions. switch (Decl->getTemplatedKind()) { case FunctionDecl::TK_NonTemplate: - case FunctionDecl::TK_DependentNonTemplate: break; case FunctionDecl::TK_MemberSpecialization: case FunctionDecl::TK_FunctionTemplateSpecialization: diff --git a/clang/lib/Sema/SemaConcept.cpp b/clang/lib/Sema/SemaConcept.cpp index 546fc71..c78b0df 100644 --- a/clang/lib/Sema/SemaConcept.cpp +++ b/clang/lib/Sema/SemaConcept.cpp @@ -30,7 +30,6 @@ using namespace sema; namespace { class LogicalBinOp { - SourceLocation Loc; OverloadedOperatorKind Op = OO_None; const Expr *LHS = nullptr; const Expr *RHS = nullptr; @@ -41,14 +40,12 @@ public: Op = BinaryOperator::getOverloadedOperator(BO->getOpcode()); LHS = BO->getLHS(); RHS = BO->getRHS(); - Loc = BO->getExprLoc(); } else if (auto *OO = dyn_cast(E)) { // If OO is not || or && it might not have exactly 2 arguments. if (OO->getNumArgs() == 2) { Op = OO->getOperator(); LHS = OO->getArg(0); RHS = OO->getArg(1); - Loc = OO->getOperatorLoc(); } } } @@ -59,25 +56,6 @@ public: const Expr *getLHS() const { return LHS; } const Expr *getRHS() const { return RHS; } - - ExprResult recreateBinOp(Sema &SemaRef, ExprResult LHS) { - return recreateBinOp(SemaRef, LHS, const_cast(getRHS())); - } - - ExprResult recreateBinOp(Sema &SemaRef, ExprResult LHS, ExprResult RHS) { - assert((isAnd() || isOr()) && "Not the right kind of op?"); - assert((!LHS.isInvalid() && !RHS.isInvalid()) && "not good expressions?"); - - if (!LHS.isUsable() || !RHS.isUsable()) - return ExprEmpty(); - - // We should just be able to 'normalize' these to the builtin Binary - // Operator, since that is how they are evaluated in constriant checks. - return BinaryOperator::Create(SemaRef.Context, LHS.get(), RHS.get(), - BinaryOperator::getOverloadedOpcode(Op), - SemaRef.Context.BoolTy, VK_PRValue, - OK_Ordinary, Loc, FPOptionsOverride{}); - } }; } @@ -144,18 +122,16 @@ bool Sema::CheckConstraintExpression(const Expr *ConstraintExpression, } template -static ExprResult +static bool calculateConstraintSatisfaction(Sema &S, const Expr *ConstraintExpr, ConstraintSatisfaction &Satisfaction, AtomicEvaluator &&Evaluator) { ConstraintExpr = ConstraintExpr->IgnoreParenImpCasts(); if (LogicalBinOp BO = ConstraintExpr) { - ExprResult LHSRes = calculateConstraintSatisfaction( - S, BO.getLHS(), Satisfaction, Evaluator); - - if (LHSRes.isInvalid()) - return ExprError(); + if (calculateConstraintSatisfaction(S, BO.getLHS(), Satisfaction, + Evaluator)) + return true; bool IsLHSSatisfied = Satisfaction.IsSatisfied; @@ -166,7 +142,7 @@ calculateConstraintSatisfaction(Sema &S, const Expr *ConstraintExpr, // is checked. If that is satisfied, the disjunction is satisfied. // Otherwise, the disjunction is satisfied if and only if the second // operand is satisfied. - return LHSRes.isUsable() ? BO.recreateBinOp(S, LHSRes) : ExprEmpty(); + return false; if (BO.isAnd() && !IsLHSSatisfied) // [temp.constr.op] p2 @@ -175,21 +151,12 @@ calculateConstraintSatisfaction(Sema &S, const Expr *ConstraintExpr, // is checked. If that is not satisfied, the conjunction is not // satisfied. Otherwise, the conjunction is satisfied if and only if // the second operand is satisfied. - return LHSRes.isUsable() ? BO.recreateBinOp(S, LHSRes) : ExprEmpty(); + return false; - ExprResult RHSRes = calculateConstraintSatisfaction( + return calculateConstraintSatisfaction( S, BO.getRHS(), Satisfaction, std::forward(Evaluator)); - if (RHSRes.isInvalid()) - return ExprError(); - - if (!LHSRes.isUsable() || !RHSRes.isUsable()) - return ExprEmpty(); - return BO.recreateBinOp(S, LHSRes, RHSRes); } else if (auto *C = dyn_cast(ConstraintExpr)) { - // These aren't evaluated, so we don't care about cleanups, so we can just - // evaluate these as if the cleanups didn't exist. - return calculateConstraintSatisfaction( - S, C->getSubExpr(), Satisfaction, + return calculateConstraintSatisfaction(S, C->getSubExpr(), Satisfaction, std::forward(Evaluator)); } @@ -197,11 +164,11 @@ calculateConstraintSatisfaction(Sema &S, const Expr *ConstraintExpr, ExprResult SubstitutedAtomicExpr = Evaluator(ConstraintExpr); if (SubstitutedAtomicExpr.isInvalid()) - return ExprError(); + return true; if (!SubstitutedAtomicExpr.isUsable()) // Evaluator has decided satisfaction without yielding an expression. - return ExprEmpty(); + return false; EnterExpressionEvaluationContext ConstantEvaluated( S, Sema::ExpressionEvaluationContext::ConstantEvaluated); @@ -218,7 +185,7 @@ calculateConstraintSatisfaction(Sema &S, const Expr *ConstraintExpr, << SubstitutedAtomicExpr.get()->getSourceRange(); for (const PartialDiagnosticAt &PDiag : EvaluationDiags) S.Diag(PDiag.first, PDiag.second); - return ExprError(); + return true; } assert(EvalResult.Val.isInt() && @@ -228,13 +195,13 @@ calculateConstraintSatisfaction(Sema &S, const Expr *ConstraintExpr, Satisfaction.Details.emplace_back(ConstraintExpr, SubstitutedAtomicExpr.get()); - return SubstitutedAtomicExpr; + return false; } -static ExprResult calculateConstraintSatisfaction( - Sema &S, const NamedDecl *Template, SourceLocation TemplateNameLoc, - const MultiLevelTemplateArgumentList &MLTAL, const Expr *ConstraintExpr, - ConstraintSatisfaction &Satisfaction) { +static bool calculateConstraintSatisfaction( + Sema &S, const NamedDecl *Template, ArrayRef TemplateArgs, + SourceLocation TemplateNameLoc, MultiLevelTemplateArgumentList &MLTAL, + const Expr *ConstraintExpr, ConstraintSatisfaction &Satisfaction) { return calculateConstraintSatisfaction( S, ConstraintExpr, Satisfaction, [&](const Expr *AtomicExpr) { EnterExpressionEvaluationContext ConstantEvaluated( @@ -252,8 +219,8 @@ static ExprResult calculateConstraintSatisfaction( return ExprError(); // We do not want error diagnostics escaping here. Sema::SFINAETrap Trap(S); - SubstitutedExpression = - S.SubstConstraintExpr(const_cast(AtomicExpr), MLTAL); + SubstitutedExpression = S.SubstExpr(const_cast(AtomicExpr), + MLTAL); // Substitution might have stripped off a contextual conversion to // bool if this is the operand of an '&&' or '||'. For example, we // might lose an lvalue-to-rvalue conversion here. If so, put it back @@ -301,92 +268,72 @@ static ExprResult calculateConstraintSatisfaction( }); } -static bool CheckConstraintSatisfaction( - Sema &S, const NamedDecl *Template, ArrayRef ConstraintExprs, - llvm::SmallVectorImpl &Converted, - const MultiLevelTemplateArgumentList &TemplateArgsList, - SourceRange TemplateIDRange, ConstraintSatisfaction &Satisfaction) { +static bool CheckConstraintSatisfaction(Sema &S, const NamedDecl *Template, + ArrayRef ConstraintExprs, + ArrayRef TemplateArgs, + SourceRange TemplateIDRange, + ConstraintSatisfaction &Satisfaction) { if (ConstraintExprs.empty()) { Satisfaction.IsSatisfied = true; return false; } - if (TemplateArgsList.isAnyArgInstantiationDependent()) { - // No need to check satisfaction for dependent constraint expressions. - Satisfaction.IsSatisfied = true; - return false; - } - - ArrayRef TemplateArgs = - TemplateArgsList.getNumSubstitutedLevels() > 0 - ? TemplateArgsList.getOutermost() - : ArrayRef{}; + for (auto& Arg : TemplateArgs) + if (Arg.isInstantiationDependent()) { + // No need to check satisfaction for dependent constraint expressions. + Satisfaction.IsSatisfied = true; + return false; + } - Sema::InstantiatingTemplate Inst( - S, TemplateIDRange.getBegin(), + Sema::InstantiatingTemplate Inst(S, TemplateIDRange.getBegin(), Sema::InstantiatingTemplate::ConstraintsCheck{}, const_cast(Template), TemplateArgs, TemplateIDRange); if (Inst.isInvalid()) return true; + MultiLevelTemplateArgumentList MLTAL; + MLTAL.addOuterTemplateArguments(TemplateArgs); + for (const Expr *ConstraintExpr : ConstraintExprs) { - ExprResult Res = calculateConstraintSatisfaction( - S, Template, TemplateIDRange.getBegin(), TemplateArgsList, - ConstraintExpr, Satisfaction); - if (Res.isInvalid()) + if (calculateConstraintSatisfaction(S, Template, TemplateArgs, + TemplateIDRange.getBegin(), MLTAL, + ConstraintExpr, Satisfaction)) return true; - - Converted.push_back(Res.get()); - if (!Satisfaction.IsSatisfied) { - // Backfill the 'converted' list with nulls so we can keep the Converted - // and unconverted lists in sync. - Converted.append(ConstraintExprs.size() - Converted.size(), nullptr); + if (!Satisfaction.IsSatisfied) // [temp.constr.op] p2 - // [...] To determine if a conjunction is satisfied, the satisfaction - // of the first operand is checked. If that is not satisfied, the - // conjunction is not satisfied. [...] + // [...] To determine if a conjunction is satisfied, the satisfaction + // of the first operand is checked. If that is not satisfied, the + // conjunction is not satisfied. [...] return false; - } } return false; } bool Sema::CheckConstraintSatisfaction( const NamedDecl *Template, ArrayRef ConstraintExprs, - llvm::SmallVectorImpl &ConvertedConstraints, - const MultiLevelTemplateArgumentList &TemplateArgsList, - SourceRange TemplateIDRange, ConstraintSatisfaction &OutSatisfaction) { + ArrayRef TemplateArgs, SourceRange TemplateIDRange, + ConstraintSatisfaction &OutSatisfaction) { if (ConstraintExprs.empty()) { OutSatisfaction.IsSatisfied = true; return false; } if (!Template) { return ::CheckConstraintSatisfaction(*this, nullptr, ConstraintExprs, - ConvertedConstraints, TemplateArgsList, - TemplateIDRange, OutSatisfaction); + TemplateArgs, TemplateIDRange, + OutSatisfaction); } - - // A list of the template argument list flattened in a predictible manner for - // the purposes of caching. The ConstraintSatisfaction type is in AST so it - // has no access to the MultiLevelTemplateArgumentList, so this has to happen - // here. - llvm::SmallVector FlattenedArgs; - for (ArrayRef List : TemplateArgsList) - FlattenedArgs.insert(FlattenedArgs.end(), List.begin(), List.end()); - llvm::FoldingSetNodeID ID; - ConstraintSatisfaction::Profile(ID, Context, Template, FlattenedArgs); - + ConstraintSatisfaction::Profile(ID, Context, Template, TemplateArgs); void *InsertPos; if (auto *Cached = SatisfactionCache.FindNodeOrInsertPos(ID, InsertPos)) { OutSatisfaction = *Cached; return false; } auto Satisfaction = - std::make_unique(Template, FlattenedArgs); + std::make_unique(Template, TemplateArgs); if (::CheckConstraintSatisfaction(*this, Template, ConstraintExprs, - ConvertedConstraints, TemplateArgsList, - TemplateIDRange, *Satisfaction)) { + TemplateArgs, TemplateIDRange, + *Satisfaction)) { return true; } OutSatisfaction = *Satisfaction; @@ -400,111 +347,20 @@ bool Sema::CheckConstraintSatisfaction( bool Sema::CheckConstraintSatisfaction(const Expr *ConstraintExpr, ConstraintSatisfaction &Satisfaction) { return calculateConstraintSatisfaction( - *this, ConstraintExpr, Satisfaction, - [](const Expr *AtomicExpr) -> ExprResult { - return ExprResult(const_cast(AtomicExpr)); - }) - .isInvalid(); -} - -bool Sema::SetupConstraintScope( - FunctionDecl *FD, llvm::Optional> TemplateArgs, - MultiLevelTemplateArgumentList MLTAL, LocalInstantiationScope &Scope) { - if (FD->isTemplateInstantiation() && FD->getPrimaryTemplate()) { - FunctionTemplateDecl *PrimaryTemplate = FD->getPrimaryTemplate(); - InstantiatingTemplate Inst( - *this, FD->getPointOfInstantiation(), - Sema::InstantiatingTemplate::ConstraintsCheck{}, PrimaryTemplate, - TemplateArgs ? *TemplateArgs : ArrayRef{}, - SourceRange()); - if (Inst.isInvalid()) - return true; - - // addInstantiatedParametersToScope creates a map of 'uninstantiated' to - // 'instantiated' parameters and adds it to the context. For the case where - // this function is a template being instantiated NOW, we also need to add - // the list of current template arguments to the list so that they also can - // be picked out of the map. - if (auto *SpecArgs = FD->getTemplateSpecializationArgs()) { - MultiLevelTemplateArgumentList JustTemplArgs(*SpecArgs); - if (addInstantiatedParametersToScope( - FD, PrimaryTemplate->getTemplatedDecl(), Scope, JustTemplArgs)) - return true; - } - - // If this is a member function, make sure we get the parameters that - // reference the original primary template. - if (const auto *FromMemTempl = - PrimaryTemplate->getInstantiatedFromMemberTemplate()) { - if (addInstantiatedParametersToScope(FD, FromMemTempl->getTemplatedDecl(), - Scope, MLTAL)) - return true; - } - } else if (FD->getTemplatedKind() == FunctionDecl::TK_MemberSpecialization || - FD->getTemplatedKind() == FunctionDecl::TK_DependentNonTemplate) { - FunctionDecl *InstantiatedFrom = - FD->getTemplatedKind() == FunctionDecl::TK_MemberSpecialization - ? FD->getInstantiatedFromMemberFunction() - : FD->getInstantiatedFromDecl(); - - InstantiatingTemplate Inst( - *this, FD->getPointOfInstantiation(), - Sema::InstantiatingTemplate::ConstraintsCheck{}, InstantiatedFrom, - TemplateArgs ? *TemplateArgs : ArrayRef{}, - SourceRange()); - if (Inst.isInvalid()) - return true; - - // Case where this was not a template, but instantiated as a child-function. - if (addInstantiatedParametersToScope(FD, InstantiatedFrom, Scope, MLTAL)) - return true; - } - - return false; -} - -// This function collects all of the template arguments for the purposes of -// constraint-instantiation and checking. -llvm::Optional -Sema::SetupConstraintCheckingTemplateArgumentsAndScope( - FunctionDecl *FD, llvm::Optional> TemplateArgs, - LocalInstantiationScope &Scope) { - MultiLevelTemplateArgumentList MLTAL; - - // Collect the list of template arguments relative to the 'primary' template. - // We need the entire list, since the constraint is completely uninstantiated - // at this point. - MLTAL = getTemplateInstantiationArgs(FD, nullptr, /*RelativeToPrimary*/ true, - /*Pattern*/ nullptr, - /*LookBeyondLambda*/ true); - if (SetupConstraintScope(FD, TemplateArgs, MLTAL, Scope)) - return {}; - - return MLTAL; + *this, ConstraintExpr, Satisfaction, + [](const Expr *AtomicExpr) -> ExprResult { + return ExprResult(const_cast(AtomicExpr)); + }); } bool Sema::CheckFunctionConstraints(const FunctionDecl *FD, ConstraintSatisfaction &Satisfaction, SourceLocation UsageLoc) { - // Don't check constraints if the function is dependent. Also don't check if - // this is a function template specialization, as the call to - // CheckinstantiatedFunctionTemplateConstraints after this will check it - // better. - if (FD->isDependentContext() || - FD->getTemplatedKind() == - FunctionDecl::TK_FunctionTemplateSpecialization) { + const Expr *RC = FD->getTrailingRequiresClause(); + if (RC->isInstantiationDependent()) { Satisfaction.IsSatisfied = true; return false; } - - ContextRAII SavedContext{ - *this, cast( - const_cast(FD)->getNonClosureContext())}; - LocalInstantiationScope Scope(*this, true); - llvm::Optional MLTAL = - SetupConstraintCheckingTemplateArgumentsAndScope( - const_cast(FD), {}, Scope); - Qualifiers ThisQuals; CXXRecordDecl *Record = nullptr; if (auto *Method = dyn_cast(FD)) { @@ -515,27 +371,14 @@ bool Sema::CheckFunctionConstraints(const FunctionDecl *FD, // We substitute with empty arguments in order to rebuild the atomic // constraint in a constant-evaluated context. // FIXME: Should this be a dedicated TreeTransform? - const Expr *RC = FD->getTrailingRequiresClause(); - llvm::SmallVector Converted; - - if (CheckConstraintSatisfaction( - FD, {RC}, Converted, *MLTAL, - SourceRange(UsageLoc.isValid() ? UsageLoc : FD->getLocation()), - Satisfaction)) - return true; - - // FIXME: we need to do this for the function constraints for - // comparison of constraints to work, but do we also need to do it for - // CheckInstantiatedFunctionConstraints? That one is more difficult, but we - // seem to always just pick up the constraints from the primary template. - assert(Converted.size() <= 1 && "Got more expressions converted?"); - if (!Converted.empty() && Converted[0] != nullptr) - const_cast(FD)->setTrailingRequiresClause(Converted[0]); - return false; + return CheckConstraintSatisfaction( + FD, {RC}, /*TemplateArgs=*/{}, + SourceRange(UsageLoc.isValid() ? UsageLoc : FD->getLocation()), + Satisfaction); } bool Sema::EnsureTemplateArgumentListConstraints( - TemplateDecl *TD, MultiLevelTemplateArgumentList TemplateArgs, + TemplateDecl *TD, ArrayRef TemplateArgs, SourceRange TemplateIDRange) { ConstraintSatisfaction Satisfaction; llvm::SmallVector AssociatedConstraints; @@ -548,8 +391,7 @@ bool Sema::EnsureTemplateArgumentListConstraints( SmallString<128> TemplateArgString; TemplateArgString = " "; TemplateArgString += getTemplateArgumentBindingsText( - TD->getTemplateParameters(), TemplateArgs.getInnermost().data(), - TemplateArgs.getInnermost().size()); + TD->getTemplateParameters(), TemplateArgs.data(), TemplateArgs.size()); Diag(TemplateIDRange.getBegin(), diag::err_template_arg_list_constraints_not_satisfied) @@ -581,13 +423,21 @@ bool Sema::CheckInstantiatedFunctionTemplateConstraints( Sema::ContextRAII savedContext(*this, Decl); LocalInstantiationScope Scope(*this); - Optional MLTAL = - SetupConstraintCheckingTemplateArgumentsAndScope(Decl, TemplateArgs, - Scope); - - if (!MLTAL) - return true; - + // If this is not an explicit specialization - we need to get the instantiated + // version of the template arguments and add them to scope for the + // substitution. + if (Decl->isTemplateInstantiation()) { + InstantiatingTemplate Inst(*this, Decl->getPointOfInstantiation(), + InstantiatingTemplate::ConstraintsCheck{}, Decl->getPrimaryTemplate(), + TemplateArgs, SourceRange()); + if (Inst.isInvalid()) + return true; + MultiLevelTemplateArgumentList MLTAL( + *Decl->getTemplateSpecializationArgs()); + if (addInstantiatedParametersToScope( + Decl, Decl->getPrimaryTemplate()->getTemplatedDecl(), Scope, MLTAL)) + return true; + } Qualifiers ThisQuals; CXXRecordDecl *Record = nullptr; if (auto *Method = dyn_cast(Decl)) { @@ -595,8 +445,7 @@ bool Sema::CheckInstantiatedFunctionTemplateConstraints( Record = Method->getParent(); } CXXThisScopeRAII ThisScope(*this, Record, ThisQuals, Record != nullptr); - llvm::SmallVector Converted; - return CheckConstraintSatisfaction(Template, TemplateAC, Converted, *MLTAL, + return CheckConstraintSatisfaction(Template, TemplateAC, TemplateArgs, PointOfInstantiation, Satisfaction); } diff --git a/clang/lib/Sema/SemaOverload.cpp b/clang/lib/Sema/SemaOverload.cpp index 4db70aa..6e45fdf 100644 --- a/clang/lib/Sema/SemaOverload.cpp +++ b/clang/lib/Sema/SemaOverload.cpp @@ -992,82 +992,6 @@ static bool checkArgPlaceholdersForOverload(Sema &S, MultiExprArg Args, return false; } -static bool FriendMembersDifferByConstraints(Sema &S, DeclContext *CurContext, - FunctionDecl *Old, - FunctionDecl *New) { - // Only necessary/valid if we're instantiating a - // ClassTemplateSpecializationDecl. - if (CurContext->getDeclKind() != Decl::ClassTemplateSpecialization) - return false; - - // Only when we're dealing with a friend function. - if (!Old->getFriendObjectKind() || !New->getFriendObjectKind()) - return false; - - // If the the two functions share lexical declaration context, they are not in - // separate instantations. - if (New->getLexicalDeclContext() == Old->getLexicalDeclContext()) - return false; - - auto *OldLexCtx = - dyn_cast(Old->getLexicalDeclContext()); - auto *NewLexCtx = - dyn_cast(New->getLexicalDeclContext()); - - if (!OldLexCtx || !NewLexCtx) - return false; - - auto InitAssocConstrs = [](FunctionDecl *FD, - SmallVectorImpl &AC) { - if (const auto *FT = FD->getDescribedFunctionTemplate()) - FT->getAssociatedConstraints(AC); - else - FD->getAssociatedConstraints(AC); - }; - SmallVector OldAC; - SmallVector NewAC; - InitAssocConstrs(Old, OldAC); - InitAssocConstrs(New, NewAC); - - assert(OldAC.size() == NewAC.size() && - "Should not have been identical unless constraints were the same?"); - - // At this point, we know the constraints lists should be the same. - auto *OldBegin = OldAC.begin(); - auto *NewBegin = NewAC.begin(); - - auto SubstConstraint = [](Sema &S, ClassTemplateSpecializationDecl *LexCtx, - const Expr *Constraint) { - Sema::ContextRAII SavedContext(S, LexCtx); - LocalInstantiationScope Scope(S); - EnterExpressionEvaluationContext EvalCtx( - S, Sema::ExpressionEvaluationContext::PotentiallyEvaluated); - Sema::SFINAETrap Trap(S); - return S.SubstConstraintExpr(const_cast(Constraint), - S.getTemplateInstantiationArgs(LexCtx)); - }; - - for (; OldBegin != OldAC.end(); ++OldBegin, ++NewBegin) { - ExprResult OldConverted = SubstConstraint(S, OldLexCtx, *OldBegin); - ExprResult NewConverted = SubstConstraint(S, NewLexCtx, *NewBegin); - - // We can consider these different, since they depend on the instantiation, - // and cannot prove they are identical. - if (OldConverted.isInvalid() || NewConverted.isInvalid()) - return true; - - // profile & compare. If they are now different, they aren't equal. - llvm::FoldingSetNodeID NewID, OldID; - NewConverted.get()->Profile(NewID, S.getASTContext(), /*Canonical=*/true); - OldConverted.get()->Profile(OldID, S.getASTContext(), /*Canonical=*/true); - if (NewID != OldID) - return true; - } - - // If we haven't found a differing constraint, these are the same. - return false; -} - /// Determine whether the given New declaration is an overload of the /// declarations in Old. This routine returns Ovl_Match or Ovl_NonFunction if /// New and Old cannot be overloaded, e.g., if New has the same signature as @@ -1144,20 +1068,6 @@ Sema::CheckOverload(Scope *S, FunctionDecl *New, const LookupResult &Old, !shouldLinkPossiblyHiddenDecl(*I, New)) continue; - // If this is a friend function currently being instantiated as a part - // of a ClassTemplateSpecializationDecl, it could have - // otherwise-identical-looking constraints that depend on the current - // instantiation. In this case, if the otherwise apparent 'match' and - // the new declaration differ by lexical declaration context (meaning - // different Class Template Specializations), AND one of the collected - // constraints seems to 'depend' on the current instantiation in some - // way, than these are not matches and are likely instead overloads. - // Note that an 'error' case might still be valid later (as it could be - // something that would be 'changed' at 'checking' time), but is proof - // we depend on the Class Template Specialization. - if (FriendMembersDifferByConstraints(*this, CurContext, OldF, New)) - continue; - Match = *I; return Ovl_Match; } diff --git a/clang/lib/Sema/SemaTemplate.cpp b/clang/lib/Sema/SemaTemplate.cpp index 34e1352..4a42969 100644 --- a/clang/lib/Sema/SemaTemplate.cpp +++ b/clang/lib/Sema/SemaTemplate.cpp @@ -4702,11 +4702,9 @@ Sema::CheckConceptTemplateId(const CXXScopeSpec &SS, bool AreArgsDependent = TemplateSpecializationType::anyDependentTemplateArguments(*TemplateArgs, Converted); - MultiLevelTemplateArgumentList MLTAL; - MLTAL.addOuterTemplateArguments(Converted); if (!AreArgsDependent && CheckConstraintSatisfaction( - NamedConcept, {NamedConcept->getConstraintExpr()}, MLTAL, + NamedConcept, {NamedConcept->getConstraintExpr()}, Converted, SourceRange(SS.isSet() ? SS.getBeginLoc() : ConceptNameInfo.getLoc(), TemplateArgs->getRAngleLoc()), Satisfaction)) @@ -5566,7 +5564,6 @@ bool Sema::CheckTemplateArgument(NamedDecl *Param, if (Inst.isInvalid()) return true; - ConstraintEvalRAII EvalRAII(*this); TemplateArgumentList TemplateArgs(TemplateArgumentList::OnStack, Converted); Params = SubstTemplateParams(Params, CurContext, MultiLevelTemplateArgumentList(TemplateArgs)); @@ -5924,20 +5921,13 @@ bool Sema::CheckTemplateArgumentList( if (UpdateArgsWithConversions) TemplateArgs = std::move(NewArgs); - if (!PartialTemplateArgs) { - TemplateArgumentList StackTemplateArgs(TemplateArgumentList::OnStack, - Converted); - MultiLevelTemplateArgumentList MLTAL = getTemplateInstantiationArgs( - Template, &StackTemplateArgs, /*RelativeToPrimary*/ true, - /*Pattern*/ nullptr, - /*LookBeyondLambda*/ true, /*IncludeContainingStruct*/ true); - if (EnsureTemplateArgumentListConstraints( - Template, MLTAL, - SourceRange(TemplateLoc, TemplateArgs.getRAngleLoc()))) { - if (ConstraintsNotSatisfied) - *ConstraintsNotSatisfied = true; - return true; - } + if (!PartialTemplateArgs && + EnsureTemplateArgumentListConstraints( + Template, Converted, SourceRange(TemplateLoc, + TemplateArgs.getRAngleLoc()))) { + if (ConstraintsNotSatisfied) + *ConstraintsNotSatisfied = true; + return true; } return false; @@ -7467,9 +7457,7 @@ bool Sema::CheckTemplateTemplateArgument(TemplateTemplateParmDecl *Param, // are not considered. if (ParamsAC.empty()) return false; - Template->getAssociatedConstraints(TemplateAC); - bool IsParamAtLeastAsConstrained; if (IsAtLeastAsConstrained(Param, ParamsAC, Template, TemplateAC, IsParamAtLeastAsConstrained)) diff --git a/clang/lib/Sema/SemaTemplateDeduction.cpp b/clang/lib/Sema/SemaTemplateDeduction.cpp index 4fa1395..0662dd7 100644 --- a/clang/lib/Sema/SemaTemplateDeduction.cpp +++ b/clang/lib/Sema/SemaTemplateDeduction.cpp @@ -2791,10 +2791,8 @@ CheckDeducedArgumentConstraints(Sema& S, TemplateDeclT *Template, TemplateDeductionInfo& Info) { llvm::SmallVector AssociatedConstraints; Template->getAssociatedConstraints(AssociatedConstraints); - MultiLevelTemplateArgumentList MLTAL; - MLTAL.addOuterTemplateArguments(DeducedArgs); - if (S.CheckConstraintSatisfaction(Template, AssociatedConstraints, MLTAL, - Info.getLocation(), + if (S.CheckConstraintSatisfaction(Template, AssociatedConstraints, + DeducedArgs, Info.getLocation(), Info.AssociatedConstraintsSatisfaction) || !Info.AssociatedConstraintsSatisfaction.IsSatisfied) { Info.reset(TemplateArgumentList::CreateCopy(S.Context, DeducedArgs)); @@ -4574,11 +4572,8 @@ CheckDeducedPlaceholderConstraints(Sema &S, const AutoType &Type, if (S.CheckTemplateArgumentList(Concept, SourceLocation(), TemplateArgs, /*PartialTemplateArgs=*/false, Converted)) return Sema::DAR_FailedAlreadyDiagnosed; - - MultiLevelTemplateArgumentList MLTAL; - MLTAL.addOuterTemplateArguments(Converted); if (S.CheckConstraintSatisfaction(Concept, {Concept->getConstraintExpr()}, - MLTAL, TypeLoc.getLocalSourceRange(), + Converted, TypeLoc.getLocalSourceRange(), Satisfaction)) return Sema::DAR_FailedAlreadyDiagnosed; if (!Satisfaction.IsSatisfied) { diff --git a/clang/lib/Sema/SemaTemplateInstantiate.cpp b/clang/lib/Sema/SemaTemplateInstantiate.cpp index a82ac32..4fd9d00 100644 --- a/clang/lib/Sema/SemaTemplateInstantiate.cpp +++ b/clang/lib/Sema/SemaTemplateInstantiate.cpp @@ -55,18 +55,9 @@ using namespace sema; /// instantiating the definition of the given declaration, \p D. This is /// used to determine the proper set of template instantiation arguments for /// friend function template specializations. -/// -/// \param LookBeyondLambda Indicates that this collection of arguments should -/// continue looking when it encounters a lambda generic call operator. -/// -/// \param IncludeContainingStructArgs Indicates that this collection of -/// arguments should include arguments for any class template that this -/// declaration is included inside of. - MultiLevelTemplateArgumentList Sema::getTemplateInstantiationArgs( const NamedDecl *D, const TemplateArgumentList *Innermost, - bool RelativeToPrimary, const FunctionDecl *Pattern, bool LookBeyondLambda, - bool IncludeContainingStructArgs) { + bool RelativeToPrimary, const FunctionDecl *Pattern) { // Accumulate the set of template argument lists in this structure. MultiLevelTemplateArgumentList Result; @@ -162,13 +153,11 @@ MultiLevelTemplateArgumentList Sema::getTemplateInstantiationArgs( break; // If this function is a generic lambda specialization, we are done. - if (!LookBeyondLambda && - isGenericLambdaCallOperatorOrStaticInvokerSpecialization(Function)) + if (isGenericLambdaCallOperatorOrStaticInvokerSpecialization(Function)) break; } else if (Function->getDescribedFunctionTemplate()) { - assert((IncludeContainingStructArgs || - Result.getNumSubstitutedLevels() == 0) && + assert(Result.getNumSubstitutedLevels() == 0 && "Outer template not instantiated?"); } @@ -185,18 +174,10 @@ MultiLevelTemplateArgumentList Sema::getTemplateInstantiationArgs( } } else if (const auto *Rec = dyn_cast(Ctx)) { if (ClassTemplateDecl *ClassTemplate = Rec->getDescribedClassTemplate()) { - assert((IncludeContainingStructArgs || - Result.getNumSubstitutedLevels() == 0) && + assert(Result.getNumSubstitutedLevels() == 0 && "Outer template not instantiated?"); if (ClassTemplate->isMemberSpecialization()) break; - if (IncludeContainingStructArgs) { - QualType RecordType = Context.getTypeDeclType(Rec); - QualType Injected = cast(RecordType) - ->getInjectedSpecializationType(); - const auto *InjectedType = cast(Injected); - Result.addOuterTemplateArguments(InjectedType->template_arguments()); - } } } @@ -2346,18 +2327,6 @@ bool Sema::SubstTypeConstraint( const MultiLevelTemplateArgumentList &TemplateArgs) { const ASTTemplateArgumentListInfo *TemplArgInfo = TC->getTemplateArgsAsWritten(); - - // If we're not checking a constraint, we shouldn't be instantiating the type - // constraint, so we should just create a copy of the previous one. - // TODO: ERICH: Should this be RebuildExprInCurrentInstantiation here? - if (!IsEvaluatingAConstraint()) { - Inst->setTypeConstraint(TC->getNestedNameSpecifierLoc(), - TC->getConceptNameInfo(), TC->getNamedConcept(), - TC->getNamedConcept(), TemplArgInfo, - TC->getImmediatelyDeclaredConstraint()); - return false; - } - TemplateArgumentListInfo InstArgs; if (TemplArgInfo) { @@ -3542,14 +3511,6 @@ Sema::SubstExpr(Expr *E, const MultiLevelTemplateArgumentList &TemplateArgs) { return Instantiator.TransformExpr(E); } -ExprResult -Sema::SubstConstraintExpr(Expr *E, - const MultiLevelTemplateArgumentList &TemplateArgs) { - - ConstraintEvalRAII EvalRAII(*this); - return SubstExpr(E, TemplateArgs); -} - ExprResult Sema::SubstInitializer(Expr *Init, const MultiLevelTemplateArgumentList &TemplateArgs, bool CXXDirectInit) { diff --git a/clang/lib/Sema/SemaTemplateInstantiateDecl.cpp b/clang/lib/Sema/SemaTemplateInstantiateDecl.cpp index e3460d5..77c5677 100644 --- a/clang/lib/Sema/SemaTemplateInstantiateDecl.cpp +++ b/clang/lib/Sema/SemaTemplateInstantiateDecl.cpp @@ -2062,7 +2062,19 @@ Decl *TemplateDeclInstantiator::VisitFunctionDecl( return nullptr; } + // FIXME: Concepts: Do not substitute into constraint expressions Expr *TrailingRequiresClause = D->getTrailingRequiresClause(); + if (TrailingRequiresClause) { + EnterExpressionEvaluationContext ConstantEvaluated( + SemaRef, Sema::ExpressionEvaluationContext::Unevaluated); + ExprResult SubstRC = SemaRef.SubstExpr(TrailingRequiresClause, + TemplateArgs); + if (SubstRC.isInvalid()) + return nullptr; + TrailingRequiresClause = SubstRC.get(); + if (!SemaRef.CheckConstraintExpression(TrailingRequiresClause)) + return nullptr; + } // If we're instantiating a local function declaration, put the result // in the enclosing namespace; otherwise we need to find the instantiated @@ -2170,11 +2182,6 @@ Decl *TemplateDeclInstantiator::VisitFunctionDecl( // definition. We don't want non-template functions to be marked as being // template instantiations. Function->setInstantiationOfMemberFunction(D, TSK_ImplicitInstantiation); - } else if (!isFriend) { - // If this is not a function template, and this is not a friend (that is, - // this is a locally declared function), save the instantiation relationship - // for the purposes of constraint instantiation. - Function->setInstantiatedFromDecl(D); } if (isFriend) { @@ -2413,6 +2420,23 @@ Decl *TemplateDeclInstantiator::VisitCXXMethodDecl( return nullptr; } + // FIXME: Concepts: Do not substitute into constraint expressions + Expr *TrailingRequiresClause = D->getTrailingRequiresClause(); + if (TrailingRequiresClause) { + EnterExpressionEvaluationContext ConstantEvaluated( + SemaRef, Sema::ExpressionEvaluationContext::Unevaluated); + auto *ThisContext = dyn_cast_or_null(Owner); + Sema::CXXThisScopeRAII ThisScope(SemaRef, ThisContext, + D->getMethodQualifiers(), ThisContext); + ExprResult SubstRC = SemaRef.SubstExpr(TrailingRequiresClause, + TemplateArgs); + if (SubstRC.isInvalid()) + return nullptr; + TrailingRequiresClause = SubstRC.get(); + if (!SemaRef.CheckConstraintExpression(TrailingRequiresClause)) + return nullptr; + } + DeclContext *DC = Owner; if (isFriend) { if (QualifierLoc) { @@ -2430,9 +2454,6 @@ Decl *TemplateDeclInstantiator::VisitCXXMethodDecl( if (!DC) return nullptr; } - CXXRecordDecl *Record = cast(DC); - Expr *TrailingRequiresClause = D->getTrailingRequiresClause(); - DeclarationNameInfo NameInfo = SemaRef.SubstDeclarationNameInfo(D->getNameInfo(), TemplateArgs); @@ -2440,6 +2461,7 @@ Decl *TemplateDeclInstantiator::VisitCXXMethodDecl( adjustForRewrite(FunctionRewriteKind, D, T, TInfo, NameInfo); // Build the instantiated method declaration. + CXXRecordDecl *Record = cast(DC); CXXMethodDecl *Method = nullptr; SourceLocation StartLoc = D->getInnerLocStart(); @@ -2746,6 +2768,9 @@ Decl *TemplateDeclInstantiator::VisitTemplateTypeParmDecl( // Invented template parameter type constraints will be instantiated with // the corresponding auto-typed parameter as it might reference other // parameters. + + // TODO: Concepts: do not instantiate the constraint (delayed constraint + // substitution) if (SemaRef.SubstTypeConstraint(Inst, TC, TemplateArgs)) return nullptr; } @@ -3988,7 +4013,18 @@ TemplateDeclInstantiator::SubstTemplateParams(TemplateParameterList *L) { if (Invalid) return nullptr; - Expr *InstRequiresClause = L->getRequiresClause(); + // FIXME: Concepts: Substitution into requires clause should only happen when + // checking satisfaction. + Expr *InstRequiresClause = nullptr; + if (Expr *E = L->getRequiresClause()) { + EnterExpressionEvaluationContext ConstantEvaluated( + SemaRef, Sema::ExpressionEvaluationContext::Unevaluated); + ExprResult Res = SemaRef.SubstExpr(E, TemplateArgs); + if (Res.isInvalid() || !Res.isUsable()) { + return nullptr; + } + InstRequiresClause = Res.get(); + } TemplateParameterList *InstL = TemplateParameterList::Create(SemaRef.Context, L->getTemplateLoc(), diff --git a/clang/lib/Sema/TreeTransform.h b/clang/lib/Sema/TreeTransform.h index 2717e4a..aef757e 100644 --- a/clang/lib/Sema/TreeTransform.h +++ b/clang/lib/Sema/TreeTransform.h @@ -12997,6 +12997,13 @@ TreeTransform::TransformLambdaExpr(LambdaExpr *E) { NewCallOpType); } + // Transform the trailing requires clause + ExprResult NewTrailingRequiresClause; + if (Expr *TRC = E->getCallOperator()->getTrailingRequiresClause()) + // FIXME: Concepts: Substitution into requires clause should only happen + // when checking satisfaction. + NewTrailingRequiresClause = getDerived().TransformExpr(TRC); + // Create the local class that will describe the lambda. // FIXME: DependencyKind below is wrong when substituting inside a templated @@ -13031,7 +13038,7 @@ TreeTransform::TransformLambdaExpr(LambdaExpr *E) { E->getCallOperator()->getEndLoc(), NewCallOpTSI->getTypeLoc().castAs().getParams(), E->getCallOperator()->getConstexprKind(), - E->getCallOperator()->getTrailingRequiresClause()); + NewTrailingRequiresClause.get()); LSI->CallOperator = NewCallOperator; diff --git a/clang/lib/Serialization/ASTReaderDecl.cpp b/clang/lib/Serialization/ASTReaderDecl.cpp index 4b9c83b..86a9c77 100644 --- a/clang/lib/Serialization/ASTReaderDecl.cpp +++ b/clang/lib/Serialization/ASTReaderDecl.cpp @@ -941,10 +941,6 @@ void ASTDeclReader::VisitFunctionDecl(FunctionDecl *FD) { case FunctionDecl::TK_NonTemplate: mergeRedeclarable(FD, Redecl); break; - case FunctionDecl::TK_DependentNonTemplate: - mergeRedeclarable(FD, Redecl); - FD->setInstantiatedFromDecl(readDeclAs()); - break; case FunctionDecl::TK_FunctionTemplate: // Merged when we merge the template. FD->setDescribedFunctionTemplate(readDeclAs()); diff --git a/clang/lib/Serialization/ASTWriterDecl.cpp b/clang/lib/Serialization/ASTWriterDecl.cpp index 49401c1..3666d5a 100644 --- a/clang/lib/Serialization/ASTWriterDecl.cpp +++ b/clang/lib/Serialization/ASTWriterDecl.cpp @@ -585,9 +585,6 @@ void ASTDeclWriter::VisitFunctionDecl(FunctionDecl *D) { switch (D->getTemplatedKind()) { case FunctionDecl::TK_NonTemplate: break; - case FunctionDecl::TK_DependentNonTemplate: - Record.AddDeclRef(D->getInstantiatedFromDecl()); - break; case FunctionDecl::TK_FunctionTemplate: Record.AddDeclRef(D->getDescribedFunctionTemplate()); break; diff --git a/clang/test/CXX/temp/temp.constr/temp.constr.constr/non-function-templates.cpp b/clang/test/CXX/temp/temp.constr/temp.constr.constr/non-function-templates.cpp index 15e00e4..dd6bfe8 100644 --- a/clang/test/CXX/temp/temp.constr/temp.constr.constr/non-function-templates.cpp +++ b/clang/test/CXX/temp/temp.constr/temp.constr.constr/non-function-templates.cpp @@ -90,24 +90,3 @@ struct D { }; static_assert(C{}); // expected-note{{while checking constraint satisfaction for template 'C' required here}} static_assert(D{}); // expected-note{{while checking constraint satisfaction for template 'D' required here}} - -// Test the delayed instantiation, the 'foo' implementation shouldn't cause the -// constraint failure(or crash!) until the use to create 'y'. -namespace DelayedInst { -template -struct AAA { - template - requires(sizeof(T) == I) // expected-note {{because 'sizeof(int) == 5U' (4 == 5) evaluated to false}} - struct B { - static constexpr int a = 0; - }; - - static constexpr auto foo() { - return B::a; // expected-error{{constraints not satisfied for class template 'B' [with T = int]}} - } -}; - -constexpr auto x = AAA<4>::foo(); -constexpr auto y = AAA<5>::foo(); // expected-note {{in instantiation of member function 'DelayedInst::AAA<5>::foo' requested here}} - -} // namespace DelayedInst diff --git a/clang/test/SemaTemplate/concepts.cpp b/clang/test/SemaTemplate/concepts.cpp index 8b3ca7f..23c7942 100644 --- a/clang/test/SemaTemplate/concepts.cpp +++ b/clang/test/SemaTemplate/concepts.cpp @@ -256,447 +256,3 @@ C auto **j1 = g(); // expected-error {{deduced type 'int' does not satisfy 'C' C auto **&j2 = g(); // expected-error {{deduced type 'int' does not satisfy 'C'}} C auto **&&j3 = g(); // expected-error {{deduced type 'int' does not satisfy 'C'}} } - -namespace DeferredInstantiationInstScope { -template -struct remove_ref { - using type = T; -}; -template -struct remove_ref { - using type = T; -}; -template -struct remove_ref { - using type = T; -}; - -template -constexpr bool IsInt = PR54443::is_same::type, - int>::value; - -template -void SingleDepthReferencesTop(U &&u) { - struct lc { - void operator()() // #SDRT_OP - requires IsInt // #SDRT_REQ - {} - }; - lc lv; - lv(); // #SDRT_CALL -} - -template -void SingleDepthReferencesTopNotCalled(U &&u) { - struct lc { - void operator()() - requires IsInt - {} - }; - lc lv; -} - -template -void SingleDepthReferencesTopCalled(U &&u) { - struct lc { - void operator()() // #CALLOP - requires IsInt // #CONSTR - {} - }; - lc lv; - lv(); - // expected-error@-1{{no matching function for call to object of type 'lc'}} - // expected-note@#SDRTC{{in instantiation of function template}} - // expected-note@#CALLOP{{constraints not satisfied}} - // expected-note@#CONSTR{{substituted constraint expression is ill-formed}} -} - -template -void SingleDepthReferencesTopLambda(U &&u) { - []() - requires IsInt - {}(); -} - -template -void DoubleDepthReferencesTop(U &&u) { - struct lc { // #DDRT_STRCT - void operator()() { - struct lc2 { - void operator()() // #DDRT_OP - requires IsInt // #DDRT_REQ - {} - }; - lc2 lv2; - lv2(); // #DDRT_CALL - } - }; - lc lv; - lv(); -} - -template -void DoubleDepthReferencesTopLambda(U &&u) { - []() { []() - requires IsInt - {}(); }(); -} - -template -void DoubleDepthReferencesAll(U &&u) { - struct lc { // #DDRA_STRCT - void operator()(U &&u2) { - struct lc2 { - void operator()(U &&u3) // #DDRA_OP - requires IsInt && // #DDRA_REQ - IsInt && IsInt - {} - }; - lc2 lv2; - lv2(u2); // #DDRA_CALL - } - }; - lc lv; - lv(u); -} - -template -void DoubleDepthReferencesAllLambda(U &&u) { - [](U &&u2) { - [](U && u3) - requires IsInt && - IsInt && IsInt - {}(u2); - }(u); -} - -template -void HasInnerFunc(U &&u) { - void InnerFunc(U && u2) - requires IsInt && // #INNERFUNC_REQ - IsInt; - InnerFunc(u); // #INNERFUNC_CALL -} - -template -struct CausesFriendConstraint { - template - friend void FriendFunc(CausesFriendConstraint, V) // #FF_DECL - requires IsInt && - IsInt // #FF_REQ - {} -}; -// FIXME: Re-enable this test when constraints are allowed to refer to captures. -// template -// void ChecksCapture(T x) { -// [y = x]() requires(IsInt){}(); -// } - -template -void ChecksLocalVar(T x) { - T Local; - []() - requires(IsInt) - {}(); -} - -template -void LocalStructMemberVar(T x) { - struct S { - T local; - void foo() - requires(IsInt) // #LSMV_REQ - {} - } s; - s.foo(); // #LSMV_CALL -}; - -template -struct ChecksMemberVar { - T t; - void foo() - requires(IsInt) // #CMV_FOO - {} - template - void foo2() // #CMV_FOO2 - requires(IsInt) // #CMV_FOO2_REQ - {} -}; - -void test_dependent() { - int v = 0; - float will_fail; - SingleDepthReferencesTop(v); - SingleDepthReferencesTop(will_fail); - // expected-error@#SDRT_CALL{{no matching function for call to object of type 'lc'}} - // expected-note@-2{{in instantiation of function template specialization}} - // expected-note@#SDRT_OP{{candidate function not viable}} - // expected-note@#SDRT_REQ{{'IsInt' evaluated to false}} - - SingleDepthReferencesTopNotCalled(v); - // Won't error unless we try to call it. - SingleDepthReferencesTopNotCalled(will_fail); - SingleDepthReferencesTopCalled(v); // #SDRTC - SingleDepthReferencesTopLambda(v); - // FIXME: This should error on constraint failure! (Lambda!) - SingleDepthReferencesTopLambda(will_fail); - DoubleDepthReferencesTop(v); - DoubleDepthReferencesTop(will_fail); - // expected-error@#DDRT_CALL{{no matching function for call to object of type 'lc2'}} - // expected-note@-2{{in instantiation of function template specialization}} - // expected-note@#DDRT_STRCT{{in instantiation of member function}} - // expected-note@#DDRT_OP{{candidate function not viable}} - // expected-note@#DDRT_REQ{{'IsInt' evaluated to false}} - - DoubleDepthReferencesTopLambda(v); - // FIXME: This should error on constraint failure! (Lambda!) - DoubleDepthReferencesTopLambda(will_fail); - DoubleDepthReferencesAll(v); - DoubleDepthReferencesAll(will_fail); - // expected-error@#DDRA_CALL{{no matching function for call to object of type 'lc2'}} - // expected-note@-2{{in instantiation of function template specialization}} - // expected-note@#DDRA_STRCT{{in instantiation of member function}} - // expected-note@#DDRA_OP{{candidate function not viable}} - // expected-note@#DDRA_REQ{{'IsInt' evaluated to false}} - - DoubleDepthReferencesAllLambda(v); - // FIXME: This should error on constraint failure! (Lambda!) - DoubleDepthReferencesAllLambda(will_fail); - HasInnerFunc(v); - HasInnerFunc(will_fail); - // expected-error@#INNERFUNC_CALL{{invalid reference to function 'InnerFunc': constraints not satisfied}} - // expected-note@-2{{in instantiation of function template specialization}} - // expected-note@#INNERFUNC_REQ{{'IsInt' evaluated to false}} - - CausesFriendConstraint CFC; - FriendFunc(CFC, 1); - FriendFunc(CFC, 1.0); - // expected-error@-1{{no matching function for call to 'FriendFunc'}} - // expected-note@#FF_DECL{{constraints not satisfied}} - // expected-note@#FF_REQ{{because 'IsInt' evaluated to false}} - - // FIXME: Re-enable this test when constraints are allowed to refer to captures. - // ChecksCapture(v); - - ChecksLocalVar(v); - // FIXME: This should error on constraint failure! (Lambda!) - ChecksLocalVar(will_fail); - - LocalStructMemberVar(v); - LocalStructMemberVar(will_fail); - // expected-error@#LSMV_CALL{{invalid reference to function 'foo'}} - // expected-note@-2{{in instantiation of function template specialization}} - // expected-note@#LSMV_REQ{{because 'IsIntlocal)>' evaluated to false}} - - ChecksMemberVar CMV; - CMV.foo(); - CMV.foo2(); - - ChecksMemberVar CMV2; - CMV2.foo(); - // expected-error@-1{{invalid reference to function 'foo'}} - // expected-note@#CMV_FOO{{because 'IsIntt)>' evaluated to false}} - CMV2.foo2(); - // expected-error@-1{{no matching member function for call to 'foo2'}} - // expected-note@#CMV_FOO2{{constraints not satisfied}} - // expected-note@#CMV_FOO2_REQ{{because 'IsIntt)>' evaluated to false}} -} -} // namespace DeferredInstantiationInstScope - -namespace LibCXXOperatorRedef { -template struct is_same { - static constexpr bool value = false; -}; -template struct is_same { - static constexpr bool value = false; -}; - -template -concept same_as = is_same::value; - -// An issue found from libcxx when trying to commit the deferred concepts patch. -// This caused an error of 'redefinition of funcN'. -template struct __range_adaptor_closure { - template - requires same_as<_Tp, _Closure> - friend constexpr decltype(auto) R1func1(_View &&__view, - _Closure &&__closure){}; - template - friend constexpr decltype(auto) R1func2(_View &&__view, - _Closure &&__closure) - requires same_as<_Tp, _Closure> - {}; - template _View, typename _Closure> - friend constexpr decltype(auto) R1func3(_View &&__view, - _Closure &&__closure) - {}; -}; - -struct A : __range_adaptor_closure {}; -struct B : __range_adaptor_closure {}; - -// These three fail because after the 1st pass of instantiation, they are still -// identical. -template struct __range_adaptor_closure2 { - template - requires same_as<_View, _Closure> - friend constexpr decltype(auto) R2func1(_View &&__view, // #FUNC1 - _Closure &&__closure){}; - template - friend constexpr decltype(auto) R2func2(_View &&__view, // #FUNC2 - _Closure &&__closure) - requires same_as<_View, _Closure> - {}; - template _Closure> - friend constexpr decltype(auto) R2func3(_View &&__view, // #FUNC3 - _Closure &&__closure){}; -}; - -struct A2 : __range_adaptor_closure2 {}; -struct B2 : __range_adaptor_closure2 {}; -// expected-error@#FUNC1{{redefinition of 'R2func1'}} -// expected-note@-2{{in instantiation of template class}} -// expected-note@#FUNC1{{previous definition is here}} -// expected-error@#FUNC2{{redefinition of 'R2func2'}} -// expected-note@#FUNC2{{previous definition is here}} -// expected-error@#FUNC3{{redefinition of 'R2func3'}} -// expected-note@#FUNC3{{previous definition is here}} - -// These three are fine, they all depend on the parent template parameter, so -// are different despite ::type not being valid. -template struct __range_adaptor_closure3 { - template - requires same_as - friend constexpr decltype(auto) R3func1(_View &&__view, - _Closure &&__closure){}; - template - friend constexpr decltype(auto) R3func2(_View &&__view, - _Closure &&__closure) - requires same_as - {}; - template _View, typename _Closure> - friend constexpr decltype(auto) R3func3(_View &&__view, - _Closure &&__closure) - {}; -}; - -struct A3 : __range_adaptor_closure3 {}; -struct B3 : __range_adaptor_closure3 {}; - -template struct __range_adaptor_closure4 { - template - requires same_as<_Tp, _View> - // expected-note@+1{{previous definition is here}} - void foo1(_View &&, _Closure &&) {} - template - requires same_as<_Tp, _View> - // expected-error@+1{{class member cannot be redeclared}} - void foo1(_View &&, _Closure &&) {} - - template - // expected-note@+1{{previous definition is here}} - void foo2(_View &&, _Closure &&) - requires same_as<_Tp, _View> - {} - template - // expected-error@+1{{class member cannot be redeclared}} - void foo2(_View &&, _Closure &&) - requires same_as<_Tp, _View> - {} - - template _View, typename _Closure> - // expected-note@+1{{previous definition is here}} - void foo3(_View &&, _Closure &&) - {} - template _View, typename _Closure> - // expected-error@+1{{class member cannot be redeclared}} - void foo3(_View &&, _Closure &&) - {} -}; - -// Requires instantiation to fail, so no errors here. -template struct __range_adaptor_closure5 { - template U> - friend void foo(){} - template U> - friend void foo(){} -}; - -template struct __range_adaptor_closure6 { - template U> - friend void foo(){} // #RAC6FOO1 - template U> - friend void foo(){} // #RAC6FOO2 -}; -struct A6 : __range_adaptor_closure6 {}; -//expected-error@#RAC6FOO2{{redefinition of 'foo'}} -//expected-note@-2{{in instantiation of template class}} -//expected-note@#RAC6FOO1{{previous definition is here}} - -template struct S1 { - template - friend void dupe(){} // #S1DUPE - - template - requires same_as - friend void dupe2(){} // #S1DUPE2 -}; -template struct S2 { - template - friend void dupe(){} // #S2DUPE - - template - requires same_as - friend void dupe2(){} // #S2DUPE2 -}; - -template struct S3 { - template - requires same_as - friend void dupe(){} // #S3DUPE -}; -template struct S4 { - template - requires same_as - friend void dupe(){} // #S4DUPE -}; - -// Same as S3 and S4, but aren't instantiated with the same T. -template struct S5 { - template - requires same_as - friend void not_dupe(){} -}; -template struct S6 { - template - requires same_as - friend void not_dupe(){} -}; - -template struct S7 { - void not_dupe() requires same_as{} -}; - -void useS() { - S1 s1; - S2 s2; - // expected-error@#S2DUPE{{redefinition}} - // expected-note@-2{{in instantiation of template class}} - // expected-note@#S1DUPE{{previous definition is here}} - // expected-error@#S2DUPE2{{redefinition}} - // expected-note@#S1DUPE2{{previous definition is here}} - - S3 s3; - S4 s4; - // expected-error@#S4DUPE{{redefinition}} - // expected-note@-2{{in instantiation of template class}} - // expected-note@#S3DUPE{{previous definition is here}} - - // OK, because only instantiated with different T. - S5 s5; - S6 s6; - - S7 s7; -} - -} // namespace LibCXXOperatorRedef diff --git a/clang/test/SemaTemplate/deferred-concept-inst.cpp b/clang/test/SemaTemplate/deferred-concept-inst.cpp deleted file mode 100644 index 00e8845..0000000 --- a/clang/test/SemaTemplate/deferred-concept-inst.cpp +++ /dev/null @@ -1,23 +0,0 @@ -// RUN: %clang_cc1 -std=c++2a -x c++ %s -verify -Wno-unused-value -// expected-no-diagnostics - -namespace GithubBug44178 { -template -struct CRTP { - void call_foo() - requires requires(D &v) { v.foo(); } - { - static_cast(this)->foo(); - } -}; - -struct Test : public CRTP { - void foo() {} -}; - -int main() { - Test t; - t.call_foo(); - return 0; -} -} // namespace GithubBug44178 diff --git a/clang/test/SemaTemplate/instantiate-requires-clause.cpp b/clang/test/SemaTemplate/instantiate-requires-clause.cpp index 3f438d8..73dd20d 100644 --- a/clang/test/SemaTemplate/instantiate-requires-clause.cpp +++ b/clang/test/SemaTemplate/instantiate-requires-clause.cpp @@ -1,4 +1,4 @@ -// RUN: %clang_cc1 -std=c++2a -x c++ %s -Wno-unused-value -verify +// RUN: %clang_cc1 -std=c++2a -x c++ %s -verify template requires ((sizeof(Args) == 1), ...) // expected-note@-1 {{because '(sizeof(int) == 1) , (sizeof(char) == 1) , (sizeof(int) == 1)' evaluated to false}} @@ -40,20 +40,6 @@ struct S { static_assert(S::f(1)); -// Similar to the 'S' test, but tries to use 'U' in the requires clause. -template -struct S1 { - // expected-note@+3 {{candidate template ignored: constraints not satisfied [with U = int]}} - // expected-note@+3 {{because substituted constraint expression is ill-formed: type 'int' cannot be used prior to '::' because it has no members}} - template - static constexpr auto f(U const index) - requires(U::foo) - { return true; } -}; - -// expected-error@+1 {{no matching function for call to 'f'}} -static_assert(S1::f(1)); - constexpr auto value = 0; template diff --git a/clang/test/SemaTemplate/trailing-return-short-circuit.cpp b/clang/test/SemaTemplate/trailing-return-short-circuit.cpp deleted file mode 100644 index 0d1c9b5..0000000 --- a/clang/test/SemaTemplate/trailing-return-short-circuit.cpp +++ /dev/null @@ -1,62 +0,0 @@ -// RUN: %clang_cc1 -std=c++20 -verify %s - -template - requires(sizeof(T) > 2) || T::value // #FOO_REQ -void Foo(T){}; // #FOO - -template -void TrailingReturn(T) // #TRAILING - requires(sizeof(T) > 2) || // #TRAILING_REQ - T::value // #TRAILING_REQ_VAL -{}; -template -struct HasValue { - static constexpr bool value = B; -}; -static_assert(sizeof(HasValue) <= 2); - -template -struct HasValueLarge { - static constexpr bool value = B; - int I; -}; -static_assert(sizeof(HasValueLarge) > 2); - -void usage() { - // Passes the 1st check, short-circuit so the 2nd ::value is not evaluated. - Foo(1.0); - TrailingReturn(1.0); - - // Fails the 1st check, but has a ::value, so the check happens correctly. - Foo(HasValue{}); - TrailingReturn(HasValue{}); - - // Passes the 1st check, but would have passed the 2nd one. - Foo(HasValueLarge{}); - TrailingReturn(HasValueLarge{}); - - // Fails the 1st check, fails 2nd because there is no ::value. - Foo(true); - // expected-error@-1{{no matching function for call to 'Foo'}} - // expected-note@#FOO{{candidate template ignored: constraints not satisfied [with T = bool]}} - // expected-note@#FOO_REQ{{because 'sizeof(_Bool) > 2' (1 > 2) evaluated to false}} - // expected-note@#FOO_REQ{{because substituted constraint expression is ill-formed: type 'bool' cannot be used prior to '::' because it has no members}} - - TrailingReturn(true); - // expected-error@-1{{no matching function for call to 'TrailingReturn'}} - // expected-note@#TRAILING{{candidate template ignored: constraints not satisfied [with T = bool]}} - // expected-note@#TRAILING_REQ{{because 'sizeof(_Bool) > 2' (1 > 2) evaluated to false}} - // expected-note@#TRAILING_REQ_VAL{{because substituted constraint expression is ill-formed: type 'bool' cannot be used prior to '::' because it has no members}} - - // Fails the 1st check, fails 2nd because ::value is false. - Foo(HasValue{}); - // expected-error@-1 {{no matching function for call to 'Foo'}} - // expected-note@#FOO{{candidate template ignored: constraints not satisfied [with T = HasValue]}} - // expected-note@#FOO_REQ{{because 'sizeof(HasValue) > 2' (1 > 2) evaluated to false}} - // expected-note@#FOO_REQ{{and 'HasValue::value' evaluated to false}} - TrailingReturn(HasValue{}); - // expected-error@-1 {{no matching function for call to 'TrailingReturn'}} - // expected-note@#TRAILING{{candidate template ignored: constraints not satisfied [with T = HasValue]}} - // expected-note@#TRAILING_REQ{{because 'sizeof(HasValue) > 2' (1 > 2) evaluated to false}} - // expected-note@#TRAILING_REQ_VAL{{and 'HasValue::value' evaluated to false}} -} -- 2.7.4