https://github.com/dyung updated 
https://github.com/llvm/llvm-project/pull/209773

>From c7280675cd04a97c958bcf46db8042e33ab35fc9 Mon Sep 17 00:00:00 2001
From: Erich Keane <[email protected]>
Date: Wed, 15 Jul 2026 06:57:31 -0700
Subject: [PATCH] Fix references to complete types in attribute references
 (#209537)

This is a regression from #197215.

Attributes are not REALLY in the body of a function (though the name of
said function is... awkwardly inaccurate at best), but still need to pay
attention to the completeness of their references. As a result, we
weren't marking the expression as invalid, but were also trying to
evaluate it.

This patch fixes this in 2 ways. First, we re-add the
CXXThisTypeOverride check, but except constant substitution, since that
has some additional 'this' behavior from #197215. x

Secondly, we also make the constant evaluator give up on incomplete
types when handling an L value member. This stops us from trying to
evaluate the value if it is incomplete during template instantiation,
when the type is incomplete. We don't diagnose, since it is still
potentially a constant expression, but isn't currently one.

Fixes: #199527
(cherry picked from commit 0d93f2aec0b4847761bd8458b7847ce37b85cf03)
---
 clang/lib/AST/ExprConstant.cpp   | 13 +++++++++--
 clang/lib/Sema/SemaExprCXX.cpp   |  8 +++++++
 clang/test/SemaCXX/enable_if.cpp | 39 ++++++++++++++++++++++++++++++++
 3 files changed, 58 insertions(+), 2 deletions(-)

diff --git a/clang/lib/AST/ExprConstant.cpp b/clang/lib/AST/ExprConstant.cpp
index 7d9dba8cd33fc..120af89a93b09 100644
--- a/clang/lib/AST/ExprConstant.cpp
+++ b/clang/lib/AST/ExprConstant.cpp
@@ -3212,8 +3212,17 @@ static bool HandleLValueMember(EvalInfo &Info, const 
Expr *E, LValue &LVal,
                                const FieldDecl *FD,
                                const ASTRecordLayout *RL = nullptr) {
   if (!RL) {
-    if (FD->getParent()->isInvalidDecl()) return false;
-    RL = &Info.Ctx.getASTRecordLayout(FD->getParent());
+    const RecordDecl *RD = FD->getParent();
+    if (RD->isInvalidDecl())
+      return false;
+    // There are some cases where the base is not yet complete but we haven't
+    // disagnosed (such as in a template instantation of an attribute that
+    // references the expression, ala enable_if).  These aren't necessarily
+    // constant expressions so we return 'false', but they might be, so we 
don't
+    // diagnose.
+    if (!RD->isCompleteDefinition())
+      return false;
+    RL = &Info.Ctx.getASTRecordLayout(RD);
   }
 
   unsigned I = FD->getFieldIndex();
diff --git a/clang/lib/Sema/SemaExprCXX.cpp b/clang/lib/Sema/SemaExprCXX.cpp
index 5f22cd409dc01..538604aa2e64b 100644
--- a/clang/lib/Sema/SemaExprCXX.cpp
+++ b/clang/lib/Sema/SemaExprCXX.cpp
@@ -1487,6 +1487,14 @@ 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'. Constraint substitution is the exception: a concept is
+  // evaluated in its own declaration context (see GH#197215), so it loses the
+  // enclosing '*this' even though it may legitimately name a member of the
+  // class currently being instantiated.
+  if (CXXThisTypeOverride.isNull() && !inConstraintSubstitution())
+    return false;
+
   // Determine whether we're looking into a class that's currently being
   // defined.
   CXXRecordDecl *Class = BaseType->getAsCXXRecordDecl();
diff --git a/clang/test/SemaCXX/enable_if.cpp b/clang/test/SemaCXX/enable_if.cpp
index a34b87064b49d..4af0922fee5ac 100644
--- a/clang/test/SemaCXX/enable_if.cpp
+++ b/clang/test/SemaCXX/enable_if.cpp
@@ -646,6 +646,45 @@ void Substitute(Arg) 
__attribute__((enable_if(PlaceholderBitmask, ""))) {
 
 }
 
+namespace GH199527 {
+struct S { // expected-note {{definition of 'GH199527::S' is not complete 
until the closing '}'}}
+  ~S() {}
+  bool b;
+  // expected-error@+1{{member access into incomplete type 'S'}}
+  void foo(S b) __attribute__((enable_if(b.b, "")));
+};
+
+template<typename T>
+struct S2 {
+  bool b;
+  void foo(S2 b) const __attribute__((enable_if(b.b, "templ_foo_disabled"))); 
// #FOO
+};
+
+void use() {
+  S2<int> s_whatever;
+  S2<int> s_true{true};
+  S2<int> s_false{false};
+
+
+  // Both fail because this isn't a constexpr.
+  // expected-error@+2{{no matching member function for call to 'foo'}}
+  // expected-note@#FOO{{candidate disabled: templ_foo_disabled}}
+  s_whatever.foo(s_true);
+  // expected-error@+2{{no matching member function for call to 'foo'}}
+  // expected-note@#FOO{{candidate disabled: templ_foo_disabled}}
+  s_whatever.foo(s_false);
+
+  constexpr S2<int> ce_s_whatever{};
+  constexpr S2<int> ce_s_true{true};
+  constexpr S2<int> ce_s_false{false};
+
+  ce_s_whatever.foo(ce_s_true);
+  // expected-error@+2{{no matching member function for call to 'foo'}}
+  // expected-note@#FOO{{candidate disabled: templ_foo_disabled}}
+  ce_s_whatever.foo(ce_s_false);
+}
+}
+
 namespace DefaultArgs {
   void f(int n = __builtin_LINE()) __attribute__((enable_if(n == 12345, "only 
callable on line 12345"))); // expected-note {{only callable on line 12345}}
   void g() { f(); } // expected-error {{no matching function}}

_______________________________________________
llvm-branch-commits mailing list
[email protected]
https://lists.llvm.org/cgi-bin/mailman/listinfo/llvm-branch-commits

Reply via email to