// 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-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: alloca // CHECK-NOSTRICT-NEXT: load // CHECK-NOSTRICT-NEXT: ret i32 // CHECK-NOSTRICT-NEXT: } // 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 }