// RUN: %clang_cc1 -triple x86_64-gnu-linux -x c++ -S -emit-llvm %s -o - | FileCheck %s --check-prefix=CHECK --check-prefix=CHECK-INTEL // RUN: %clang_cc1 -triple aarch64-gnu-linux -x c++ -S -emit-llvm %s -o - | FileCheck %s --check-prefix=CHECK --check-prefix=CHECK-AARCH // RUN: %clang_cc1 -triple x86_64-gnu-linux -x c++ -S -emit-llvm -fsanitize-memory-param-retval %s -o - | FileCheck %s --check-prefix=CHECK --check-prefix=CHECK-INTEL // RUN: %clang_cc1 -triple aarch64-gnu-linux -x c++ -S -emit-llvm -fsanitize-memory-param-retval %s -o - | FileCheck %s --check-prefix=CHECK --check-prefix=CHECK-AARCH // no-sanitize-memory-param-retval does NOT conflict with enable-noundef-analysis // RUN: %clang_cc1 -triple x86_64-gnu-linux -x c++ -S -emit-llvm -fno-sanitize-memory-param-retval %s -o - | FileCheck %s --check-prefix=CHECK --check-prefix=CHECK-INTEL //************ Passing structs by value // TODO: No structs may currently be marked noundef namespace check_structs { struct Trivial { int a; }; Trivial ret_trivial() { return {}; } void pass_trivial(Trivial e) {} // CHECK-INTEL: [[DEF:define( dso_local)?]] i32 @{{.*}}ret_trivial // CHECK-AARCH: [[DEF:define( dso_local)?]] i32 @{{.*}}ret_trivial // CHECK-INTEL: [[DEF]] void @{{.*}}pass_trivial{{.*}}(i32 % // CHECK-AARCH: [[DEF]] void @{{.*}}pass_trivial{{.*}}(i64 % struct NoCopy { int a; NoCopy(NoCopy &) = delete; }; NoCopy ret_nocopy() { return {}; } void pass_nocopy(NoCopy e) {} // CHECK: [[DEF]] void @{{.*}}ret_nocopy{{.*}}(ptr dead_on_unwind noalias writable sret({{[^)]+}}) align 4 % // CHECK: [[DEF]] void @{{.*}}pass_nocopy{{.*}}(ptr noundef % struct Huge { int a[1024]; }; Huge ret_huge() { return {}; } void pass_huge(Huge h) {} // CHECK: [[DEF]] void @{{.*}}ret_huge{{.*}}(ptr dead_on_unwind noalias writable sret({{[^)]+}}) align 4 % // CHECK: [[DEF]] void @{{.*}}pass_huge{{.*}}(ptr noundef } // namespace check_structs //************ Passing unions by value // No unions may be marked noundef namespace check_unions { union Trivial { int a; }; Trivial ret_trivial() { return {}; } void pass_trivial(Trivial e) {} // CHECK-INTEL: [[DEF]] i32 @{{.*}}ret_trivial // CHECK-AARCH: [[DEF]] i32 @{{.*}}ret_trivial // CHECK-INTEL: [[DEF]] void @{{.*}}pass_trivial{{.*}}(i32 % // CHECK-AARCH: [[DEF]] void @{{.*}}pass_trivial{{.*}}(i64 % union NoCopy { int a; NoCopy(NoCopy &) = delete; }; NoCopy ret_nocopy() { return {}; } void pass_nocopy(NoCopy e) {} // CHECK: [[DEF]] void @{{.*}}ret_nocopy{{.*}}(ptr dead_on_unwind noalias writable sret({{[^)]+}}) align 4 % // CHECK: [[DEF]] void @{{.*}}pass_nocopy{{.*}}(ptr noundef % } // namespace check_unions //************ Passing `this` pointers // `this` pointer must always be defined namespace check_this { struct Object { int data[]; Object() { this->data[0] = 0; } int getData() { return this->data[0]; } Object *getThis() { return this; } }; void use_object() { Object obj; obj.getData(); obj.getThis(); } // CHECK: define linkonce_odr void @{{.*}}Object{{.*}}(ptr noundef nonnull align 4 dereferenceable(1) % // CHECK: define linkonce_odr noundef i32 @{{.*}}Object{{.*}}getData{{.*}}(ptr noundef nonnull align 4 dereferenceable(1) % // CHECK: define linkonce_odr noundef ptr @{{.*}}Object{{.*}}getThis{{.*}}(ptr noundef nonnull align 4 dereferenceable(1) % } // namespace check_this //************ Passing vector types namespace check_vecs { typedef int __attribute__((vector_size(12))) i32x3; i32x3 ret_vec() { return {}; } void pass_vec(i32x3 v) { } // CHECK: [[DEF]] noundef <3 x i32> @{{.*}}ret_vec{{.*}}() // CHECK-INTEL: [[DEF]] void @{{.*}}pass_vec{{.*}}(<3 x i32> noundef % // CHECK-AARCH: [[DEF]] void @{{.*}}pass_vec{{.*}}(<4 x i32> % } // namespace check_vecs //************ Passing exotic types // Function/Array pointers, Function member / Data member pointers, nullptr_t, ExtInt types namespace check_exotic { struct Object { int mfunc(); int mdata; }; typedef int Object::*mdptr; typedef int (Object::*mfptr)(); typedef decltype(nullptr) nullptr_t; typedef int (*arrptr)[32]; typedef int (*fnptr)(int); arrptr ret_arrptr() { return nullptr; } fnptr ret_fnptr() { return nullptr; } mdptr ret_mdptr() { return nullptr; } mfptr ret_mfptr() { return nullptr; } nullptr_t ret_npt() { return nullptr; } void pass_npt(nullptr_t t) { } _BitInt(3) ret_BitInt() { return 0; } void pass_BitInt(_BitInt(3) e) { } void pass_large_BitInt(_BitInt(127) e) { } // Pointers to arrays/functions are always noundef // CHECK: [[DEF]] noundef ptr @{{.*}}ret_arrptr{{.*}}() // CHECK: [[DEF]] noundef ptr @{{.*}}ret_fnptr{{.*}}() // Pointers to members are never noundef // CHECK: [[DEF]] i64 @{{.*}}ret_mdptr{{.*}}() // CHECK-INTEL: [[DEF]] { i64, i64 } @{{.*}}ret_mfptr{{.*}}() // CHECK-AARCH: [[DEF]] [2 x i64] @{{.*}}ret_mfptr{{.*}}() // nullptr_t is never noundef // CHECK: [[DEF]] ptr @{{.*}}ret_npt{{.*}}() // CHECK: [[DEF]] void @{{.*}}pass_npt{{.*}}(ptr % // TODO: for now, ExtInt is only noundef if it is sign/zero-extended // CHECK-INTEL: [[DEF]] noundef signext i3 @{{.*}}ret_BitInt{{.*}}() // CHECK-AARCH: [[DEF]] i3 @{{.*}}ret_BitInt{{.*}}() // CHECK-INTEL: [[DEF]] void @{{.*}}pass_BitInt{{.*}}(i3 noundef signext % // CHECK-AARCH: [[DEF]] void @{{.*}}pass_BitInt{{.*}}(i3 % // CHECK-INTEL: [[DEF]] void @{{.*}}pass_large_BitInt{{.*}}(i64 %{{.*}}, i64 % // CHECK-AARCH: [[DEF]] void @{{.*}}pass_large_BitInt{{.*}}(i127 % } // namespace check_exotic