[clang] 9fae0c6 - Reapply "[clang][Interp] Fix CheckCallable for undefined-and-not-constexpr fns"

Timm Bäder via cfe-commits cfe-commits at lists.llvm.org
Thu Jul 18 07:16:30 PDT 2024


Author: Timm Bäder
Date: 2024-07-18T16:15:59+02:00
New Revision: 9fae0c6f9c05915a5daac5b368258a40e1fab237

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

LOG: Reapply "[clang][Interp] Fix CheckCallable for undefined-and-not-constexpr fns"

This reverts commit ad7aeb0ff58ebd29f68adb85c64e8010639e2a76.

Added: 
    clang/test/AST/Interp/cxx2a.cpp

Modified: 
    clang/lib/AST/Interp/Interp.cpp
    clang/lib/AST/Interp/Interp.h

Removed: 
    


################################################################################
diff  --git a/clang/lib/AST/Interp/Interp.cpp b/clang/lib/AST/Interp/Interp.cpp
index 2be9b5360d055..e6e9298982887 100644
--- a/clang/lib/AST/Interp/Interp.cpp
+++ b/clang/lib/AST/Interp/Interp.cpp
@@ -579,57 +579,62 @@ bool CheckCallable(InterpState &S, CodePtr OpPC, const Function *F) {
     return false;
   }
 
-  if (!F->isConstexpr() || !F->hasBody()) {
-    const SourceLocation &Loc = S.Current->getLocation(OpPC);
-    if (S.getLangOpts().CPlusPlus11) {
-      const FunctionDecl *DiagDecl = F->getDecl();
+  if (F->isConstexpr() && F->hasBody() &&
+      (F->getDecl()->isConstexpr() || F->getDecl()->hasAttr<MSConstexprAttr>()))
+    return true;
 
-      // Invalid decls have been diagnosed before.
-      if (DiagDecl->isInvalidDecl())
-        return false;
+  // Implicitly constexpr.
+  if (F->isLambdaStaticInvoker())
+    return true;
 
-      // 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;
-      }
+  const SourceLocation &Loc = S.Current->getLocation(OpPC);
+  if (S.getLangOpts().CPlusPlus11) {
+    const FunctionDecl *DiagDecl = F->getDecl();
+
+    // Invalid decls have been diagnosed before.
+    if (DiagDecl->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(Loc, diag::note_constexpr_invalid_inhctor, 1)
+    // 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(Loc, 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;
-        if (!DiagDecl->isDefined() && !IsExtern &&
-            S.checkingPotentialConstantExpression())
-          return false;
+      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;
+      if (!DiagDecl->isDefined() && !IsExtern && DiagDecl->isConstexpr() &&
+          S.checkingPotentialConstantExpression())
+        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;
+      // 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;
 
-        S.FFDiag(Loc, diag::note_constexpr_invalid_function, 1)
+      S.FFDiag(Loc, diag::note_constexpr_invalid_function, 1)
           << DiagDecl->isConstexpr() << (bool)CD << DiagDecl;
-        S.Note(DiagDecl->getLocation(), diag::note_declared_at);
-      }
-    } else {
-      S.FFDiag(Loc, diag::note_invalid_subexpr_in_const_expr);
+      S.Note(DiagDecl->getLocation(), diag::note_declared_at);
     }
-    return false;
+  } else {
+    S.FFDiag(Loc, diag::note_invalid_subexpr_in_const_expr);
   }
 
-  return true;
+  return false;
 }
 
 bool CheckCallDepth(InterpState &S, CodePtr OpPC) {

diff  --git a/clang/lib/AST/Interp/Interp.h b/clang/lib/AST/Interp/Interp.h
index 17b3157cb40a9..2e159012f5ffd 100644
--- a/clang/lib/AST/Interp/Interp.h
+++ b/clang/lib/AST/Interp/Interp.h
@@ -2531,14 +2531,14 @@ inline bool Call(InterpState &S, CodePtr OpPC, const Function *Func,
       if (!CheckInvoke(S, OpPC, ThisPtr))
         return false;
     }
-
-    if (S.checkingPotentialConstantExpression())
-      return false;
   }
 
   if (!CheckCallable(S, OpPC, Func))
     return false;
 
+  if (Func->hasThisPointer() && S.checkingPotentialConstantExpression())
+    return false;
+
   if (!CheckCallDepth(S, OpPC))
     return false;
 

diff  --git a/clang/test/AST/Interp/cxx2a.cpp b/clang/test/AST/Interp/cxx2a.cpp
new file mode 100644
index 0000000000000..27d1aa1a27f75
--- /dev/null
+++ b/clang/test/AST/Interp/cxx2a.cpp
@@ -0,0 +1,15 @@
+// RUN: %clang_cc1 -std=c++2a -fsyntax-only -fcxx-exceptions -verify=ref,both %s
+// RUN: %clang_cc1 -std=c++2a -fsyntax-only -fcxx-exceptions -verify=expected,both %s -fexperimental-new-constant-interpreter
+
+template <unsigned N>
+struct S {
+  S() requires (N==1) = default;
+  S() requires (N==2) {} // both-note {{declared here}}
+  consteval S() requires (N==3) = default;
+};
+
+consteval int aConstevalFunction() { // both-error {{consteval function never produces a constant expression}}
+  S<2> s4; // both-note {{non-constexpr constructor 'S' cannot be used in a constant expression}}
+  return 0;
+}
+/// We're NOT calling the above function. The diagnostics should appear anyway.


        


More information about the cfe-commits mailing list