[clang] [Clang] No longer require complete types with __builtin_launder (PR #91070)
Mital Ashok via cfe-commits
cfe-commits at lists.llvm.org
Sat May 4 09:35:59 PDT 2024
https://github.com/MitalAshok created https://github.com/llvm/llvm-project/pull/91070
Incomplete types are assumed to need the llvm.launder.invariant.group intrinsic
Fixes #90949
>From 21d9f27692b2a2fa9ac99f4644109e62e3730133 Mon Sep 17 00:00:00 2001
From: Mital Ashok <mital at mitalashok.co.uk>
Date: Sat, 4 May 2024 17:31:31 +0100
Subject: [PATCH] [Clang] No longer require complete types with
__builtin_launder
Incomplete types are assumed to need the llvm.launder.invariant.group intrinsic
Fixes #90949
---
clang/docs/ReleaseNotes.rst | 2 +
clang/lib/CodeGen/CGBuiltin.cpp | 5 +-
clang/lib/Sema/SemaChecking.cpp | 20 +-------
clang/test/CodeGenCXX/builtin-launder.cpp | 56 +++++++++++++++++++++++
clang/test/SemaCXX/builtins.cpp | 14 ++++--
5 files changed, 73 insertions(+), 24 deletions(-)
diff --git a/clang/docs/ReleaseNotes.rst b/clang/docs/ReleaseNotes.rst
index 54b58b1ae99fbd..e22a80a6f281c9 100644
--- a/clang/docs/ReleaseNotes.rst
+++ b/clang/docs/ReleaseNotes.rst
@@ -552,6 +552,8 @@ Bug Fixes in This Version
- Clang will no longer emit a duplicate -Wunused-value warning for an expression
`(A, B)` which evaluates to glvalue `B` that can be converted to non ODR-use. (#GH45783)
+- `__builtin_launder` no longer requires a pointer to a complete type. (#GH90949)
+
Bug Fixes to Compiler Builtins
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
diff --git a/clang/lib/CodeGen/CGBuiltin.cpp b/clang/lib/CodeGen/CGBuiltin.cpp
index 8e31652f4dabef..6a544f97cac5e2 100644
--- a/clang/lib/CodeGen/CGBuiltin.cpp
+++ b/clang/lib/CodeGen/CGBuiltin.cpp
@@ -2487,8 +2487,9 @@ TypeRequiresBuiltinLaunderImp(const ASTContext &Ctx, QualType Ty,
if (!Seen.insert(Record).second)
return false;
- assert(Record->hasDefinition() &&
- "Incomplete types should already be diagnosed");
+ // Assume incomplete types need to be laundered
+ if (!Record->hasDefinition())
+ return true;
if (Record->isDynamicClass())
return true;
diff --git a/clang/lib/Sema/SemaChecking.cpp b/clang/lib/Sema/SemaChecking.cpp
index 3179d542b1f926..c2eb5b51975c1a 100644
--- a/clang/lib/Sema/SemaChecking.cpp
+++ b/clang/lib/Sema/SemaChecking.cpp
@@ -2164,15 +2164,7 @@ static ExprResult BuiltinLaunder(Sema &S, CallExpr *TheCall) {
// * The type of the argument if it's not an array or function type,
// Otherwise,
// * The decayed argument type.
- QualType ParamTy = [&]() {
- QualType ArgTy = TheCall->getArg(0)->getType();
- if (const ArrayType *Ty = ArgTy->getAsArrayTypeUnsafe())
- return S.Context.getPointerType(Ty->getElementType());
- if (ArgTy->isFunctionType()) {
- return S.Context.getPointerType(ArgTy);
- }
- return ArgTy;
- }();
+ QualType ParamTy = S.Context.getAdjustedParameterType(TheCall->getArg(0)->getType());
TheCall->setType(ParamTy);
@@ -2191,16 +2183,6 @@ static ExprResult BuiltinLaunder(Sema &S, CallExpr *TheCall) {
return ExprError();
}
- // We either have an incomplete class type, or we have a class template
- // whose instantiation has not been forced. Example:
- //
- // template <class T> struct Foo { T value; };
- // Foo<int> *p = nullptr;
- // auto *d = __builtin_launder(p);
- if (S.RequireCompleteType(TheCall->getBeginLoc(), ParamTy->getPointeeType(),
- diag::err_incomplete_type))
- return ExprError();
-
assert(ParamTy->getPointeeType()->isObjectType() &&
"Unhandled non-object pointer case");
diff --git a/clang/test/CodeGenCXX/builtin-launder.cpp b/clang/test/CodeGenCXX/builtin-launder.cpp
index 06a93d1c441d29..8cfbc3101e30d3 100644
--- a/clang/test/CodeGenCXX/builtin-launder.cpp
+++ b/clang/test/CodeGenCXX/builtin-launder.cpp
@@ -53,10 +53,66 @@ extern "C" void test_builtin_launder_virtual_base(TestVirtualBase *p) {
TestVirtualBase *d = __builtin_launder(p);
}
+struct IncompleteNeedsLaunder;
+
+// CHECK-LABEL: define{{.*}} void @test_builtin_launder_incomplete_later_needs_launder
+extern "C" void test_builtin_launder_incomplete_later_needs_launder(IncompleteNeedsLaunder *p) {
+ // CHECK-STRICT-NOT: ret void
+ // CHECK-STRICT: @llvm.launder.invariant.group
+
+ // CHECK-NONSTRICT-NOT: @llvm.launder.invariant.group
+
+ // CHECK: ret void
+ IncompleteNeedsLaunder *d = __builtin_launder(p);
+}
+
+struct IncompleteNeedsLaunder {
+ virtual void foo() {}
+};
+
+// CHECK-LABEL: define{{.*}} void @test_builtin_launder_completed_needs_launder
+extern "C" void test_builtin_launder_completed_needs_launder(IncompleteNeedsLaunder *p) {
+ // CHECK-STRICT-NOT: ret void
+ // CHECK-STRICT: @llvm.launder.invariant.group
+
+ // CHECK-NONSTRICT-NOT: @llvm.launder.invariant.group
+
+ // CHECK: ret void
+ IncompleteNeedsLaunder *d = __builtin_launder(p);
+}
+
+struct IncompleteDoesntNeedLaunder;
+
+// CHECK-LABEL: define{{.*}} void @test_builtin_launder_incomplete_later_doesnt_needs_launder
+extern "C" void test_builtin_launder_incomplete_later_doesnt_needs_launder(IncompleteDoesntNeedLaunder *p) {
+ // CHECK-STRICT-NOT: ret void
+ // CHECK-STRICT: @llvm.launder.invariant.group
+
+ // CHECK-NONSTRICT-NOT: @llvm.launder.invariant.group
+
+ // CHECK: ret void
+ IncompleteDoesntNeedLaunder *d = __builtin_launder(p);
+}
+
//===----------------------------------------------------------------------===//
// Negative Cases
//===----------------------------------------------------------------------===//
+struct IncompleteDoesntNeedLaunder {};
+
+// CHECK-LABEL: define{{.*}} void @test_builtin_launder_completed_doesnt_need_launder
+extern "C" void test_builtin_launder_completed_doesnt_need_launder(IncompleteDoesntNeedLaunder *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
+ IncompleteDoesntNeedLaunder *d = __builtin_launder(p);
+}
+
// CHECK-LABEL: define{{.*}} void @test_builtin_launder_ommitted_one
extern "C" void test_builtin_launder_ommitted_one(int *p) {
// CHECK: entry
diff --git a/clang/test/SemaCXX/builtins.cpp b/clang/test/SemaCXX/builtins.cpp
index 080b4476c7eec1..bf587c3aa0ccb9 100644
--- a/clang/test/SemaCXX/builtins.cpp
+++ b/clang/test/SemaCXX/builtins.cpp
@@ -144,16 +144,24 @@ void f() {
static_assert(test_in_constexpr(i), "");
}
-struct Incomplete; // expected-note {{forward declaration}}
+struct Incomplete;
struct IncompleteMember {
Incomplete &i;
};
void test_incomplete(Incomplete *i, IncompleteMember *im) {
- // expected-error at +1 {{incomplete type 'Incomplete' where a complete type is required}}
- __builtin_launder(i);
+ __builtin_launder(i); // OK
__builtin_launder(&i); // OK
__builtin_launder(im); // OK
}
+extern Incomplete incomplete;
+extern IncompleteMember incomplete_member;
+static_assert(test_constexpr_launder(&incomplete) == &incomplete, "");
+static_assert(test_constexpr_launder(&incomplete_member) == &incomplete_member, "");
+template<typename> struct X { static_assert(false, ""); };
+extern X<void> x;
+static_assert(__builtin_launder(__builtin_addressof(x)) == __builtin_addressof(x), "");
+static_assert((test_constexpr_launder)(__builtin_addressof(x)) == __builtin_addressof(x), "");
+template<> struct X<void> {};
void test_noexcept(int *i) {
static_assert(noexcept(__builtin_launder(i)), "");
More information about the cfe-commits
mailing list