Skip to content

[clang] Fix potential constant expression checking with constexpr-unknown. #149227

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged

Conversation

efriedma-quic
Copy link
Collaborator

0717657 improved constexpr-unkown diagnostics, but potential constant expression checking broke in the process: we produce diagnostics in more cases. Supress the diagnostics as appropriate.

This fix affects -Winvalid-constexpr and the enable_if attribute. (The -Winvalid-constexpr diagnostic isn't really important right now, but it will become important if we allow constexpr-unknown with pre-C++23 standards.)

Fixes #149041. Fixes #149188.

…nown.

0717657 improved constexpr-unkown
diagnostics, but potential constant expression checking broke in the
process: we produce diagnostics in more cases.  Supress the diagnostics
as appropriate.

This fix affects -Winvalid-constexpr and the enable_if attribute.  (The
-Winvalid-constexpr diagnostic isn't really important right now, but it
will become important if we allow constexpr-unknown with pre-C++23
standards.)

Fixes llvm#149041.  Fixes llvm#149188.
@llvmbot llvmbot added clang Clang issues not falling into any other category clang:frontend Language frontend issues, e.g. anything involving "Sema" labels Jul 17, 2025
@llvmbot
Copy link
Member

llvmbot commented Jul 17, 2025

@llvm/pr-subscribers-clang

Author: Eli Friedman (efriedma-quic)

Changes

0717657 improved constexpr-unkown diagnostics, but potential constant expression checking broke in the process: we produce diagnostics in more cases. Supress the diagnostics as appropriate.

This fix affects -Winvalid-constexpr and the enable_if attribute. (The -Winvalid-constexpr diagnostic isn't really important right now, but it will become important if we allow constexpr-unknown with pre-C++23 standards.)

Fixes #149041. Fixes #149188.


Full diff: https://github.com/llvm/llvm-project/pull/149227.diff

3 Files Affected:

  • (modified) clang/lib/AST/ExprConstant.cpp (+7-4)
  • (modified) clang/test/SemaCXX/constant-expression-p2280r4.cpp (+24)
  • (modified) clang/test/SemaCXX/constexpr-never-constant.cpp (+5)
diff --git a/clang/lib/AST/ExprConstant.cpp b/clang/lib/AST/ExprConstant.cpp
index 767cc4c3b19eb..8797eaddd0e18 100644
--- a/clang/lib/AST/ExprConstant.cpp
+++ b/clang/lib/AST/ExprConstant.cpp
@@ -4450,7 +4450,8 @@ static CompleteObject findCompleteObject(EvalInfo &Info, const Expr *E,
         }
       } else if (!IsAccess) {
         return CompleteObject(LVal.getLValueBase(), nullptr, BaseType);
-      } else if (IsConstant && Info.checkingPotentialConstantExpression() &&
+      } else if ((IsConstant || BaseType->isReferenceType()) &&
+                 Info.checkingPotentialConstantExpression() &&
                  BaseType->isLiteralType(Info.Ctx) && !VD->hasDefinition()) {
         // This variable might end up being constexpr. Don't diagnose it yet.
       } else if (IsConstant) {
@@ -4491,9 +4492,11 @@ static CompleteObject findCompleteObject(EvalInfo &Info, const Expr *E,
     // a null BaseVal. Any constexpr-unknown variable seen here is an error:
     // we can't access a constexpr-unknown object.
     if (AK != clang::AK_Dereference && !BaseVal) {
-      Info.FFDiag(E, diag::note_constexpr_access_unknown_variable, 1)
-          << AK << VD;
-      Info.Note(VD->getLocation(), diag::note_declared_at);
+      if (!Info.checkingPotentialConstantExpression()) {
+        Info.FFDiag(E, diag::note_constexpr_access_unknown_variable, 1)
+            << AK << VD;
+        Info.Note(VD->getLocation(), diag::note_declared_at);
+      }
       return CompleteObject();
     }
   } else if (DynamicAllocLValue DA = LVal.Base.dyn_cast<DynamicAllocLValue>()) {
diff --git a/clang/test/SemaCXX/constant-expression-p2280r4.cpp b/clang/test/SemaCXX/constant-expression-p2280r4.cpp
index 03fea91169787..979d29476c119 100644
--- a/clang/test/SemaCXX/constant-expression-p2280r4.cpp
+++ b/clang/test/SemaCXX/constant-expression-p2280r4.cpp
@@ -357,3 +357,27 @@ namespace pointer_comparisons {
   static_assert(!f4()); // expected-error {{static assertion expression is not an integral constant expression}} \
                         // expected-note {{in call to 'f4()'}}
 }
+
+namespace enable_if_1 {
+  template <__SIZE_TYPE__ N>
+  constexpr void foo(const char (&Str)[N])
+  __attribute((enable_if(__builtin_strlen(Str), ""))) {}
+
+  void x() {
+      foo("1234");
+  }
+}
+
+namespace enable_if_2 {
+  constexpr const char (&f())[];
+  extern const char (&Str)[];
+  constexpr int foo()
+  __attribute((enable_if(__builtin_strlen(Str), "")))
+  {return __builtin_strlen(Str);}
+
+  constexpr const char (&f())[] {return "a";}
+  constexpr const char (&Str)[] = f();
+  void x() {
+      constexpr int x = foo();
+  }
+}
diff --git a/clang/test/SemaCXX/constexpr-never-constant.cpp b/clang/test/SemaCXX/constexpr-never-constant.cpp
index 307810ee263dd..ca6dff22275d5 100644
--- a/clang/test/SemaCXX/constexpr-never-constant.cpp
+++ b/clang/test/SemaCXX/constexpr-never-constant.cpp
@@ -24,3 +24,8 @@ constexpr void other_func() {
 
   throw 12;
 }
+
+// Make sure these don't trigger the diagnostic.
+extern const bool& b;
+constexpr bool fun1() { return b; }
+constexpr bool fun2(const bool& b) { return b; }

Copy link
Contributor

@cor3ntin cor3ntin left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

LGTM (presumably, we want to backport that)

Comment on lines +361 to +383
namespace enable_if_1 {
template <__SIZE_TYPE__ N>
constexpr void foo(const char (&Str)[N])
__attribute((enable_if(__builtin_strlen(Str), ""))) {}

void x() {
foo("1234");
}
}

namespace enable_if_2 {
constexpr const char (&f())[];
extern const char (&Str)[];
constexpr int foo()
__attribute((enable_if(__builtin_strlen(Str), "")))
{return __builtin_strlen(Str);}

constexpr const char (&f())[] {return "a";}
constexpr const char (&Str)[] = f();
void x() {
constexpr int x = foo();
}
}
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Can you reference the issue (either a comment or in the namespace name)?

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We normally use the namespace name, I think we should stick w/ that.

// Make sure these don't trigger the diagnostic.
extern const bool& b;
constexpr bool fun1() { return b; }
constexpr bool fun2(const bool& b) { return b; }
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Can you reference the issue (either a comment or in the namespace name)?

@efriedma-quic efriedma-quic merged commit 6a60f18 into llvm:main Jul 17, 2025
8 of 9 checks passed
@github-project-automation github-project-automation bot moved this from Needs Triage to Done in LLVM Release Status Jul 17, 2025
@efriedma-quic
Copy link
Collaborator Author

/cherry-pick 6a60f18

@llvmbot
Copy link
Member

llvmbot commented Jul 17, 2025

Failed to cherry-pick: 6a60f18

https://github.com/llvm/llvm-project/actions/runs/16355033735

Please manually backport the fix and push it to your github fork. Once this is done, please create a pull request

Copy link
Collaborator

@shafik shafik left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thank you!

Comment on lines +361 to +383
namespace enable_if_1 {
template <__SIZE_TYPE__ N>
constexpr void foo(const char (&Str)[N])
__attribute((enable_if(__builtin_strlen(Str), ""))) {}

void x() {
foo("1234");
}
}

namespace enable_if_2 {
constexpr const char (&f())[];
extern const char (&Str)[];
constexpr int foo()
__attribute((enable_if(__builtin_strlen(Str), "")))
{return __builtin_strlen(Str);}

constexpr const char (&f())[] {return "a";}
constexpr const char (&Str)[] = f();
void x() {
constexpr int x = foo();
}
}
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We normally use the namespace name, I think we should stick w/ that.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
clang:frontend Language frontend issues, e.g. anything involving "Sema" clang Clang issues not falling into any other category release:cherry-pick-failed
Projects
Development

Successfully merging this pull request may close these issues.

[Clang] Error on an enable_if attribute in ADT/StringRef.h in C++23 mode [Clang] -Winvalid-constexpr misbehaves in C++23 mode
5 participants