Skip to content

Commit b0e93f1

Browse files
[BoundsSafety] Allow evaluating the same CLE in a bounds-check
BoundsSafety can reuse the same CompoundLiteralExpr when emitting a bounds-check condition. This change disables constant-eval when inside of CompoundLiteralExpr. rdar://157033241
1 parent 6f25a1f commit b0e93f1

File tree

5 files changed

+82
-15
lines changed

5 files changed

+82
-15
lines changed

clang/include/clang/Sema/Sema.h

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -7901,7 +7901,8 @@ class Sema final : public SemaBase {
79017901
/// built-in operations; ActOnBinOp handles overloaded operators.
79027902
ExprResult CreateBuiltinBinOp(SourceLocation OpLoc, BinaryOperatorKind Opc,
79037903
Expr *LHSExpr, Expr *RHSExpr,
7904-
bool ForFoldExpression = false);
7904+
bool ForFoldExpression = false,
7905+
bool ForBoundsCheckExpression = false);
79057906
void LookupBinOp(Scope *S, SourceLocation OpLoc, BinaryOperatorKind Opc,
79067907
UnresolvedSetImpl &Functions);
79077908

@@ -8609,7 +8610,7 @@ class Sema final : public SemaBase {
86098610
BinaryOperatorKind Opc);
86108611
QualType CheckLogicalOperands( // C99 6.5.[13,14]
86118612
ExprResult &LHS, ExprResult &RHS, SourceLocation Loc,
8612-
BinaryOperatorKind Opc);
8613+
BinaryOperatorKind Opc, bool Diagnose = true);
86138614
// CheckAssignmentOperands is used for both simple and compound assignment.
86148615
// For simple assignment, pass both expressions and a null converted type.
86158616
// For compound assignment, pass both expressions and the converted type.

clang/lib/AST/ExprConstant.cpp

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9426,6 +9426,22 @@ LValueExprEvaluator::VisitCompoundLiteralExpr(const CompoundLiteralExpr *E) {
94269426
*Lit = APValue();
94279427
} else {
94289428
assert(!Info.getLangOpts().CPlusPlus);
9429+
9430+
#if 0
9431+
// TO_UPSTREAM(BoundsSafety) ON
9432+
// BoundsSafety can reuse the same CLE when emitting a bounds-check
9433+
// condition. If the state already exist, reset it and evaluate again.
9434+
// FIXME: Same as above, we could re-use the previously evaluated value.
9435+
APValue *Val;
9436+
if (Info.getLangOpts().BoundsSafety &&
9437+
(Val = Info.CurrentCall->getCurrentTemporary(E))) {
9438+
Lit = Val;
9439+
Result.set(E);
9440+
*Lit = APValue();
9441+
} else
9442+
// TO_UPSTREAM(BoundsSafety) OFF
9443+
#endif
9444+
94299445
Lit = &Info.CurrentCall->createTemporary(E, E->getInitializer()->getType(),
94309446
ScopeKind::Block, Result);
94319447
}

clang/lib/Sema/SemaChecking.cpp

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -14245,6 +14245,14 @@ class SequenceChecker : public ConstEvaluatedExprVisitor<SequenceChecker> {
1424514245
SequenceExpressionsInOrder(PLIE->getInitExprs());
1424614246
}
1424714247

14248+
void VisitMaterializeSequenceExpr(const MaterializeSequenceExpr *MSE) {
14249+
Visit(MSE->getWrappedExpr());
14250+
}
14251+
14252+
void VisitBoundsCheckExpr(const BoundsCheckExpr *BCE) {
14253+
Visit(BCE->getGuardedExpr());
14254+
}
14255+
1424814256
private:
1424914257
void SequenceExpressionsInOrder(ArrayRef<const Expr *> ExpressionList) {
1425014258
SmallVector<SequenceTree::Seq, 32> Elts;

clang/lib/Sema/SemaExpr.cpp

Lines changed: 29 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -16476,7 +16476,8 @@ inline QualType Sema::CheckBitwiseOperands(ExprResult &LHS, ExprResult &RHS,
1647616476
// C99 6.5.[13,14]
1647716477
inline QualType Sema::CheckLogicalOperands(ExprResult &LHS, ExprResult &RHS,
1647816478
SourceLocation Loc,
16479-
BinaryOperatorKind Opc) {
16479+
BinaryOperatorKind Opc,
16480+
bool Diagnose) {
1648016481
// Check vector operands differently.
1648116482
if (LHS.get()->getType()->isVectorType() ||
1648216483
RHS.get()->getType()->isVectorType())
@@ -16507,7 +16508,8 @@ inline QualType Sema::CheckLogicalOperands(ExprResult &LHS, ExprResult &RHS,
1650716508
// Diagnose cases where the user write a logical and/or but probably meant a
1650816509
// bitwise one. We do this when the LHS is a non-bool integer and the RHS
1650916510
// is a constant.
16510-
if (!EnumConstantInBoolContext && LHS.get()->getType()->isIntegerType() &&
16511+
if (Diagnose && !EnumConstantInBoolContext &&
16512+
LHS.get()->getType()->isIntegerType() &&
1651116513
!LHS.get()->getType()->isBooleanType() &&
1651216514
RHS.get()->getType()->isIntegerType() && !RHS.get()->isValueDependent() &&
1651316515
// Don't warn in macros or template instantiations.
@@ -18222,7 +18224,8 @@ static bool needsConversionOfHalfVec(bool OpRequiresConversion, ASTContext &Ctx,
1822218224

1822318225
ExprResult Sema::CreateBuiltinBinOp(SourceLocation OpLoc,
1822418226
BinaryOperatorKind Opc, Expr *LHSExpr,
18225-
Expr *RHSExpr, bool ForFoldExpression) {
18227+
Expr *RHSExpr, bool ForFoldExpression,
18228+
bool ForBoundsCheckExpression) {
1822618229
if (getLangOpts().CPlusPlus11 && isa<InitListExpr>(RHSExpr)) {
1822718230
// The syntax only allows initializer lists on the RHS of assignment,
1822818231
// so we don't need to worry about accepting invalid code for
@@ -18376,7 +18379,8 @@ ExprResult Sema::CreateBuiltinBinOp(SourceLocation OpLoc,
1837618379
case BO_LAnd:
1837718380
case BO_LOr:
1837818381
ConvertHalfVec = true;
18379-
ResultTy = CheckLogicalOperands(LHS, RHS, OpLoc, Opc);
18382+
ResultTy = CheckLogicalOperands(LHS, RHS, OpLoc, Opc,
18383+
/*Diagnose=*/!ForBoundsCheckExpression);
1838018384
break;
1838118385
case BO_MulAssign:
1838218386
case BO_DivAssign:
@@ -26099,7 +26103,9 @@ ExprResult BoundsCheckBuilder::BuildImplicitPointerArith(Sema &S,
2609926103
Pointer = CastResult.get();
2610026104
}
2610126105

26102-
return S.CreateBuiltinBinOp(SourceLocation(), Opc, Pointer, RHS);
26106+
return S.CreateBuiltinBinOp(SourceLocation(), Opc, Pointer, RHS,
26107+
/*ForFoldExpression=*/false,
26108+
/*ForBoundsCheckExpression=*/true);
2610326109
}
2610426110

2610526111
OpaqueValueExpr *BoundsCheckBuilder::OpaqueWrap(Sema &S, Expr *E) {
@@ -26118,7 +26124,9 @@ bool BoundsCheckBuilder::BuildIndexBounds(Sema &S, Expr *Min, Expr *Max,
2611826124
if (!(Max = Upper.get()))
2611926125
return false;
2612026126
}
26121-
ExprResult Count = S.CreateBuiltinBinOp(Max->getBeginLoc(), BO_Sub, Max, Min);
26127+
ExprResult Count = S.CreateBuiltinBinOp(Max->getBeginLoc(), BO_Sub, Max, Min,
26128+
/*ForFoldExpression=*/false,
26129+
/*ForBoundsCheckExpression=*/true);
2612226130
if (!Count.get())
2612326131
return false;
2612426132

@@ -26141,7 +26149,8 @@ bool BoundsCheckBuilder::BuildIndexBounds(Sema &S, Expr *Min, Expr *Max,
2614126149
R.push_back(OpaqueStart);
2614226150
IsSigned |= OpaqueStart->getType()->isSignedIntegerOrEnumerationType();
2614326151
ExprResult CountTotal = S.CreateBuiltinBinOp(
26144-
OpaqueStart->getBeginLoc(), BO_Add, OpaqueStart, AccessCount);
26152+
OpaqueStart->getBeginLoc(), BO_Add, OpaqueStart, AccessCount,
26153+
/*ForFoldExpression=*/false, /*ForBoundsCheckExpression=*/true);
2614526154
if (!(AccessCount = CountTotal.get()))
2614626155
return false;
2614726156
}
@@ -26326,7 +26335,9 @@ ExprResult BoundsCheckBuilder::Build(Sema &S, Expr *GuardedValue) {
2632626335
if (NullCheck.isInvalid())
2632726336
return ExprError();
2632826337
// !Ptr || 0 <= Count <= (Upper - Ptr)
26329-
Cond = S.CreateBuiltinBinOp(Loc, BO_LOr, NullCheck.get(), Cond.get());
26338+
Cond = S.CreateBuiltinBinOp(Loc, BO_LOr, NullCheck.get(), Cond.get(),
26339+
/*ForFoldExpression=*/false,
26340+
/*ForBoundsCheckExpression=*/true);
2633026341
if (Cond.isInvalid())
2633126342
return ExprError();
2633226343
}
@@ -26341,8 +26352,10 @@ ExprResult BoundsCheckBuilder::Build(Sema &S, Expr *GuardedValue) {
2634126352
ExprResult BasePtrBoundsCheck = BuildLEChecks(S, Loc, Bounds, OVEs);
2634226353
if (!BasePtrBoundsCheck.get())
2634326354
return ExprError();
26344-
Cond = S.CreateBuiltinBinOp(
26345-
Loc, BO_LAnd, BasePtrBoundsCheck.get(), Cond.get());
26355+
Cond =
26356+
S.CreateBuiltinBinOp(Loc, BO_LAnd, BasePtrBoundsCheck.get(), Cond.get(),
26357+
/*ForFoldExpression=*/false,
26358+
/*ForBoundsCheckExpression=*/true);
2634626359
if (!Cond.get())
2634726360
return ExprError();
2634826361
}
@@ -26382,15 +26395,18 @@ ExprResult BoundsCheckBuilder::BuildLEChecks(
2638226395
Bound = OVEs.back();
2638326396
}
2638426397

26385-
ExprResult LEBounds = S.CreateBuiltinBinOp(Loc, BO_LE, Bound, Next);
26398+
ExprResult LEBounds = S.CreateBuiltinBinOp(
26399+
Loc, BO_LE, Bound, Next, /*ForFoldExpression=*/false,
26400+
/*ForBoundsCheckExpression=*/true);
2638626401
if (LEBounds.isInvalid())
2638726402
return ExprError();
2638826403

2638926404
if (!CondAccum) {
2639026405
CondAccum = LEBounds.get();
2639126406
} else {
26392-
ExprResult CondAnd = S.CreateBuiltinBinOp(Loc, BO_LAnd,
26393-
CondAccum, LEBounds.get());
26407+
ExprResult CondAnd = S.CreateBuiltinBinOp(
26408+
Loc, BO_LAnd, CondAccum, LEBounds.get(), /*ForFoldExpression=*/false,
26409+
/*ForBoundsCheckExpression=*/true);
2639426410
if (CondAnd.isInvalid())
2639526411
return ExprError();
2639626412
CondAccum = CondAnd.get();
Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,26 @@
1+
// NOTE: Assertions have been autogenerated by utils/update_cc_test_checks.py UTC_ARGS: --version 5
2+
3+
// RUN: %clang_cc1 -O2 -triple arm64-apple-ios -emit-llvm -fbounds-safety -o - %s | FileCheck %s
4+
5+
void foo(char tag[3]);
6+
7+
// CHECK-LABEL: define void @bar(
8+
// CHECK-SAME: ) local_unnamed_addr #[[ATTR0:[0-9]+]] {
9+
// CHECK-NEXT: [[ENTRY:.*:]]
10+
// CHECK-NEXT: [[DOTCOMPOUNDLITERAL:%.*]] = alloca [3 x i8], align 1
11+
// CHECK-NEXT: store i8 65, ptr [[DOTCOMPOUNDLITERAL]], align 1, !tbaa [[TBAA2:![0-9]+]]
12+
// CHECK-NEXT: [[ARRAYINIT_ELEMENT:%.*]] = getelementptr inbounds nuw i8, ptr [[DOTCOMPOUNDLITERAL]], i64 1
13+
// CHECK-NEXT: store i8 66, ptr [[ARRAYINIT_ELEMENT]], align 1, !tbaa [[TBAA2]]
14+
// CHECK-NEXT: [[ARRAYINIT_ELEMENT1:%.*]] = getelementptr inbounds nuw i8, ptr [[DOTCOMPOUNDLITERAL]], i64 2
15+
// CHECK-NEXT: store i8 67, ptr [[ARRAYINIT_ELEMENT1]], align 1, !tbaa [[TBAA2]]
16+
// CHECK-NEXT: call void @foo(ptr noundef nonnull [[DOTCOMPOUNDLITERAL]]) #[[ATTR2:[0-9]+]]
17+
// CHECK-NEXT: ret void
18+
//
19+
void bar(void) {
20+
foo((char[3]){'A', 'B', 'C'});
21+
}
22+
//.
23+
// CHECK: [[TBAA2]] = !{[[META3:![0-9]+]], [[META3]], i64 0}
24+
// CHECK: [[META3]] = !{!"omnipotent char", [[META4:![0-9]+]], i64 0}
25+
// CHECK: [[META4]] = !{!"Simple C/C++ TBAA"}
26+
//.

0 commit comments

Comments
 (0)