From 36ef0d54cfddf31cd48816e78ab4db73b31a6c1d Mon Sep 17 00:00:00 2001 From: Richard Smith Date: Thu, 4 Oct 2012 23:52:29 +0000 Subject: [PATCH] If we flow off the end of a value-returning function: - outside C++, return undef (behavior is not undefined unless the value is used) - in C++, with -fcatch-undefined-behavior, perform an appropriate trap - in C++, produce an 'unreachable' (behavior is undefined immediately) git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@165273 91177308-0d34-0410-b5e6-96231b3b80d8 --- lib/CodeGen/CodeGenFunction.cpp | 14 ++++++++++++++ test/CodeGen/catch-undef-behavior.c | 8 ++++++++ test/CodeGenCXX/catch-undef-behavior.cpp | 6 ++++++ test/CodeGenCXX/return.cpp | 6 ++++++ 4 files changed, 34 insertions(+) create mode 100644 test/CodeGenCXX/return.cpp diff --git a/lib/CodeGen/CodeGenFunction.cpp b/lib/CodeGen/CodeGenFunction.cpp index 1d02861ed7..5c0247a33f 100644 --- a/lib/CodeGen/CodeGenFunction.cpp +++ b/lib/CodeGen/CodeGenFunction.cpp @@ -535,6 +535,20 @@ void CodeGenFunction::GenerateCode(GlobalDecl GD, llvm::Function *Fn, else EmitFunctionBody(Args); + // C++11 [stmt.return]p2: + // Flowing off the end of a function [...] results in undefined behavior in + // a value-returning function. + // C11 6.9.1p12: + // If the '}' that terminates a function is reached, and the value of the + // function call is used by the caller, the behavior is undefined. + if (getContext().getLangOpts().CPlusPlus && !FD->hasImplicitReturnZero() && + !FD->getResultType()->isVoidType() && Builder.GetInsertBlock()) { + if (CatchUndefined) + EmitCheck(Builder.getFalse()); + Builder.CreateUnreachable(); + Builder.ClearInsertionPoint(); + } + // Emit the standard function epilogue. FinishFunction(BodyRange.getEnd()); diff --git a/test/CodeGen/catch-undef-behavior.c b/test/CodeGen/catch-undef-behavior.c index 5832b6c830..53dda5c8b2 100644 --- a/test/CodeGen/catch-undef-behavior.c +++ b/test/CodeGen/catch-undef-behavior.c @@ -44,3 +44,11 @@ int rsh_inbounds(int a, int b) { // CHECK-NEXT: ret i32 %[[RET]] return a >> b; } + +// CHECK: @no_return +int no_return() { + // Reaching the end of a noreturn function is fine in C. + // CHECK-NOT: call + // CHECK-NOT: unreachable + // CHECK: ret i32 +} diff --git a/test/CodeGenCXX/catch-undef-behavior.cpp b/test/CodeGenCXX/catch-undef-behavior.cpp index 0ec1cc1e05..fdc2b00bcb 100644 --- a/test/CodeGenCXX/catch-undef-behavior.cpp +++ b/test/CodeGenCXX/catch-undef-behavior.cpp @@ -86,3 +86,9 @@ int lsh_overflow(int a, int b) { // CHECK-NEXT: ret i32 %[[RET]] return a << b; } + +// CHECK: @_Z9no_return +int no_return() { + // CHECK: call void @llvm.trap + // CHECK: unreachable +} diff --git a/test/CodeGenCXX/return.cpp b/test/CodeGenCXX/return.cpp new file mode 100644 index 0000000000..2af1a5266e --- /dev/null +++ b/test/CodeGenCXX/return.cpp @@ -0,0 +1,6 @@ +// RUN: %clang_cc1 -emit-llvm -o - %s | FileCheck %s + +// CHECK: @_Z9no_return +int no_return() { + // CHECK: unreachable +} -- 2.40.0