blob: e5cb7215149ffe84f28b6978ece5cc455aba2e9e [file] [edit]
// RUN: %clang_analyze_cc1 -analyzer-checker=debug.DumpCFG -std=c++17 %s 2>&1 | FileCheck %s
// RUN: %clang_analyze_cc1 -analyzer-checker=debug.DumpCFG -std=c++11 %s 2>&1 | FileCheck %s
// The C++11 run intentionally reuses the same expectations.
// Before C++17 these orders are unspecified, so these lines pin
// a deliberate implementation choice.
int getL();
int getR();
int getIdx();
int arr[10];
// [expr.shift]: the left operand is sequenced before the right operand.
void test_shift() {
int x = getL() << getR();
}
// CHECK-LABEL: void test_shift()
// CHECK: 1: getL
// CHECK-NEXT: 2: [B1.1] (ImplicitCastExpr, FunctionToPointerDecay, int (*)(void))
// CHECK-NEXT: 3: [B1.2]()
// CHECK-NEXT: 4: getR
// CHECK-NEXT: 5: [B1.4] (ImplicitCastExpr, FunctionToPointerDecay, int (*)(void))
// CHECK-NEXT: 6: [B1.5]()
// CHECK-NEXT: 7: [B1.3] << [B1.6]
// [expr.sub] (C++17): the array operand is sequenced before the index operand.
void test_subscript() {
int x = arr[getIdx()];
}
// CHECK-LABEL: void test_subscript()
// CHECK: 1: arr
// CHECK-NEXT: 2: [B1.1] (ImplicitCastExpr, ArrayToPointerDecay, int *)
// CHECK-NEXT: 3: getIdx
// CHECK-NEXT: 4: [B1.3] (ImplicitCastExpr, FunctionToPointerDecay, int (*)(void))
// CHECK-NEXT: 5: [B1.4]()
// CHECK-NEXT: 6: [B1.2]{{\[\[}}B1.5]]
struct Obj {
int m;
};
int Obj::*getPMD();
Obj *getObj();
// [expr.mptr.oper]: the left operand is sequenced before the right operand.
void test_ptr_to_member() {
int x = getObj()->*getPMD();
}
// CHECK-LABEL: void test_ptr_to_member()
// CHECK: 1: getObj
// CHECK-NEXT: 2: [B1.1] (ImplicitCastExpr, FunctionToPointerDecay, Obj *(*)(void))
// CHECK-NEXT: 3: [B1.2]()
// CHECK-NEXT: 4: getPMD
// CHECK-NEXT: 5: [B1.4] (ImplicitCastExpr, FunctionToPointerDecay, int Obj::*(*)(void))
// CHECK-NEXT: 6: [B1.5]()
// CHECK-NEXT: 7: [B1.3] ->* [B1.6]
// [expr.comma]: the left operand is sequenced before the right operand.
void test_comma() {
getL(), getR();
}
// CHECK-LABEL: void test_comma()
// CHECK: 1: getL
// CHECK-NEXT: 2: [B1.1] (ImplicitCastExpr, FunctionToPointerDecay, int (*)(void))
// CHECK-NEXT: 3: [B1.2]()
// CHECK-NEXT: 4: getR
// CHECK-NEXT: 5: [B1.4] (ImplicitCastExpr, FunctionToPointerDecay, int (*)(void))
// CHECK-NEXT: 6: [B1.5]()
// CHECK-NEXT: 7: ... , [B1.6]
int callee(int, int);
// [expr.call] (C++17): the callee (postfix-expression) is sequenced before the
// arguments. (The order among the arguments themselves is unspecified and is
// not pinned here.)
void test_call_callee_before_args() {
callee(getL(), getR());
}
// CHECK-LABEL: void test_call_callee_before_args()
// CHECK: 1: callee
// CHECK-NEXT: 2: [B1.1] (ImplicitCastExpr, FunctionToPointerDecay, int (*)(int, int))
// CHECK-NEXT: 3: getL
// CHECK: 9: [B1.2]([B1.5], [B1.8])
struct Stream {
Stream &operator<<(int);
};
Stream &getStream();
// A chained overloaded oper<< is left-associative: the inner call (object and
// its argument) is fully evaluated before the outer call's argument, matching
// the built-in left-to-right shift order.
void test_overloaded_shift() {
getStream() << getL() << getR();
}
// CHECK-LABEL: void test_overloaded_shift()
// CHECK: 5: getStream
// CHECK: 7: [B1.6]()
// CHECK-NEXT: 8: getL
// CHECK: 10: [B1.9]()
// CHECK-NEXT: 11: [B1.7] << [B1.10] (OperatorCall)
// CHECK-NEXT: 12: getR
// CHECK: 14: [B1.13]()
// CHECK-NEXT: 15: [B1.11] << [B1.14] (OperatorCall)