llvmorg-github-actions[bot] wrote:
<!--LLVM PR SUMMARY COMMENT--> @llvm/pr-subscribers-clang Author: Younan Zhang (zyn0217) <details> <summary>Changes</summary> This reverts llvm/llvm-project#<!-- -->221707 This broke std::map as reported in https://github.com/llvm/llvm-project/issues/223220 --- Patch is 24.49 KiB, truncated to 20.00 KiB below, full version: https://github.com/llvm/llvm-project/pull/223235.diff 7 Files Affected: - (modified) clang/docs/ReleaseNotes.md (-3) - (modified) clang/include/clang/Sema/Sema.h (+19-7) - (modified) clang/include/clang/Sema/Template.h (-2) - (modified) clang/lib/Sema/SemaConcept.cpp (+144-32) - (modified) clang/lib/Sema/SemaTemplateInstantiate.cpp (+35-79) - (modified) clang/test/SemaCXX/cxx2c-fold-exprs.cpp (-26) - (modified) clang/test/SemaTemplate/concepts-lambda.cpp (-16) ``````````diff diff --git a/clang/docs/ReleaseNotes.md b/clang/docs/ReleaseNotes.md index fc7ab3efa9731..043a0ddae2a6c 100644 --- a/clang/docs/ReleaseNotes.md +++ b/clang/docs/ReleaseNotes.md @@ -589,9 +589,6 @@ features cannot lower the translation-unit ABI level; - Fixed a crash when module directive export module foo not following a semicolon and there are no rest pp-tokens in current module file. (#GH187771) -- Fixed concept evaluation bugs where some declarations were not added to - the current instantiation scope. (#GH198052), (#GH209632) - - Fixed a crash when a lambda parameter pack was given a default argument that is a pack expansion referencing an enclosing function's parameter pack (e.g. `[](Types... = args...) {}`). Clang now diagnoses the illegal default diff --git a/clang/include/clang/Sema/Sema.h b/clang/include/clang/Sema/Sema.h index fc8da0ed56005..4ff4c669a6b70 100644 --- a/clang/include/clang/Sema/Sema.h +++ b/clang/include/clang/Sema/Sema.h @@ -15129,17 +15129,11 @@ class Sema final : public SemaBase { const NamedDecl *D1, ArrayRef<AssociatedConstraint> AC1, const NamedDecl *D2, ArrayRef<AssociatedConstraint> AC2); -private: - friend class ConstraintSatisfactionChecker; - friend class SubstituteParameterMappings; - - UnsignedOrNone EvaluateFoldExpandedConstraintSize( - const Expr *Pattern, const MultiLevelTemplateArgumentList &MLTAL); - /// Cache the satisfaction of an atomic constraint. /// The key is based on the unsubstituted expression and the parameter /// mapping. This lets us not substituting the mapping more than once, /// which is (very!) expensive. + /// FIXME: this should be private. llvm::DenseMap<llvm::FoldingSetNodeID, UnsubstitutedConstraintSatisfactionCacheResult> UnsubstitutedConstraintSatisfactionCache; @@ -15151,6 +15145,7 @@ class Sema final : public SemaBase { llvm::DenseMap<llvm::FoldingSetNodeID, TemplateArgumentLoc> *CurrentCachedTemplateArgs = nullptr; +private: /// 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. @@ -15171,6 +15166,23 @@ class Sema final : public SemaBase { // The current stack of constraint satisfactions, so we can exit-early. llvm::SmallVector<SatisfactionStackEntryTy, 10> SatisfactionStack; + /// Used by SetupConstraintCheckingTemplateArgumentsAndScope to set up the + /// LocalInstantiationScope of the current non-lambda function. For lambdas, + /// use LambdaScopeForCallOperatorInstantiationRAII. + bool + SetupConstraintScope(FunctionDecl *FD, + std::optional<ArrayRef<TemplateArgument>> TemplateArgs, + const MultiLevelTemplateArgumentList &MLTAL, + LocalInstantiationScope &Scope); + + /// Used during constraint checking, sets up the constraint template argument + /// lists, and calls SetupConstraintScope to set up the + /// LocalInstantiationScope to have the proper set of ParVarDecls configured. + std::optional<MultiLevelTemplateArgumentList> + SetupConstraintCheckingTemplateArgumentsAndScope( + FunctionDecl *FD, std::optional<ArrayRef<TemplateArgument>> TemplateArgs, + LocalInstantiationScope &Scope); + ///@} // diff --git a/clang/include/clang/Sema/Template.h b/clang/include/clang/Sema/Template.h index 818528744511d..50e950e56c6ca 100644 --- a/clang/include/clang/Sema/Template.h +++ b/clang/include/clang/Sema/Template.h @@ -540,8 +540,6 @@ enum class TemplateSubstitutionKind : char { llvm::PointerUnion<Decl *, DeclArgumentPack *> * getInstantiationOfIfExists(const Decl *D); - LocalInstantiationScope *getOuterScope() const { return Outer; } - void InstantiatedLocal(const Decl *D, Decl *Inst); void InstantiatedLocalPackArg(const Decl *D, VarDecl *Inst); void MakeInstantiatedLocalArgPack(const Decl *D); diff --git a/clang/lib/Sema/SemaConcept.cpp b/clang/lib/Sema/SemaConcept.cpp index 0122e920e5d89..ee17f826dc32c 100644 --- a/clang/lib/Sema/SemaConcept.cpp +++ b/clang/lib/Sema/SemaConcept.cpp @@ -549,9 +549,7 @@ class HashParameterMapping : public RecursiveASTVisitor<HashParameterMapping> { } } }; -} // namespace -namespace clang { class ConstraintSatisfactionChecker { Sema &S; const NamedDecl *Template; @@ -654,6 +652,10 @@ class ConstraintSatisfactionChecker { EvaluateAtomicConstraint(const Expr *AtomicExpr, const MultiLevelTemplateArgumentList &MLTAL); + UnsignedOrNone EvaluateFoldExpandedConstraintSize( + const FoldExpandedConstraint &FE, + const MultiLevelTemplateArgumentList &MLTAL); + // XXX: It is SLOW! Use it very carefully. std::optional<MultiLevelTemplateArgumentList> SubstitutionInTemplateArguments( const NormalizedConstraintWithParamMapping &Constraint, @@ -698,7 +700,7 @@ class ConstraintSatisfactionChecker { const MultiLevelTemplateArgumentList &MLTAL); }; -} // namespace clang +} // namespace ExprResult ConstraintSatisfactionChecker::EvaluateAtomicConstraint( const Expr *AtomicExpr, const MultiLevelTemplateArgumentList &MLTAL) { @@ -946,6 +948,31 @@ ExprResult ConstraintSatisfactionChecker::Evaluate( return PMCache.cache(EvaluateSlow(Constraint, MLTAL)); } +UnsignedOrNone +ConstraintSatisfactionChecker::EvaluateFoldExpandedConstraintSize( + const FoldExpandedConstraint &FE, + const MultiLevelTemplateArgumentList &MLTAL) { + + Expr *Pattern = const_cast<Expr *>(FE.getPattern()); + + SmallVector<UnexpandedParameterPack, 2> Unexpanded; + S.collectUnexpandedParameterPacks(Pattern, Unexpanded); + assert(!Unexpanded.empty() && "Pack expansion without parameter packs?"); + bool Expand = true; + bool RetainExpansion = false; + UnsignedOrNone NumExpansions(std::nullopt); + if (S.CheckParameterPacksForExpansion( + Pattern->getExprLoc(), Pattern->getSourceRange(), Unexpanded, MLTAL, + /*FailOnPackProducingTemplates=*/false, Expand, RetainExpansion, + NumExpansions, /*Diagnose=*/false) || + !Expand || RetainExpansion) + return std::nullopt; + + if (NumExpansions && S.getLangOpts().BracketDepth < *NumExpansions) + return std::nullopt; + return NumExpansions; +} + ExprResult ConstraintSatisfactionChecker::EvaluateSlow( const FoldExpandedConstraint &Constraint, const MultiLevelTemplateArgumentList &MLTAL) { @@ -966,15 +993,9 @@ ExprResult ConstraintSatisfactionChecker::EvaluateSlow( return ExprError(); } - UnsignedOrNone NumExpansions(std::nullopt); - { - Sema::InstantiatingTemplate InstTemplate( - S, TemplateNameLoc, - Sema::InstantiatingTemplate::ConstraintSubstitution{}, - const_cast<NamedDecl *>(Template), Constraint.getSourceRange()); - NumExpansions = S.EvaluateFoldExpandedConstraintSize( - Constraint.getPattern(), *SubstitutedArgs); - } + ExprResult Out; + UnsignedOrNone NumExpansions = + EvaluateFoldExpandedConstraintSize(Constraint, *SubstitutedArgs); if (!NumExpansions) return ExprEmpty(); @@ -983,7 +1004,6 @@ ExprResult ConstraintSatisfactionChecker::EvaluateSlow( return ExprEmpty(); } - ExprResult Out; for (unsigned I = 0; I < *NumExpansions; I++) { Sema::ArgPackSubstIndexRAII SubstIndex(S, I); Satisfaction.IsSatisfied = false; @@ -1392,6 +1412,98 @@ SubstituteConceptsInConstraintExpression(Sema &S, const NamedDecl *D, MLTAL); } +bool Sema::SetupConstraintScope( + FunctionDecl *FD, std::optional<ArrayRef<TemplateArgument>> TemplateArgs, + const MultiLevelTemplateArgumentList &MLTAL, + LocalInstantiationScope &Scope) { + assert(!isLambdaCallOperator(FD) && + "Use LambdaScopeForCallOperatorInstantiationRAII to handle lambda " + "instantiations"); + if (FD->isTemplateInstantiation() && FD->getPrimaryTemplate()) { + FunctionTemplateDecl *PrimaryTemplate = FD->getPrimaryTemplate(); + InstantiatingTemplate Inst( + *this, FD->getPointOfInstantiation(), + Sema::InstantiatingTemplate::ConstraintsCheck{}, PrimaryTemplate, + TemplateArgs ? *TemplateArgs : ArrayRef<TemplateArgument>{}, + SourceRange()); + if (Inst.isInvalid()) + return true; + + // addInstantiatedParametersToScope creates a map of 'uninstantiated' to + // 'instantiated' parameters and adds it to the context. For the case where + // this function is a template being instantiated NOW, we also need to add + // the list of current template arguments to the list so that they also can + // be picked out of the map. + if (auto *SpecArgs = FD->getTemplateSpecializationArgs()) { + MultiLevelTemplateArgumentList JustTemplArgs(FD, SpecArgs->asArray(), + /*Final=*/false); + 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 (FunctionTemplateDecl *FromMemTempl = + PrimaryTemplate->getInstantiatedFromMemberTemplate()) { + if (addInstantiatedParametersToScope(FD, FromMemTempl->getTemplatedDecl(), + Scope, MLTAL)) + return true; + } + + return false; + } + + if (FD->getTemplatedKind() == FunctionDecl::TK_MemberSpecialization || + FD->getTemplatedKind() == FunctionDecl::TK_DependentNonTemplate) { + FunctionDecl *InstantiatedFrom = + FD->getTemplatedKind() == FunctionDecl::TK_MemberSpecialization + ? FD->getInstantiatedFromMemberFunction() + : FD->getInstantiatedFromDecl(); + + InstantiatingTemplate Inst( + *this, FD->getPointOfInstantiation(), + Sema::InstantiatingTemplate::ConstraintsCheck{}, InstantiatedFrom, + TemplateArgs ? *TemplateArgs : ArrayRef<TemplateArgument>{}, + SourceRange()); + if (Inst.isInvalid()) + return true; + + // Case where this was not a template, but instantiated as a + // child-function. + if (addInstantiatedParametersToScope(FD, InstantiatedFrom, Scope, MLTAL)) + return true; + } + + return false; +} + +// This function collects all of the template arguments for the purposes of +// constraint-instantiation and checking. +std::optional<MultiLevelTemplateArgumentList> +Sema::SetupConstraintCheckingTemplateArgumentsAndScope( + FunctionDecl *FD, std::optional<ArrayRef<TemplateArgument>> TemplateArgs, + LocalInstantiationScope &Scope) { + MultiLevelTemplateArgumentList MLTAL; + + // Collect the list of template arguments relative to the 'primary' template. + // We need the entire list, since the constraint is completely uninstantiated + // at this point. + MLTAL = + getTemplateInstantiationArgs(FD, FD->getLexicalDeclContext(), + /*Final=*/false, /*Innermost=*/std::nullopt, + /*RelativeToPrimary=*/true, + /*Pattern=*/nullptr, + /*ForConstraintInstantiation=*/true); + // Lambdas are handled by LambdaScopeForCallOperatorInstantiationRAII. + if (isLambdaCallOperator(FD)) + return MLTAL; + if (SetupConstraintScope(FD, TemplateArgs, MLTAL, Scope)) + return std::nullopt; + + return MLTAL; +} + bool Sema::CheckFunctionConstraints(const FunctionDecl *FD, ConstraintSatisfaction &Satisfaction, SourceLocation UsageLoc, @@ -1431,12 +1543,12 @@ bool Sema::CheckFunctionConstraints(const FunctionDecl *FD, ContextRAII SavedContext{*this, CtxToSave}; LocalInstantiationScope Scope(*this, !ForOverloadResolution); - MultiLevelTemplateArgumentList MLTAL = - getTemplateInstantiationArgs(FD, FD->getLexicalDeclContext(), - /*Final=*/false, /*Innermost=*/std::nullopt, - /*RelativeToPrimary=*/true, - /*Pattern=*/nullptr, - /*ForConstraintInstantiation=*/true); + std::optional<MultiLevelTemplateArgumentList> MLTAL = + SetupConstraintCheckingTemplateArgumentsAndScope( + const_cast<FunctionDecl *>(FD), {}, Scope); + + if (!MLTAL) + return true; Qualifiers ThisQuals; CXXRecordDecl *Record = nullptr; @@ -1447,11 +1559,11 @@ bool Sema::CheckFunctionConstraints(const FunctionDecl *FD, CXXThisScopeRAII ThisScope(*this, Record, ThisQuals, Record != nullptr); LambdaScopeForCallOperatorInstantiationRAII LambdaScope( - *this, const_cast<FunctionDecl *>(FD), MLTAL, Scope, + *this, const_cast<FunctionDecl *>(FD), *MLTAL, Scope, ForOverloadResolution); return CheckConstraintSatisfaction( - FD, FD->getTrailingRequiresClause(), MLTAL, + FD, FD->getTrailingRequiresClause(), *MLTAL, SourceRange(UsageLoc.isValid() ? UsageLoc : FD->getLocation()), Satisfaction); } @@ -1684,12 +1796,12 @@ bool Sema::CheckFunctionTemplateConstraints( Sema::ContextRAII savedContext(*this, Decl); LocalInstantiationScope Scope(*this); - MultiLevelTemplateArgumentList MLTAL = - getTemplateInstantiationArgs(Decl, Decl->getLexicalDeclContext(), - /*Final=*/false, /*Innermost=*/std::nullopt, - /*RelativeToPrimary=*/true, - /*Pattern=*/nullptr, - /*ForConstraintInstantiation=*/true); + std::optional<MultiLevelTemplateArgumentList> MLTAL = + SetupConstraintCheckingTemplateArgumentsAndScope(Decl, TemplateArgs, + Scope); + + if (!MLTAL) + return true; Qualifiers ThisQuals; CXXRecordDecl *Record = nullptr; @@ -1699,10 +1811,10 @@ bool Sema::CheckFunctionTemplateConstraints( } CXXThisScopeRAII ThisScope(*this, Record, ThisQuals, Record != nullptr); - LambdaScopeForCallOperatorInstantiationRAII LambdaScope(*this, Decl, MLTAL, + LambdaScopeForCallOperatorInstantiationRAII LambdaScope(*this, Decl, *MLTAL, Scope); - return CheckConstraintSatisfaction(Template, TemplateAC, MLTAL, + return CheckConstraintSatisfaction(Template, TemplateAC, *MLTAL, PointOfInstantiation, Satisfaction); } @@ -1975,7 +2087,7 @@ void Sema::DiagnoseUnsatisfiedConstraint( ConstraintExpr->getBeginLoc(), First); } -namespace clang { +namespace { class SubstituteParameterMappings { Sema &SemaRef; @@ -2013,8 +2125,6 @@ class SubstituteParameterMappings { bool substitute(NormalizedConstraint &N); }; -} // namespace clang - void SubstituteParameterMappings::buildParameterMapping( NormalizedConstraintWithParamMapping &N) { TemplateParameterList *TemplateParams = @@ -2308,6 +2418,8 @@ bool SubstituteParameterMappings::substitute(NormalizedConstraint &N) { llvm_unreachable("Unknown ConstraintKind enum"); } +} // namespace + NormalizedConstraint *NormalizedConstraint::fromAssociatedConstraints( Sema &S, const NamedDecl *D, ArrayRef<AssociatedConstraint> ACs) { assert(ACs.size() != 0); diff --git a/clang/lib/Sema/SemaTemplateInstantiate.cpp b/clang/lib/Sema/SemaTemplateInstantiate.cpp index cadc5689cebc2..ffbe8bb0506bc 100644 --- a/clang/lib/Sema/SemaTemplateInstantiate.cpp +++ b/clang/lib/Sema/SemaTemplateInstantiate.cpp @@ -1324,10 +1324,11 @@ namespace { bool BailOutOnIncomplete; std::optional<llvm::FoldingSetNodeID> TemplateArgsHashValue; - llvm::DenseMap<llvm::FoldingSetNodeID, TemplateArgumentLoc> - *CurrentCachedTemplateArgs = nullptr; - bool instantiateMissingDeclsToScopeForConcepts(Decl *D); + // CWG2770: Function parameters should be instantiated when they are + // needed by a satisfaction check of an atomic constraint or + // (recursively) by another function parameter. + bool maybeInstantiateFunctionParameterToScope(ParmVarDecl *OldParm); public: typedef TreeTransform<TemplateInstantiator> inherited; @@ -1357,14 +1358,12 @@ namespace { inline static struct ForConstraintSubstitution_t { } ForConstraintSubstitution; - TemplateInstantiator( - ForParameterMappingSubstitution_t, Sema &SemaRef, SourceLocation Loc, - const MultiLevelTemplateArgumentList &TemplateArgs, - llvm::DenseMap<llvm::FoldingSetNodeID, TemplateArgumentLoc> *Cache) + TemplateInstantiator(ForParameterMappingSubstitution_t, Sema &SemaRef, + SourceLocation Loc, + const MultiLevelTemplateArgumentList &TemplateArgs) : inherited(SemaRef), TemplateArgs(TemplateArgs), Loc(Loc), - EvaluateLambdaConstraint(true), BailOutOnIncomplete(false), - CurrentCachedTemplateArgs(Cache) { - if (!Cache) + EvaluateLambdaConstraint(true), BailOutOnIncomplete(false) { + if (!SemaRef.CurrentCachedTemplateArgs) return; auto &V = TemplateArgsHashValue.emplace(); for (auto &Level : TemplateArgs) @@ -1411,18 +1410,22 @@ namespace { ArrayRef<UnexpandedParameterPack> Unexpanded, bool FailOnPackProducingTemplates, bool &ShouldExpand, bool &RetainExpansion, - UnsignedOrNone &NumExpansions, - bool Diagnose = true) { - for (UnexpandedParameterPack ParmPack : Unexpanded) { - if (instantiateMissingDeclsToScopeForConcepts( - dyn_cast<NamedDecl *>(ParmPack.first))) - return true; + UnsignedOrNone &NumExpansions) { + if (SemaRef.CurrentInstantiationScope && + (SemaRef.inConstraintSubstitution() || + SemaRef.inParameterMappingSubstitution())) { + for (UnexpandedParameterPack ParmPack : Unexpanded) { + NamedDecl *VD = ParmPack.first.dyn_cast<NamedDecl *>(); + if (auto *PVD = dyn_cast_if_present<ParmVarDecl>(VD); + PVD && maybeInstantiateFunctionParameterToScope(PVD)) + return true; + } } return getSema().CheckParameterPacksForExpansion( EllipsisLoc, PatternRange, Unexpanded, TemplateArgs, FailOnPackProducingTemplates, ShouldExpand, RetainExpansion, - NumExpansions, Diagnose); + NumExpansions); } void ExpandingFunctionParameterPack(ParmVarDecl *Pack) { @@ -1634,7 +1637,7 @@ namespace { TemplateArgumentLoc &Output, bool Uneval = false) { const TemplateArgument &Arg = Input.getArgument(); - if (auto *Cache = CurrentCachedTemplateArgs; + if (auto *Cache = SemaRef.CurrentCachedTemplateArgs; Cache && TemplateArgsHashValue) { llvm::FoldingSetNodeID ID = *TemplateArgsHashValue; ID.AddInteger(SemaRef.ArgPackSubstIndex.toInternalRepresentation()); @@ -1977,7 +1980,11 @@ Decl *TemplateInstantiator::TransformDecl(SourceLocation Loc, Decl *D) { // template parameter. } - if (instantiateMissingDeclsToScopeForConcepts(D)) + if (ParmVarDecl *PVD = dyn_cast<ParmVarDecl>(D); + PVD && SemaRef.CurrentInstantiationScope && + (SemaRef.inConstraintSubstitution() || + SemaRef.inParameterMappingSubstitution()) && + maybeInstantiateFunctionParameterToScope(PVD)) return nullptr; if (isa<CXXExpansionStmtDecl>(D)) { @@ -1989,39 +1996,9 @@ Decl *TemplateInstantiator::TransformDecl(SourceLocation Loc, Decl *D) { return SemaRef.FindInstantiatedDecl(Loc, cast<NamedDecl>(D), TemplateArgs); } -bool TemplateInstantiator::instantiateMissingDeclsToScopeForConcepts(Decl *D) { - if (!(D && (SemaRef.inConstraintSubstitution() || - SemaRef.inParameterMappingSubstitution()))) - return false; - - auto *Current = SemaRef.CurrentInstantiationScope; - if (!Current) - return false; - if (Current->getInstantiationOfIfExists(D)) - return false; - - for (auto *Outer = Current... [truncated] `````````` </details> https://github.com/llvm/llvm-project/pull/223235 _______________________________________________ cfe-commits mailing list [email protected] https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
