Skip to content

Commit 39659b3

Browse files
authored
Bind all compound literals to temporaries (#899)
* Bind all CompoundLiteralExprs to a temp for Checked C * Strip parentheses off outer and inner temp binding to get the child expression * Return unknown lvalue bounds for struct-typed compound literals * Fix equiv-exprs test * Add test for inferring compound literal bounds * Only bind compound literals with array or function type to temps * Add case for CHKCBindTemporaryExpr to GetArrayPtrDereference * Add case for CHKCBindTemporaryExpr to updateGNUCompoundLiteralRValue * Remove non-lvalue assert from VisitCHKCBindTemporaryExpr * Add Expr::IgnoreParenTmp method * Remove expected temp from struct-typed compound literal in compound-literals test * Add expected temp to array-typed compound literal in ast-dump-expr test * Add expected temps for array-typed compound literals to bounds-context test * Implement VisitCHKCBindTemporaryExpr for aggregate and complex expressions * Fix failing tests * Emit an lvalue for an lvalue subexpression of a scalar temp binding * Bind all compound literals to temporaries * Bind all compound literals to temporaries * Infer lvalue bounds for struct-typed compound literals * Fix compound-literals test * Add compound literal cases to bounds-context test * Use ASTContext::getPrebuiltCountOne for struct-typed lvalue bounds * Return unknown lvalue bounds for function-typed compound literals
1 parent 5b7f19b commit 39659b3

File tree

9 files changed

+115
-27
lines changed

9 files changed

+115
-27
lines changed

clang/lib/CodeGen/CGExprAgg.cpp

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -109,6 +109,9 @@ class AggExprEmitter : public StmtVisitor<AggExprEmitter> {
109109
CGF.ErrorUnsupported(S, "aggregate expression");
110110
}
111111
void VisitParenExpr(ParenExpr *PE) { Visit(PE->getSubExpr()); }
112+
void VisitCHKCBindTemporaryExpr(CHKCBindTemporaryExpr *E) {
113+
Visit(E->getSubExpr());
114+
}
112115
void VisitGenericSelectionExpr(GenericSelectionExpr *GE) {
113116
Visit(GE->getResultExpr());
114117
}

clang/lib/CodeGen/CGExprComplex.cpp

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -104,6 +104,9 @@ class ComplexExprEmitter
104104
return Visit(E->getSubExpr());
105105
}
106106
ComplexPairTy VisitParenExpr(ParenExpr *PE) { return Visit(PE->getSubExpr());}
107+
ComplexPairTy VisitCHKCBindTemporaryExpr(CHKCBindTemporaryExpr *E) {
108+
return Visit(E->getSubExpr());
109+
}
107110
ComplexPairTy VisitGenericSelectionExpr(GenericSelectionExpr *GE) {
108111
return Visit(GE->getResultExpr());
109112
}

clang/lib/CodeGen/CGExprScalar.cpp

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -847,7 +847,11 @@ class ScalarExprEmitter
847847
}
848848

849849
Value *VisitCHKCBindTemporaryExpr(CHKCBindTemporaryExpr *E) {
850-
assert(!E->getSubExpr()->isLValue());
850+
if (E->getSubExpr()->isLValue()) {
851+
LValue LV = CGF.EmitLValue(E->getSubExpr());
852+
CGF.setBoundsTemporaryLValueMapping(E, LV);
853+
return EmitLoadOfLValue(LV, E->getExprLoc());
854+
}
851855
Value *Result = Visit(E->getSubExpr());
852856
CGF.setBoundsTemporaryRValueMapping(E, RValue::get(Result));
853857
return Result;

clang/lib/Sema/SemaBounds.cpp

Lines changed: 21 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -3684,21 +3684,28 @@ namespace {
36843684
Expr *SubExpr = E->getSubExpr()->IgnoreParens();
36853685

36863686
if (isa<CompoundLiteralExpr>(SubExpr)) {
3687-
// Only expressions with array or function type can have a decayed
3688-
// type, which is used to create the lvalue bounds. Compound literals
3689-
// with non-array, non-function types do not have lvalue bounds.
3690-
// TODO: checkedc-clang issue #870: bind all compound literals to
3691-
// temporaries and infer lvalue bounds for struct compound literals.
3692-
if (!(E->getType()->isArrayType() || E->getType()->isFunctionType()))
3693-
return CreateBoundsAlwaysUnknown();
3687+
// The lvalue bounds of a struct-typed compound literal expression e
3688+
// are bounds(&value(temp(e), &value(temp(e)) + 1).
3689+
if (E->getType()->isStructureType()) {
3690+
Expr *TempUse = CreateTemporaryUse(E);
3691+
Expr *Addr = CreateAddressOfOperator(TempUse);
3692+
return ExpandToRange(Addr, Context.getPrebuiltCountOne());
3693+
}
3694+
3695+
// The lvalue bounds of an array-typed compound literal expression e
3696+
// are based on the dimension size of e.
3697+
if (E->getType()->isArrayType()) {
3698+
BoundsExpr *BE = CreateBoundsForArrayType(E->getType());
3699+
QualType PtrType = Context.getDecayedType(E->getType());
3700+
Expr *ArrLValue = CreateTemporaryUse(E);
3701+
Expr *Base = CreateImplicitCast(PtrType,
3702+
CastKind::CK_ArrayToPointerDecay,
3703+
ArrLValue);
3704+
return ExpandToRange(Base, BE);
3705+
}
36943706

3695-
BoundsExpr *BE = CreateBoundsForArrayType(E->getType());
3696-
QualType PtrType = Context.getDecayedType(E->getType());
3697-
Expr *ArrLValue = CreateTemporaryUse(E);
3698-
Expr *Base = CreateImplicitCast(PtrType,
3699-
CastKind::CK_ArrayToPointerDecay,
3700-
ArrLValue);
3701-
return ExpandToRange(Base, BE);
3707+
// All other types of compound literals do not have lvalue bounds.
3708+
return CreateBoundsAlwaysUnknown();
37023709
}
37033710

37043711
if (auto *SL = dyn_cast<StringLiteral>(SubExpr))

clang/lib/Sema/SemaExpr.cpp

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -6372,8 +6372,7 @@ Sema::BuildCompoundLiteralExpr(SourceLocation LParenLoc, TypeSourceInfo *TInfo,
63726372
// bound to temporaries.
63736373
// TODO: checkedc-clang issue #870: bind all compound literal expressions
63746374
// to temporaries.
6375-
if (getLangOpts().CheckedC &&
6376-
(E->getType()->isArrayType() || E->getType()->isFunctionType()))
6375+
if (getLangOpts().CheckedC)
63776376
return new (Context) CHKCBindTemporaryExpr(E);
63786377

63796378
return MaybeBindToTemporary(E);

clang/test/AST/ast-dump-expr.c

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -272,6 +272,7 @@ void PostfixOperators(int *a, struct S b, struct S *c) {
272272

273273
(struct S){1};
274274
// CHECK: ImplicitCastExpr
275+
// CHECK-NEXT: CHKCBindTemporaryExpr 0x{{[^ ]*}} <col:3, col:15> 'struct S':'struct S' lvalue
275276
// CHECK-NEXT: CompoundLiteralExpr 0x{{[^ ]*}} <col:3, col:15> 'struct S':'struct S' lvalue
276277
// CHECK-NEXT: InitListExpr 0x{{[^ ]*}} <col:13, col:15> 'struct S':'struct S'
277278
// CHECK-NEXT: IntegerLiteral 0x{{[^ ]*}} <col:14> 'int' 1

clang/test/Analysis/designated-initializer.c

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -33,9 +33,9 @@ void test() {
3333
// CHECK: 13: 2
3434
// CHECK: 14: /*implicit*/(int)0
3535
// CHECK: 15: {[B1.12], [B1.13]}
36-
// CHECK: 18: /*no init*/
3736
// CHECK: 19: /*no init*/
38-
// CHECK: 20: 3
39-
// CHECK: 21: {[B1.18], [B1.19], [B1.20]}
40-
// CHECK: 22: {/*base*/[B1.17], /*updater*/[B1.21]}
41-
// CHECK: 24: struct Q s[] = {[0] = (struct Q){1, 2}, [0].c = 3};
37+
// CHECK: 20: /*no init*/
38+
// CHECK: 21: 3
39+
// CHECK: 22: {[B1.19], [B1.20], [B1.21]}
40+
// CHECK: 23: {/*base*/[B1.18], /*updater*/[B1.22]}
41+
// CHECK: 25: struct Q s[] = {[0] = (struct Q){1, 2}, [0].c = 3};

clang/test/CheckedC/inferred-bounds/bounds-context.c

Lines changed: 64 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1072,6 +1072,70 @@ void source_bounds4(array_ptr<int> arr : count(1)) {
10721072
// CHECK-NEXT: }
10731073
}
10741074

1075+
// Assignments to variables set the observed bounds to the source bounds
1076+
// where the source is an array-typed compound literal
1077+
void source_bounds5(array_ptr<int> arr_array_literal : count(2)) {
1078+
// Observed bounds context: { arr_array_literal => bounds(value(temp((int checked[2]){ 0, 1 })), value(temp((int checked[2]){ 0, 1 })) + 2) }
1079+
arr_array_literal = (int checked[2]){0, 1};
1080+
// CHECK: Statement S:
1081+
// CHECK-NEXT: BinaryOperator {{.*}} '='
1082+
// CHECK-NEXT: DeclRefExpr {{.*}} 'arr_array_literal'
1083+
// CHECK-NEXT: ImplicitCastExpr {{.*}} <ArrayToPointerDecay>
1084+
// CHECK-NEXT: CHKCBindTemporaryExpr {{.*}} 'int _Checked[2]' lvalue
1085+
// CHECK-NEXT: CompoundLiteralExpr {{.*}} 'int _Checked[2]' lvalue
1086+
// CHECK-NEXT: InitListExpr {{.*}} 'int _Checked[2]'
1087+
// CHECK-NEXT: IntegerLiteral {{.*}} 0
1088+
// CHECK-NEXT: IntegerLiteral {{.*}} 1
1089+
// CHECK-NEXT: Observed bounds context after checking S:
1090+
// CHECK-NEXT: {
1091+
// CHECK-NEXT: Variable:
1092+
// CHECK-NEXT: ParmVarDecl {{.*}} arr_array_literal
1093+
// CHECK: Bounds:
1094+
// CHECK-NEXT: RangeBoundsExpr
1095+
// CHECK-NEXT: ImplicitCastExpr {{.*}} <ArrayToPointerDecay>
1096+
// CHECK-NEXT: BoundsValueExpr {{.*}} 'int _Checked[2]' lvalue
1097+
// CHECK-NEXT: BinaryOperator {{.*}} '+'
1098+
// CHECK-NEXT: ImplicitCastExpr {{.*}} <ArrayToPointerDecay>
1099+
// CHECK-NEXT: BoundsValueExpr {{.*}} 'int _Checked[2]' lvalue
1100+
// CHECK-NEXT: IntegerLiteral {{.*}} 'int' 2
1101+
// CHECK-NEXT: }
1102+
}
1103+
1104+
struct a {
1105+
int f;
1106+
};
1107+
1108+
// Assignments to variables set the observed bounds to the source bounds
1109+
// where the source is a struct-typed compound literal
1110+
void source_bounds6() {
1111+
// Observed bounds context: { arr_struct_literal => bounds(&value(temp((struct a){ 0 })), &value(temp((struct a){ 0 })) + 1) }
1112+
array_ptr<struct a> arr_struct_literal : count(1) = &(struct a){0};
1113+
// CHECK: Statement S:
1114+
// CHECK-NEXT: DeclStmt
1115+
// CHECK-NEXT: VarDecl {{.*}} a
1116+
// CHECK-NEXT: CountBoundsExpr {{.*}} Element
1117+
// CHECK-NEXT: IntegerLiteral {{.*}} 1
1118+
// CHECK-NEXT: ImplicitCastExpr {{.*}} <BitCast>
1119+
// CHECK-NEXT: UnaryOperator {{.*}} prefix '&'
1120+
// CHECK-NEXT: CHKCBindTemporaryExpr {{.*}} 'struct a':'struct a' lvalue
1121+
// CHECK-NEXT: CompoundLiteralExpr {{.*}} 'struct a':'struct a' lvalue
1122+
// CHECK-NEXT: InitListExpr {{.*}} 'struct a':'struct a'
1123+
// CHECK-NEXT: IntegerLiteral {{.*}} 'int' 0
1124+
// CHECK-NEXT: Observed bounds context after checking S:
1125+
// CHECK-NEXT: {
1126+
// CHECK-NEXT: Variable:
1127+
// CHECK-NEXT: VarDecl {{.*}} arr_struct_literal
1128+
// CHECK: Bounds:
1129+
// CHECK-NEXT: RangeBoundsExpr
1130+
// CHECK-NEXT: UnaryOperator {{.*}} prefix '&'
1131+
// CHECK-NEXT: BoundsValueExpr {{.*}} 'struct a':'struct a' lvalue
1132+
// CHECK-NEXT: BinaryOperator {{.*}} '+'
1133+
// CHECK-NEXT: UnaryOperator {{.*}} prefix '&'
1134+
// CHECK-NEXT: BoundsValueExpr {{.*}} 'struct a':'struct a' lvalue
1135+
// CHECK-NEXT: IntegerLiteral {{.*}} 'int' 1
1136+
// CHECK-NEXT: }
1137+
}
1138+
10751139
////////////////////////////////////////////////////////////////////////////////
10761140
// Multiple assignments within one expression that can affect bounds checking //
10771141
////////////////////////////////////////////////////////////////////////////////

clang/test/CheckedC/inferred-bounds/compound-literals.c

Lines changed: 12 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,8 @@
1111
// This line is for the clang test infrastructure:
1212
// RUN: %clang_cc1 -fcheckedc-extension -verify -verify-ignore-unexpected=warning -verify-ignore-unexpected=note -fdump-inferred-bounds %s | FileCheck %s --dump-input=always
1313

14+
// expected-no-diagnostics
15+
1416
struct S {
1517
int i;
1618
_Ptr<int> p;
@@ -110,14 +112,13 @@ void f2(_Array_ptr<struct S> arr : count(1), struct S s) {
110112
// CHECK: `-IntegerLiteral {{0x[0-9a-f]+}} 'int' 1
111113

112114
// Target LHS bounds: bounds(arr, arr + 1)
113-
// Inferred RHS bounds: invalid
114-
// TODO: checkedc-clang issue #870: once struct-typed compound literals are bound to temporaries,
115-
// the inferred RHS bounds should be bounds(&temp((struct S){ 0 }), &temp((struct S){ 0 }) + 1)
116-
arr = &(struct S){ 0 }; // expected-error {{inferred bounds for 'arr' are unknown after statement}}
115+
// Inferred RHS bounds: bounds(&value(temp((struct S){ 0 })), &value(temp((struct S){ 0 })) + 1)
116+
arr = &(struct S){ 0 };
117117
// CHECK: BinaryOperator {{0x[0-9a-f]+}} '_Array_ptr<struct S>' '='
118118
// CHECK: |-DeclRefExpr {{0x[0-9a-f]+}} '_Array_ptr<struct S>' lvalue ParmVar {{0x[0-9a-f]+}} 'arr' '_Array_ptr<struct S>'
119119
// CHECK: `-ImplicitCastExpr {{0x[0-9a-f]+}} '_Array_ptr<struct S>' <BitCast>
120120
// CHECK: `-UnaryOperator {{0x[0-9a-f]+}} 'struct S *' prefix '&' cannot overflow
121+
// CHECK: `-CHKCBindTemporaryExpr {{0x[0-9a-f]+}} 'struct S':'struct S' lvalue
121122
// CHECK: `-CompoundLiteralExpr {{0x[0-9a-f]+}} 'struct S':'struct S' lvalue
122123
// CHECK: `-InitListExpr {{0x[0-9a-f]+}} 'struct S':'struct S'
123124
// CHECK: |-IntegerLiteral {{0x[0-9a-f]+}} 'int' 0
@@ -132,5 +133,11 @@ void f2(_Array_ptr<struct S> arr : count(1), struct S s) {
132133
// CHECK: | `-DeclRefExpr {{0x[0-9a-f]+}} '_Array_ptr<struct S>' lvalue ParmVar {{0x[0-9a-f]+}} 'arr' '_Array_ptr<struct S>'
133134
// CHECK: `-IntegerLiteral {{0x[0-9a-f]+}} 'int' 1
134135
// CHECK: RHS Bounds:
135-
// CHECK: NullaryBoundsExpr {{0x[0-9a-f]+}} 'NULL TYPE' Invalid
136+
// CHECK: RangeBoundsExpr {{0x[0-9a-f]+}} 'NULL TYPE'
137+
// CHECK: |-UnaryOperator {{0x[0-9a-f]+}} '_Array_ptr<struct S>' prefix '&' cannot overflow
138+
// CHECK: | `-BoundsValueExpr {{0x[0-9a-f]+}} 'struct S':'struct S' lvalue _BoundTemporary
139+
// CHECK: `-BinaryOperator {{0x[0-9a-f]+}} '_Array_ptr<struct S>' '+'
140+
// CHECK: |-UnaryOperator {{0x[0-9a-f]+}} '_Array_ptr<struct S>' prefix '&' cannot overflow
141+
// CHECK: | `-BoundsValueExpr {{0x[0-9a-f]+}} 'struct S':'struct S' lvalue _BoundTemporary
142+
// CHECK: `-IntegerLiteral {{0x[0-9a-f]+}} 'int' 1
136143
}

0 commit comments

Comments
 (0)