https://github.com/cor3ntin created 
https://github.com/llvm/llvm-project/pull/197215

Concepts appearing in a constraint expression of a class member had access to 
both `this` and the private member of the class.

This changes fixes that by setting the concext to that of the context before 
evaluation of its constraint expression.

This is done after we have substituted the template argument.

Code in `Sema::isThisOutsideMemberFunctionBody` that no longer seems useful is 
renoved as it was interefering with this change.

This is not an implementation of CWG2589 - at least not a complete one, as we 
still check access when doing substitution in the parameter mapping.

Fixes #115838
Fixes #194803

>From 991e8bec48709220b1240b92ec23120cf12fa84d Mon Sep 17 00:00:00 2001
From: Corentin Jabot <[email protected]>
Date: Tue, 12 May 2026 15:45:54 +0200
Subject: [PATCH] [Clang] Evaluate concepts in their declaration context.

Concepts appearing in a constraint expression of a class member
had access to both `this` and the private member of the class.

This changes fixes that by setting the concext to that of the context
before evaluation of its constraint expression.

This is done after we have substituted the template argument.

Code in `Sema::isThisOutsideMemberFunctionBody` that no longer seems
useful is renoved as it was interefering with this change.

This is not an implementation of CWG2589 - at least not a complete one,
as we still check access when doing substitution in the parameter mapping.

Fixes #115838
Fixes #194803
---
 clang/docs/ReleaseNotes.rst          |  2 +
 clang/lib/Sema/SemaConcept.cpp       | 13 ++++++
 clang/lib/Sema/SemaExprCXX.cpp       |  5 --
 clang/test/SemaTemplate/concepts.cpp | 69 +++++++++++++++++++++++++++-
 4 files changed, 83 insertions(+), 6 deletions(-)

diff --git a/clang/docs/ReleaseNotes.rst b/clang/docs/ReleaseNotes.rst
index bd91b8723a5c6..fdfb360515e97 100644
--- a/clang/docs/ReleaseNotes.rst
+++ b/clang/docs/ReleaseNotes.rst
@@ -566,6 +566,8 @@ Bug Fixes to C++ Support
 - Clang now rejects constant template parameters with block pointer types, 
since these are not implemented anyway and would lead to crashes. (#GH189247)
 - Fixed a crash on error recovery when dealing with invalid templates. 
(#GH183075)
 - Fixed a crash when instantiating ``requires`` expressions involving 
substitution failures in C++ concepts. (#GH176402)
+- Concepts appearing in the require-clause of a member function no longer have 
access to non-public members of that class,
+  or to a current class object. (#GH115838) (#GH194803)
 - We no longer caches invalid variable specializations. (#GH132592)
 - Fixed an incorrect template argument deduction when matching packs of 
template
   template parameters when one of its parameters is also a pack. (#GH181166)
diff --git a/clang/lib/Sema/SemaConcept.cpp b/clang/lib/Sema/SemaConcept.cpp
index bb3de89c42ccc..c80853af8d353 100644
--- a/clang/lib/Sema/SemaConcept.cpp
+++ b/clang/lib/Sema/SemaConcept.cpp
@@ -482,6 +482,10 @@ class ConstraintSatisfactionChecker {
   ConstraintSatisfaction &Satisfaction;
   bool BuildExpression;
 
+
+  // The closest concept declaration when evaluating atomic constraints.
+  ConceptDecl *ParentConcept = nullptr;
+
   // This is for TemplateInstantiator to not instantiate the same template
   // parameter mapping many times, in order to improve substitution 
performance.
   llvm::DenseMap<llvm::FoldingSetNodeID, TemplateArgumentLoc>
@@ -725,6 +729,12 @@ ExprResult ConstraintSatisfactionChecker::EvaluateSlow(
     return ExprEmpty();
   }
 
+  // Make sure that concepts are not evaluated in the context they are used,
+  // i.e they should not have access to the current class object or its 
non-public members.
+  std::optional<Sema::ContextRAII> ConceptContext;
+  if (ParentConcept)
+    ConceptContext.emplace(S, ParentConcept->getDeclContext());
+
   Sema::ArgPackSubstIndexRAII SubstIndex(S, PackSubstitutionIndex);
   ExprResult SubstitutedAtomicExpr = EvaluateAtomicConstraint(
       Constraint.getConstraintExpr(), *SubstitutedArgs);
@@ -1035,6 +1045,9 @@ ExprResult ConstraintSatisfactionChecker::Evaluate(
 
   unsigned Size = Satisfaction.Details.size();
 
+  llvm::SaveAndRestore PushConceptDecl(
+      ParentConcept, cast<ConceptDecl>(ConceptId->getNamedConcept()));
+
   ExprResult E = Evaluate(Constraint.getNormalizedConstraint(), MLTAL);
 
   if (E.isInvalid()) {
diff --git a/clang/lib/Sema/SemaExprCXX.cpp b/clang/lib/Sema/SemaExprCXX.cpp
index e60d5d7748b44..357ceb7f4ea6d 100644
--- a/clang/lib/Sema/SemaExprCXX.cpp
+++ b/clang/lib/Sema/SemaExprCXX.cpp
@@ -1485,11 +1485,6 @@ void Sema::MarkThisReferenced(CXXThisExpr *This) {
 }
 
 bool Sema::isThisOutsideMemberFunctionBody(QualType BaseType) {
-  // If we're outside the body of a member function, then we'll have a 
specified
-  // type for 'this'.
-  if (CXXThisTypeOverride.isNull())
-    return false;
-
   // Determine whether we're looking into a class that's currently being
   // defined.
   CXXRecordDecl *Class = BaseType->getAsCXXRecordDecl();
diff --git a/clang/test/SemaTemplate/concepts.cpp 
b/clang/test/SemaTemplate/concepts.cpp
index 1b7cfc96243ef..72a2fab99c581 100644
--- a/clang/test/SemaTemplate/concepts.cpp
+++ b/clang/test/SemaTemplate/concepts.cpp
@@ -1241,7 +1241,7 @@ struct SVGPropertyOwnerRegistry {
   }
 };
 
-class SVGCircleElement {
+struct SVGCircleElement {
   friend SVGPropertyOwnerRegistry<SVGCircleElement>;
   void propertyForAttribute(int);
 };
@@ -1880,3 +1880,70 @@ void g() { static_assert(f<1>() == 42); }
 } // namespace VAR
 
 } // namespace GH188640
+
+namespace GH194803 {
+
+struct B {
+    void f();
+};
+template <typename Base>
+concept C = requires() { Base::f(); }; // expected-note {{because 'Base::f()' 
would be invalid: call to non-static member function without an object 
argument}}
+
+template <typename> struct S : B {
+    void g()
+        requires C<B>; // expected-note {{because 'B' does not satisfy 'C'}}
+    void h()
+        requires requires() { B::f(); }; // #2
+};
+void f() {
+    S<int>{}.g(); // expected-error {{invalid reference to function 'g': 
constraints not satisfied}}
+    S<int>{}.h();
+}
+
+}
+
+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;
+};
+
+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
[email protected]
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits

Reply via email to