Author: Younan Zhang Date: 2025-06-06T19:13:59+08:00 New Revision: c3b870eb3f4fb15403b49a976aea860e6da9084e
URL: https://github.com/llvm/llvm-project/commit/c3b870eb3f4fb15403b49a976aea860e6da9084e DIFF: https://github.com/llvm/llvm-project/commit/c3b870eb3f4fb15403b49a976aea860e6da9084e.diff LOG: [Clang] Fail the constraint substitution early after CWG2369 (#143096) CWG2369 revealed another case where we were SFINAE'ing out the invalid result of substitution, but the expression now makes the way into evaluation. We switch to the concept specialization's context before we check it. This ensures that we're able to realize the invalid expression earlier, so we can avoid evaluating invalid expression, which is a hard error. This also fixes #115838 Added: Modified: clang/docs/ReleaseNotes.rst clang/lib/Sema/SemaTemplate.cpp clang/test/SemaTemplate/concepts.cpp Removed: ################################################################################ diff --git a/clang/docs/ReleaseNotes.rst b/clang/docs/ReleaseNotes.rst index e926d60589808..d118270abd445 100644 --- a/clang/docs/ReleaseNotes.rst +++ b/clang/docs/ReleaseNotes.rst @@ -833,6 +833,7 @@ Bug Fixes to C++ Support - Fixed an access checking bug when initializing non-aggregates in default arguments (#GH62444), (#GH83608) - Fixed a pack substitution bug in deducing class template partial specializations. (#GH53609) - Fixed a crash when constant evaluating some explicit object member assignment operators. (#GH142835) +- Fixed an access checking bug when substituting into concepts (#GH115838) Bug Fixes to AST Handling ^^^^^^^^^^^^^^^^^^^^^^^^^ diff --git a/clang/lib/Sema/SemaTemplate.cpp b/clang/lib/Sema/SemaTemplate.cpp index 1d8fea1d72008..ccc532e1fd3de 100644 --- a/clang/lib/Sema/SemaTemplate.cpp +++ b/clang/lib/Sema/SemaTemplate.cpp @@ -4749,6 +4749,8 @@ Sema::CheckConceptTemplateId(const CXXScopeSpec &SS, EnterExpressionEvaluationContext EECtx{ *this, ExpressionEvaluationContext::Unevaluated, CSD}; + ContextRAII CurContext(*this, CSD->getDeclContext(), + /*NewThisContext=*/false); if (!AreArgsDependent && CheckConstraintSatisfaction( NamedConcept, AssociatedConstraint(NamedConcept->getConstraintExpr()), diff --git a/clang/test/SemaTemplate/concepts.cpp b/clang/test/SemaTemplate/concepts.cpp index 3e50a8bce24af..a99df2390a551 100644 --- a/clang/test/SemaTemplate/concepts.cpp +++ b/clang/test/SemaTemplate/concepts.cpp @@ -1200,3 +1200,57 @@ bool test_val_types() { } } + +namespace CWG2369_Regression { + +enum class KindEnum { + Unknown = 0, + Foo = 1, +}; + +template <typename T> +concept KnownKind = T::kind() != KindEnum::Unknown; + +template <KnownKind T> struct KnownType; + +struct Type { + KindEnum kind() const; + + static Type f(Type t); + + template <KnownKind T> static KnownType<T> f(T t); + + static void g() { + Type t; + f(t); + } +}; + +template <KnownKind T> struct KnownType { + static constexpr KindEnum kind() { return KindEnum::Foo; } +}; + +} + +namespace GH115838 { + +template<typename T> concept has_x = requires(T t) {{ t.x };}; + +class Publ { public: int x = 0; }; +class Priv { private: int x = 0; }; +class Prot { protected: int x = 0; }; +class Same { protected: int x = 0; }; + +template<typename T> class D; +template<typename T> requires ( has_x<T>) class D<T>: public T { public: static constexpr bool has = 1; }; +template<typename T> requires (!has_x<T>) class D<T>: public T { public: static constexpr bool has = 0; }; + +// "Same" is identical to "Prot" but queried before used. +static_assert(!has_x<Same>, "Protected should be invisible."); +static_assert(!D<Same>::has, "Protected should be invisible."); + +static_assert( D<Publ>::has, "Public should be visible."); +static_assert(!D<Priv>::has, "Private should be invisible."); +static_assert(!D<Prot>::has, "Protected should be invisible."); + +} _______________________________________________ cfe-commits mailing list cfe-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits