[clang] [clang][Interp] Fix compiling undefined templated functions (PR #67232)

Timm Baeder via cfe-commits cfe-commits at lists.llvm.org
Sat Sep 23 03:47:38 PDT 2023


https://github.com/tbaederr created https://github.com/llvm/llvm-project/pull/67232

None

>From ed30d89a3c8f0ec5296561e128b2af8b05ade5ca Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Timm=20B=C3=A4der?= <tbaeder at redhat.com>
Date: Fri, 22 Sep 2023 21:26:51 +0200
Subject: [PATCH] [clang][Interp] Fix compiling undefined templated functions

---
 clang/lib/AST/Interp/ByteCodeEmitter.cpp |  6 +++++-
 clang/lib/AST/Interp/Context.cpp         |  4 ++--
 clang/lib/AST/Interp/Function.h          |  5 +++++
 clang/test/AST/Interp/functions.cpp      | 11 +++++++++++
 4 files changed, 23 insertions(+), 3 deletions(-)

diff --git a/clang/lib/AST/Interp/ByteCodeEmitter.cpp b/clang/lib/AST/Interp/ByteCodeEmitter.cpp
index 9b6adcc29bac5f1..f33a151037fd130 100644
--- a/clang/lib/AST/Interp/ByteCodeEmitter.cpp
+++ b/clang/lib/AST/Interp/ByteCodeEmitter.cpp
@@ -94,8 +94,12 @@ ByteCodeEmitter::compileFunc(const FunctionDecl *FuncDecl) {
   assert(Func);
   // For not-yet-defined functions, we only create a Function instance and
   // compile their body later.
-  if (!FuncDecl->isDefined())
+  if (!FuncDecl->isDefined()) {
+    Func->setDefined(false);
     return Func;
+  }
+
+  Func->setDefined(true);
 
   // Lambda static invokers are a special case that we emit custom code for.
   bool IsEligibleForCompilation = false;
diff --git a/clang/lib/AST/Interp/Context.cpp b/clang/lib/AST/Interp/Context.cpp
index 1a732b6c1a092ac..f2f4a5cadc47a4c 100644
--- a/clang/lib/AST/Interp/Context.cpp
+++ b/clang/lib/AST/Interp/Context.cpp
@@ -214,8 +214,8 @@ Context::getOverridingFunction(const CXXRecordDecl *DynamicDecl,
 const Function *Context::getOrCreateFunction(const FunctionDecl *FD) {
   assert(FD);
   const Function *Func = P->getFunction(FD);
-  bool IsBeingCompiled = Func && !Func->isFullyCompiled();
-  bool WasNotDefined = Func && !Func->isConstexpr() && !Func->hasBody();
+  bool IsBeingCompiled = Func && Func->isDefined() && !Func->isFullyCompiled();
+  bool WasNotDefined = Func && !Func->isConstexpr() && !Func->isDefined();
 
   if (IsBeingCompiled)
     return Func;
diff --git a/clang/lib/AST/Interp/Function.h b/clang/lib/AST/Interp/Function.h
index 5444c9f59cda7ea..0bae314e97701d9 100644
--- a/clang/lib/AST/Interp/Function.h
+++ b/clang/lib/AST/Interp/Function.h
@@ -169,6 +169,9 @@ class Function final {
   /// Checks if the function already has a body attached.
   bool hasBody() const { return HasBody; }
 
+  /// Checks if the function is defined.
+  bool isDefined() const { return Defined; }
+
   unsigned getBuiltinID() const { return F->getBuiltinID(); }
 
   bool isBuiltin() const { return F->getBuiltinID() != 0; }
@@ -204,6 +207,7 @@ class Function final {
   }
 
   void setIsFullyCompiled(bool FC) { IsFullyCompiled = FC; }
+  void setDefined(bool D) { Defined = D; }
 
 private:
   friend class Program;
@@ -245,6 +249,7 @@ class Function final {
   bool HasRVO = false;
   /// If we've already compiled the function's body.
   bool HasBody = false;
+  bool Defined = false;
 
 public:
   /// Dumps the disassembled bytecode to \c llvm::errs().
diff --git a/clang/test/AST/Interp/functions.cpp b/clang/test/AST/Interp/functions.cpp
index 331df74d50b3d62..5cdecbff1e9d3d4 100644
--- a/clang/test/AST/Interp/functions.cpp
+++ b/clang/test/AST/Interp/functions.cpp
@@ -332,3 +332,14 @@ namespace InvalidReclRefs {
   }
 #endif
 }
+
+namespace TemplateUndefined {
+  template<typename T> constexpr int consume(T);
+  // ok, not a constant expression.
+  const int k = consume(0);
+
+  template<typename T> constexpr int consume(T) { return 0; }
+  // ok, constant expression.
+  constexpr int l = consume(0);
+  static_assert(l == 0, "");
+}



More information about the cfe-commits mailing list