Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Bind array and function-typed compound literals to temporaries #864

Merged
merged 16 commits into from
Jul 24, 2020
Merged
Show file tree
Hide file tree
Changes from 14 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
9 changes: 9 additions & 0 deletions clang/include/clang/AST/Expr.h
Original file line number Diff line number Diff line change
Expand Up @@ -862,6 +862,15 @@ class Expr : public ValueStmt {
return const_cast<Expr *>(this)->ignoreParenBaseCasts();
}

/// Skip past any parentheses and Checked C expression temporaries until
/// reaching a fixed point. Skips:
/// * What IgnoreParens() skips
/// * What IgnoreExprTmp() skips (CHKCBindTemporaryExpr)
Expr *IgnoreParenTmp() LLVM_READONLY;
const Expr* IgnoreParenTmp() const LLVM_READONLY {
return const_cast<Expr *>(this)->IgnoreParenTmp();
}

/// Ignore Checked C expression temporaries (CHCKBindTemporaryExpr).
Expr *IgnoreExprTmp() LLVM_READONLY;

Expand Down
4 changes: 4 additions & 0 deletions clang/lib/AST/Expr.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -3044,6 +3044,10 @@ Expr *Expr::IgnoreParenNoopCasts(const ASTContext &Ctx) {
});
}

Expr* Expr::IgnoreParenTmp() {
return this->IgnoreParens()->IgnoreExprTmp()->IgnoreParens();
}

Expr *Expr::IgnoreExprTmp() {
Expr *E = this;
if (CHKCBindTemporaryExpr *Binding = dyn_cast<CHKCBindTemporaryExpr>(E))
Expand Down
4 changes: 2 additions & 2 deletions clang/lib/CodeGen/CGExprScalar.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -847,9 +847,9 @@ class ScalarExprEmitter
}

Value *VisitCHKCBindTemporaryExpr(CHKCBindTemporaryExpr *E) {
assert(!E->getSubExpr()->isLValue());
Value *Result = Visit(E->getSubExpr());
CGF.setBoundsTemporaryRValueMapping(E, RValue::get(Result));
if (!E->getSubExpr()->isLValue())
CGF.setBoundsTemporaryRValueMapping(E, RValue::get(Result));
return Result;
}
};
Expand Down
10 changes: 10 additions & 0 deletions clang/lib/Sema/SemaBounds.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -3633,6 +3633,12 @@ namespace {
Expr *SubExpr = E->getSubExpr()->IgnoreParens();

if (isa<CompoundLiteralExpr>(SubExpr)) {
// Only expressions with array or function type can have a decayed
// type, which is used to create the lvalue bounds. Compound literals
// with non-array, non-function types do not have lvalue bounds.
if (!(E->getType()->isArrayType() || E->getType()->isFunctionType()))
return CreateBoundsAlwaysUnknown();

BoundsExpr *BE = CreateBoundsForArrayType(E->getType());
QualType PtrType = Context.getDecayedType(E->getType());
Expr *ArrLValue = CreateTemporaryUse(E);
Expand Down Expand Up @@ -5401,6 +5407,10 @@ Expr *Sema::GetArrayPtrDereference(Expr *E, QualType &Result) {
return GetArrayPtrDereference(IC->getSubExpr(), Result);
return nullptr;
}
case Expr::CHKCBindTemporaryExprClass: {
CHKCBindTemporaryExpr *Temp = cast<CHKCBindTemporaryExpr>(E);
return GetArrayPtrDereference(Temp->getSubExpr(), Result);
}
default: {
llvm_unreachable("unexpected lvalue expression");
return nullptr;
Expand Down
6 changes: 5 additions & 1 deletion clang/lib/Sema/SemaExpr.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -6365,6 +6365,10 @@ Sema::BuildCompoundLiteralExpr(SourceLocation LParenLoc, TypeSourceInfo *TInfo,
checkNonTrivialCUnionInInitializer(E->getInitializer(),
E->getInitializer()->getExprLoc());

if (getLangOpts().CheckedC &&
(E->getType()->isArrayType() || E->getType()->isFunctionType()))
return new (Context) CHKCBindTemporaryExpr(E);

return MaybeBindToTemporary(E);
}

Expand Down Expand Up @@ -8875,7 +8879,7 @@ static bool arrayConstantCheckedConversion(Sema &S, QualType LHSType,
if (ICE->getCastKind() != CK_ArrayToPointerDecay)
return false;

Expr *Child = ICE->getSubExpr()->IgnoreExprTmp()->IgnoreParens();
Expr *Child = ICE->getSubExpr()->IgnoreParenTmp();
if (!isa<InitListExpr>(Child) && !isa<StringLiteral>(Child) &&
!isa<CompoundLiteralExpr>(Child))
return false;
Expand Down
4 changes: 3 additions & 1 deletion clang/lib/Sema/SemaInit.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -178,6 +178,8 @@ static void updateGNUCompoundLiteralRValue(Expr *E) {
E = GSE->getResultExpr();
} else if (ChooseExpr *CE = dyn_cast<ChooseExpr>(E)) {
E = CE->getChosenSubExpr();
} else if (CHKCBindTemporaryExpr *Temp = dyn_cast<CHKCBindTemporaryExpr>(E)) {
E = Temp->getSubExpr();
} else {
llvm_unreachable("unexpected expr in array compound literal init");
}
Expand Down Expand Up @@ -5607,7 +5609,7 @@ void InitializationSequence::InitializeFrom(Sema &S,
// array from a compound literal that creates an array of the same
// type, so long as the initializer has no side effects.
if (!S.getLangOpts().CPlusPlus && Initializer &&
isa<CompoundLiteralExpr>(Initializer->IgnoreParens()) &&
isa<CompoundLiteralExpr>(Initializer->IgnoreParenTmp()) &&
Initializer->getType()->isArrayType()) {
const ArrayType *SourceAT
= Context.getAsArrayType(Initializer->getType());
Expand Down
1 change: 1 addition & 0 deletions clang/test/AST/ast-dump-expr.c
Original file line number Diff line number Diff line change
Expand Up @@ -262,6 +262,7 @@ void PostfixOperators(int *a, struct S b, struct S *c) {

(int [4]){1, 2, 3, 4, };
// CHECK: ImplicitCastExpr
// CHECK: CHKCBindTemporaryExpr 0x{{[^ ]*}} <col:3, col:25> 'int [4]' lvalue
// CHECK: CompoundLiteralExpr 0x{{[^ ]*}} <col:3, col:25> 'int [4]' lvalue
// CHECK-NEXT: InitListExpr 0x{{[^ ]*}} <col:12, col:25> 'int [4]'
// CHECK-NEXT: IntegerLiteral 0x{{[^ ]*}} <col:13> 'int' 1
Expand Down
53 changes: 30 additions & 23 deletions clang/test/CheckedC/inferred-bounds/bounds-context.c
Original file line number Diff line number Diff line change
Expand Up @@ -25,9 +25,10 @@ void declared1(array_ptr<int> arr : count(len), int len, int size) {
// CHECK-NEXT: VarDecl {{.*}} a
// CHECK-NEXT: CountBoundsExpr
// CHECK-NEXT: IntegerLiteral {{.*}} 5
// CHECK-NEXT: CompoundLiteralExpr {{.*}} 'int _Checked[1]'
// CHECK-NEXT: InitListExpr {{.*}} 'int _Checked[1]'
// CHECK-NEXT: IntegerLiteral {{.*}} 0
// CHECK-NEXT: CHKCBindTemporaryExpr {{.*}} 'int _Checked[1]'
// CHECK-NEXT: CompoundLiteralExpr {{.*}} 'int _Checked[1]'
// CHECK-NEXT: InitListExpr {{.*}} 'int _Checked[1]'
// CHECK-NEXT: IntegerLiteral {{.*}} 0
// CHECK-NEXT: Observed bounds context after checking S:
// CHECK-NEXT: {
// CHECK-NEXT: Variable:
Expand Down Expand Up @@ -66,9 +67,10 @@ void declared1(array_ptr<int> arr : count(len), int len, int size) {
// CHECK-NEXT: CountBoundsExpr
// CHECK-NEXT: ImplicitCastExpr {{.*}} <LValueToRValue>
// CHECK-NEXT: DeclRefExpr {{.*}} 'size'
// CHECK-NEXT: CompoundLiteralExpr {{.*}} 'int _Checked[1]'
// CHECK-NEXT: InitListExpr {{.*}} 'int _Checked[1]'
// CHECK-NEXT: IntegerLiteral {{.*}} 0
// CHECK-NEXT: CHKCBindTemporaryExpr {{.*}} 'int _Checked[1]'
// CHECK-NEXT: CompoundLiteralExpr {{.*}} 'int _Checked[1]'
// CHECK-NEXT: InitListExpr {{.*}} 'int _Checked[1]'
// CHECK-NEXT: IntegerLiteral {{.*}} 0
// CHECK-NEXT: Observed bounds context after checking S:
// CHECK-NEXT: {
// CHECK: Variable:
Expand Down Expand Up @@ -124,9 +126,10 @@ void declared2(int flag, int x, int y) {
// CHECK-NEXT: CountBoundsExpr
// CHECK-NEXT: ImplicitCastExpr {{.*}} <LValueToRValue>
// CHECK-NEXT: DeclRefExpr {{.*}} 'x'
// CHECK-NEXT: CompoundLiteralExpr {{.*}} 'int _Checked[1]'
// CHECK-NEXT: InitListExpr {{.*}} 'int _Checked[1]'
// CHECK-NEXT: IntegerLiteral {{.*}} 0
// CHECK-NEXT: CHKCBindTemporaryExpr {{.*}} 'int _Checked[1]'
// CHECK-NEXT: CompoundLiteralExpr {{.*}} 'int _Checked[1]'
// CHECK-NEXT: InitListExpr {{.*}} 'int _Checked[1]'
// CHECK-NEXT: IntegerLiteral {{.*}} 0
// CHECK-NEXT: Observed bounds context after checking S:
// CHECK-NEXT: {
// CHECK-NEXT: Variable:
Expand Down Expand Up @@ -154,9 +157,10 @@ void declared2(int flag, int x, int y) {
// CHECK-NEXT: CountBoundsExpr
// CHECK-NEXT: ImplicitCastExpr {{.*}} <LValueToRValue>
// CHECK-NEXT: DeclRefExpr {{.*}} 'y'
// CHECK-NEXT: CompoundLiteralExpr {{.*}} 'int _Checked[1]'
// CHECK-NEXT: InitListExpr {{.*}} 'int _Checked[1]'
// CHECK-NEXT: IntegerLiteral {{.*}} 0
// CHECK-NEXT: CHKCBindTemporaryExpr {{.*}} 'int _Checked[1]'
// CHECK-NEXT: CompoundLiteralExpr {{.*}} 'int _Checked[1]'
// CHECK-NEXT: InitListExpr {{.*}} 'int _Checked[1]'
// CHECK-NEXT: IntegerLiteral {{.*}} 0
// CHECK-NEXT: Observed bounds context after checking S:
// CHECK-NEXT: {
// CHECK-NEXT: Variable:
Expand Down Expand Up @@ -197,9 +201,10 @@ void declared2(int flag, int x, int y) {
// CHECK-NEXT: CountBoundsExpr
// CHECK-NEXT: ImplicitCastExpr {{.*}} <LValueToRValue>
// CHECK-NEXT: DeclRefExpr {{.*}} 'y'
// CHECK-NEXT: CompoundLiteralExpr {{.*}} 'int _Checked[1]'
// CHECK-NEXT: InitListExpr {{.*}} 'int _Checked[1]'
// CHECK-NEXT: IntegerLiteral {{.*}} 0
// CHECK-NEXT: CHKCBindTemporaryExpr {{.*}} 'int _Checked[1]'
// CHECK-NEXT: CompoundLiteralExpr {{.*}} 'int _Checked[1]'
// CHECK-NEXT: InitListExpr {{.*}} 'int _Checked[1]'
// CHECK-NEXT: IntegerLiteral {{.*}} 0
// CHECK-NEXT: Observed bounds context after checking S:
// CHECK-NEXT: {
// CHECK-NEXT: Variable:
Expand Down Expand Up @@ -255,9 +260,10 @@ void declared2(int flag, int x, int y) {
// CHECK-NEXT: CountBoundsExpr
// CHECK-NEXT: ImplicitCastExpr {{.*}} <LValueToRValue>
// CHECK-NEXT: DeclRefExpr {{.*}} 'x'
// CHECK-NEXT: CompoundLiteralExpr {{.*}} 'int _Checked[1]'
// CHECK-NEXT: InitListExpr {{.*}} 'int _Checked[1]'
// CHECK-NEXT: IntegerLiteral {{.*}} 0
// CHECK-NEXT: CHKCBindTemporaryExpr {{.*}} 'int _Checked[1]'
// CHECK-NEXT: CompoundLiteralExpr {{.*}} 'int _Checked[1]'
// CHECK-NEXT: InitListExpr {{.*}} 'int _Checked[1]'
// CHECK-NEXT: IntegerLiteral {{.*}} 0
// CHECK-NEXT: Observed bounds context after checking S:
// CHECK-NEXT: {
// CHECK-NEXT: Variable:
Expand Down Expand Up @@ -826,11 +832,12 @@ void source_bounds2(void) {
// CHECK-NEXT: VarDecl {{.*}} arr
// CHECK-NEXT: CountBoundsExpr {{.*}} Element
// CHECK-NEXT: IntegerLiteral {{.*}} 1
// CHECK-NEXT: CompoundLiteralExpr {{.*}} 'int _Checked[3]'
// CHECK-NEXT: InitListExpr {{.*}} 'int _Checked[3]'
// CHECK-NEXT: IntegerLiteral {{.*}} 0
// CHECK-NEXT: IntegerLiteral {{.*}} 1
// CHECK-NEXT: IntegerLiteral {{.*}} 2
// CHECK-NEXT: CHKCBindTemporaryExpr {{.*}} 'int _Checked[3]'
// CHECK-NEXT: CompoundLiteralExpr {{.*}} 'int _Checked[3]'
// CHECK-NEXT: InitListExpr {{.*}} 'int _Checked[3]'
// CHECK-NEXT: IntegerLiteral {{.*}} 0
// CHECK-NEXT: IntegerLiteral {{.*}} 1
// CHECK-NEXT: IntegerLiteral {{.*}} 2
// CHECK-NEXT: Observed bounds context after checking S:
// CHECK-NEXT: {
// CHECK-NEXT: Variable:
Expand Down
134 changes: 134 additions & 0 deletions clang/test/CheckedC/inferred-bounds/compound-literals.c
Original file line number Diff line number Diff line change
@@ -0,0 +1,134 @@
// Tests of inferred bounds for expressions involving compound literals.
// The goal is to check that the bounds are being inferred correctly.
//
// The tests have the general form:
// 1. Some C code.
// 2. A description of the inferred bounds for that C code:
// a. The expression
// b. The inferred bounds.
// The description uses AST dumps.
//
// This line is for the clang test infrastructure:
// RUN: %clang_cc1 -fcheckedc-extension -verify -verify-ignore-unexpected=warning -verify-ignore-unexpected=note -fdump-inferred-bounds %s | FileCheck %s --dump-input=always

struct S {
int i;
_Ptr<int> p;
_Nt_array_ptr<char> buf;
};

//-------------------------------------------------------------------------//
// Test array-typed compound literals //
//-------------------------------------------------------------------------//

void f1(_Array_ptr<int> a : count(2), _Array_ptr<int[1]> b : count(1)) {
// Target LHS bounds: bounds(a, a + 2)
// Inferred RHS bounds: bounds(temp((int[]){ 0, 1 }), temp((int[]){ 0, 1 }) + 2)
a = (int[]){ 0, 1 };
// CHECK: BinaryOperator {{0x[0-9a-f]+}} '_Array_ptr<int>' '='
// CHECK: |-DeclRefExpr {{0x[0-9a-f]+}} '_Array_ptr<int>' lvalue ParmVar {{0x[0-9a-f]+}} 'a' '_Array_ptr<int>'
// CHECK: `-ImplicitCastExpr {{0x[0-9a-f]+}} '_Array_ptr<int>' <ArrayToPointerDecay> BoundsSafeInterface
// CHECK: `-CHKCBindTemporaryExpr {{0x[0-9a-f]+}} 'int [2]' lvalue
// CHECK: `-CompoundLiteralExpr {{0x[0-9a-f]+}} 'int [2]' lvalue
// CHECK: `-InitListExpr {{0x[0-9a-f]+}} 'int [2]'
// CHECK: |-IntegerLiteral {{0x[0-9a-f]+}} 'int' 0
// CHECK: `-IntegerLiteral {{0x[0-9a-f]+}} 'int' 1
// CHECK: Target Bounds:
// CHECK: RangeBoundsExpr {{0x[0-9a-f]+}} 'NULL TYPE'
// CHECK: |-ImplicitCastExpr {{0x[0-9a-f]+}} '_Array_ptr<int>' <LValueToRValue>
// CHECK: | `-DeclRefExpr {{0x[0-9a-f]+}} '_Array_ptr<int>' lvalue ParmVar {{0x[0-9a-f]+}} 'a' '_Array_ptr<int>'
// CHECK: `-BinaryOperator {{0x[0-9a-f]+}} '_Array_ptr<int>' '+'
// CHECK: |-ImplicitCastExpr {{0x[0-9a-f]+}} '_Array_ptr<int>' <LValueToRValue>
// CHECK: | `-DeclRefExpr {{0x[0-9a-f]+}} '_Array_ptr<int>' lvalue ParmVar {{0x[0-9a-f]+}} 'a' '_Array_ptr<int>'
// CHECK: `-IntegerLiteral {{0x[0-9a-f]+}} 'int' 2
// CHECK: RHS Bounds:
// CHECK: RangeBoundsExpr {{0x[0-9a-f]+}} 'NULL TYPE'
// CHECK: |-ImplicitCastExpr {{0x[0-9a-f]+}} 'int *':'int *' <ArrayToPointerDecay>
// CHECK: | `-BoundsValueExpr {{0x[0-9a-f]+}} 'int [2]' lvalue _BoundTemporary {{0x[0-9a-f]+}}
// CHECK: `-BinaryOperator {{0x[0-9a-f]+}} 'int *':'int *' '+'
// CHECK: |-ImplicitCastExpr {{0x[0-9a-f]+}} 'int *':'int *' <ArrayToPointerDecay>
// CHECK: | `-BoundsValueExpr {{0x[0-9a-f]+}} 'int [2]' lvalue _BoundTemporary {{0x[0-9a-f]+}}
// CHECK: `-IntegerLiteral {{0x[0-9a-f]+}} 'int' 2

// Target LHS bounds: bounds(b, b + 1)
// Inferred RHS bounds: bounds(temp((int[1]{ 0, 1, 2 })), temp(int[1]{ 0, 1, 2 }) + 1)
b = &(int[1]){ 0, 1, 2 };
// CHECK: BinaryOperator {{0x[0-9a-f]+}} '_Array_ptr<int [1]>' '='
// CHECK: |-DeclRefExpr {{0x[0-9a-f]+}} '_Array_ptr<int [1]>' lvalue ParmVar {{0x[0-9a-f]+}} 'b' '_Array_ptr<int [1]>'
// CHECK: `-ImplicitCastExpr {{0x[0-9a-f]+}} '_Array_ptr<int [1]>' <BitCast>
// CHECK: `-UnaryOperator {{0x[0-9a-f]+}} 'int (*)[1]' prefix '&' cannot overflow
// CHECK: `-CHKCBindTemporaryExpr {{0x[0-9a-f]+}} 'int [1]' lvalue
// CHECK: `-CompoundLiteralExpr {{0x[0-9a-f]+}} 'int [1]' lvalue
// CHECK: `-InitListExpr {{0x[0-9a-f]+}} 'int [1]'
// CHECK: `-IntegerLiteral {{0x[0-9a-f]+}} 'int' 0
// CHECK: Target Bounds:
// CHECK: RangeBoundsExpr {{0x[0-9a-f]+}} 'NULL TYPE'
// CHECK: |-ImplicitCastExpr {{0x[0-9a-f]+}} '_Array_ptr<int [1]>' <LValueToRValue>
// CHECK: | `-DeclRefExpr {{0x[0-9a-f]+}} '_Array_ptr<int [1]>' lvalue ParmVar {{0x[0-9a-f]+}} 'b' '_Array_ptr<int [1]>'
// CHECK: `-BinaryOperator {{0x[0-9a-f]+}} '_Array_ptr<int [1]>' '+'
// CHECK: |-ImplicitCastExpr {{0x[0-9a-f]+}} '_Array_ptr<int [1]>' <LValueToRValue>
// CHECK: | `-DeclRefExpr {{0x[0-9a-f]+}} '_Array_ptr<int [1]>' lvalue ParmVar {{0x[0-9a-f]+}} 'b' '_Array_ptr<int [1]>'
// CHECK: `-IntegerLiteral {{0x[0-9a-f]+}} 'int' 1
// CHECK: RHS Bounds:
// CHECK: RangeBoundsExpr {{0x[0-9a-f]+}} 'NULL TYPE'
// CHECK: |-ImplicitCastExpr {{0x[0-9a-f]+}} 'int *':'int *' <ArrayToPointerDecay>
// CHECK: | `-BoundsValueExpr {{0x[0-9a-f]+}} 'int [1]' lvalue _BoundTemporary {{0x[0-9a-f]+}}
// CHECK: `-BinaryOperator {{0x[0-9a-f]+}} 'int *':'int *' '+'
// CHECK: |-ImplicitCastExpr {{0x[0-9a-f]+}} 'int *':'int *' <ArrayToPointerDecay>
// CHECK: | `-BoundsValueExpr {{0x[0-9a-f]+}} 'int [1]' lvalue _BoundTemporary {{0x[0-9a-f]+}}
// CHECK: `-IntegerLiteral {{0x[0-9a-f]+}} 'int' 1
}

//-------------------------------------------------------------------------//
// Test struct-typed compound literals (and variables) //
//-------------------------------------------------------------------------//

void f2(_Array_ptr<struct S> arr : count(1), struct S s) {
// Target LHS bounds: bounds(arr, arr + 1)
// Inferred RHS bounds: bounds(&s, &s + 1)
arr = &s;
// CHECK: BinaryOperator {{0x[0-9a-f]+}} '_Array_ptr<struct S>' '='
// CHECK: |-DeclRefExpr {{0x[0-9a-f]+}} '_Array_ptr<struct S>' lvalue ParmVar {{0x[0-9a-f]+}} 'arr' '_Array_ptr<struct S>'
// CHECK: `-ImplicitCastExpr {{0x[0-9a-f]+}} '_Array_ptr<struct S>' <BitCast>
// CHECK: `-UnaryOperator {{0x[0-9a-f]+}} 'struct S *' prefix '&' cannot overflow
// CHECK: `-DeclRefExpr {{0x[0-9a-f]+}} 'struct S':'struct S' lvalue ParmVar {{0x[0-9a-f]+}} 's' 'struct S':'struct S'
// CHECK: Target Bounds:
// CHECK: RangeBoundsExpr {{0x[0-9a-f]+}} 'NULL TYPE'
// CHECK: |-ImplicitCastExpr {{0x[0-9a-f]+}} '_Array_ptr<struct S>' <LValueToRValue>
// CHECK: | `-DeclRefExpr {{0x[0-9a-f]+}} '_Array_ptr<struct S>' lvalue ParmVar {{0x[0-9a-f]+}} 'arr' '_Array_ptr<struct S>'
// CHECK: `-BinaryOperator {{0x[0-9a-f]+}} '_Array_ptr<struct S>' '+'
// CHECK: |-ImplicitCastExpr {{0x[0-9a-f]+}} '_Array_ptr<struct S>' <LValueToRValue>
// CHECK: | `-DeclRefExpr {{0x[0-9a-f]+}} '_Array_ptr<struct S>' lvalue ParmVar {{0x[0-9a-f]+}} 'arr' '_Array_ptr<struct S>'
// CHECK: `-IntegerLiteral {{0x[0-9a-f]+}} 'int' 1
// CHECK: RHS Bounds:
// CHECK: RangeBoundsExpr {{0x[0-9a-f]+}} 'NULL TYPE'
// CHECK: |-UnaryOperator {{0x[0-9a-f]+}} '_Array_ptr<struct S>' prefix '&' cannot overflow
// CHECK: | `-DeclRefExpr {{0x[0-9a-f]+}} 'struct S':'struct S' lvalue ParmVar {{0x[0-9a-f]+}} 's' 'struct S':'struct S'
// CHECK: `-BinaryOperator {{0x[0-9a-f]+}} '_Array_ptr<struct S>' '+'
// CHECK: |-UnaryOperator {{0x[0-9a-f]+}} '_Array_ptr<struct S>' prefix '&' cannot overflow
// CHECK: | `-DeclRefExpr {{0x[0-9a-f]+}} 'struct S':'struct S' lvalue ParmVar {{0x[0-9a-f]+}} 's' 'struct S':'struct S'
// CHECK: `-IntegerLiteral {{0x[0-9a-f]+}} 'int' 1

// Target LHS bounds: bounds(arr, arr + 1)
// Inferred RHS bounds: invalid
arr = &(struct S){ 0 }; // expected-error {{expression has unknown bounds, right-hand side of assignment expected to have bounds because the left-hand side has bounds}}
// CHECK: BinaryOperator {{0x[0-9a-f]+}} '_Array_ptr<struct S>' '='
// CHECK: |-DeclRefExpr {{0x[0-9a-f]+}} '_Array_ptr<struct S>' lvalue ParmVar {{0x[0-9a-f]+}} 'arr' '_Array_ptr<struct S>'
// CHECK: `-ImplicitCastExpr {{0x[0-9a-f]+}} '_Array_ptr<struct S>' <BitCast>
// CHECK: `-UnaryOperator {{0x[0-9a-f]+}} 'struct S *' prefix '&' cannot overflow
// CHECK: `-CompoundLiteralExpr {{0x[0-9a-f]+}} 'struct S':'struct S' lvalue
// CHECK: `-InitListExpr {{0x[0-9a-f]+}} 'struct S':'struct S'
// CHECK: |-IntegerLiteral {{0x[0-9a-f]+}} 'int' 0
// CHECK: |-ImplicitValueInitExpr {{0x[0-9a-f]+}} '_Ptr<int>'
// CHECK: `-ImplicitValueInitExpr {{0x[0-9a-f]+}} '_Nt_array_ptr<char>'
// CHECK: Target Bounds:
// CHECK: RangeBoundsExpr {{0x[0-9a-f]+}} 'NULL TYPE'
// CHECK: |-ImplicitCastExpr {{0x[0-9a-f]+}} '_Array_ptr<struct S>' <LValueToRValue>
// CHECK: | `-DeclRefExpr {{0x[0-9a-f]+}} '_Array_ptr<struct S>' lvalue ParmVar {{0x[0-9a-f]+}} 'arr' '_Array_ptr<struct S>'
// CHECK: `-BinaryOperator {{0x[0-9a-f]+}} '_Array_ptr<struct S>' '+'
// CHECK: |-ImplicitCastExpr {{0x[0-9a-f]+}} '_Array_ptr<struct S>' <LValueToRValue>
// CHECK: | `-DeclRefExpr {{0x[0-9a-f]+}} '_Array_ptr<struct S>' lvalue ParmVar {{0x[0-9a-f]+}} 'arr' '_Array_ptr<struct S>'
// CHECK: `-IntegerLiteral {{0x[0-9a-f]+}} 'int' 1
// CHECK: RHS Bounds:
// CHECK: NullaryBoundsExpr {{0x[0-9a-f]+}} 'NULL TYPE' Invalid
}
7 changes: 4 additions & 3 deletions clang/test/CheckedC/inferred-bounds/equiv-exprs.c
Original file line number Diff line number Diff line change
Expand Up @@ -289,9 +289,10 @@ void f8(void) {
&(double []){ 2.72 };
// CHECK: Statement S:
// CHECK-NEXT: UnaryOperator {{.*}} prefix '&'
// CHECK-NEXT: CompoundLiteralExpr {{.*}} 'double [1]'
// CHECK-NEXT: InitListExpr {{.*}} 'double [1]'
// CHECK-NEXT: FloatingLiteral 0{{.*}} 'double' 2.72
// CHECK-NEXT: CHKCBindTemporaryExpr {{.*}} 'double [1]'
// CHECK-NEXT: CompoundLiteralExpr {{.*}} 'double [1]'
// CHECK-NEXT: InitListExpr {{.*}} 'double [1]'
// CHECK-NEXT: FloatingLiteral 0{{.*}} 'double' 2.72
// CHECK: Expressions that produce the same value as S:
// CHECK-NEXT: { }
}
Expand Down