diff options
author | Alex Lorenz <arphaman@gmail.com> | 2017-01-04 13:40:34 +0000 |
---|---|---|
committer | Alex Lorenz <arphaman@gmail.com> | 2017-01-04 13:40:34 +0000 |
commit | c1608f7f691438d6d457b317c681775621aeac7c (patch) | |
tree | d2c423d3ad6fefcb41862808037f0087736192fe /clang/test/CodeGenCXX/return.cpp | |
parent | af16c50639289fd0875100519a1161bc7058f215 (diff) | |
download | bcm5719-llvm-c1608f7f691438d6d457b317c681775621aeac7c.tar.gz bcm5719-llvm-c1608f7f691438d6d457b317c681775621aeac7c.zip |
Add -f[no-]strict-return flag that can be used to avoid undefined behaviour
in non-void functions that fall off at the end without returning a value when
compiling C++.
Clang uses the new compiler flag to determine when it should treat control flow
paths that fall off the end of a non-void function as unreachable. If
-fno-strict-return is on, the code generator emits the ureachable and trap
IR only when the function returns either a record type with a non-trivial
destructor or another non-trivially copyable type.
The primary goal of this flag is to avoid treating falling off the end of a
non-void function as undefined behaviour. The burden of undefined behaviour
is placed on the caller instead: if the caller ignores the returned value then
the undefined behaviour is avoided. This kind of behaviour is useful in
several cases, e.g. when compiling C code in C++ mode.
rdar://13102603
Differential Revision: https://reviews.llvm.org/D27163
llvm-svn: 290960
Diffstat (limited to 'clang/test/CodeGenCXX/return.cpp')
-rw-r--r-- | clang/test/CodeGenCXX/return.cpp | 101 |
1 files changed, 97 insertions, 4 deletions
diff --git a/clang/test/CodeGenCXX/return.cpp b/clang/test/CodeGenCXX/return.cpp index 5c1cfdaeed7..6166cccd724 100644 --- a/clang/test/CodeGenCXX/return.cpp +++ b/clang/test/CodeGenCXX/return.cpp @@ -1,12 +1,105 @@ -// RUN: %clang_cc1 -emit-llvm -triple %itanium_abi_triple -o - %s | FileCheck %s -// RUN: %clang_cc1 -emit-llvm -triple %itanium_abi_triple -O -o - %s | FileCheck %s --check-prefix=CHECK-OPT +// RUN: %clang_cc1 -emit-llvm -triple %itanium_abi_triple -std=c++11 -o - %s | FileCheck --check-prefixes=CHECK,CHECK-COMMON %s +// RUN: %clang_cc1 -emit-llvm -triple %itanium_abi_triple -std=c++11 -O -o - %s | FileCheck %s --check-prefixes=CHECK-OPT,CHECK-COMMON +// RUN: %clang_cc1 -emit-llvm -triple %itanium_abi_triple -std=c++11 -fno-strict-return -o - %s | FileCheck %s --check-prefixes=CHECK-NOSTRICT,CHECK-COMMON +// RUN: %clang_cc1 -emit-llvm -triple %itanium_abi_triple -std=c++11 -fno-strict-return -Wno-return-type -o - %s | FileCheck %s --check-prefixes=CHECK-NOSTRICT,CHECK-COMMON +// RUN: %clang_cc1 -emit-llvm -triple %itanium_abi_triple -std=c++11 -fno-strict-return -O -o - %s | FileCheck %s --check-prefixes=CHECK-NOSTRICT-OPT,CHECK-COMMON -// CHECK: @_Z9no_return -// CHECK-OPT: @_Z9no_return +// CHECK-COMMON-LABEL: @_Z9no_return int no_return() { // CHECK: call void @llvm.trap // CHECK-NEXT: unreachable // CHECK-OPT-NOT: call void @llvm.trap // CHECK-OPT: unreachable + + // -fno-strict-return should not emit trap + unreachable but it should return + // an undefined value instead. + + // CHECK-NOSTRICT: entry: + // CHECK-NOSTRICT-NEXT: alloca + // CHECK-NOSTRICT-NEXT: load + // CHECK-NOSTRICT-NEXT: ret i32 + // CHECK-NOSTRICT-NEXT: } + + // CHECK-NOSTRICT-OPT: entry: + // CHECK-NOSTRICT-OPT: ret i32 undef +} + +enum Enum { + A, B +}; + +// CHECK-COMMON-LABEL: @_Z27returnNotViableDontOptimize4Enum +int returnNotViableDontOptimize(Enum e) { + switch (e) { + case A: return 1; + case B: return 2; + } + // Undefined behaviour optimization shouldn't be used when -fno-strict-return + // is turned on, even if all the enum cases are covered in this function. + + // CHECK-NOSTRICT-NOT: call void @llvm.trap + // CHECK-NOSTRICT-NOT: unreachable +} + +struct Trivial { + int x; +}; + +// CHECK-NOSTRICT-LABEL: @_Z7trivialv +Trivial trivial() { + // This function returns a trivial record so -fno-strict-return should avoid + // the undefined behaviour optimization. + + // CHECK-NOSTRICT-NOT: call void @llvm.trap + // CHECK-NOSTRICT-NOT: unreachable +} + +struct NonTrivialCopy { + NonTrivialCopy(const NonTrivialCopy &); +}; + +// CHECK-NOSTRICT-LABEL: @_Z14nonTrivialCopyv +NonTrivialCopy nonTrivialCopy() { + // CHECK-NOSTRICT-NOT: call void @llvm.trap + // CHECK-NOSTRICT-NOT: unreachable +} + +struct NonTrivialDefaultConstructor { + int x; + + NonTrivialDefaultConstructor() { } +}; + +// CHECK-NOSTRICT-LABEL: @_Z28nonTrivialDefaultConstructorv +NonTrivialDefaultConstructor nonTrivialDefaultConstructor() { + // CHECK-NOSTRICT-NOT: call void @llvm.trap + // CHECK-NOSTRICT-NOT: unreachable +} + +// Functions that return records with non-trivial destructors should always use +// the -fstrict-return optimization. + +struct NonTrivialDestructor { + ~NonTrivialDestructor(); +}; + +// CHECK-NOSTRICT-LABEL: @_Z20nonTrivialDestructorv +NonTrivialDestructor nonTrivialDestructor() { + // CHECK-NOSTRICT: call void @llvm.trap + // CHECK-NOSTRICT-NEXT: unreachable +} + +// The behavior for lambdas should be identical to functions. +// CHECK-COMMON-LABEL: @_Z10lambdaTestv +void lambdaTest() { + auto lambda1 = []() -> int { + }; + lambda1(); + + // CHECK: call void @llvm.trap + // CHECK-NEXT: unreachable + + // CHECK-NOSTRICT-NOT: call void @llvm.trap + // CHECK-NOSTRICT-NOT: unreachable } |