cb424d7448
verify-patch-sanity.py validates every active recipe .patch has internally- consistent hunk line counts — catching the 'malformed patch at line N' failure at commit/CI/preflight time instead of hours into a cook. This cycle hit that class three times (qtwaylandscanner, sddm, xwayland), each only discovered when cookbook tried to apply the patch. Running it across the repo found 29 latent malformed patches (validated against GNU patch: e.g. relibc/P3-sysv-ipc reproduces 'malformed patch at line 22'). They were harmless only because they sit in vendored recipes (baked, not re- applied) — but would fail on any version-bump re-derivation. --fix recounts the hunk headers (body untouched) and repaired all 29. Wired into build-preflight.sh (Phase 1.0D) and redbear-ci.yml, with a unit test (test-patch-sanity.sh). Skips archived/legacy trees and unvalidatable formats (empty placeholders, bare-@@ git hunks).
320 lines
10 KiB
C++
320 lines
10 KiB
C++
// RUN: %clang_cc1 -triple=x86_64-linux-gnu -emit-llvm -fstrict-vtable-pointers -o - %s \
|
|
// RUN: | FileCheck --check-prefixes=CHECK,CHECK-STRICT %s
|
|
// RUN: %clang_cc1 -triple=x86_64-linux-gnu -emit-llvm -o - %s \
|
|
// RUN: | FileCheck --check-prefixes=CHECK,CHECK-NONSTRICT %s
|
|
|
|
//===----------------------------------------------------------------------===//
|
|
// Positive Cases
|
|
//===----------------------------------------------------------------------===//
|
|
|
|
struct TestVirtualFn {
|
|
virtual void foo() {}
|
|
};
|
|
|
|
// CHECK-LABEL: define{{.*}} void @test_builtin_launder_virtual_fn
|
|
extern "C" void test_builtin_launder_virtual_fn(TestVirtualFn *p) {
|
|
// CHECK: store ptr %p, ptr %p.addr
|
|
// CHECK-NEXT: [[TMP0:%.*]] = load ptr, ptr %p.addr
|
|
|
|
// CHECK-NONSTRICT-NEXT: store ptr [[TMP0]], ptr %d
|
|
|
|
// CHECK-STRICT-NEXT: [[TMP2:%.*]] = call ptr @llvm.launder.invariant.group.p0(ptr [[TMP0]])
|
|
// CHECK-STRICT-NEXT: store ptr [[TMP2]], ptr %d
|
|
|
|
// CHECK-NEXT: ret void
|
|
TestVirtualFn *d = __builtin_launder(p);
|
|
}
|
|
|
|
struct TestPolyBase : TestVirtualFn {
|
|
};
|
|
|
|
// CHECK-LABEL: define{{.*}} void @test_builtin_launder_poly_base
|
|
extern "C" void test_builtin_launder_poly_base(TestPolyBase *p) {
|
|
// CHECK-STRICT-NOT: ret void
|
|
// CHECK-STRICT: @llvm.launder.invariant.group
|
|
|
|
// CHECK-NONSTRICT-NOT: @llvm.launder.invariant.group
|
|
|
|
// CHECK: ret void
|
|
TestPolyBase *d = __builtin_launder(p);
|
|
}
|
|
|
|
struct TestBase {};
|
|
struct TestVirtualBase : virtual TestBase {};
|
|
|
|
// CHECK-LABEL: define{{.*}} void @test_builtin_launder_virtual_base
|
|
extern "C" void test_builtin_launder_virtual_base(TestVirtualBase *p) {
|
|
// CHECK-STRICT-NOT: ret void
|
|
// CHECK-STRICT: @llvm.launder.invariant.group
|
|
|
|
// CHECK-NONSTRICT-NOT: @llvm.launder.invariant.group
|
|
|
|
// CHECK: ret void
|
|
TestVirtualBase *d = __builtin_launder(p);
|
|
}
|
|
|
|
//===----------------------------------------------------------------------===//
|
|
// Negative Cases
|
|
//===----------------------------------------------------------------------===//
|
|
|
|
// CHECK-LABEL: define{{.*}} void @test_builtin_launder_ommitted_one
|
|
extern "C" void test_builtin_launder_ommitted_one(int *p) {
|
|
// CHECK: entry
|
|
// CHECK-NEXT: %p.addr = alloca ptr
|
|
// CHECK-NEXT: %d = alloca ptr
|
|
// CHECK-NEXT: store ptr %p, ptr %p.addr, align 8
|
|
// CHECK-NEXT: [[TMP:%.*]] = load ptr, ptr %p.addr
|
|
// CHECK-NEXT: store ptr [[TMP]], ptr %d
|
|
// CHECK-NEXT: ret void
|
|
int *d = __builtin_launder(p);
|
|
}
|
|
|
|
struct TestNoInvariant {
|
|
int x;
|
|
};
|
|
|
|
// CHECK-LABEL: define{{.*}} void @test_builtin_launder_ommitted_two
|
|
extern "C" void test_builtin_launder_ommitted_two(TestNoInvariant *p) {
|
|
// CHECK: entry
|
|
// CHECK-NOT: llvm.launder.invariant.group
|
|
// CHECK-NEXT: %p.addr = alloca ptr, align 8
|
|
// CHECK-NEXT: %d = alloca ptr
|
|
// CHECK-NEXT: store ptr %p, ptr %p.addr
|
|
// CHECK-NEXT: [[TMP:%.*]] = load ptr, ptr %p.addr
|
|
// CHECK-NEXT: store ptr [[TMP]], ptr %d
|
|
// CHECK-NEXT: ret void
|
|
TestNoInvariant *d = __builtin_launder(p);
|
|
}
|
|
|
|
struct TestVirtualMember {
|
|
TestVirtualFn member;
|
|
};
|
|
|
|
// CHECK-LABEL: define{{.*}} void @test_builtin_launder_virtual_member
|
|
extern "C" void test_builtin_launder_virtual_member(TestVirtualMember *p) {
|
|
// CHECK: entry
|
|
// CHECK-NONSTRICT-NOT: @llvm.launder.invariant.group
|
|
// CHECK-STRICT: @llvm.launder.invariant.group
|
|
// CHECK: ret void
|
|
TestVirtualMember *d = __builtin_launder(p);
|
|
}
|
|
|
|
struct TestVirtualMemberDepth2 {
|
|
TestVirtualMember member;
|
|
};
|
|
|
|
// CHECK-LABEL: define{{.*}} void @test_builtin_launder_virtual_member_depth_2
|
|
extern "C" void test_builtin_launder_virtual_member_depth_2(TestVirtualMemberDepth2 *p) {
|
|
// CHECK: entry
|
|
// CHECK-NONSTRICT-NOT: @llvm.launder.invariant.group
|
|
// CHECK-STRICT: @llvm.launder.invariant.group
|
|
// CHECK: ret void
|
|
TestVirtualMemberDepth2 *d = __builtin_launder(p);
|
|
}
|
|
|
|
struct TestVirtualReferenceMember {
|
|
TestVirtualFn &member;
|
|
};
|
|
|
|
// CHECK-LABEL: define{{.*}} void @test_builtin_launder_virtual_reference_member
|
|
extern "C" void test_builtin_launder_virtual_reference_member(TestVirtualReferenceMember *p) {
|
|
// CHECK: entry
|
|
// CHECK-NOT: @llvm.launder.invariant.group
|
|
// CHECK: ret void
|
|
TestVirtualReferenceMember *d = __builtin_launder(p);
|
|
}
|
|
|
|
struct TestRecursiveMember {
|
|
TestRecursiveMember() : member(*this) {}
|
|
TestRecursiveMember &member;
|
|
};
|
|
|
|
// CHECK-LABEL: define{{.*}} void @test_builtin_launder_recursive_member
|
|
extern "C" void test_builtin_launder_recursive_member(TestRecursiveMember *p) {
|
|
// CHECK: entry
|
|
// CHECK-NOT: @llvm.launder.invariant.group
|
|
// CHECK: ret void
|
|
TestRecursiveMember *d = __builtin_launder(p);
|
|
}
|
|
|
|
struct TestVirtualRecursiveMember {
|
|
TestVirtualRecursiveMember() : member(*this) {}
|
|
TestVirtualRecursiveMember &member;
|
|
virtual void foo();
|
|
};
|
|
|
|
// CHECK-LABEL: define{{.*}} void @test_builtin_launder_virtual_recursive_member
|
|
extern "C" void test_builtin_launder_virtual_recursive_member(TestVirtualRecursiveMember *p) {
|
|
// CHECK: entry
|
|
// CHECK-NONSTRICT-NOT: @llvm.launder.invariant.group
|
|
// CHECK-STRICT: @llvm.launder.invariant.group
|
|
// CHECK: ret void
|
|
TestVirtualRecursiveMember *d = __builtin_launder(p);
|
|
}
|
|
|
|
// CHECK-LABEL: define{{.*}} void @test_builtin_launder_array(
|
|
extern "C" void test_builtin_launder_array(TestVirtualFn (&Arr)[5]) {
|
|
// CHECK: entry
|
|
// CHECK-NONSTRICT-NOT: @llvm.launder.invariant.group
|
|
// CHECK-STRICT: @llvm.launder.invariant.group
|
|
// CHECK: ret void
|
|
TestVirtualFn *d = __builtin_launder(Arr);
|
|
}
|
|
|
|
// CHECK-LABEL: define{{.*}} void @test_builtin_launder_array_nested(
|
|
extern "C" void test_builtin_launder_array_nested(TestVirtualFn (&Arr)[5][2]) {
|
|
// CHECK: entry
|
|
// CHECK-NONSTRICT-NOT: @llvm.launder.invariant.group
|
|
// CHECK-STRICT: @llvm.launder.invariant.group
|
|
// CHECK: ret void
|
|
using RetTy = TestVirtualFn(*)[2];
|
|
RetTy d = __builtin_launder(Arr);
|
|
}
|
|
|
|
// CHECK-LABEL: define{{.*}} void @test_builtin_launder_array_no_invariant(
|
|
extern "C" void test_builtin_launder_array_no_invariant(TestNoInvariant (&Arr)[5]) {
|
|
// CHECK: entry
|
|
// CHECK-NOT: @llvm.launder.invariant.group
|
|
// CHECK: ret void
|
|
TestNoInvariant *d = __builtin_launder(Arr);
|
|
}
|
|
|
|
// CHECK-LABEL: define{{.*}} void @test_builtin_launder_array_nested_no_invariant(
|
|
extern "C" void test_builtin_launder_array_nested_no_invariant(TestNoInvariant (&Arr)[5][2]) {
|
|
// CHECK: entry
|
|
// CHECK-NOT: @llvm.launder.invariant.group
|
|
// CHECK: ret void
|
|
using RetTy = TestNoInvariant(*)[2];
|
|
RetTy d = __builtin_launder(Arr);
|
|
}
|
|
|
|
template <class Member>
|
|
struct WithMember {
|
|
Member mem;
|
|
};
|
|
|
|
template struct WithMember<TestVirtualFn[5]>;
|
|
|
|
// CHECK-LABEL: define{{.*}} void @test_builtin_launder_member_array(
|
|
extern "C" void test_builtin_launder_member_array(WithMember<TestVirtualFn[5]> *p) {
|
|
// CHECK: entry
|
|
// CHECK-NONSTRICT-NOT: @llvm.launder.invariant.group
|
|
// CHECK-STRICT: @llvm.launder.invariant.group
|
|
// CHECK: ret void
|
|
auto *d = __builtin_launder(p);
|
|
}
|
|
|
|
template struct WithMember<TestVirtualFn[5][2]>;
|
|
|
|
// CHECK-LABEL: define{{.*}} void @test_builtin_launder_member_array_nested(
|
|
extern "C" void test_builtin_launder_member_array_nested(WithMember<TestVirtualFn[5][2]> *p) {
|
|
// CHECK: entry
|
|
// CHECK-NONSTRICT-NOT: @llvm.launder.invariant.group
|
|
// CHECK-STRICT: @llvm.launder.invariant.group
|
|
// CHECK: ret void
|
|
auto *d = __builtin_launder(p);
|
|
}
|
|
|
|
template struct WithMember<TestNoInvariant[5]>;
|
|
|
|
// CHECK-LABEL: define{{.*}} void @test_builtin_launder_member_array_no_invariant(
|
|
extern "C" void test_builtin_launder_member_array_no_invariant(WithMember<TestNoInvariant[5]> *p) {
|
|
// CHECK: entry
|
|
// CHECK-NOT: @llvm.launder.invariant.group
|
|
// CHECK: ret void
|
|
auto *d = __builtin_launder(p);
|
|
}
|
|
|
|
template struct WithMember<TestNoInvariant[5][2]>;
|
|
|
|
// CHECK-LABEL: define{{.*}} void @test_builtin_launder_member_array_nested_no_invariant(
|
|
extern "C" void test_builtin_launder_member_array_nested_no_invariant(WithMember<TestNoInvariant[5][2]> *p) {
|
|
// CHECK: entry
|
|
// CHECK-NOT: @llvm.launder.invariant.group
|
|
// CHECK: ret void
|
|
auto *d = __builtin_launder(p);
|
|
}
|
|
|
|
template <class T>
|
|
struct WithBase : T {};
|
|
|
|
template struct WithBase<TestNoInvariant>;
|
|
|
|
// CHECK-LABEL: define{{.*}} void @test_builtin_launder_base_no_invariant(
|
|
extern "C" void test_builtin_launder_base_no_invariant(WithBase<TestNoInvariant> *p) {
|
|
// CHECK: entry
|
|
// CHECK-NOT: @llvm.launder.invariant.group
|
|
// CHECK: ret void
|
|
auto *d = __builtin_launder(p);
|
|
}
|
|
|
|
template struct WithBase<TestVirtualFn>;
|
|
|
|
// CHECK-LABEL: define{{.*}} void @test_builtin_launder_base(
|
|
extern "C" void test_builtin_launder_base(WithBase<TestVirtualFn> *p) {
|
|
// CHECK: entry
|
|
// CHECK-NONSTRICT-NOT: @llvm.launder.invariant.group
|
|
// CHECK-STRICT: @llvm.launder.invariant.group
|
|
// CHECK: ret void
|
|
auto *d = __builtin_launder(p);
|
|
}
|
|
|
|
/// The test cases in this namespace technically need to be laundered according
|
|
/// to the language in the standard (ie they have const or reference subobjects)
|
|
/// but LLVM doesn't currently optimize on these cases -- so Clang emits
|
|
/// __builtin_launder as a nop.
|
|
///
|
|
/// NOTE: Adding optimizations for these cases later is an LTO ABI break. That's
|
|
/// probably OK for now -- but is something to keep in mind.
|
|
namespace pessimizing_cases {
|
|
|
|
struct TestConstMember {
|
|
const int x;
|
|
};
|
|
|
|
// CHECK-LABEL: define{{.*}} void @test_builtin_launder_const_member
|
|
extern "C" void test_builtin_launder_const_member(TestConstMember *p) {
|
|
// CHECK: entry
|
|
// CHECK-NOT: @llvm.launder.invariant.group
|
|
// CHECK: ret void
|
|
TestConstMember *d = __builtin_launder(p);
|
|
}
|
|
|
|
struct TestConstSubobject {
|
|
TestConstMember x;
|
|
};
|
|
|
|
// CHECK-LABEL: define{{.*}} void @test_builtin_launder_const_subobject
|
|
extern "C" void test_builtin_launder_const_subobject(TestConstSubobject *p) {
|
|
// CHECK: entry
|
|
// CHECK-NOT: @llvm.launder.invariant.group
|
|
// CHECK: ret void
|
|
TestConstSubobject *d = __builtin_launder(p);
|
|
}
|
|
|
|
struct TestConstObject {
|
|
const struct TestConstMember x;
|
|
};
|
|
|
|
// CHECK-LABEL: define{{.*}} void @test_builtin_launder_const_object
|
|
extern "C" void test_builtin_launder_const_object(TestConstObject *p) {
|
|
// CHECK: entry
|
|
// CHECK-NOT: @llvm.launder.invariant.group
|
|
// CHECK: ret void
|
|
TestConstObject *d = __builtin_launder(p);
|
|
}
|
|
|
|
struct TestReferenceMember {
|
|
int &x;
|
|
};
|
|
|
|
// CHECK-LABEL: define{{.*}} void @test_builtin_launder_reference_member
|
|
extern "C" void test_builtin_launder_reference_member(TestReferenceMember *p) {
|
|
// CHECK: entry
|
|
// CHECK-NOT: @llvm.launder.invariant.group
|
|
// CHECK: ret void
|
|
TestReferenceMember *d = __builtin_launder(p);
|
|
}
|
|
|
|
} // namespace pessimizing_cases
|