diff --git a/clang/docs/ReleaseNotes.rst b/clang/docs/ReleaseNotes.rst index 323157c4db1f1..7b7a5b937a61e 100644 --- a/clang/docs/ReleaseNotes.rst +++ b/clang/docs/ReleaseNotes.rst @@ -168,6 +168,9 @@ Bug Fixes to C++ Support parameter where we did an incorrect specialization of the initialization of the default parameter. Fixes (`#68490 `_) +- Addressed an issue where constraints involving injected class types are perceived + distinct from its specialization types. + (`#56482 `_) - Fixed a bug where variables referenced by requires-clauses inside nested generic lambdas were not properly injected into the constraint scope. (`#73418 `_) diff --git a/clang/lib/AST/DeclTemplate.cpp b/clang/lib/AST/DeclTemplate.cpp index 7d7556e670f95..946a34ea8830e 100644 --- a/clang/lib/AST/DeclTemplate.cpp +++ b/clang/lib/AST/DeclTemplate.cpp @@ -1583,6 +1583,10 @@ void TemplateParamObjectDecl::printAsInit(llvm::raw_ostream &OS, TemplateParameterList *clang::getReplacedTemplateParameterList(Decl *D) { switch (D->getKind()) { + case Decl::Kind::CXXRecord: + return cast(D) + ->getDescribedTemplate() + ->getTemplateParameters(); case Decl::Kind::ClassTemplate: return cast(D)->getTemplateParameters(); case Decl::Kind::ClassTemplateSpecialization: { diff --git a/clang/lib/Sema/SemaConcept.cpp b/clang/lib/Sema/SemaConcept.cpp index 19a460f411757..5028879eda22f 100644 --- a/clang/lib/Sema/SemaConcept.cpp +++ b/clang/lib/Sema/SemaConcept.cpp @@ -807,8 +807,20 @@ static const Expr *SubstituteConstraintExpressionWithoutSatisfaction( ScopeForParameters.InstantiatedLocal(PVD, PVD); std::optional ThisScope; - if (auto *RD = dyn_cast(DeclInfo.getDeclContext())) + + // See TreeTransform::RebuildTemplateSpecializationType. A context scope is + // essential for having an injected class as the canonical type for a template + // specialization type at the rebuilding stage. This guarantees that, for + // out-of-line definitions, injected class name types and their equivalent + // template specializations can be profiled to the same value, which makes it + // possible that e.g. constraints involving C> and C are + // perceived identical. + std::optional ContextScope; + if (auto *RD = dyn_cast(DeclInfo.getDeclContext())) { ThisScope.emplace(S, const_cast(RD), Qualifiers()); + ContextScope.emplace(S, const_cast(cast(RD)), + /*NewThisContext=*/false); + } ExprResult SubstConstr = S.SubstConstraintExprWithoutSatisfaction( const_cast(ConstrExpr), MLTAL); if (SFINAE.hasErrorOccurred() || !SubstConstr.isUsable()) diff --git a/clang/test/SemaTemplate/concepts-out-of-line-def.cpp b/clang/test/SemaTemplate/concepts-out-of-line-def.cpp index 7323ad8d9ef2c..b6fea2e0b4b31 100644 --- a/clang/test/SemaTemplate/concepts-out-of-line-def.cpp +++ b/clang/test/SemaTemplate/concepts-out-of-line-def.cpp @@ -537,6 +537,29 @@ template void X::bar(decltype(requires { requires is_not_same_v; })) {} } // namespace GH74314 +namespace GH56482 { +template +concept slot_map_has_reserve = true; + +template struct Slot_map { + constexpr void reserve() const noexcept + requires slot_map_has_reserve; + + constexpr void reserve(int) const noexcept + requires slot_map_has_reserve>; +}; + +template +constexpr void Slot_map::reserve() const noexcept + requires slot_map_has_reserve> +{} + +template +constexpr void Slot_map::reserve(int) const noexcept + requires slot_map_has_reserve +{} +} // namespace GH56482 + namespace GH74447 { template struct S { template