<div dir="ltr">Hello all!<div><br></div><div>On LLDB, if I build LLVM and clang with Release + Asserts, and then build LLDB in Debug mode, I find the llvm::Value class presents itself in a way that creates a linkage issue.</div><div><br></div><div>I fixed it with the diff at the end of the email.</div><div><br></div><div>Essentially what happens is that during the LLVM/clang lib build step, NDEBUG is defined, so Value::assertModuleIsMaterialized() is defined inline (empty method).  This method is called via inline definitions elsewhere in the Value class that clients may call.</div><div><br></div><div>Now, when a client of this library uses it (in this case LLDB), and that client is being built without NDEBUG, then the inline definitions in the header for the Value class are seeing the definition of Value::assertModuleIsMaterialized() that is claiming to be *not* inlined.  However, when the LLVM lib was compiled, no such method was defined and therefore is not in the lib.  This leads to the symbol missing at link time because LLDB's usage of the header with the inline definitions expected to find a non-inlined version of the assertModuleIsMaterialized() method.</div><div><br></div><div>The header is broken w/r/t whether NDEBUG is defined at the time the LLVM library is built vs. when it is used by a client.</div><div><br></div><div>The patch below is a simplistic solution that says "assertModuleIsMaterialized() is always defined in the .cpp file".  Therefore it makes it always a function call, and the call exists regardless of the NDEBUG state of the caller vs. the time the LLVM lib was built.  However, this also means all those assert calls in the header-implemented methods now turn into function calls instead of no-ops.  If there's a better pattern for handling this in LLVM, feel free to suggest.</div><div><br></div><div>Thanks!</div><div><br></div><div>-Todd</div><div><br></div><div><div>diff --git a/include/llvm/IR/Value.h b/include/llvm/IR/Value.h</div><div>index 348ad97..c2997e9 100644</div><div>--- a/include/llvm/IR/Value.h</div><div>+++ b/include/llvm/IR/Value.h</div><div>@@ -280,11 +280,7 @@ public:</div><div>   // when using them since you might not get all uses.</div><div>   // The methods that don't start with materialized_ assert that modules is</div><div>   // fully materialized.</div><div>-#ifdef NDEBUG</div><div>-  void assertModuleIsMaterialized() const {}</div><div>-#else</div><div>   void assertModuleIsMaterialized() const;</div><div>-#endif</div><div> </div><div>   bool use_empty() const {</div><div>     assertModuleIsMaterialized();</div><div>diff --git a/lib/IR/Value.cpp b/lib/IR/Value.cpp</div><div>index 250f451..955204a 100644</div><div>--- a/lib/IR/Value.cpp</div><div>+++ b/lib/IR/Value.cpp</div><div>@@ -314,8 +314,8 @@ void Value::takeName(Value *V) {</div><div>     ST->reinsertValue(this);</div><div> }</div><div> </div><div>-#ifndef NDEBUG</div><div> void Value::assertModuleIsMaterialized() const {</div><div>+#ifndef NDEBUG</div><div>   const GlobalValue *GV = dyn_cast<GlobalValue>(this);</div><div>   if (!GV)</div><div>     return;</div><div>@@ -323,8 +323,10 @@ void Value::assertModuleIsMaterialized() const {</div><div>   if (!M)</div><div>     return;</div><div>   assert(M->isMaterialized());</div><div>+#endif</div><div> }</div><div> </div><div>+#ifndef NDEBUG</div><div> static bool contains(SmallPtrSetImpl<ConstantExpr *> &Cache, ConstantExpr *Expr,</div><div>                      Constant *C) {</div><div>   if (!Cache.insert(Expr).second)</div></div><div><br></div></div>