llvmbot wrote:
<!--LLVM PR SUMMARY COMMENT--> @llvm/pr-subscribers-clang-codegen Author: Mital Ashok (MitalAshok) <details> <summary>Changes</summary> Incomplete types are assumed to need the llvm.launder.invariant.group intrinsic Fixes #<!-- -->90949 --- Full diff: https://github.com/llvm/llvm-project/pull/91070.diff 5 Files Affected: - (modified) clang/docs/ReleaseNotes.rst (+2) - (modified) clang/lib/CodeGen/CGBuiltin.cpp (+3-2) - (modified) clang/lib/Sema/SemaChecking.cpp (+1-19) - (modified) clang/test/CodeGenCXX/builtin-launder.cpp (+56) - (modified) clang/test/SemaCXX/builtins.cpp (+11-3) ``````````diff 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)), ""); `````````` </details> https://github.com/llvm/llvm-project/pull/91070 _______________________________________________ cfe-commits mailing list cfe-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits