diff --git a/llvm/lib/Transforms/IPO/FunctionAttrs.cpp b/llvm/lib/Transforms/IPO/FunctionAttrs.cpp --- a/llvm/lib/Transforms/IPO/FunctionAttrs.cpp +++ b/llvm/lib/Transforms/IPO/FunctionAttrs.cpp @@ -1432,6 +1432,12 @@ } static bool functionWillReturn(const Function &F) { + // We can infer and propagate function attributes only when we know that the + // definition we'll get at link time is *exactly* the definition we see now. + // For more details, see GlobalValue::mayBeDerefined. + if (!F.hasExactDefinition()) + return false; + // Must-progress function without side-effects must return. if (F.mustProgress() && F.onlyReadsMemory()) return true; diff --git a/llvm/test/Transforms/FunctionAttrs/willreturn.ll b/llvm/test/Transforms/FunctionAttrs/willreturn.ll --- a/llvm/test/Transforms/FunctionAttrs/willreturn.ll +++ b/llvm/test/Transforms/FunctionAttrs/willreturn.ll @@ -153,5 +153,12 @@ br label %bb1 } +define linkonce i32 @square(i32) { +; CHECK-NOT: Function Attrs: {{.*}}willreturn +; CHECK: define linkonce i32 @square( + %2 = mul nsw i32 %0, %0 + ret i32 %2 +} + declare i64 @fn_noread() readnone declare void @fn_willreturn() willreturn