[llvm-branch-commits] [clang] release/23.x: Fix references to complete types in attribute references (#209537) (PR #209773)
via llvm-branch-commits
llvm-branch-commits at lists.llvm.org
Wed Jul 15 07:39:46 PDT 2026
llvmorg-github-actions[bot] wrote:
<!--LLVM PR SUMMARY COMMENT-->
@llvm/pr-subscribers-clang
Author: llvmbot
<details>
<summary>Changes</summary>
Backport 0d93f2aec0b4847761bd8458b7847ce37b85cf03
Requested by: @<!-- -->erichkeane
---
Full diff: https://github.com/llvm/llvm-project/pull/209773.diff
3 Files Affected:
- (modified) clang/lib/AST/ExprConstant.cpp (+11-2)
- (modified) clang/lib/Sema/SemaExprCXX.cpp (+8)
- (modified) clang/test/SemaCXX/enable_if.cpp (+39)
``````````diff
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 at +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 at +2{{no matching member function for call to 'foo'}}
+ // expected-note@#FOO{{candidate disabled: templ_foo_disabled}}
+ s_whatever.foo(s_true);
+ // expected-error at +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 at +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}}
``````````
</details>
https://github.com/llvm/llvm-project/pull/209773
More information about the llvm-branch-commits
mailing list