// NOTE: Assertions have been autogenerated by utils/update_cc_test_checks.py UTC_ARGS: --include-generated-funcs --version 5 // with MERGE/NO-MERGE assertions added manually. // N.B. although the clang driver defaults to merge, clang_cc1 defaults to non-merge. // (This is similar to -fsanitize-recover, for which the default is also applied // at the driver level only.) // If optimization is disabled, merging is disabled (overrides -fsanitize-merge). // RUN: %clang_cc1 -O3 -triple x86_64-unknown-linux -fsanitize=cfi-mfcall -fsanitize-trap=cfi-mfcall -fvisibility=hidden -emit-llvm -o - %s | FileCheck %s --check-prefixes=NO-MERGE // RUN: %clang_cc1 -O3 -triple x86_64-unknown-linux -fsanitize-merge=cfi-mfcall -fsanitize=cfi-mfcall -fsanitize-trap=cfi-mfcall -fvisibility=hidden -emit-llvm -o - %s | FileCheck %s --check-prefixes=MERGE struct B1 {}; struct B2 {}; struct B3 : B2 {}; struct S : B1, B3 {}; void f(S *s, void (S::*p)()) { (s->*p)(); (s->*p)(); (s->*p)(); } // NO-MERGE-LABEL: define hidden void @_Z1fP1SMS_FvvE( // NO-MERGE-SAME: ptr noundef [[S:%.*]], i64 [[P_COERCE0:%.*]], i64 [[P_COERCE1:%.*]]) local_unnamed_addr #[[ATTR0:[0-9]+]] { // NO-MERGE-NEXT: [[ENTRY:.*:]] // NO-MERGE-NEXT: [[TMP0:%.*]] = getelementptr inbounds i8, ptr [[S]], i64 [[P_COERCE1]] // NO-MERGE-NEXT: [[TMP1:%.*]] = and i64 [[P_COERCE0]], 1 // NO-MERGE-NEXT: [[MEMPTR_ISVIRTUAL_NOT:%.*]] = icmp eq i64 [[TMP1]], 0 // NO-MERGE-NEXT: br i1 [[MEMPTR_ISVIRTUAL_NOT]], label %[[MEMPTR_NONVIRTUAL:.*]], label %[[MEMPTR_VIRTUAL:.*]] // NO-MERGE: [[MEMPTR_VIRTUAL]]: // NO-MERGE-NEXT: [[VTABLE:%.*]] = load ptr, ptr [[TMP0]], align 8, !tbaa [[TBAA2:![0-9]+]] // NO-MERGE-NEXT: [[TMP2:%.*]] = getelementptr i8, ptr [[VTABLE]], i64 [[P_COERCE0]] // NO-MERGE-NEXT: [[TMP3:%.*]] = getelementptr i8, ptr [[TMP2]], i64 -1 // NO-MERGE-NEXT: [[TMP4:%.*]] = tail call i1 @llvm.type.test(ptr [[TMP3]], metadata !"_ZTSM1SFvvE.virtual"), !nosanitize [[META5:![0-9]+]] // NO-MERGE-NEXT: br i1 [[TMP4]], label %[[MEMPTR_VIRTUAL7:.*]], label %[[TRAP:.*]], !prof [[PROF6:![0-9]+]], !nosanitize [[META5]] // NO-MERGE: [[TRAP]]: // NO-MERGE-NEXT: tail call void @llvm.ubsantrap(i8 2) #[[ATTR3:[0-9]+]], !nosanitize [[META5]] // NO-MERGE-NEXT: unreachable, !nosanitize [[META5]] // NO-MERGE: [[MEMPTR_NONVIRTUAL]]: // NO-MERGE-NEXT: [[MEMPTR_NONVIRTUALFN:%.*]] = inttoptr i64 [[P_COERCE0]] to ptr // NO-MERGE-NEXT: [[TMP5:%.*]] = tail call i1 @llvm.type.test(ptr [[MEMPTR_NONVIRTUALFN]], metadata !"_ZTSM2B1FvvE") // NO-MERGE-NEXT: [[TMP6:%.*]] = tail call i1 @llvm.type.test(ptr [[MEMPTR_NONVIRTUALFN]], metadata !"_ZTSM2B2FvvE") // NO-MERGE-NEXT: [[TMP7:%.*]] = or i1 [[TMP5]], [[TMP6]], !nosanitize [[META5]] // NO-MERGE-NEXT: br i1 [[TMP7]], label %[[MEMPTR_NONVIRTUAL23:.*]], label %[[TRAP2:.*]], !prof [[PROF6]], !nosanitize [[META5]] // NO-MERGE: [[TRAP2]]: // NO-MERGE-NEXT: tail call void @llvm.ubsantrap(i8 2) #[[ATTR4:[0-9]+]], !nosanitize [[META5]] // NO-MERGE-NEXT: unreachable, !nosanitize [[META5]] // NO-MERGE: [[MEMPTR_VIRTUAL7]]: // NO-MERGE-NEXT: [[MEMPTR_VIRTUALFN:%.*]] = load ptr, ptr [[TMP3]], align 8, !nosanitize [[META5]] // NO-MERGE-NEXT: tail call void [[MEMPTR_VIRTUALFN]](ptr noundef nonnull align 1 dereferenceable(1) [[TMP0]]) #[[ATTR5:[0-9]+]] // NO-MERGE-NEXT: [[VTABLE8:%.*]] = load ptr, ptr [[TMP0]], align 8, !tbaa [[TBAA2]] // NO-MERGE-NEXT: [[TMP8:%.*]] = getelementptr i8, ptr [[VTABLE8]], i64 [[P_COERCE0]] // NO-MERGE-NEXT: [[TMP9:%.*]] = getelementptr i8, ptr [[TMP8]], i64 -1 // NO-MERGE-NEXT: [[TMP10:%.*]] = tail call i1 @llvm.type.test(ptr [[TMP9]], metadata !"_ZTSM1SFvvE.virtual"), !nosanitize [[META5]] // NO-MERGE-NEXT: br i1 [[TMP10]], label %[[MEMPTR_VIRTUAL19:.*]], label %[[TRAP2]], !prof [[PROF6]], !nosanitize [[META5]] // NO-MERGE: [[TRAP13:.*]]: // NO-MERGE-NEXT: tail call void @llvm.ubsantrap(i8 2) #[[ATTR4]], !nosanitize [[META5]] // NO-MERGE-NEXT: unreachable, !nosanitize [[META5]] // NO-MERGE: [[MEMPTR_VIRTUAL19]]: // NO-MERGE-NEXT: [[MEMPTR_VIRTUALFN9:%.*]] = load ptr, ptr [[TMP9]], align 8, !nosanitize [[META5]] // NO-MERGE-NEXT: tail call void [[MEMPTR_VIRTUALFN9]](ptr noundef nonnull align 1 dereferenceable(1) [[TMP0]]) #[[ATTR5]] // NO-MERGE-NEXT: [[VTABLE20:%.*]] = load ptr, ptr [[TMP0]], align 8, !tbaa [[TBAA2]] // NO-MERGE-NEXT: [[TMP11:%.*]] = getelementptr i8, ptr [[VTABLE20]], i64 [[P_COERCE0]] // NO-MERGE-NEXT: [[TMP12:%.*]] = getelementptr i8, ptr [[TMP11]], i64 -1 // NO-MERGE-NEXT: [[TMP13:%.*]] = tail call i1 @llvm.type.test(ptr [[TMP12]], metadata !"_ZTSM1SFvvE.virtual"), !nosanitize [[META5]] // NO-MERGE-NEXT: [[MEMPTR_VIRTUALFN21:%.*]] = load ptr, ptr [[TMP12]], align 8, !nosanitize [[META5]] // NO-MERGE-NEXT: br i1 [[TMP13]], label %[[MEMPTR_END27:.*]], label %[[TRAP13]], !prof [[PROF6]], !nosanitize [[META5]] // NO-MERGE: [[MEMPTR_NONVIRTUAL23]]: // NO-MERGE-NEXT: tail call void [[MEMPTR_NONVIRTUALFN]](ptr noundef nonnull align 1 dereferenceable(1) [[TMP0]]) #[[ATTR5]] // NO-MERGE-NEXT: tail call void [[MEMPTR_NONVIRTUALFN]](ptr noundef nonnull align 1 dereferenceable(1) [[TMP0]]) #[[ATTR5]] // NO-MERGE-NEXT: br label %[[MEMPTR_END27]] // NO-MERGE: [[MEMPTR_END27]]: // NO-MERGE-NEXT: [[TMP14:%.*]] = phi ptr [ [[MEMPTR_VIRTUALFN21]], %[[MEMPTR_VIRTUAL19]] ], [ [[MEMPTR_NONVIRTUALFN]], %[[MEMPTR_NONVIRTUAL23]] ] // NO-MERGE-NEXT: tail call void [[TMP14]](ptr noundef nonnull align 1 dereferenceable(1) [[TMP0]]) #[[ATTR5]] // NO-MERGE-NEXT: ret void // // // MERGE-LABEL: define hidden void @_Z1fP1SMS_FvvE( // MERGE-SAME: ptr noundef [[S:%.*]], i64 [[P_COERCE0:%.*]], i64 [[P_COERCE1:%.*]]) local_unnamed_addr #[[ATTR0:[0-9]+]] { // MERGE-NEXT: [[ENTRY:.*:]] // MERGE-NEXT: [[TMP0:%.*]] = getelementptr inbounds i8, ptr [[S]], i64 [[P_COERCE1]] // MERGE-NEXT: [[TMP1:%.*]] = and i64 [[P_COERCE0]], 1 // MERGE-NEXT: [[MEMPTR_ISVIRTUAL_NOT:%.*]] = icmp eq i64 [[TMP1]], 0 // MERGE-NEXT: br i1 [[MEMPTR_ISVIRTUAL_NOT]], label %[[MEMPTR_NONVIRTUAL:.*]], label %[[MEMPTR_VIRTUAL:.*]] // MERGE: [[MEMPTR_VIRTUAL]]: // MERGE-NEXT: [[VTABLE:%.*]] = load ptr, ptr [[TMP0]], align 8, !tbaa [[TBAA2:![0-9]+]] // MERGE-NEXT: [[TMP2:%.*]] = getelementptr i8, ptr [[VTABLE]], i64 [[P_COERCE0]] // MERGE-NEXT: [[TMP3:%.*]] = getelementptr i8, ptr [[TMP2]], i64 -1 // MERGE-NEXT: [[TMP4:%.*]] = tail call i1 @llvm.type.test(ptr [[TMP3]], metadata !"_ZTSM1SFvvE.virtual"), !nosanitize [[META5:![0-9]+]] // MERGE-NEXT: br i1 [[TMP4]], label %[[MEMPTR_VIRTUAL6:.*]], label %[[TRAP:.*]], !prof [[PROF6:![0-9]+]], !nosanitize [[META5]] // MERGE: [[TRAP]]: // MERGE-NEXT: tail call void @llvm.ubsantrap(i8 2) #[[ATTR3:[0-9]+]], !nosanitize [[META5]] // MERGE-NEXT: unreachable, !nosanitize [[META5]] // MERGE: [[MEMPTR_NONVIRTUAL]]: // MERGE-NEXT: [[MEMPTR_NONVIRTUALFN:%.*]] = inttoptr i64 [[P_COERCE0]] to ptr // MERGE-NEXT: [[TMP5:%.*]] = tail call i1 @llvm.type.test(ptr [[MEMPTR_NONVIRTUALFN]], metadata !"_ZTSM2B1FvvE") // MERGE-NEXT: [[TMP6:%.*]] = tail call i1 @llvm.type.test(ptr [[MEMPTR_NONVIRTUALFN]], metadata !"_ZTSM2B2FvvE") // MERGE-NEXT: [[TMP7:%.*]] = or i1 [[TMP5]], [[TMP6]], !nosanitize [[META5]] // MERGE-NEXT: br i1 [[TMP7]], label %[[MEMPTR_NONVIRTUAL21:.*]], label %[[TRAP]], !prof [[PROF6]], !nosanitize [[META5]] // MERGE: [[MEMPTR_VIRTUAL6]]: // MERGE-NEXT: [[MEMPTR_VIRTUALFN:%.*]] = load ptr, ptr [[TMP3]], align 8, !nosanitize [[META5]] // MERGE-NEXT: tail call void [[MEMPTR_VIRTUALFN]](ptr noundef nonnull align 1 dereferenceable(1) [[TMP0]]) #[[ATTR4:[0-9]+]] // MERGE-NEXT: [[VTABLE7:%.*]] = load ptr, ptr [[TMP0]], align 8, !tbaa [[TBAA2]] // MERGE-NEXT: [[TMP8:%.*]] = getelementptr i8, ptr [[VTABLE7]], i64 [[P_COERCE0]] // MERGE-NEXT: [[TMP9:%.*]] = getelementptr i8, ptr [[TMP8]], i64 -1 // MERGE-NEXT: [[TMP10:%.*]] = tail call i1 @llvm.type.test(ptr [[TMP9]], metadata !"_ZTSM1SFvvE.virtual"), !nosanitize [[META5]] // MERGE-NEXT: br i1 [[TMP10]], label %[[MEMPTR_VIRTUAL17:.*]], label %[[TRAP]], !prof [[PROF6]], !nosanitize [[META5]] // MERGE: [[MEMPTR_VIRTUAL17]]: // MERGE-NEXT: [[MEMPTR_VIRTUALFN8:%.*]] = load ptr, ptr [[TMP9]], align 8, !nosanitize [[META5]] // MERGE-NEXT: tail call void [[MEMPTR_VIRTUALFN8]](ptr noundef nonnull align 1 dereferenceable(1) [[TMP0]]) #[[ATTR4]] // MERGE-NEXT: [[VTABLE18:%.*]] = load ptr, ptr [[TMP0]], align 8, !tbaa [[TBAA2]] // MERGE-NEXT: [[TMP11:%.*]] = getelementptr i8, ptr [[VTABLE18]], i64 [[P_COERCE0]] // MERGE-NEXT: [[TMP12:%.*]] = getelementptr i8, ptr [[TMP11]], i64 -1 // MERGE-NEXT: [[TMP13:%.*]] = tail call i1 @llvm.type.test(ptr [[TMP12]], metadata !"_ZTSM1SFvvE.virtual"), !nosanitize [[META5]] // MERGE-NEXT: [[MEMPTR_VIRTUALFN19:%.*]] = load ptr, ptr [[TMP12]], align 8, !nosanitize [[META5]] // MERGE-NEXT: br i1 [[TMP13]], label %[[MEMPTR_END24:.*]], label %[[TRAP]], !prof [[PROF6]], !nosanitize [[META5]] // MERGE: [[MEMPTR_NONVIRTUAL21]]: // MERGE-NEXT: tail call void [[MEMPTR_NONVIRTUALFN]](ptr noundef nonnull align 1 dereferenceable(1) [[TMP0]]) #[[ATTR4]] // MERGE-NEXT: tail call void [[MEMPTR_NONVIRTUALFN]](ptr noundef nonnull align 1 dereferenceable(1) [[TMP0]]) #[[ATTR4]] // MERGE-NEXT: br label %[[MEMPTR_END24]] // MERGE: [[MEMPTR_END24]]: // MERGE-NEXT: [[TMP14:%.*]] = phi ptr [ [[MEMPTR_VIRTUALFN19]], %[[MEMPTR_VIRTUAL17]] ], [ [[MEMPTR_NONVIRTUALFN]], %[[MEMPTR_NONVIRTUAL21]] ] // MERGE-NEXT: tail call void [[TMP14]](ptr noundef nonnull align 1 dereferenceable(1) [[TMP0]]) #[[ATTR4]] // MERGE-NEXT: ret void // MERGE: [[ATTR3]] = { noreturn nounwind } // MERGE: [[ATTR4]] = { nounwind } // NO-MERGE: [[ATTR4]] = { nomerge noreturn nounwind } // NO-MERGE: [[ATTR5]] = { nounwind }