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 <mi...@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@+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)), "");

_______________________________________________
cfe-commits mailing list
cfe-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits

Reply via email to