[Clang][OpenCL] Bug in handling non-extern inline function definition when optimization is disabled?

Consider the following OpenCL testcase:
$ cat -n test.cl
1
2 inline void bar()
3 {
4 }
5
6 void __kernel foo()
7 {
8 bar();
9 }

Compilation command:
$ clang -x cl -cl-std=CL3.0 -cl-opt-disable -S -emit-llvm test.cl

Since the definition of bar( ) doesn’t have the extern keyword, its linkage type is available_externally. With optimizations disabled (-cl-opt-disable), the Clang frontend is not inlining the call to bar( ) on line 8 — this seems like the correct behaviour — but it is also deleting the definition of bar( ) because of its linkage type. Consequently, we end up with a call to a function whose definition is missing. Isn’t this incorrect?

In clang/lib/CodeGen/CodeGenModule.cpp, we have this code in the function CodeGenModule::shouldEmitFunction:

bool CodeGenModule::shouldEmitFunction(GlobalDecl GD) {
if (getFunctionLinkage(GD) != llvm::Function::AvailableExternallyLinkage)
return true;
const auto *F = cast(GD.getDecl());
if (CodeGenOpts.OptimizationLevel == 0 && !F->hasAttr())
return false;

Shouldn’t the last line be “return true;”?

I don’t believe so, I think what that is doing is making sure we emit it in optimized modes, so we can use the definition for optimization decisions. In O0 mode, we have no reason to do so, since the optimizer won’t be running there.

I would have expected the USE of ‘bar’ to be sufficient to emit it, however I believe the rules in C are slightly different (as to what ‘inline’ means). Aaron will have to come along as I believe ‘inline’ means something slightly different in C than in C++, but you can see the differences here: Compiler Explorer