From 28009c8880209a87d83b5901cfaf8d8e96be5693 Mon Sep 17 00:00:00 2001 From: Younan Zhang Date: Wed, 14 Jan 2026 23:16:15 +0800 Subject: [PATCH] [Clang] Check enable_if attribute in the DC of current function (#175899) A ContextRAII here ensures immediate access control checking within the current context, allowing us to rule out inaccessible constructors during potential overload resolution, where access diagnostics are converted from hard errors into SFINAE errors, making the behavior more preferrable with the nature of the enable_if attribute. Fixes https://github.com/llvm/llvm-project/issues/175895 --- clang/docs/ReleaseNotes.rst | 1 + clang/lib/Sema/SemaOverload.cpp | 2 ++ clang/test/SemaCXX/enable_if.cpp | 35 ++++++++++++++++++++++++++++++++ 3 files changed, 38 insertions(+) diff --git a/clang/docs/ReleaseNotes.rst b/clang/docs/ReleaseNotes.rst index 4139d1d80ed4..c9d21558c94f 100644 --- a/clang/docs/ReleaseNotes.rst +++ b/clang/docs/ReleaseNotes.rst @@ -120,6 +120,7 @@ Bug Fixes to Compiler Builtins Bug Fixes to Attribute Support ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +- Fixed a behavioral discrepancy between deleted functions and private members when checking the ``enable_if`` attribute. (#GH175895) Bug Fixes to C++ Support ^^^^^^^^^^^^^^^^^^^^^^^^ diff --git a/clang/lib/Sema/SemaOverload.cpp b/clang/lib/Sema/SemaOverload.cpp index 7115b8b7d446..5592cd254535 100644 --- a/clang/lib/Sema/SemaOverload.cpp +++ b/clang/lib/Sema/SemaOverload.cpp @@ -7551,6 +7551,8 @@ EnableIfAttr *Sema::CheckEnableIf(FunctionDecl *Function, return nullptr; SFINAETrap Trap(*this); + // Switching the DC to ensure the immediate access control checking. + ContextRAII SavedContext(*this, Function->getDeclContext()); SmallVector ConvertedArgs; // FIXME: We should look into making enable_if late-parsed. Expr *DiscardedThis; diff --git a/clang/test/SemaCXX/enable_if.cpp b/clang/test/SemaCXX/enable_if.cpp index 1c307881e5d4..845ccf00864a 100644 --- a/clang/test/SemaCXX/enable_if.cpp +++ b/clang/test/SemaCXX/enable_if.cpp @@ -562,6 +562,41 @@ namespace IgnoreUnusedArgSideEffects { #endif } +namespace GH175895 { + +using int32_t = int; + +struct wxuin_t { + wxuin_t() {} + wxuin_t(int32_t v) __attribute__((enable_if(v == 0, "Expect only constant expressions"))) {} +}; + +struct wxuin64_t { + wxuin64_t() {} + + explicit operator wxuin_t() const { return {}; } + +private: + operator int() const { return 0; } +}; + +struct wxuin64_t_deleted { + wxuin64_t_deleted() {} + + explicit operator wxuin_t() const { return {}; } + + operator int() = delete; +}; + +void main() { + wxuin64_t uin64{}; + wxuin64_t_deleted deleted{}; + auto b = static_cast(uin64); + auto c = static_cast(deleted); +} + +} + 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}}