Index: llvm/trunk/lib/Analysis/Lint.cpp =================================================================== --- llvm/trunk/lib/Analysis/Lint.cpp +++ llvm/trunk/lib/Analysis/Lint.cpp @@ -285,15 +285,24 @@ } } - if (CS.isCall() && cast(CS.getInstruction())->isTailCall()) - for (CallSite::arg_iterator AI = CS.arg_begin(), AE = CS.arg_end(); - AI != AE; ++AI) { - Value *Obj = findValue(*AI, /*OffsetOk=*/true); - Assert(!isa(Obj), - "Undefined behavior: Call with \"tail\" keyword references " - "alloca", - &I); + if (CS.isCall()) { + const CallInst *CI = cast(CS.getInstruction()); + if (CI->isTailCall()) { + const AttributeList &PAL = CI->getAttributes(); + unsigned ArgNo = 0; + for (Value *Arg : CS.args()) { + // Skip ByVal arguments since they will be memcpy'd to the callee's + // stack anyway. + if (PAL.hasParamAttribute(ArgNo++, Attribute::ByVal)) + continue; + Value *Obj = findValue(Arg, /*OffsetOk=*/true); + Assert(!isa(Obj), + "Undefined behavior: Call with \"tail\" keyword references " + "alloca", + &I); + } } + } if (IntrinsicInst *II = dyn_cast(&I)) Index: llvm/trunk/test/Analysis/Lint/tail-call-byval.ll =================================================================== --- llvm/trunk/test/Analysis/Lint/tail-call-byval.ll +++ llvm/trunk/test/Analysis/Lint/tail-call-byval.ll @@ -0,0 +1,33 @@ +; RUN: opt < %s -lint -disable-output 2>&1 | FileCheck %s + +%s = type { i8 } + +declare void @f1(%s*) + +define void @f2() { +entry: + %c = alloca %s + tail call void @f1(%s* %c) + ret void +} + +; Lint should complain about the tail call passing the alloca'd value %c to f1. +; CHECK: Undefined behavior: Call with "tail" keyword references alloca +; CHECK-NEXT: tail call void @f1(%s* %c) + +declare void @f3(%s* byval) + +define void @f4() { +entry: + %c = alloca %s + tail call void @f3(%s* byval %c) + ret void +} + +; Lint should not complain about passing the alloca'd %c since it's passed +; byval, effectively copying the data to the stack instead of leaking the +; pointer itself. +; CHECK-NOT: Undefined behavior: Call with "tail" keyword references alloca +; CHECK-NOT: tail call void @f3(%s* byval %c) + +