Author: Timm Baeder
Date: 2025-10-27T14:06:54+01:00
New Revision: f29235d6981ed2f7aa96034fe53e4c00d4ede90b

URL: 
https://github.com/llvm/llvm-project/commit/f29235d6981ed2f7aa96034fe53e4c00d4ede90b
DIFF: 
https://github.com/llvm/llvm-project/commit/f29235d6981ed2f7aa96034fe53e4c00d4ede90b.diff

LOG: [clang][bytecode] Don't diagnose defined functions that will have a body 
(#165002)

Don't use `hasBody()`, which checks all declarations.

Fixes https://github.com/llvm/llvm-project/issues/164995

Added: 
    

Modified: 
    clang/lib/AST/ByteCode/Interp.cpp
    clang/test/AST/ByteCode/records.cpp

Removed: 
    


################################################################################
diff  --git a/clang/lib/AST/ByteCode/Interp.cpp 
b/clang/lib/AST/ByteCode/Interp.cpp
index 910868b27f48e..df74d80495783 100644
--- a/clang/lib/AST/ByteCode/Interp.cpp
+++ b/clang/lib/AST/ByteCode/Interp.cpp
@@ -932,6 +932,15 @@ static bool CheckCallable(InterpState &S, CodePtr OpPC, 
const Function *F) {
   if (F->isValid() && F->hasBody() && F->isConstexpr())
     return true;
 
+  const FunctionDecl *DiagDecl = F->getDecl();
+  const FunctionDecl *Definition = nullptr;
+  DiagDecl->getBody(Definition);
+
+  if (!Definition && S.checkingPotentialConstantExpression() &&
+      DiagDecl->isConstexpr()) {
+    return false;
+  }
+
   // Implicitly constexpr.
   if (F->isLambdaStaticInvoker())
     return true;
@@ -939,7 +948,7 @@ static bool CheckCallable(InterpState &S, CodePtr OpPC, 
const Function *F) {
   // Bail out if the function declaration itself is invalid.  We will
   // have produced a relevant diagnostic while parsing it, so just
   // note the problematic sub-expression.
-  if (F->getDecl()->isInvalidDecl())
+  if (DiagDecl->isInvalidDecl())
     return Invalid(S, OpPC);
 
   // Diagnose failed assertions specially.
@@ -957,64 +966,61 @@ static bool CheckCallable(InterpState &S, CodePtr OpPC, 
const Function *F) {
     }
   }
 
-  if (S.getLangOpts().CPlusPlus11) {
-    const FunctionDecl *DiagDecl = F->getDecl();
-
-    // Invalid decls have been diagnosed before.
-    if (DiagDecl->isInvalidDecl())
-      return false;
+  if (!S.getLangOpts().CPlusPlus11) {
+    S.FFDiag(S.Current->getLocation(OpPC),
+             diag::note_invalid_subexpr_in_const_expr);
+    return false;
+  }
 
-    // If this function is not constexpr because it is an inherited
-    // non-constexpr constructor, diagnose that directly.
-    const auto *CD = dyn_cast<CXXConstructorDecl>(DiagDecl);
-    if (CD && CD->isInheritingConstructor()) {
-      const auto *Inherited = CD->getInheritedConstructor().getConstructor();
-      if (!Inherited->isConstexpr())
-        DiagDecl = CD = Inherited;
-    }
+  // Invalid decls have been diagnosed before.
+  if (DiagDecl->isInvalidDecl())
+    return false;
 
-    // Silently reject constructors of invalid classes. The invalid class
-    // has been rejected elsewhere before.
-    if (CD && CD->getParent()->isInvalidDecl())
-      return false;
+  // If this function is not constexpr because it is an inherited
+  // non-constexpr constructor, diagnose that directly.
+  const auto *CD = dyn_cast<CXXConstructorDecl>(DiagDecl);
+  if (CD && CD->isInheritingConstructor()) {
+    const auto *Inherited = CD->getInheritedConstructor().getConstructor();
+    if (!Inherited->isConstexpr())
+      DiagDecl = CD = Inherited;
+  }
 
-    // FIXME: If DiagDecl is an implicitly-declared special member function
-    // or an inheriting constructor, we should be much more explicit about why
-    // it's not constexpr.
-    if (CD && CD->isInheritingConstructor()) {
-      S.FFDiag(S.Current->getLocation(OpPC),
-               diag::note_constexpr_invalid_inhctor, 1)
-          << CD->getInheritedConstructor().getConstructor()->getParent();
-      S.Note(DiagDecl->getLocation(), diag::note_declared_at);
-    } else {
-      // Don't emit anything if the function isn't defined and we're checking
-      // for a constant expression. It might be defined at the point we're
-      // actually calling it.
-      bool IsExtern = DiagDecl->getStorageClass() == SC_Extern;
-      bool IsDefined = F->isDefined();
-      if (!IsDefined && !IsExtern && DiagDecl->isConstexpr() &&
-          S.checkingPotentialConstantExpression())
-        return false;
+  // Silently reject constructors of invalid classes. The invalid class
+  // has been rejected elsewhere before.
+  if (CD && CD->getParent()->isInvalidDecl())
+    return false;
 
-      // If the declaration is defined, declared 'constexpr' _and_ has a body,
-      // the below diagnostic doesn't add anything useful.
-      if (DiagDecl->isDefined() && DiagDecl->isConstexpr() &&
-          DiagDecl->hasBody())
-        return false;
+  // FIXME: If DiagDecl is an implicitly-declared special member function
+  // or an inheriting constructor, we should be much more explicit about why
+  // it's not constexpr.
+  if (CD && CD->isInheritingConstructor()) {
+    S.FFDiag(S.Current->getLocation(OpPC), 
diag::note_constexpr_invalid_inhctor,
+             1)
+        << CD->getInheritedConstructor().getConstructor()->getParent();
+    S.Note(DiagDecl->getLocation(), diag::note_declared_at);
+  } else {
+    // Don't emit anything if the function isn't defined and we're checking
+    // for a constant expression. It might be defined at the point we're
+    // actually calling it.
+    bool IsExtern = DiagDecl->getStorageClass() == SC_Extern;
+    bool IsDefined = F->isDefined();
+    if (!IsDefined && !IsExtern && DiagDecl->isConstexpr() &&
+        S.checkingPotentialConstantExpression())
+      return false;
 
-      S.FFDiag(S.Current->getLocation(OpPC),
-               diag::note_constexpr_invalid_function, 1)
-          << DiagDecl->isConstexpr() << (bool)CD << DiagDecl;
+    // If the declaration is defined, declared 'constexpr' _and_ has a body,
+    // the below diagnostic doesn't add anything useful.
+    if (DiagDecl->isDefined() && DiagDecl->isConstexpr() && 
DiagDecl->hasBody())
+      return false;
 
-      if (DiagDecl->getDefinition())
-        S.Note(DiagDecl->getDefinition()->getLocation(),
-               diag::note_declared_at);
-      else
-        S.Note(DiagDecl->getLocation(), diag::note_declared_at);
-    }
-  } else {
     S.FFDiag(S.Current->getLocation(OpPC),
-             diag::note_invalid_subexpr_in_const_expr);
+             diag::note_constexpr_invalid_function, 1)
+        << DiagDecl->isConstexpr() << (bool)CD << DiagDecl;
+
+    if (DiagDecl->getDefinition())
+      S.Note(DiagDecl->getDefinition()->getLocation(), diag::note_declared_at);
+    else
+      S.Note(DiagDecl->getLocation(), diag::note_declared_at);
   }
 
   return false;

diff  --git a/clang/test/AST/ByteCode/records.cpp 
b/clang/test/AST/ByteCode/records.cpp
index 00218ba02bb31..83f32c97c50c7 100644
--- a/clang/test/AST/ByteCode/records.cpp
+++ b/clang/test/AST/ByteCode/records.cpp
@@ -1861,3 +1861,24 @@ namespace PrimitiveInitializedByInitList {
   } c{ 17 };
   static_assert(c.b == 17, "");
 }
+
+namespace MethodWillHaveBody {
+  class A {
+  public:
+    static constexpr int get_value2() { return 1 + get_value(); }
+    static constexpr int get_value() { return 1; }
+  };
+  static_assert(A::get_value2() == 2, "");
+
+  template<typename T> constexpr T f(T);
+  template<typename T> constexpr T g(T t) {
+    typedef int arr[f(T())]; // both-warning {{variable length array}} \
+                             // both-note {{undefined function 'f<int>'}}
+    return t;
+  }
+  template<typename T> constexpr T f(T t) { // both-note {{declared here}}
+    typedef int arr[g(T())]; // both-note {{instantiation of}}
+    return t;
+  }
+  int n = f(0); // both-note {{instantiation of}}
+}


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

Reply via email to