[clang] [UBSAN] add null and alignment checks for aggregates and update coverage (PR #175032)
VASU SHARMA via cfe-commits
cfe-commits at lists.llvm.org
Thu Jan 8 23:18:36 PST 2026
https://github.com/vasu-the-sharma updated https://github.com/llvm/llvm-project/pull/175032
>From f10bbba299bfcda6ac69af7aa3b7e11107484d72 Mon Sep 17 00:00:00 2001
From: vasu-ibm <Vasu.Sharma2 at ibm.com>
Date: Thu, 8 Jan 2026 11:49:39 -0500
Subject: [PATCH 1/4] add coverage ubsan-aggregate-null-align.c
---
.../test/CodeGen/ubsan-aggregate-null-align.c | 48 +++++++++++++++++++
1 file changed, 48 insertions(+)
create mode 100644 clang/test/CodeGen/ubsan-aggregate-null-align.c
diff --git a/clang/test/CodeGen/ubsan-aggregate-null-align.c b/clang/test/CodeGen/ubsan-aggregate-null-align.c
new file mode 100644
index 0000000000000..7ca9d32c3305b
--- /dev/null
+++ b/clang/test/CodeGen/ubsan-aggregate-null-align.c
@@ -0,0 +1,48 @@
+// RUN: %clang_cc1 -triple x86_64-linux-gnu -emit-llvm %s -o - \
+// RUN: -fsanitize=null,alignment | FileCheck %s --check-prefix=CHECK-SANITIZE
+// RUN: %clang_cc1 -triple x86_64-linux-gnu -emit-llvm %s -o - \
+// RUN: | FileCheck %s --check-prefix=CHECK-NO-SANITIZE
+
+struct Small { int x; };
+struct Container { struct Small inner; };
+
+// CHECK-SANITIZE-LABEL: define {{.*}}void @test_direct_assign_ptr(
+// CHECK-SANITIZE: %[[D:.*]] = load ptr, ptr %dest.addr
+// CHECK-SANITIZE: %[[S:.*]] = load ptr, ptr %src.addr
+// CHECK-SANITIZE: call void @llvm.memcpy.p0.p0.i64(ptr align 4 %[[D]], ptr align 4 %[[S]], i64 4, i1 false)
+//
+// CHECK-NO-SANITIZE-LABEL: define {{.*}}void @test_direct_assign_ptr(
+// CHECK-NO-SANITIZE-NOT: @__ubsan_handle_type_mismatch
+void test_direct_assign_ptr(struct Small *dest, struct Small *src) {
+ *dest = *src;
+}
+
+// CHECK-SANITIZE-LABEL: define {{.*}}void @test_null_dest(
+// CHECK-SANITIZE: %[[D:.*]] = load ptr, ptr %dest
+// CHECK-SANITIZE: call void @llvm.memcpy.p0.p0.i64(ptr align 4 %[[D]], ptr {{.*}}, i64 4, i1 false)
+//
+// CHECK-NO-SANITIZE-LABEL: define {{.*}}void @test_null_dest(
+// CHECK-NO-SANITIZE-NOT: @__ubsan_handle_type_mismatch
+void test_null_dest(struct Small *src) {
+ struct Small *dest = 0;
+ *dest = *src;
+}
+
+// CHECK-SANITIZE-LABEL: define {{.*}}void @test_nested_struct(
+// CHECK-SANITIZE: %[[VAL1:.*]] = icmp ne ptr %[[C:.*]], null
+// CHECK-SANITIZE: br i1 %{{.*}}, label %cont, label %handler.type_mismatch
+//
+// CHECK-NO-SANITIZE-LABEL: define {{.*}}void @test_nested_struct(
+// CHECK-NO-SANITIZE-NOT: @__ubsan_handle_type_mismatch
+void test_nested_struct(struct Container *c, struct Small *s) {
+ c->inner = *s;
+}
+
+// CHECK-SANITIZE-LABEL: define {{.*}}void @test_comma_operator(
+// CHECK-SANITIZE: call void @llvm.memcpy.p0.p0.i64(ptr align 4 %{{.*}}, ptr align 4 %{{.*}}, i64 4, i1 false)
+//
+// CHECK-NO-SANITIZE-LABEL: define {{.*}}void @test_comma_operator(
+// CHECK-NO-SANITIZE-NOT: @__ubsan_handle_type_mismatch
+void test_comma_operator(struct Small *dest, struct Small *src) {
+ *dest = (0, *src);
+}
>From cc64e3f111e790760b1c624fa27ae03701f1d021 Mon Sep 17 00:00:00 2001
From: vasu-ibm <Vasu.Sharma2 at ibm.com>
Date: Thu, 8 Jan 2026 12:15:28 -0500
Subject: [PATCH 2/4] add null and alignment checks for aggregates
---
clang/lib/CodeGen/CGExprAgg.cpp | 43 +++------
clang/lib/CodeGen/CGExprCXX.cpp | 29 +++---
.../test/CodeGen/ubsan-aggregate-null-align.c | 91 +++++++++++--------
3 files changed, 82 insertions(+), 81 deletions(-)
diff --git a/clang/lib/CodeGen/CGExprAgg.cpp b/clang/lib/CodeGen/CGExprAgg.cpp
index 7cc4d6c8f06f6..919e510a82af0 100644
--- a/clang/lib/CodeGen/CGExprAgg.cpp
+++ b/clang/lib/CodeGen/CGExprAgg.cpp
@@ -1292,45 +1292,29 @@ static bool isBlockVarRef(const Expr *E) {
void AggExprEmitter::VisitBinAssign(const BinaryOperator *E) {
ApplyAtomGroup Grp(CGF.getDebugInfo());
- // For an assignment to work, the value on the right has
- // to be compatible with the value on the left.
assert(CGF.getContext().hasSameUnqualifiedType(E->getLHS()->getType(),
E->getRHS()->getType())
- && "Invalid assignment");
+ && "Invalid assignment");
- // If the LHS might be a __block variable, and the RHS can
- // potentially cause a block copy, we need to evaluate the RHS first
- // so that the assignment goes the right place.
- // This is pretty semantically fragile.
if (isBlockVarRef(E->getLHS()) &&
E->getRHS()->HasSideEffects(CGF.getContext())) {
- // Ensure that we have a destination, and evaluate the RHS into that.
EnsureDest(E->getRHS()->getType());
Visit(E->getRHS());
-
- // Now emit the LHS and copy into it.
LValue LHS = CGF.EmitCheckedLValue(E->getLHS(), CodeGenFunction::TCK_Store);
- // That copy is an atomic copy if the LHS is atomic.
if (LHS.getType()->isAtomicType() ||
CGF.LValueIsSuitableForInlineAtomic(LHS)) {
CGF.EmitAtomicStore(Dest.asRValue(), LHS, /*isInit*/ false);
return;
}
-
- EmitCopy(E->getLHS()->getType(),
- AggValueSlot::forLValue(LHS, AggValueSlot::IsDestructed,
- needsGC(E->getLHS()->getType()),
- AggValueSlot::IsAliased,
- AggValueSlot::MayOverlap),
- Dest);
+ EmitFinalDestCopy(E->getLHS()->getType(), LHS);
return;
}
- LValue LHS = CGF.EmitLValue(E->getLHS());
+ // ✅ FIX: Use EmitCheckedLValue for LHS
+ LValue LHS = CGF.EmitCheckedLValue(E->getLHS(), CodeGenFunction::TCK_Store);
- // If we have an atomic type, evaluate into the destination and then
- // do an atomic copy.
+ // ✅ RE-ADD: Original atomic handling logic
if (LHS.getType()->isAtomicType() ||
CGF.LValueIsSuitableForInlineAtomic(LHS)) {
EnsureDest(E->getRHS()->getType());
@@ -1339,20 +1323,23 @@ void AggExprEmitter::VisitBinAssign(const BinaryOperator *E) {
return;
}
- // Codegen the RHS so that it stores directly into the LHS.
+ // ✅ FIX: Handle RHS based on LValue/RValue
AggValueSlot LHSSlot = AggValueSlot::forLValue(
LHS, AggValueSlot::IsDestructed, needsGC(E->getLHS()->getType()),
AggValueSlot::IsAliased, AggValueSlot::MayOverlap);
- // A non-volatile aggregate destination might have volatile member.
- if (!LHSSlot.isVolatile() &&
- CGF.hasVolatileMember(E->getLHS()->getType()))
- LHSSlot.setVolatile(true);
- CGF.EmitAggExpr(E->getRHS(), LHSSlot);
+ if (E->getRHS()->isLValue()) {
+ LValue RHS = CGF.EmitCheckedLValue(E->getRHS(), CodeGenFunction::TCK_Load);
+ CGF.EmitAggregateCopy(LHS, RHS, E->getType(), Dest.isVolatile());
+ } else {
+ if (!LHSSlot.isVolatile() && CGF.hasVolatileMember(E->getLHS()->getType()))
+ LHSSlot.setVolatile(true);
+ CGF.EmitAggExpr(E->getRHS(), LHSSlot);
+ }
- // Copy into the destination if the assignment isn't ignored.
EmitFinalDestCopy(E->getType(), LHS);
+ // ✅ RE-ADD: Original Nontrivial C struct destruction logic
if (!Dest.isIgnored() && !Dest.isExternallyDestructed() &&
E->getType().isDestructedType() == QualType::DK_nontrivial_c_struct)
CGF.pushDestroy(QualType::DK_nontrivial_c_struct, Dest.getAddress(),
diff --git a/clang/lib/CodeGen/CGExprCXX.cpp b/clang/lib/CodeGen/CGExprCXX.cpp
index ce2ed9026fa1f..eae27a6a3f1c8 100644
--- a/clang/lib/CodeGen/CGExprCXX.cpp
+++ b/clang/lib/CodeGen/CGExprCXX.cpp
@@ -267,7 +267,7 @@ RValue CodeGenFunction::EmitCXXMemberOrOperatorMemberCallExpr(
if (auto *OCE = dyn_cast<CXXOperatorCallExpr>(CE)) {
if (OCE->isAssignmentOp()) {
if (TrivialAssignment) {
- TrivialAssignmentRHS = EmitLValue(CE->getArg(1));
+ TrivialAssignmentRHS = EmitCheckedLValue(CE->getArg(1), TCK_Load);
} else {
RtlArgs = &RtlArgStorage;
EmitCallArgs(*RtlArgs, MD->getType()->castAs<FunctionProtoType>(),
@@ -309,22 +309,21 @@ RValue CodeGenFunction::EmitCXXMemberOrOperatorMemberCallExpr(
if (TrivialForCodegen) {
if (isa<CXXDestructorDecl>(MD))
return RValue::get(nullptr);
+ }
- if (TrivialAssignment) {
- // We don't like to generate the trivial copy/move assignment operator
- // when it isn't necessary; just produce the proper effect here.
- // It's important that we use the result of EmitLValue here rather than
- // emitting call arguments, in order to preserve TBAA information from
- // the RHS.
- LValue RHS = isa<CXXOperatorCallExpr>(CE)
- ? TrivialAssignmentRHS
- : EmitLValue(*CE->arg_begin());
- EmitAggregateAssign(This, RHS, CE->getType());
- return RValue::get(This.getPointer(*this));
- }
+ if (TrivialAssignment) {
+ // 1. Evaluate 'this' (Destination) as a checked store.
+ LValue This = EmitCheckedLValue(Base, TCK_Store);
+
+ // 2. Evaluate RHS (Source) as a checked load.
+ // If it's an operator call (a = b), we use the RHS evaluated at line 270.
+ // If it's a direct call (constructor), we evaluate the first argument.
+ LValue RHS = isa<CXXOperatorCallExpr>(CE)
+ ? TrivialAssignmentRHS
+ : EmitCheckedLValue(*CE->arg_begin(), TCK_Load);
- assert(MD->getParent()->mayInsertExtraPadding() &&
- "unknown trivial member function");
+ EmitAggregateAssign(This, RHS, CE->getType());
+ return RValue::get(This.getPointer(*this));
}
// Compute the function type we're calling.
diff --git a/clang/test/CodeGen/ubsan-aggregate-null-align.c b/clang/test/CodeGen/ubsan-aggregate-null-align.c
index 7ca9d32c3305b..18133327f0fc8 100644
--- a/clang/test/CodeGen/ubsan-aggregate-null-align.c
+++ b/clang/test/CodeGen/ubsan-aggregate-null-align.c
@@ -1,48 +1,63 @@
-// RUN: %clang_cc1 -triple x86_64-linux-gnu -emit-llvm %s -o - \
-// RUN: -fsanitize=null,alignment | FileCheck %s --check-prefix=CHECK-SANITIZE
-// RUN: %clang_cc1 -triple x86_64-linux-gnu -emit-llvm %s -o - \
-// RUN: | FileCheck %s --check-prefix=CHECK-NO-SANITIZE
-
-struct Small { int x; };
-struct Container { struct Small inner; };
-
-// CHECK-SANITIZE-LABEL: define {{.*}}void @test_direct_assign_ptr(
-// CHECK-SANITIZE: %[[D:.*]] = load ptr, ptr %dest.addr
-// CHECK-SANITIZE: %[[S:.*]] = load ptr, ptr %src.addr
-// CHECK-SANITIZE: call void @llvm.memcpy.p0.p0.i64(ptr align 4 %[[D]], ptr align 4 %[[S]], i64 4, i1 false)
-//
-// CHECK-NO-SANITIZE-LABEL: define {{.*}}void @test_direct_assign_ptr(
-// CHECK-NO-SANITIZE-NOT: @__ubsan_handle_type_mismatch
+// RUN: %clang_cc1 -triple x86_64-linux-gnu -fsanitize=alignment,null \
+// RUN: -emit-llvm -std=c23 %s -o - \
+// RUN: | FileCheck %s --check-prefixes=CHECK,CHECK-UBSAN
+// RUN: %clang_cc1 -triple x86_64-linux-gnu -emit-llvm -std=c23 %s -o - \
+// RUN: | FileCheck %s --check-prefixes=CHECK,CHECK-NO-UBSAN
+// RUN: %clang_cc1 -triple x86_64-linux-gnu -fsanitize=alignment,null \
+// RUN: -emit-llvm -xc++ %s -o - \
+// RUN: | FileCheck %s --check-prefixes=CHECK,CHECK-UBSAN
+// RUN: %clang_cc1 -triple x86_64-linux-gnu -emit-llvm -xc++ %s -o - \
+// RUN: | FileCheck %s --check-prefixes=CHECK,CHECK-NO-UBSAN
+
+typedef struct Small { int x; } Small;
+typedef struct Container { struct Small inner; } Container;
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+// CHECK-LABEL: define {{.*}}void @test_direct_assign_ptr(
void test_direct_assign_ptr(struct Small *dest, struct Small *src) {
- *dest = *src;
-}
+ // CHECK-UBSAN: %[[D:.*]] = load ptr, ptr %dest.addr
+ // CHECK-UBSAN: %[[S:.*]] = load ptr, ptr %src.addr
+
+ // Verify LHS (Dest) Check
+ // CHECK-UBSAN: %[[D_NULL:.*]] = icmp ne ptr %[[D]], null
+ // CHECK-UBSAN: %[[D_ALIGN:.*]] = and i64 %{{.*}}, 3
+ // CHECK-UBSAN: %[[D_ALIGN_OK:.*]] = icmp eq i64 %[[D_ALIGN]], 0
+ // CHECK-UBSAN: %[[D_OK:.*]] = and i1 %[[D_NULL]], %[[D_ALIGN_OK]]
+ // CHECK-UBSAN: br i1 %[[D_OK]], label %[[D_CONT:.*]], label %[[D_HANDLER:.*]]
+
+ // CHECK-UBSAN: [[D_HANDLER]]:
+ // CHECK-UBSAN: call void @__ubsan_handle_type_mismatch_v1_abort
+ // CHECK-UBSAN: unreachable
+
+ // CHECK-UBSAN: [[D_CONT]]:
+ // Verify RHS (Src) Check
+ // CHECK-UBSAN: %[[S_NULL:.*]] = icmp ne ptr %[[S]], null
+ // CHECK-UBSAN: br i1 %[[S_NULL]], label %[[S_CONT:.*]], label %[[S_HANDLER:.*]]
+
+ // CHECK-UBSAN: [[S_HANDLER]]:
+ // CHECK-UBSAN: call void @__ubsan_handle_type_mismatch_v1_abort
-// CHECK-SANITIZE-LABEL: define {{.*}}void @test_null_dest(
-// CHECK-SANITIZE: %[[D:.*]] = load ptr, ptr %dest
-// CHECK-SANITIZE: call void @llvm.memcpy.p0.p0.i64(ptr align 4 %[[D]], ptr {{.*}}, i64 4, i1 false)
-//
-// CHECK-NO-SANITIZE-LABEL: define {{.*}}void @test_null_dest(
-// CHECK-NO-SANITIZE-NOT: @__ubsan_handle_type_mismatch
-void test_null_dest(struct Small *src) {
- struct Small *dest = 0;
+ // CHECK-UBSAN: [[S_CONT]]:
+ // CHECK: call void @llvm.memcpy.p0.p0.i64(ptr align 4 %[[D]], ptr align 4 %[[S]], i64 4, i1 false)
+
+ // CHECK-NO-UBSAN-NOT: @__ubsan_handle_type_mismatch
*dest = *src;
}
-// CHECK-SANITIZE-LABEL: define {{.*}}void @test_nested_struct(
-// CHECK-SANITIZE: %[[VAL1:.*]] = icmp ne ptr %[[C:.*]], null
-// CHECK-SANITIZE: br i1 %{{.*}}, label %cont, label %handler.type_mismatch
-//
-// CHECK-NO-SANITIZE-LABEL: define {{.*}}void @test_nested_struct(
-// CHECK-NO-SANITIZE-NOT: @__ubsan_handle_type_mismatch
+// CHECK-LABEL: define {{.*}}void @test_nested_struct(
void test_nested_struct(struct Container *c, struct Small *s) {
+ // CHECK-UBSAN: %[[C:.*]] = load ptr, ptr %c.addr
+ // CHECK-UBSAN: icmp ne ptr %[[C]], null
+ // CHECK-UBSAN: br i1 %{{.*}}, label %[[CONT:.*]], label %[[HANDLER:.*]]
+
+ // CHECK-UBSAN: [[HANDLER]]:
+ // CHECK-UBSAN: call void @__ubsan_handle_type_mismatch_v1_abort
c->inner = *s;
}
-// CHECK-SANITIZE-LABEL: define {{.*}}void @test_comma_operator(
-// CHECK-SANITIZE: call void @llvm.memcpy.p0.p0.i64(ptr align 4 %{{.*}}, ptr align 4 %{{.*}}, i64 4, i1 false)
-//
-// CHECK-NO-SANITIZE-LABEL: define {{.*}}void @test_comma_operator(
-// CHECK-NO-SANITIZE-NOT: @__ubsan_handle_type_mismatch
-void test_comma_operator(struct Small *dest, struct Small *src) {
- *dest = (0, *src);
+#ifdef __cplusplus
}
+#endif
>From d2f768b38404f718c06fbfc3e7ba2b952c9802e2 Mon Sep 17 00:00:00 2001
From: vasu-ibm <Vasu.Sharma2 at ibm.com>
Date: Fri, 9 Jan 2026 02:16:03 -0500
Subject: [PATCH 3/4] handle git clang format error
---
clang/lib/CodeGen/CGExprAgg.cpp | 24 ++++++++++++++++++------
1 file changed, 18 insertions(+), 6 deletions(-)
diff --git a/clang/lib/CodeGen/CGExprAgg.cpp b/clang/lib/CodeGen/CGExprAgg.cpp
index 919e510a82af0..7cc1174b98e66 100644
--- a/clang/lib/CodeGen/CGExprAgg.cpp
+++ b/clang/lib/CodeGen/CGExprAgg.cpp
@@ -1292,29 +1292,41 @@ static bool isBlockVarRef(const Expr *E) {
void AggExprEmitter::VisitBinAssign(const BinaryOperator *E) {
ApplyAtomGroup Grp(CGF.getDebugInfo());
+ // For an assignment to work, the value on the right has
+ // to be compatible with the value on the left.
assert(CGF.getContext().hasSameUnqualifiedType(E->getLHS()->getType(),
E->getRHS()->getType())
- && "Invalid assignment");
+ && "Invalid assignment");
+ // If the LHS might be a __block variable, and the RHS can
+ // potentially cause a block copy, we need to evaluate the RHS first
+ // so that the assignment goes the right place.
+ // This is pretty semantically fragile.
if (isBlockVarRef(E->getLHS()) &&
E->getRHS()->HasSideEffects(CGF.getContext())) {
+ // Ensure that we have a destination, and evaluate the RHS into that.
EnsureDest(E->getRHS()->getType());
Visit(E->getRHS());
+
+ // Now emit the LHS and copy into it.
LValue LHS = CGF.EmitCheckedLValue(E->getLHS(), CodeGenFunction::TCK_Store);
+ // That copy is an atomic copy if the LHS is atomic.
if (LHS.getType()->isAtomicType() ||
CGF.LValueIsSuitableForInlineAtomic(LHS)) {
CGF.EmitAtomicStore(Dest.asRValue(), LHS, /*isInit*/ false);
- return;
+ return;
}
+
EmitFinalDestCopy(E->getLHS()->getType(), LHS);
return;
}
- // ✅ FIX: Use EmitCheckedLValue for LHS
+ // Use EmitCheckedLValue for LHS
LValue LHS = CGF.EmitCheckedLValue(E->getLHS(), CodeGenFunction::TCK_Store);
- // ✅ RE-ADD: Original atomic handling logic
+ // If we have an atomic type, evaluate into the destination and then
+ // do an atomic copy.
if (LHS.getType()->isAtomicType() ||
CGF.LValueIsSuitableForInlineAtomic(LHS)) {
EnsureDest(E->getRHS()->getType());
@@ -1323,7 +1335,7 @@ void AggExprEmitter::VisitBinAssign(const BinaryOperator *E) {
return;
}
- // ✅ FIX: Handle RHS based on LValue/RValue
+ // Codegen the RHS so that it stores directly into the LHS.
AggValueSlot LHSSlot = AggValueSlot::forLValue(
LHS, AggValueSlot::IsDestructed, needsGC(E->getLHS()->getType()),
AggValueSlot::IsAliased, AggValueSlot::MayOverlap);
@@ -1337,9 +1349,9 @@ void AggExprEmitter::VisitBinAssign(const BinaryOperator *E) {
CGF.EmitAggExpr(E->getRHS(), LHSSlot);
}
+ // Copy into the destination if the assignment isn't ignored.
EmitFinalDestCopy(E->getType(), LHS);
- // ✅ RE-ADD: Original Nontrivial C struct destruction logic
if (!Dest.isIgnored() && !Dest.isExternallyDestructed() &&
E->getType().isDestructedType() == QualType::DK_nontrivial_c_struct)
CGF.pushDestroy(QualType::DK_nontrivial_c_struct, Dest.getAddress(),
>From c2dab866cd2720196da7f0bb5225d10cd29d7b56 Mon Sep 17 00:00:00 2001
From: vasu-ibm <Vasu.Sharma2 at ibm.com>
Date: Fri, 9 Jan 2026 02:18:13 -0500
Subject: [PATCH 4/4] update git clang-format
---
clang/lib/CodeGen/CGExprAgg.cpp | 178 ++++++------
clang/lib/CodeGen/CGExprCXX.cpp | 488 +++++++++++++++-----------------
2 files changed, 314 insertions(+), 352 deletions(-)
diff --git a/clang/lib/CodeGen/CGExprAgg.cpp b/clang/lib/CodeGen/CGExprAgg.cpp
index 7cc1174b98e66..b0e112c493c19 100644
--- a/clang/lib/CodeGen/CGExprAgg.cpp
+++ b/clang/lib/CodeGen/CGExprAgg.cpp
@@ -50,11 +50,13 @@ class AggExprEmitter : public StmtVisitor<AggExprEmitter> {
bool IsResultUnused;
AggValueSlot EnsureSlot(QualType T) {
- if (!Dest.isIgnored()) return Dest;
+ if (!Dest.isIgnored())
+ return Dest;
return CGF.CreateAggTemp(T, "agg.tmp.ensured");
}
void EnsureDest(QualType T) {
- if (!Dest.isIgnored()) return;
+ if (!Dest.isIgnored())
+ return;
Dest = CGF.CreateAggTemp(T, "agg.tmp.ensured");
}
@@ -72,8 +74,8 @@ class AggExprEmitter : public StmtVisitor<AggExprEmitter> {
public:
AggExprEmitter(CodeGenFunction &cgf, AggValueSlot Dest, bool IsResultUnused)
- : CGF(cgf), Builder(CGF.Builder), Dest(Dest),
- IsResultUnused(IsResultUnused) { }
+ : CGF(cgf), Builder(CGF.Builder), Dest(Dest),
+ IsResultUnused(IsResultUnused) {}
//===--------------------------------------------------------------------===//
// Utilities
@@ -114,9 +116,7 @@ class AggExprEmitter : public StmtVisitor<AggExprEmitter> {
StmtVisitor<AggExprEmitter>::Visit(E);
}
- void VisitStmt(Stmt *S) {
- CGF.ErrorUnsupported(S, "aggregate expression");
- }
+ void VisitStmt(Stmt *S) { CGF.ErrorUnsupported(S, "aggregate expression"); }
void VisitParenExpr(ParenExpr *PE) { Visit(PE->getSubExpr()); }
void VisitGenericSelectionExpr(GenericSelectionExpr *GE) {
Visit(GE->getResultExpr());
@@ -157,9 +157,7 @@ class AggExprEmitter : public StmtVisitor<AggExprEmitter> {
void VisitArraySubscriptExpr(ArraySubscriptExpr *E) {
EmitAggLoadOfLValue(E);
}
- void VisitPredefinedExpr(const PredefinedExpr *E) {
- EmitAggLoadOfLValue(E);
- }
+ void VisitPredefinedExpr(const PredefinedExpr *E) { EmitAggLoadOfLValue(E); }
// Operators.
void VisitCastExpr(CastExpr *E);
@@ -175,9 +173,7 @@ class AggExprEmitter : public StmtVisitor<AggExprEmitter> {
}
void VisitObjCMessageExpr(ObjCMessageExpr *E);
- void VisitObjCIvarRefExpr(ObjCIvarRefExpr *E) {
- EmitAggLoadOfLValue(E);
- }
+ void VisitObjCIvarRefExpr(ObjCIvarRefExpr *E) { EmitAggLoadOfLValue(E); }
void VisitDesignatedInitUpdateExpr(DesignatedInitUpdateExpr *E);
void VisitAbstractConditionalOperator(const AbstractConditionalOperator *CO);
@@ -189,7 +185,7 @@ class AggExprEmitter : public StmtVisitor<AggExprEmitter> {
void VisitArrayInitLoopExpr(const ArrayInitLoopExpr *E,
llvm::Value *outerBegin = nullptr);
void VisitImplicitValueInitExpr(ImplicitValueInitExpr *E);
- void VisitNoInitExpr(NoInitExpr *E) { } // Do nothing.
+ void VisitNoInitExpr(NoInitExpr *E) {} // Do nothing.
void VisitCXXDefaultArgExpr(CXXDefaultArgExpr *DAE) {
CodeGenFunction::CXXDefaultArgExprScope Scope(CGF, DAE);
Visit(DAE->getExpr());
@@ -244,7 +240,7 @@ class AggExprEmitter : public StmtVisitor<AggExprEmitter> {
Visit(E->getSelectedExpr());
}
};
-} // end anonymous namespace.
+} // end anonymous namespace.
//===----------------------------------------------------------------------===//
// Utilities
@@ -393,10 +389,8 @@ void AggExprEmitter::EmitCopy(QualType type, const AggValueSlot &dest,
if (dest.requiresGCollection()) {
CharUnits sz = dest.getPreferredSize(CGF.getContext(), type);
llvm::Value *size = llvm::ConstantInt::get(CGF.SizeTy, sz.getQuantity());
- CGF.CGM.getObjCRuntime().EmitGCMemmoveCollectable(CGF,
- dest.getAddress(),
- src.getAddress(),
- size);
+ CGF.CGM.getObjCRuntime().EmitGCMemmoveCollectable(CGF, dest.getAddress(),
+ src.getAddress(), size);
return;
}
@@ -411,8 +405,8 @@ void AggExprEmitter::EmitCopy(QualType type, const AggValueSlot &dest,
/// Emit the initializer for a std::initializer_list initialized with a
/// real initializer list.
-void
-AggExprEmitter::VisitCXXStdInitializerListExpr(CXXStdInitializerListExpr *E) {
+void AggExprEmitter::VisitCXXStdInitializerListExpr(
+ CXXStdInitializerListExpr *E) {
// Emit an array containing the elements. The array is externally destructed
// if the std::initializer_list object is.
ASTContext &Ctx = CGF.getContext();
@@ -454,7 +448,7 @@ AggExprEmitter::VisitCXXStdInitializerListExpr(CXXStdInitializerListExpr *E) {
ArrayType->getElementType()) &&
"Expected std::initializer_list second field to be const E *");
llvm::Value *Zero = llvm::ConstantInt::get(CGF.PtrDiffTy, 0);
- llvm::Value *IdxEnd[] = { Zero, Size };
+ llvm::Value *IdxEnd[] = {Zero, Size};
llvm::Value *ArrayEnd = Builder.CreateInBoundsGEP(
ArrayPtr.getElementType(), ArrayPtr.emitRawPointer(CGF), IdxEnd,
"arrayend");
@@ -571,7 +565,7 @@ void AggExprEmitter::EmitArrayInit(Address DestPtr, llvm::ArrayType *AType,
CGF.getContext().getAsArrayType(ArrayQTy)->getElementType();
CharUnits elementSize = CGF.getContext().getTypeSizeInChars(elementType);
CharUnits elementAlign =
- DestPtr.getAlignment().alignmentOfArrayElement(elementSize);
+ DestPtr.getAlignment().alignmentOfArrayElement(elementSize);
llvm::Type *llvmElementType = CGF.ConvertTypeForMem(elementType);
// Consider initializing the array by copying from a global. For this to be
@@ -686,7 +680,8 @@ void AggExprEmitter::EmitArrayInit(Address DestPtr, llvm::ArrayType *AType,
llvmElementType, element,
llvm::ConstantInt::get(CGF.SizeTy, NumInitElements),
"arrayinit.start");
- if (endOfInit.isValid()) Builder.CreateStore(element, endOfInit);
+ if (endOfInit.isValid())
+ Builder.CreateStore(element, endOfInit);
}
// Compute the end of the array.
@@ -700,7 +695,7 @@ void AggExprEmitter::EmitArrayInit(Address DestPtr, llvm::ArrayType *AType,
// Jump into the body.
CGF.EmitBlock(bodyBB);
llvm::PHINode *currentElement =
- Builder.CreatePHI(element->getType(), 2, "arrayinit.cur");
+ Builder.CreatePHI(element->getType(), 2, "arrayinit.cur");
currentElement->addIncoming(element, entryBB);
// Emit the actual filler expression.
@@ -724,11 +719,12 @@ void AggExprEmitter::EmitArrayInit(Address DestPtr, llvm::ArrayType *AType,
llvmElementType, currentElement, one, "arrayinit.next");
// Tell the EH cleanup that we finished with the last element.
- if (endOfInit.isValid()) Builder.CreateStore(nextElement, endOfInit);
+ if (endOfInit.isValid())
+ Builder.CreateStore(nextElement, endOfInit);
// Leave the loop if we're done.
- llvm::Value *done = Builder.CreateICmpEQ(nextElement, end,
- "arrayinit.done");
+ llvm::Value *done =
+ Builder.CreateICmpEQ(nextElement, end, "arrayinit.done");
llvm::BasicBlock *endBB = CGF.createBasicBlock("arrayinit.end");
Builder.CreateCondBr(done, endBB, bodyBB);
currentElement->addIncoming(nextElement, Builder.GetInsertBlock());
@@ -741,7 +737,8 @@ void AggExprEmitter::EmitArrayInit(Address DestPtr, llvm::ArrayType *AType,
// Visitor Methods
//===----------------------------------------------------------------------===//
-void AggExprEmitter::VisitMaterializeTemporaryExpr(MaterializeTemporaryExpr *E){
+void AggExprEmitter::VisitMaterializeTemporaryExpr(
+ MaterializeTemporaryExpr *E) {
Visit(E->getSubExpr());
}
@@ -753,8 +750,7 @@ void AggExprEmitter::VisitOpaqueValueExpr(OpaqueValueExpr *e) {
EmitFinalDestCopy(e->getType(), CGF.getOrCreateOpaqueLValueMapping(e));
}
-void
-AggExprEmitter::VisitCompoundLiteralExpr(CompoundLiteralExpr *E) {
+void AggExprEmitter::VisitCompoundLiteralExpr(CompoundLiteralExpr *E) {
if (Dest.isPotentiallyAliased()) {
// Just emit a load of the lvalue + a copy, because our compound literal
// might alias the destination.
@@ -798,8 +794,8 @@ void AggExprEmitter::VisitCastExpr(CastExpr *E) {
case CK_Dynamic: {
// FIXME: Can this actually happen? We have no test coverage for it.
assert(isa<CXXDynamicCastExpr>(E) && "CK_Dynamic without a dynamic_cast?");
- LValue LV = CGF.EmitCheckedLValue(E->getSubExpr(),
- CodeGenFunction::TCK_Load);
+ LValue LV =
+ CGF.EmitCheckedLValue(E->getSubExpr(), CodeGenFunction::TCK_Load);
// FIXME: Do we also need to handle property references here?
if (LV.isSimple())
CGF.EmitDynamicCast(LV.getAddress(), cast<CXXDynamicCastExpr>(E));
@@ -848,7 +844,7 @@ void AggExprEmitter::VisitCastExpr(CastExpr *E) {
case CK_BaseToDerived:
case CK_UncheckedDerivedToBase: {
llvm_unreachable("cannot perform hierarchy conversion in EmitAggExpr: "
- "should have been unpacked before we got here");
+ "should have been unpacked before we got here");
}
case CK_NonAtomicToAtomic:
@@ -858,11 +854,12 @@ void AggExprEmitter::VisitCastExpr(CastExpr *E) {
// Determine the atomic and value types.
QualType atomicType = E->getSubExpr()->getType();
QualType valueType = E->getType();
- if (isToAtomic) std::swap(atomicType, valueType);
+ if (isToAtomic)
+ std::swap(atomicType, valueType);
assert(atomicType->isAtomicType());
- assert(CGF.getContext().hasSameUnqualifiedType(valueType,
- atomicType->castAs<AtomicType>()->getValueType()));
+ assert(CGF.getContext().hasSameUnqualifiedType(
+ valueType, atomicType->castAs<AtomicType>()->getValueType()));
// Just recurse normally if we're ignoring the result or the
// atomic type doesn't change representation.
@@ -871,14 +868,14 @@ void AggExprEmitter::VisitCastExpr(CastExpr *E) {
}
CastKind peepholeTarget =
- (isToAtomic ? CK_AtomicToNonAtomic : CK_NonAtomicToAtomic);
+ (isToAtomic ? CK_AtomicToNonAtomic : CK_NonAtomicToAtomic);
// These two cases are reverses of each other; try to peephole them.
if (Expr *op =
findPeephole(E->getSubExpr(), peepholeTarget, CGF.getContext())) {
assert(CGF.getContext().hasSameUnqualifiedType(op->getType(),
E->getType()) &&
- "peephole significantly changed types?");
+ "peephole significantly changed types?");
return Visit(op);
}
@@ -895,13 +892,11 @@ void AggExprEmitter::VisitCastExpr(CastExpr *E) {
// Build a GEP to refer to the subobject.
Address valueAddr =
CGF.Builder.CreateStructGEP(valueDest.getAddress(), 0);
- valueDest = AggValueSlot::forAddr(valueAddr,
- valueDest.getQualifiers(),
- valueDest.isExternallyDestructed(),
- valueDest.requiresGCollection(),
- valueDest.isPotentiallyAliased(),
- AggValueSlot::DoesNotOverlap,
- AggValueSlot::IsZeroed);
+ valueDest = AggValueSlot::forAddr(
+ valueAddr, valueDest.getQualifiers(),
+ valueDest.isExternallyDestructed(), valueDest.requiresGCollection(),
+ valueDest.isPotentiallyAliased(), AggValueSlot::DoesNotOverlap,
+ AggValueSlot::IsZeroed);
}
CGF.EmitAggExpr(E->getSubExpr(), valueDest);
@@ -911,7 +906,7 @@ void AggExprEmitter::VisitCastExpr(CastExpr *E) {
// Otherwise, we're converting an atomic type to a non-atomic type.
// Make an atomic temporary, emit into that, and then copy the value out.
AggValueSlot atomicSlot =
- CGF.CreateAggTemp(atomicType, "atomic-to-nonatomic.temp");
+ CGF.CreateAggTemp(atomicType, "atomic-to-nonatomic.temp");
CGF.EmitAggExpr(E->getSubExpr(), atomicSlot);
Address valueAddr = Builder.CreateStructGEP(atomicSlot.getAddress(), 0);
@@ -919,7 +914,7 @@ void AggExprEmitter::VisitCastExpr(CastExpr *E) {
return EmitFinalDestCopy(valueType, rvalue);
}
case CK_AddressSpaceConversion:
- return Visit(E->getSubExpr());
+ return Visit(E->getSubExpr());
case CK_LValueToRValue:
// If we're loading from a volatile type, force the destination
@@ -1054,9 +1049,8 @@ void AggExprEmitter::VisitCallExpr(const CallExpr *E) {
return;
}
- withReturnValueSlot(E, [&](ReturnValueSlot Slot) {
- return CGF.EmitCallExpr(E, Slot);
- });
+ withReturnValueSlot(
+ E, [&](ReturnValueSlot Slot) { return CGF.EmitCallExpr(E, Slot); });
}
void AggExprEmitter::VisitObjCMessageExpr(ObjCMessageExpr *E) {
@@ -1219,7 +1213,7 @@ void AggExprEmitter::VisitBinaryOperator(const BinaryOperator *E) {
}
void AggExprEmitter::VisitPointerToDataMemberBinaryOperator(
- const BinaryOperator *E) {
+ const BinaryOperator *E) {
LValue LV = CGF.EmitPointerToDataMemberBinaryExpr(E);
EmitFinalDestCopy(E->getType(), LV);
}
@@ -1252,37 +1246,36 @@ static bool isBlockVarRef(const Expr *E) {
// FIXME: pointer arithmetic?
return false;
- // Check both sides of a conditional operator.
- } else if (const AbstractConditionalOperator *op
- = dyn_cast<AbstractConditionalOperator>(E)) {
- return isBlockVarRef(op->getTrueExpr())
- || isBlockVarRef(op->getFalseExpr());
+ // Check both sides of a conditional operator.
+ } else if (const AbstractConditionalOperator *op =
+ dyn_cast<AbstractConditionalOperator>(E)) {
+ return isBlockVarRef(op->getTrueExpr()) ||
+ isBlockVarRef(op->getFalseExpr());
- // OVEs are required to support BinaryConditionalOperators.
- } else if (const OpaqueValueExpr *op
- = dyn_cast<OpaqueValueExpr>(E)) {
+ // OVEs are required to support BinaryConditionalOperators.
+ } else if (const OpaqueValueExpr *op = dyn_cast<OpaqueValueExpr>(E)) {
if (const Expr *src = op->getSourceExpr())
return isBlockVarRef(src);
- // Casts are necessary to get things like (*(int*)&var) = foo().
- // We don't really care about the kind of cast here, except
- // we don't want to look through l2r casts, because it's okay
- // to get the *value* in a __block variable.
+ // Casts are necessary to get things like (*(int*)&var) = foo().
+ // We don't really care about the kind of cast here, except
+ // we don't want to look through l2r casts, because it's okay
+ // to get the *value* in a __block variable.
} else if (const CastExpr *cast = dyn_cast<CastExpr>(E)) {
if (cast->getCastKind() == CK_LValueToRValue)
return false;
return isBlockVarRef(cast->getSubExpr());
- // Handle unary operators. Again, just aggressively look through
- // it, ignoring the operation.
+ // Handle unary operators. Again, just aggressively look through
+ // it, ignoring the operation.
} else if (const UnaryOperator *uop = dyn_cast<UnaryOperator>(E)) {
return isBlockVarRef(uop->getSubExpr());
- // Look into the base of a field access.
+ // Look into the base of a field access.
} else if (const MemberExpr *mem = dyn_cast<MemberExpr>(E)) {
return isBlockVarRef(mem->getBase());
- // Look into the base of a subscript.
+ // Look into the base of a subscript.
} else if (const ArraySubscriptExpr *sub = dyn_cast<ArraySubscriptExpr>(E)) {
return isBlockVarRef(sub->getBase());
}
@@ -1295,8 +1288,8 @@ void AggExprEmitter::VisitBinAssign(const BinaryOperator *E) {
// For an assignment to work, the value on the right has
// to be compatible with the value on the left.
assert(CGF.getContext().hasSameUnqualifiedType(E->getLHS()->getType(),
- E->getRHS()->getType())
- && "Invalid assignment");
+ E->getRHS()->getType()) &&
+ "Invalid assignment");
// If the LHS might be a __block variable, and the RHS can
// potentially cause a block copy, we need to evaluate the RHS first
@@ -1315,7 +1308,7 @@ void AggExprEmitter::VisitBinAssign(const BinaryOperator *E) {
if (LHS.getType()->isAtomicType() ||
CGF.LValueIsSuitableForInlineAtomic(LHS)) {
CGF.EmitAtomicStore(Dest.asRValue(), LHS, /*isInit*/ false);
- return;
+ return;
}
EmitFinalDestCopy(E->getLHS()->getType(), LHS);
@@ -1358,8 +1351,8 @@ void AggExprEmitter::VisitBinAssign(const BinaryOperator *E) {
E->getType());
}
-void AggExprEmitter::
-VisitAbstractConditionalOperator(const AbstractConditionalOperator *E) {
+void AggExprEmitter::VisitAbstractConditionalOperator(
+ const AbstractConditionalOperator *E) {
llvm::BasicBlock *LHSBlock = CGF.createBasicBlock("cond.true");
llvm::BasicBlock *RHSBlock = CGF.createBasicBlock("cond.false");
llvm::BasicBlock *ContBlock = CGF.createBasicBlock("cond.end");
@@ -1444,8 +1437,7 @@ void AggExprEmitter::VisitCXXBindTemporaryExpr(CXXBindTemporaryExpr *E) {
CGF.EmitCXXTemporary(E->getTemporary(), E->getType(), Dest.getAddress());
}
-void
-AggExprEmitter::VisitCXXConstructExpr(const CXXConstructExpr *E) {
+void AggExprEmitter::VisitCXXConstructExpr(const CXXConstructExpr *E) {
AggValueSlot Slot = EnsureSlot(E->getType());
CGF.EmitCXXConstructExpr(E, Slot);
}
@@ -1453,13 +1445,12 @@ AggExprEmitter::VisitCXXConstructExpr(const CXXConstructExpr *E) {
void AggExprEmitter::VisitCXXInheritedCtorInitExpr(
const CXXInheritedCtorInitExpr *E) {
AggValueSlot Slot = EnsureSlot(E->getType());
- CGF.EmitInheritedCXXConstructorCall(
- E->getConstructor(), E->constructsVBase(), Slot.getAddress(),
- E->inheritedFromVBase(), E);
+ CGF.EmitInheritedCXXConstructorCall(E->getConstructor(), E->constructsVBase(),
+ Slot.getAddress(),
+ E->inheritedFromVBase(), E);
}
-void
-AggExprEmitter::VisitLambdaExpr(LambdaExpr *E) {
+void AggExprEmitter::VisitLambdaExpr(LambdaExpr *E) {
AggValueSlot Slot = EnsureSlot(E->getType());
LValue SlotLV = CGF.MakeAddrLValue(Slot.getAddress(), E->getType());
@@ -1643,9 +1634,7 @@ static bool isSimpleZero(const Expr *E, CodeGenFunction &CGF) {
return false;
}
-
-void
-AggExprEmitter::EmitInitializationToLValue(Expr *E, LValue LV) {
+void AggExprEmitter::EmitInitializationToLValue(Expr *E, LValue LV) {
QualType type = LV.getType();
// FIXME: Ignore result?
// FIXME: Are initializers affected by volatile?
@@ -1788,10 +1777,8 @@ void AggExprEmitter::VisitCXXParenListOrInitListExpr(
Dest.getAddress(), CXXRD, BaseRD,
/*isBaseVirtual*/ false);
AggValueSlot AggSlot = AggValueSlot::forAddr(
- V, Qualifiers(),
- AggValueSlot::IsDestructed,
- AggValueSlot::DoesNotNeedGCBarriers,
- AggValueSlot::IsNotAliased,
+ V, Qualifiers(), AggValueSlot::IsDestructed,
+ AggValueSlot::DoesNotNeedGCBarriers, AggValueSlot::IsNotAliased,
CGF.getOverlapForBaseInit(CXXRD, BaseRD, Base.isVirtual()));
CGF.EmitAggExpr(InitExprs[curInitIndex++], AggSlot);
@@ -1887,8 +1874,8 @@ void AggExprEmitter::VisitCXXParenListOrInitListExpr(
// Push a destructor if necessary.
// FIXME: if we have an array of structures, all explicitly
// initialized, we can end up pushing a linear number of cleanups.
- if (QualType::DestructionKind dtorKind
- = field->getType().isDestructedType()) {
+ if (QualType::DestructionKind dtorKind =
+ field->getType().isDestructedType()) {
assert(LV.isSimple());
if (dtorKind) {
CGF.pushDestroyAndDeferDeactivation(NormalAndEHCleanup, LV.getAddress(),
@@ -2043,7 +2030,8 @@ void AggExprEmitter::VisitArrayInitLoopExpr(const ArrayInitLoopExpr *E,
CGF.DeactivateCleanupBlock(cleanup, index);
}
-void AggExprEmitter::VisitDesignatedInitUpdateExpr(DesignatedInitUpdateExpr *E) {
+void AggExprEmitter::VisitDesignatedInitUpdateExpr(
+ DesignatedInitUpdateExpr *E) {
AggValueSlot Dest = EnsureSlot(E->getType());
LValue DestLV = CGF.MakeAddrLValue(Dest.getAddress(), E->getType());
@@ -2064,7 +2052,8 @@ static CharUnits GetNumNonZeroBytesInInit(const Expr *E, CodeGenFunction &CGF) {
E = E->IgnoreParenNoopCasts(CGF.getContext());
// 0 and 0.0 won't require any non-zero stores!
- if (isSimpleZero(E, CGF)) return CharUnits::Zero();
+ if (isSimpleZero(E, CGF))
+ return CharUnits::Zero();
// If this is an initlist expr, sum up the size of sizes of the (present)
// elements. If this is something weird, assume the whole thing is non-zero.
@@ -2145,7 +2134,7 @@ static void CheckAggExprForMemSetUse(AggValueSlot &Slot, const Expr *E,
// Check to see if over 3/4 of the initializer are known to be zero. If so,
// we prefer to emit memset + individual stores for the rest.
CharUnits NumNonZeroBytes = GetNumNonZeroBytesInInit(E, CGF);
- if (NumNonZeroBytes*4 > Size)
+ if (NumNonZeroBytes * 4 > Size)
return;
// Okay, it seems like a good idea to use an initial memset, emit the call.
@@ -2158,9 +2147,6 @@ static void CheckAggExprForMemSetUse(AggValueSlot &Slot, const Expr *E,
Slot.setZeroed();
}
-
-
-
/// EmitAggExpr - Emit the computation of the specified expression of aggregate
/// type. The result is computed into DestPtr. Note that if DestPtr is null,
/// the value of the aggregate expression is not needed. If VolatileDest is
@@ -2174,7 +2160,7 @@ void CodeGenFunction::EmitAggExpr(const Expr *E, AggValueSlot Slot) {
// Optimize the slot if possible.
CheckAggExprForMemSetUse(Slot, E, *this);
- AggExprEmitter(*this, Slot, Slot.isIgnored()).Visit(const_cast<Expr*>(E));
+ AggExprEmitter(*this, Slot, Slot.isIgnored()).Visit(const_cast<Expr *>(E));
}
LValue CodeGenFunction::EmitAggExprToLValue(const Expr *E) {
diff --git a/clang/lib/CodeGen/CGExprCXX.cpp b/clang/lib/CodeGen/CGExprCXX.cpp
index eae27a6a3f1c8..1a6c99beadb76 100644
--- a/clang/lib/CodeGen/CGExprCXX.cpp
+++ b/clang/lib/CodeGen/CGExprCXX.cpp
@@ -30,7 +30,7 @@ struct MemberCallInfo {
// Number of prefix arguments for the call. Ignores the `this` pointer.
unsigned PrefixSize;
};
-}
+} // namespace
static MemberCallInfo
commonEmitCXXMemberOrOperatorCall(CodeGenFunction &CGF, GlobalDecl GD,
@@ -125,8 +125,8 @@ RValue CodeGenFunction::EmitCXXDestructorCall(
CE ? CE->getExprLoc() : SourceLocation{});
}
-RValue CodeGenFunction::EmitCXXPseudoDestructorExpr(
- const CXXPseudoDestructorExpr *E) {
+RValue
+CodeGenFunction::EmitCXXPseudoDestructorExpr(const CXXPseudoDestructorExpr *E) {
QualType DestroyedType = E->getDestroyedType();
if (DestroyedType.hasStrongOrWeakObjCLifetime()) {
// Automatic Reference Counting:
@@ -155,9 +155,9 @@ RValue CodeGenFunction::EmitCXXPseudoDestructorExpr(
break;
case Qualifiers::OCL_Strong:
- EmitARCRelease(Builder.CreateLoad(BaseValue,
- DestroyedType.isVolatileQualified()),
- ARCPreciseLifetime);
+ EmitARCRelease(
+ Builder.CreateLoad(BaseValue, DestroyedType.isVolatileQualified()),
+ ARCPreciseLifetime);
break;
case Qualifiers::OCL_Weak:
@@ -272,7 +272,7 @@ RValue CodeGenFunction::EmitCXXMemberOrOperatorMemberCallExpr(
RtlArgs = &RtlArgStorage;
EmitCallArgs(*RtlArgs, MD->getType()->castAs<FunctionProtoType>(),
drop_begin(CE->arguments(), 1), CE->getDirectCallee(),
- /*ParamsToSkip*/0, EvaluationOrder::ForceRightToLeft);
+ /*ParamsToSkip*/ 0, EvaluationOrder::ForceRightToLeft);
}
}
}
@@ -468,9 +468,8 @@ CodeGenFunction::EmitCXXMemberPointerCallExpr(const CXXMemberCallExpr *E,
// Ask the ABI to load the callee. Note that This is modified.
llvm::Value *ThisPtrForCall = nullptr;
- CGCallee Callee =
- CGM.getCXXABI().EmitLoadOfMemberFunctionPointer(*this, BO, This,
- ThisPtrForCall, MemFnPtr, MPT);
+ CGCallee Callee = CGM.getCXXABI().EmitLoadOfMemberFunctionPointer(
+ *this, BO, This, ThisPtrForCall, MemFnPtr, MPT);
CallArgList Args;
@@ -582,9 +581,9 @@ static void EmitNullBaseClassInitialization(CodeGenFunction &CGF,
StoreSizeVal);
}
- // Otherwise, just memset the whole thing to zero. This is legal
- // because in LLVM, all default initializers (other than the ones we just
- // handled above) are guaranteed to have a bit pattern of all zeros.
+ // Otherwise, just memset the whole thing to zero. This is legal
+ // because in LLVM, all default initializers (other than the ones we just
+ // handled above) are guaranteed to have a bit pattern of all zeros.
} else {
for (std::pair<CharUnits, CharUnits> Store : Stores) {
CharUnits StoreOffset = Store.first;
@@ -597,9 +596,8 @@ static void EmitNullBaseClassInitialization(CodeGenFunction &CGF,
}
}
-void
-CodeGenFunction::EmitCXXConstructExpr(const CXXConstructExpr *E,
- AggValueSlot Dest) {
+void CodeGenFunction::EmitCXXConstructExpr(const CXXConstructExpr *E,
+ AggValueSlot Dest) {
assert(!Dest.isIgnored() && "Must have a destination!");
const CXXConstructorDecl *CD = E->getConstructor();
@@ -640,8 +638,7 @@ CodeGenFunction::EmitCXXConstructExpr(const CXXConstructExpr *E,
return;
}
- if (const ArrayType *arrayType
- = getContext().getAsArrayType(E->getType())) {
+ if (const ArrayType *arrayType = getContext().getAsArrayType(E->getType())) {
EmitCXXAggrConstructorCall(CD, arrayType, Dest.getAddress(), E,
Dest.isSanitizerChecked());
} else {
@@ -666,10 +663,10 @@ CodeGenFunction::EmitCXXConstructExpr(const CXXConstructExpr *E,
case CXXConstructionKind::NonVirtualBase:
Type = Ctor_Base;
- }
+ }
- // Call the constructor.
- EmitCXXConstructorCall(CD, Type, ForVirtualBase, Delegating, Dest, E);
+ // Call the constructor.
+ EmitCXXConstructorCall(CD, Type, ForVirtualBase, Delegating, Dest, E);
}
}
@@ -679,7 +676,7 @@ void CodeGenFunction::EmitSynthesizedCXXCopyCtor(Address Dest, Address Src,
Exp = E->getSubExpr();
assert(isa<CXXConstructExpr>(Exp) &&
"EmitSynthesizedCXXCopyCtor - unknown copy ctor expr");
- const CXXConstructExpr* E = cast<CXXConstructExpr>(Exp);
+ const CXXConstructExpr *E = cast<CXXConstructExpr>(Exp);
const CXXConstructorDecl *CD = E->getConstructor();
RunCleanupsScope Scope(*this);
@@ -690,8 +687,8 @@ void CodeGenFunction::EmitSynthesizedCXXCopyCtor(Address Dest, Address Src,
if (E->requiresZeroInitialization())
EmitNullInitialization(Dest, E->getType());
- assert(!getContext().getAsConstantArrayType(E->getType())
- && "EmitSynthesizedCXXCopyCtor - Copied-in Array");
+ assert(!getContext().getAsConstantArrayType(E->getType()) &&
+ "EmitSynthesizedCXXCopyCtor - Copied-in Array");
EmitSynthesizedCXXCopyCtorCall(CD, Dest, Src, E);
}
@@ -717,8 +714,8 @@ static llvm::Value *EmitCXXNewAllocSize(CodeGenFunction &CGF,
if (!e->isArray()) {
CharUnits typeSize = CGF.getContext().getTypeSizeInChars(type);
- sizeWithoutCookie
- = llvm::ConstantInt::get(CGF.SizeTy, typeSize.getQuantity());
+ sizeWithoutCookie =
+ llvm::ConstantInt::get(CGF.SizeTy, typeSize.getQuantity());
return sizeWithoutCookie;
}
@@ -744,16 +741,16 @@ static llvm::Value *EmitCXXNewAllocSize(CodeGenFunction &CGF,
// size_t. That's just a gloss, though, and it's wrong in one
// important way: if the count is negative, it's an error even if
// the cookie size would bring the total size >= 0.
- bool isSigned
- = (*e->getArraySize())->getType()->isSignedIntegerOrEnumerationType();
- llvm::IntegerType *numElementsType
- = cast<llvm::IntegerType>(numElements->getType());
+ bool isSigned =
+ (*e->getArraySize())->getType()->isSignedIntegerOrEnumerationType();
+ llvm::IntegerType *numElementsType =
+ cast<llvm::IntegerType>(numElements->getType());
unsigned numElementsWidth = numElementsType->getBitWidth();
// Compute the constant factor.
llvm::APInt arraySizeMultiplier(sizeWidth, 1);
- while (const ConstantArrayType *CAT
- = CGF.getContext().getAsConstantArrayType(type)) {
+ while (const ConstantArrayType *CAT =
+ CGF.getContext().getAsConstantArrayType(type)) {
type = CAT->getElementType();
arraySizeMultiplier *= CAT->getSize();
}
@@ -768,7 +765,7 @@ static llvm::Value *EmitCXXNewAllocSize(CodeGenFunction &CGF,
// If someone is doing 'new int[42]' there is no need to do a dynamic check.
// Don't bloat the -O0 code.
if (llvm::ConstantInt *numElementsC =
- dyn_cast<llvm::ConstantInt>(numElements)) {
+ dyn_cast<llvm::ConstantInt>(numElements)) {
const llvm::APInt &count = numElementsC->getValue();
bool hasAnyOverflow = false;
@@ -795,13 +792,13 @@ static llvm::Value *EmitCXXNewAllocSize(CodeGenFunction &CGF,
// Scale numElements by that. This might overflow, but we don't
// care because it only overflows if allocationSize does, too, and
// if that overflows then we shouldn't use this.
- numElements = llvm::ConstantInt::get(CGF.SizeTy,
- adjustedCount * arraySizeMultiplier);
+ numElements =
+ llvm::ConstantInt::get(CGF.SizeTy, adjustedCount * arraySizeMultiplier);
// Compute the size before cookie, and track whether it overflowed.
bool overflow;
- llvm::APInt allocationSize
- = adjustedCount.umul_ov(typeSizeMultiplier, overflow);
+ llvm::APInt allocationSize =
+ adjustedCount.umul_ov(typeSizeMultiplier, overflow);
hasAnyOverflow |= overflow;
// Add in the cookie, and check whether it's overflowed.
@@ -821,7 +818,7 @@ static llvm::Value *EmitCXXNewAllocSize(CodeGenFunction &CGF,
size = llvm::ConstantInt::get(CGF.SizeTy, allocationSize);
}
- // Otherwise, we might need to use the overflow intrinsics.
+ // Otherwise, we might need to use the overflow intrinsics.
} else {
// There are up to five conditions we need to test for:
// 1) if isSigned, we need to check whether numElements is negative;
@@ -845,13 +842,13 @@ static llvm::Value *EmitCXXNewAllocSize(CodeGenFunction &CGF,
llvm::APInt threshold =
llvm::APInt::getOneBitSet(numElementsWidth, sizeWidth);
- llvm::Value *thresholdV
- = llvm::ConstantInt::get(numElementsType, threshold);
+ llvm::Value *thresholdV =
+ llvm::ConstantInt::get(numElementsType, threshold);
hasOverflow = CGF.Builder.CreateICmpUGE(numElements, thresholdV);
numElements = CGF.Builder.CreateTrunc(numElements, CGF.SizeTy);
- // Otherwise, if we're signed, we want to sext up to size_t.
+ // Otherwise, if we're signed, we want to sext up to size_t.
} else if (isSigned) {
if (numElementsWidth < sizeWidth)
numElements = CGF.Builder.CreateSExt(numElements, CGF.SizeTy);
@@ -862,10 +859,10 @@ static llvm::Value *EmitCXXNewAllocSize(CodeGenFunction &CGF,
// unsigned overflow. Otherwise, we have to do it here. But at least
// in this case, we can subsume the >= minElements check.
if (typeSizeMultiplier == 1)
- hasOverflow = CGF.Builder.CreateICmpSLT(numElements,
- llvm::ConstantInt::get(CGF.SizeTy, minElements));
+ hasOverflow = CGF.Builder.CreateICmpSLT(
+ numElements, llvm::ConstantInt::get(CGF.SizeTy, minElements));
- // Otherwise, zext up to size_t if necessary.
+ // Otherwise, zext up to size_t if necessary.
} else if (numElementsWidth < sizeWidth) {
numElements = CGF.Builder.CreateZExt(numElements, CGF.SizeTy);
}
@@ -875,15 +872,16 @@ static llvm::Value *EmitCXXNewAllocSize(CodeGenFunction &CGF,
if (minElements) {
// Don't allow allocation of fewer elements than we have initializers.
if (!hasOverflow) {
- hasOverflow = CGF.Builder.CreateICmpULT(numElements,
- llvm::ConstantInt::get(CGF.SizeTy, minElements));
+ hasOverflow = CGF.Builder.CreateICmpULT(
+ numElements, llvm::ConstantInt::get(CGF.SizeTy, minElements));
} else if (numElementsWidth > sizeWidth) {
// The other existing overflow subsumes this check.
// We do an unsigned comparison, since any signed value < -1 is
// taken care of either above or below.
- hasOverflow = CGF.Builder.CreateOr(hasOverflow,
- CGF.Builder.CreateICmpULT(numElements,
- llvm::ConstantInt::get(CGF.SizeTy, minElements)));
+ hasOverflow = CGF.Builder.CreateOr(
+ hasOverflow,
+ CGF.Builder.CreateICmpULT(
+ numElements, llvm::ConstantInt::get(CGF.SizeTy, minElements)));
}
}
@@ -897,11 +895,11 @@ static llvm::Value *EmitCXXNewAllocSize(CodeGenFunction &CGF,
// can be ignored because the result shouldn't be used if
// allocation fails.
if (typeSizeMultiplier != 1) {
- llvm::Function *umul_with_overflow
- = CGF.CGM.getIntrinsic(llvm::Intrinsic::umul_with_overflow, CGF.SizeTy);
+ llvm::Function *umul_with_overflow =
+ CGF.CGM.getIntrinsic(llvm::Intrinsic::umul_with_overflow, CGF.SizeTy);
llvm::Value *tsmV =
- llvm::ConstantInt::get(CGF.SizeTy, typeSizeMultiplier);
+ llvm::ConstantInt::get(CGF.SizeTy, typeSizeMultiplier);
llvm::Value *result =
CGF.Builder.CreateCall(umul_with_overflow, {size, tsmV});
@@ -921,10 +919,10 @@ static llvm::Value *EmitCXXNewAllocSize(CodeGenFunction &CGF,
assert(arraySizeMultiplier == typeSizeMultiplier);
numElements = size;
- // Otherwise we need a separate multiply.
+ // Otherwise we need a separate multiply.
} else {
llvm::Value *asmV =
- llvm::ConstantInt::get(CGF.SizeTy, arraySizeMultiplier);
+ llvm::ConstantInt::get(CGF.SizeTy, arraySizeMultiplier);
numElements = CGF.Builder.CreateMul(numElements, asmV);
}
}
@@ -937,8 +935,8 @@ static llvm::Value *EmitCXXNewAllocSize(CodeGenFunction &CGF,
if (cookieSize != 0) {
sizeWithoutCookie = size;
- llvm::Function *uadd_with_overflow
- = CGF.CGM.getIntrinsic(llvm::Intrinsic::uadd_with_overflow, CGF.SizeTy);
+ llvm::Function *uadd_with_overflow =
+ CGF.CGM.getIntrinsic(llvm::Intrinsic::uadd_with_overflow, CGF.SizeTy);
llvm::Value *cookieSizeV = llvm::ConstantInt::get(CGF.SizeTy, cookieSize);
llvm::Value *result =
@@ -957,9 +955,8 @@ static llvm::Value *EmitCXXNewAllocSize(CodeGenFunction &CGF,
// overwrite 'size' with an all-ones value, which should cause
// operator new to throw.
if (hasOverflow)
- size = CGF.Builder.CreateSelect(hasOverflow,
- llvm::Constant::getAllOnesValue(CGF.SizeTy),
- size);
+ size = CGF.Builder.CreateSelect(
+ hasOverflow, llvm::Constant::getAllOnesValue(CGF.SizeTy), size);
}
if (cookieSize == 0)
@@ -976,21 +973,19 @@ static void StoreAnyExprIntoOneUnit(CodeGenFunction &CGF, const Expr *Init,
// FIXME: Refactor with EmitExprAsInit.
switch (CGF.getEvaluationKind(AllocType)) {
case TEK_Scalar:
- CGF.EmitScalarInit(Init, nullptr,
- CGF.MakeAddrLValue(NewPtr, AllocType), false);
+ CGF.EmitScalarInit(Init, nullptr, CGF.MakeAddrLValue(NewPtr, AllocType),
+ false);
return;
case TEK_Complex:
CGF.EmitComplexExprIntoLValue(Init, CGF.MakeAddrLValue(NewPtr, AllocType),
/*isInit*/ true);
return;
case TEK_Aggregate: {
- AggValueSlot Slot
- = AggValueSlot::forAddr(NewPtr, AllocType.getQualifiers(),
- AggValueSlot::IsDestructed,
- AggValueSlot::DoesNotNeedGCBarriers,
- AggValueSlot::IsNotAliased,
- MayOverlap, AggValueSlot::IsNotZeroed,
- AggValueSlot::IsSanitizerChecked);
+ AggValueSlot Slot = AggValueSlot::forAddr(
+ NewPtr, AllocType.getQualifiers(), AggValueSlot::IsDestructed,
+ AggValueSlot::DoesNotNeedGCBarriers, AggValueSlot::IsNotAliased,
+ MayOverlap, AggValueSlot::IsNotZeroed,
+ AggValueSlot::IsSanitizerChecked);
CGF.EmitAggExpr(Init, Slot);
return;
}
@@ -1019,7 +1014,7 @@ void CodeGenFunction::EmitNewArrayInitializer(
CharUnits ElementSize = getContext().getTypeSizeInChars(ElementType);
CharUnits ElementAlign =
- BeginPtr.getAlignment().alignmentOfArrayElement(ElementSize);
+ BeginPtr.getAlignment().alignmentOfArrayElement(ElementSize);
// Attempt to perform zero-initialization using memset.
auto TryMemsetInitialization = [&]() -> bool {
@@ -1069,22 +1064,19 @@ void CodeGenFunction::EmitNewArrayInitializer(
// Initialize the initial portion of length equal to that of the string
// literal. The allocation must be for at least this much; we emitted a
// check for that earlier.
- AggValueSlot Slot =
- AggValueSlot::forAddr(CurPtr, ElementType.getQualifiers(),
- AggValueSlot::IsDestructed,
- AggValueSlot::DoesNotNeedGCBarriers,
- AggValueSlot::IsNotAliased,
- AggValueSlot::DoesNotOverlap,
- AggValueSlot::IsNotZeroed,
- AggValueSlot::IsSanitizerChecked);
+ AggValueSlot Slot = AggValueSlot::forAddr(
+ CurPtr, ElementType.getQualifiers(), AggValueSlot::IsDestructed,
+ AggValueSlot::DoesNotNeedGCBarriers, AggValueSlot::IsNotAliased,
+ AggValueSlot::DoesNotOverlap, AggValueSlot::IsNotZeroed,
+ AggValueSlot::IsSanitizerChecked);
EmitAggExpr(ILE ? ILE->getInit(0) : Init, Slot);
// Move past these elements.
InitListElements =
cast<ConstantArrayType>(Init->getType()->getAsArrayTypeUnsafe())
->getZExtSize();
- CurPtr = Builder.CreateConstInBoundsGEP(
- CurPtr, InitListElements, "string.init.end");
+ CurPtr = Builder.CreateConstInBoundsGEP(CurPtr, InitListElements,
+ "string.init.end");
// Zero out the rest, if any remain.
llvm::ConstantInt *ConstNum = dyn_cast<llvm::ConstantInt>(NumElements);
@@ -1207,7 +1199,7 @@ void CodeGenFunction::EmitNewArrayInitializer(
NumElements,
llvm::ConstantInt::get(NumElements->getType(), InitListElements));
EmitCXXAggrConstructorCall(Ctor, NumElements, CurPtr, CCE,
- /*NewPointerIsChecked*/true,
+ /*NewPointerIsChecked*/ true,
CCE->requiresZeroInitialization());
return;
}
@@ -1343,10 +1335,9 @@ static RValue EmitNewDeleteCall(CodeGenFunction &CGF,
llvm::CallBase *CallOrInvoke;
llvm::Constant *CalleePtr = CGF.CGM.GetAddrOfFunction(CalleeDecl);
CGCallee Callee = CGCallee::forDirect(CalleePtr, GlobalDecl(CalleeDecl));
- RValue RV =
- CGF.EmitCall(CGF.CGM.getTypes().arrangeFreeFunctionCall(
- Args, CalleeType, /*ChainCall=*/false),
- Callee, ReturnValueSlot(), Args, &CallOrInvoke);
+ RValue RV = CGF.EmitCall(CGF.CGM.getTypes().arrangeFreeFunctionCall(
+ Args, CalleeType, /*ChainCall=*/false),
+ Callee, ReturnValueSlot(), Args, &CallOrInvoke);
/// C++1y [expr.new]p10:
/// [In a new-expression,] an implementation is allowed to omit a call
@@ -1354,8 +1345,8 @@ static RValue EmitNewDeleteCall(CodeGenFunction &CGF,
///
/// We model such elidable calls with the 'builtin' attribute.
llvm::Function *Fn = dyn_cast<llvm::Function>(CalleePtr);
- if (CalleeDecl->isReplaceableGlobalAllocationFunction() &&
- Fn && Fn->hasFnAttribute(llvm::Attribute::NoBuiltin)) {
+ if (CalleeDecl->isReplaceableGlobalAllocationFunction() && Fn &&
+ Fn->hasFnAttribute(llvm::Attribute::NoBuiltin)) {
CallOrInvoke->addFnAttr(llvm::Attribute::Builtin);
}
@@ -1369,8 +1360,8 @@ RValue CodeGenFunction::EmitBuiltinNewDeleteCall(const FunctionProtoType *Type,
EmitCallArgs(Args, Type, TheCall->arguments());
// Find the allocation or deallocation function that we're calling.
ASTContext &Ctx = getContext();
- DeclarationName Name = Ctx.DeclarationNames
- .getCXXOperatorName(IsDelete ? OO_Delete : OO_New);
+ DeclarationName Name =
+ Ctx.DeclarationNames.getCXXOperatorName(IsDelete ? OO_Delete : OO_New);
for (auto *Decl : Ctx.getTranslationUnitDecl()->lookup(Name))
if (auto *FD = dyn_cast<FunctionDecl>(Decl))
@@ -1388,113 +1379,111 @@ RValue CodeGenFunction::EmitBuiltinNewDeleteCall(const FunctionProtoType *Type,
}
namespace {
- /// A cleanup to call the given 'operator delete' function upon abnormal
- /// exit from a new expression. Templated on a traits type that deals with
- /// ensuring that the arguments dominate the cleanup if necessary.
- template<typename Traits>
- class CallDeleteDuringNew final : public EHScopeStack::Cleanup {
- /// Type used to hold llvm::Value*s.
- typedef typename Traits::ValueTy ValueTy;
- /// Type used to hold RValues.
- typedef typename Traits::RValueTy RValueTy;
- struct PlacementArg {
- RValueTy ArgValue;
- QualType ArgType;
- };
-
- unsigned NumPlacementArgs : 30;
- LLVM_PREFERRED_TYPE(AlignedAllocationMode)
- unsigned PassAlignmentToPlacementDelete : 1;
- const FunctionDecl *OperatorDelete;
- RValueTy TypeIdentity;
- ValueTy Ptr;
- ValueTy AllocSize;
- CharUnits AllocAlign;
-
- PlacementArg *getPlacementArgs() {
- return reinterpret_cast<PlacementArg *>(this + 1);
- }
+/// A cleanup to call the given 'operator delete' function upon abnormal
+/// exit from a new expression. Templated on a traits type that deals with
+/// ensuring that the arguments dominate the cleanup if necessary.
+template <typename Traits>
+class CallDeleteDuringNew final : public EHScopeStack::Cleanup {
+ /// Type used to hold llvm::Value*s.
+ typedef typename Traits::ValueTy ValueTy;
+ /// Type used to hold RValues.
+ typedef typename Traits::RValueTy RValueTy;
+ struct PlacementArg {
+ RValueTy ArgValue;
+ QualType ArgType;
+ };
- public:
- static size_t getExtraSize(size_t NumPlacementArgs) {
- return NumPlacementArgs * sizeof(PlacementArg);
- }
+ unsigned NumPlacementArgs : 30;
+ LLVM_PREFERRED_TYPE(AlignedAllocationMode)
+ unsigned PassAlignmentToPlacementDelete : 1;
+ const FunctionDecl *OperatorDelete;
+ RValueTy TypeIdentity;
+ ValueTy Ptr;
+ ValueTy AllocSize;
+ CharUnits AllocAlign;
+
+ PlacementArg *getPlacementArgs() {
+ return reinterpret_cast<PlacementArg *>(this + 1);
+ }
- CallDeleteDuringNew(size_t NumPlacementArgs,
- const FunctionDecl *OperatorDelete,
- RValueTy TypeIdentity, ValueTy Ptr, ValueTy AllocSize,
- const ImplicitAllocationParameters &IAP,
- CharUnits AllocAlign)
- : NumPlacementArgs(NumPlacementArgs),
- PassAlignmentToPlacementDelete(
- isAlignedAllocation(IAP.PassAlignment)),
- OperatorDelete(OperatorDelete), TypeIdentity(TypeIdentity), Ptr(Ptr),
- AllocSize(AllocSize), AllocAlign(AllocAlign) {}
-
- void setPlacementArg(unsigned I, RValueTy Arg, QualType Type) {
- assert(I < NumPlacementArgs && "index out of range");
- getPlacementArgs()[I] = {Arg, Type};
- }
+public:
+ static size_t getExtraSize(size_t NumPlacementArgs) {
+ return NumPlacementArgs * sizeof(PlacementArg);
+ }
- void Emit(CodeGenFunction &CGF, Flags flags) override {
- const auto *FPT = OperatorDelete->getType()->castAs<FunctionProtoType>();
- CallArgList DeleteArgs;
- unsigned FirstNonTypeArg = 0;
- TypeAwareAllocationMode TypeAwareDeallocation =
- TypeAwareAllocationMode::No;
- if (OperatorDelete->isTypeAwareOperatorNewOrDelete()) {
- TypeAwareDeallocation = TypeAwareAllocationMode::Yes;
- QualType SpecializedTypeIdentity = FPT->getParamType(0);
- ++FirstNonTypeArg;
- DeleteArgs.add(Traits::get(CGF, TypeIdentity), SpecializedTypeIdentity);
- }
- // The first argument after type-identity parameter (if any) is always
- // a void* (or C* for a destroying operator delete for class type C).
- DeleteArgs.add(Traits::get(CGF, Ptr), FPT->getParamType(FirstNonTypeArg));
-
- // Figure out what other parameters we should be implicitly passing.
- UsualDeleteParams Params;
- if (NumPlacementArgs) {
- // A placement deallocation function is implicitly passed an alignment
- // if the placement allocation function was, but is never passed a size.
- Params.Alignment =
- alignedAllocationModeFromBool(PassAlignmentToPlacementDelete);
- Params.TypeAwareDelete = TypeAwareDeallocation;
- Params.Size = isTypeAwareAllocation(Params.TypeAwareDelete);
- } else {
- // For a non-placement new-expression, 'operator delete' can take a
- // size and/or an alignment if it has the right parameters.
- Params = OperatorDelete->getUsualDeleteParams();
- }
+ CallDeleteDuringNew(size_t NumPlacementArgs,
+ const FunctionDecl *OperatorDelete, RValueTy TypeIdentity,
+ ValueTy Ptr, ValueTy AllocSize,
+ const ImplicitAllocationParameters &IAP,
+ CharUnits AllocAlign)
+ : NumPlacementArgs(NumPlacementArgs),
+ PassAlignmentToPlacementDelete(isAlignedAllocation(IAP.PassAlignment)),
+ OperatorDelete(OperatorDelete), TypeIdentity(TypeIdentity), Ptr(Ptr),
+ AllocSize(AllocSize), AllocAlign(AllocAlign) {}
+
+ void setPlacementArg(unsigned I, RValueTy Arg, QualType Type) {
+ assert(I < NumPlacementArgs && "index out of range");
+ getPlacementArgs()[I] = {Arg, Type};
+ }
- assert(!Params.DestroyingDelete &&
- "should not call destroying delete in a new-expression");
-
- // The second argument can be a std::size_t (for non-placement delete).
- if (Params.Size)
- DeleteArgs.add(Traits::get(CGF, AllocSize),
- CGF.getContext().getSizeType());
-
- // The next (second or third) argument can be a std::align_val_t, which
- // is an enum whose underlying type is std::size_t.
- // FIXME: Use the right type as the parameter type. Note that in a call
- // to operator delete(size_t, ...), we may not have it available.
- if (isAlignedAllocation(Params.Alignment))
- DeleteArgs.add(RValue::get(llvm::ConstantInt::get(
- CGF.SizeTy, AllocAlign.getQuantity())),
- CGF.getContext().getSizeType());
-
- // Pass the rest of the arguments, which must match exactly.
- for (unsigned I = 0; I != NumPlacementArgs; ++I) {
- auto Arg = getPlacementArgs()[I];
- DeleteArgs.add(Traits::get(CGF, Arg.ArgValue), Arg.ArgType);
- }
+ void Emit(CodeGenFunction &CGF, Flags flags) override {
+ const auto *FPT = OperatorDelete->getType()->castAs<FunctionProtoType>();
+ CallArgList DeleteArgs;
+ unsigned FirstNonTypeArg = 0;
+ TypeAwareAllocationMode TypeAwareDeallocation = TypeAwareAllocationMode::No;
+ if (OperatorDelete->isTypeAwareOperatorNewOrDelete()) {
+ TypeAwareDeallocation = TypeAwareAllocationMode::Yes;
+ QualType SpecializedTypeIdentity = FPT->getParamType(0);
+ ++FirstNonTypeArg;
+ DeleteArgs.add(Traits::get(CGF, TypeIdentity), SpecializedTypeIdentity);
+ }
+ // The first argument after type-identity parameter (if any) is always
+ // a void* (or C* for a destroying operator delete for class type C).
+ DeleteArgs.add(Traits::get(CGF, Ptr), FPT->getParamType(FirstNonTypeArg));
+
+ // Figure out what other parameters we should be implicitly passing.
+ UsualDeleteParams Params;
+ if (NumPlacementArgs) {
+ // A placement deallocation function is implicitly passed an alignment
+ // if the placement allocation function was, but is never passed a size.
+ Params.Alignment =
+ alignedAllocationModeFromBool(PassAlignmentToPlacementDelete);
+ Params.TypeAwareDelete = TypeAwareDeallocation;
+ Params.Size = isTypeAwareAllocation(Params.TypeAwareDelete);
+ } else {
+ // For a non-placement new-expression, 'operator delete' can take a
+ // size and/or an alignment if it has the right parameters.
+ Params = OperatorDelete->getUsualDeleteParams();
+ }
- // Call 'operator delete'.
- EmitNewDeleteCall(CGF, OperatorDelete, FPT, DeleteArgs);
+ assert(!Params.DestroyingDelete &&
+ "should not call destroying delete in a new-expression");
+
+ // The second argument can be a std::size_t (for non-placement delete).
+ if (Params.Size)
+ DeleteArgs.add(Traits::get(CGF, AllocSize),
+ CGF.getContext().getSizeType());
+
+ // The next (second or third) argument can be a std::align_val_t, which
+ // is an enum whose underlying type is std::size_t.
+ // FIXME: Use the right type as the parameter type. Note that in a call
+ // to operator delete(size_t, ...), we may not have it available.
+ if (isAlignedAllocation(Params.Alignment))
+ DeleteArgs.add(RValue::get(llvm::ConstantInt::get(
+ CGF.SizeTy, AllocAlign.getQuantity())),
+ CGF.getContext().getSizeType());
+
+ // Pass the rest of the arguments, which must match exactly.
+ for (unsigned I = 0; I != NumPlacementArgs; ++I) {
+ auto Arg = getPlacementArgs()[I];
+ DeleteArgs.add(Traits::get(CGF, Arg.ArgValue), Arg.ArgType);
}
- };
-}
+
+ // Call 'operator delete'.
+ EmitNewDeleteCall(CGF, OperatorDelete, FPT, DeleteArgs);
+ }
+};
+} // namespace
/// Enter a cleanup to call 'operator delete' if the initializer in a
/// new-expression throws.
@@ -1532,7 +1521,7 @@ static void EnterNewDeleteCleanup(CodeGenFunction &CGF, const CXXNewExpr *E,
DominatingValue<RValue>::saved_type SavedNewPtr =
DominatingValue<RValue>::save(CGF, RValue::get(NewPtr, CGF));
DominatingValue<RValue>::saved_type SavedAllocSize =
- DominatingValue<RValue>::save(CGF, RValue::get(AllocSize));
+ DominatingValue<RValue>::save(CGF, RValue::get(AllocSize));
DominatingValue<RValue>::saved_type SavedTypeIdentity =
DominatingValue<RValue>::save(CGF, TypeIdentity);
struct ConditionalCleanupTraits {
@@ -1586,9 +1575,8 @@ llvm::Value *CodeGenFunction::EmitCXXNewExpr(const CXXNewExpr *E) {
llvm::Value *numElements = nullptr;
llvm::Value *allocSizeWithoutCookie = nullptr;
- llvm::Value *allocSize =
- EmitCXXNewAllocSize(*this, E, minElements, numElements,
- allocSizeWithoutCookie);
+ llvm::Value *allocSize = EmitCXXNewAllocSize(
+ *this, E, minElements, numElements, allocSizeWithoutCookie);
CharUnits allocAlign = getContext().getTypeAlignInChars(allocType);
// Emit the allocation call. If the allocator is a global placement
@@ -1619,7 +1607,7 @@ llvm::Value *CodeGenFunction::EmitCXXNewExpr(const CXXNewExpr *E) {
} else {
const FunctionProtoType *allocatorType =
- allocator->getType()->castAs<FunctionProtoType>();
+ allocator->getType()->castAs<FunctionProtoType>();
ImplicitAllocationParameters IAP = E->implicitAllocationParameters();
unsigned ParamsToSkip = 0;
if (isTypeAwareAllocation(IAP.PassTypeIdentity)) {
@@ -1661,10 +1649,10 @@ llvm::Value *CodeGenFunction::EmitCXXNewExpr(const CXXNewExpr *E) {
// FIXME: Why do we not pass a CalleeDecl here?
EmitCallArgs(allocatorArgs, allocatorType, E->placement_arguments(),
- /*AC*/AbstractCallee(), /*ParamsToSkip*/ParamsToSkip);
+ /*AC*/ AbstractCallee(), /*ParamsToSkip*/ ParamsToSkip);
RValue RV =
- EmitNewDeleteCall(*this, allocator, allocatorType, allocatorArgs);
+ EmitNewDeleteCall(*this, allocator, allocatorType, allocatorArgs);
if (auto *newCall = dyn_cast<llvm::CallBase>(RV.getScalarVal())) {
if (auto *CGDI = getDebugInfo()) {
@@ -1736,9 +1724,8 @@ llvm::Value *CodeGenFunction::EmitCXXNewExpr(const CXXNewExpr *E) {
CalculateCookiePadding(*this, E).isZero());
if (allocSize != allocSizeWithoutCookie) {
assert(E->isArray());
- allocation = CGM.getCXXABI().InitializeArrayCookie(*this, allocation,
- numElements,
- E, allocType);
+ allocation = CGM.getCXXABI().InitializeArrayCookie(
+ *this, allocation, numElements, E, allocType);
}
llvm::Type *elementTy = ConvertTypeForMem(allocType);
@@ -1871,27 +1858,25 @@ void CodeGenFunction::EmitDeleteCall(const FunctionDecl *DeleteFD,
(*TagAlloca)->eraseFromParent();
}
namespace {
- /// Calls the given 'operator delete' on a single object.
- struct CallObjectDelete final : EHScopeStack::Cleanup {
- llvm::Value *Ptr;
- const FunctionDecl *OperatorDelete;
- QualType ElementType;
-
- CallObjectDelete(llvm::Value *Ptr,
- const FunctionDecl *OperatorDelete,
- QualType ElementType)
+/// Calls the given 'operator delete' on a single object.
+struct CallObjectDelete final : EHScopeStack::Cleanup {
+ llvm::Value *Ptr;
+ const FunctionDecl *OperatorDelete;
+ QualType ElementType;
+
+ CallObjectDelete(llvm::Value *Ptr, const FunctionDecl *OperatorDelete,
+ QualType ElementType)
: Ptr(Ptr), OperatorDelete(OperatorDelete), ElementType(ElementType) {}
- void Emit(CodeGenFunction &CGF, Flags flags) override {
- CGF.EmitDeleteCall(OperatorDelete, Ptr, ElementType);
- }
- };
-}
+ void Emit(CodeGenFunction &CGF, Flags flags) override {
+ CGF.EmitDeleteCall(OperatorDelete, Ptr, ElementType);
+ }
+};
+} // namespace
-void
-CodeGenFunction::pushCallObjectDeleteCleanup(const FunctionDecl *OperatorDelete,
- llvm::Value *CompletePtr,
- QualType ElementType) {
+void CodeGenFunction::pushCallObjectDeleteCleanup(
+ const FunctionDecl *OperatorDelete, llvm::Value *CompletePtr,
+ QualType ElementType) {
EHStack.pushCleanup<CallObjectDelete>(NormalAndEHCleanup, CompletePtr,
OperatorDelete, ElementType);
}
@@ -1915,10 +1900,8 @@ static void EmitDestroyingObjectDelete(CodeGenFunction &CGF,
/// Emit the code for deleting a single object.
/// \return \c true if we started emitting UnconditionalDeleteBlock, \c false
/// if not.
-static bool EmitObjectDelete(CodeGenFunction &CGF,
- const CXXDeleteExpr *DE,
- Address Ptr,
- QualType ElementType,
+static bool EmitObjectDelete(CodeGenFunction &CGF, const CXXDeleteExpr *DE,
+ Address Ptr, QualType ElementType,
llvm::BasicBlock *UnconditionalDeleteBlock) {
// C++11 [expr.delete]p3:
// If the static type of the object to be deleted is different from its
@@ -1941,10 +1924,9 @@ static bool EmitObjectDelete(CodeGenFunction &CGF,
if (Dtor->isVirtual()) {
bool UseVirtualCall = true;
const Expr *Base = DE->getArgument();
- if (auto *DevirtualizedDtor =
- dyn_cast_or_null<const CXXDestructorDecl>(
- Dtor->getDevirtualizedMethod(
- Base, CGF.CGM.getLangOpts().AppleKext))) {
+ if (auto *DevirtualizedDtor = dyn_cast_or_null<const CXXDestructorDecl>(
+ Dtor->getDevirtualizedMethod(
+ Base, CGF.CGM.getLangOpts().AppleKext))) {
UseVirtualCall = false;
const CXXRecordDecl *DevirtualizedClass =
DevirtualizedDtor->getParent();
@@ -1979,8 +1961,7 @@ static bool EmitObjectDelete(CodeGenFunction &CGF,
if (Dtor)
CGF.EmitCXXDestructorCall(Dtor, Dtor_Complete,
/*ForVirtualBase=*/false,
- /*Delegating=*/false,
- Ptr, ElementType);
+ /*Delegating=*/false, Ptr, ElementType);
else if (auto Lifetime = ElementType.getObjCLifetime()) {
switch (Lifetime) {
case Qualifiers::OCL_None:
@@ -2010,34 +1991,30 @@ static bool EmitObjectDelete(CodeGenFunction &CGF,
}
namespace {
- /// Calls the given 'operator delete' on an array of objects.
- struct CallArrayDelete final : EHScopeStack::Cleanup {
- llvm::Value *Ptr;
- const FunctionDecl *OperatorDelete;
- llvm::Value *NumElements;
- QualType ElementType;
- CharUnits CookieSize;
-
- CallArrayDelete(llvm::Value *Ptr,
- const FunctionDecl *OperatorDelete,
- llvm::Value *NumElements,
- QualType ElementType,
- CharUnits CookieSize)
+/// Calls the given 'operator delete' on an array of objects.
+struct CallArrayDelete final : EHScopeStack::Cleanup {
+ llvm::Value *Ptr;
+ const FunctionDecl *OperatorDelete;
+ llvm::Value *NumElements;
+ QualType ElementType;
+ CharUnits CookieSize;
+
+ CallArrayDelete(llvm::Value *Ptr, const FunctionDecl *OperatorDelete,
+ llvm::Value *NumElements, QualType ElementType,
+ CharUnits CookieSize)
: Ptr(Ptr), OperatorDelete(OperatorDelete), NumElements(NumElements),
ElementType(ElementType), CookieSize(CookieSize) {}
- void Emit(CodeGenFunction &CGF, Flags flags) override {
- CGF.EmitDeleteCall(OperatorDelete, Ptr, ElementType, NumElements,
- CookieSize);
- }
- };
-}
+ void Emit(CodeGenFunction &CGF, Flags flags) override {
+ CGF.EmitDeleteCall(OperatorDelete, Ptr, ElementType, NumElements,
+ CookieSize);
+ }
+};
+} // namespace
/// Emit the code for deleting an array of objects.
-static void EmitArrayDelete(CodeGenFunction &CGF,
- const CXXDeleteExpr *E,
- Address deletedPtr,
- QualType elementType) {
+static void EmitArrayDelete(CodeGenFunction &CGF, const CXXDeleteExpr *E,
+ Address deletedPtr, QualType elementType) {
llvm::Value *numElements = nullptr;
llvm::Value *allocatedPtr = nullptr;
CharUnits cookieSize;
@@ -2048,10 +2025,9 @@ static void EmitArrayDelete(CodeGenFunction &CGF,
// Make sure that we call delete even if one of the dtors throws.
const FunctionDecl *operatorDelete = E->getOperatorDelete();
- CGF.EHStack.pushCleanup<CallArrayDelete>(NormalAndEHCleanup,
- allocatedPtr, operatorDelete,
- numElements, elementType,
- cookieSize);
+ CGF.EHStack.pushCleanup<CallArrayDelete>(NormalAndEHCleanup, allocatedPtr,
+ operatorDelete, numElements,
+ elementType, cookieSize);
// Destroy the elements.
if (QualType::DestructionKind dtorKind = elementType.isDestructedType()) {
@@ -2059,11 +2035,11 @@ static void EmitArrayDelete(CodeGenFunction &CGF,
CharUnits elementSize = CGF.getContext().getTypeSizeInChars(elementType);
CharUnits elementAlign =
- deletedPtr.getAlignment().alignmentOfArrayElement(elementSize);
+ deletedPtr.getAlignment().alignmentOfArrayElement(elementSize);
llvm::Value *arrayBegin = deletedPtr.emitRawPointer(CGF);
llvm::Value *arrayEnd = CGF.Builder.CreateInBoundsGEP(
- deletedPtr.getElementType(), arrayBegin, numElements, "delete.end");
+ deletedPtr.getElementType(), arrayBegin, numElements, "delete.end");
// Note that it is legal to allocate a zero-length array, and we
// can never fold the check away because the length should always
More information about the cfe-commits
mailing list