https://github.com/MitalAshok updated https://github.com/llvm/llvm-project/pull/91070
>From 11ad517cede0902945c0b7eba0e7f1ff93f08ea0 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 | 21 +------- clang/test/AST/Interp/builtin-functions.cpp | 14 ++++-- clang/test/CodeGenCXX/builtin-launder.cpp | 56 +++++++++++++++++++++ clang/test/SemaCXX/builtins.cpp | 14 ++++-- 6 files changed, 85 insertions(+), 27 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..9ed404f9e7c936 100644 --- a/clang/lib/Sema/SemaChecking.cpp +++ b/clang/lib/Sema/SemaChecking.cpp @@ -2164,15 +2164,8 @@ 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 +2184,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/AST/Interp/builtin-functions.cpp b/clang/test/AST/Interp/builtin-functions.cpp index 0cbab1fcd91d09..efb2c5f825932e 100644 --- a/clang/test/AST/Interp/builtin-functions.cpp +++ b/clang/test/AST/Interp/builtin-functions.cpp @@ -457,16 +457,24 @@ void f() { static_assert(test_in_constexpr(i), ""); } -struct Incomplete; // both-note {{forward declaration}} +struct Incomplete; struct IncompleteMember { Incomplete &i; }; void test_incomplete(Incomplete *i, IncompleteMember *im) { - // both-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)), ""); 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