Summary: public C++ assignment operation result is lvalue, while in C it was rvalue. This leads to different AST produced by clang for then same code! Use language information from clang (`-x` flag) to distinguish these cases. More specifically, let's look at following code: int r; int f = (r = 3); // type of (r = 3) expression: // C/objC -> int rvalue // C++/objC++ -> int lvalue Existing code did extra dereference because it was rvalue in C and there was no cast afterwards in C++ there will be extra LValueToRvalue cast when neccesary so we don't have to do extra dereference manually Reference: http://en.cppreference.com/w/c/language/value_category (search for 'assignment and compound assignment operators') NOTE: AST output doesn't change when something is hidden behind `extern "C"`, so we should use global language information Reviewed By: ddino Differential Revision: D2549866 fb-gh-sync-id: b193b11master
parent
b86af1e5d1
commit
5a07f767bb
@ -0,0 +1 @@
|
||||
assign_in_condition.c
|
@ -0,0 +1,34 @@
|
||||
digraph iCFG {
|
||||
8 [label="8: Return Stmt \n *&return:int =32 [line 12]\n APPLY_ABSTRACTION; [line 12]\n " shape="box"]
|
||||
|
||||
|
||||
8 -> 2 ;
|
||||
7 [label="7: Prune (false branch) \n n$1=*n$0:int [line 11]\n PRUNE((n$1 == 0), false); [line 11]\n REMOVE_TEMPS(n$0,n$1); [line 11]\n " shape="invhouse"]
|
||||
|
||||
|
||||
7 -> 4 ;
|
||||
6 [label="6: Prune (true branch) \n n$1=*n$0:int [line 11]\n PRUNE((n$1 != 0), true); [line 11]\n REMOVE_TEMPS(n$0,n$1); [line 11]\n " shape="invhouse"]
|
||||
|
||||
|
||||
6 -> 8 ;
|
||||
5 [label="5: BinaryOperatorStmt: Assign \n n$0=*&p:int * [line 11]\n *n$0:int =0 [line 11]\n NULLIFY(&p,false); [line 11]\n " shape="box"]
|
||||
|
||||
|
||||
5 -> 6 ;
|
||||
5 -> 7 ;
|
||||
4 [label="4: + \n " ]
|
||||
|
||||
|
||||
4 -> 3 ;
|
||||
3 [label="3: Return Stmt \n *&return:int =52 [line 14]\n APPLY_ABSTRACTION; [line 14]\n " shape="box"]
|
||||
|
||||
|
||||
3 -> 2 ;
|
||||
2 [label="2: Exit foo \n " color=yellow style=filled]
|
||||
|
||||
|
||||
1 [label="1: Start foo\nFormals: p:int *\nLocals: \n DECLARE_LOCALS(&return); [line 10]\n " color=yellow style=filled]
|
||||
|
||||
|
||||
1 -> 5 ;
|
||||
}
|
@ -0,0 +1,30 @@
|
||||
/*
|
||||
* Copyright (c) 2015 - present Facebook, Inc.
|
||||
* All rights reserved.
|
||||
*
|
||||
* This source code is licensed under the BSD style license found in the
|
||||
* LICENSE file in the root directory of this source tree. An additional grant
|
||||
* of patent rights can be found in the PATENTS file in the same directory.
|
||||
*/
|
||||
|
||||
void normal() {
|
||||
int a = 3;
|
||||
int &ref_from_val = a;
|
||||
int &ref_from_ref = ref_from_val;
|
||||
}
|
||||
|
||||
void nested() {
|
||||
int a = 3;
|
||||
int &ref_from_val = a = 4;
|
||||
int &ref_from_ref = ref_from_val = 6;
|
||||
}
|
||||
|
||||
|
||||
void crazy_nested() {
|
||||
int a = 3;
|
||||
int b = a;
|
||||
|
||||
// a will refer to same object as ref_from_val and ref_from_ref, but different than b
|
||||
int& ref_from_val = a = b = 4;
|
||||
int& ref_from_ref = ref_from_val = b = 5;
|
||||
}
|
@ -0,0 +1,63 @@
|
||||
digraph iCFG {
|
||||
16 [label="16: DeclStmt \n *&a:int =3 [line 24]\n " shape="box"]
|
||||
|
||||
|
||||
16 -> 15 ;
|
||||
15 [label="15: DeclStmt \n n$3=*&a:int [line 25]\n *&b:int =n$3 [line 25]\n REMOVE_TEMPS(n$3); [line 25]\n NULLIFY(&b,false); [line 25]\n " shape="box"]
|
||||
|
||||
|
||||
15 -> 14 ;
|
||||
14 [label="14: DeclStmt \n *&b:int =4 [line 28]\n n$2=*&b:int [line 28]\n *&a:int =n$2 [line 28]\n *&ref_from_val:int =&a [line 28]\n REMOVE_TEMPS(n$2); [line 28]\n NULLIFY(&b,false); [line 28]\n " shape="box"]
|
||||
|
||||
|
||||
14 -> 13 ;
|
||||
13 [label="13: DeclStmt \n n$0=*&ref_from_val:int & [line 29]\n *&b:int =5 [line 29]\n n$1=*&b:int [line 29]\n *n$0:int =n$1 [line 29]\n *&ref_from_ref:int =n$0 [line 29]\n REMOVE_TEMPS(n$0,n$1); [line 29]\n NULLIFY(&b,false); [line 29]\n NULLIFY(&ref_from_ref,false); [line 29]\n NULLIFY(&ref_from_val,false); [line 29]\n NULLIFY(&a,false); [line 29]\n APPLY_ABSTRACTION; [line 29]\n " shape="box"]
|
||||
|
||||
|
||||
13 -> 12 ;
|
||||
12 [label="12: Exit crazy_nested \n " color=yellow style=filled]
|
||||
|
||||
|
||||
11 [label="11: Start crazy_nested\nFormals: \nLocals: ref_from_ref:int & ref_from_val:int & b:int a:int \n DECLARE_LOCALS(&return,&ref_from_ref,&ref_from_val,&b,&a); [line 23]\n NULLIFY(&b,false); [line 23]\n NULLIFY(&ref_from_ref,false); [line 23]\n NULLIFY(&ref_from_val,false); [line 23]\n " color=yellow style=filled]
|
||||
|
||||
|
||||
11 -> 16 ;
|
||||
10 [label="10: DeclStmt \n *&a:int =3 [line 17]\n " shape="box"]
|
||||
|
||||
|
||||
10 -> 9 ;
|
||||
9 [label="9: DeclStmt \n *&a:int =4 [line 18]\n *&ref_from_val:int =&a [line 18]\n " shape="box"]
|
||||
|
||||
|
||||
9 -> 8 ;
|
||||
8 [label="8: DeclStmt \n n$0=*&ref_from_val:int & [line 19]\n *n$0:int =6 [line 19]\n *&ref_from_ref:int =n$0 [line 19]\n REMOVE_TEMPS(n$0); [line 19]\n NULLIFY(&ref_from_ref,false); [line 19]\n NULLIFY(&ref_from_val,false); [line 19]\n NULLIFY(&a,false); [line 19]\n APPLY_ABSTRACTION; [line 19]\n " shape="box"]
|
||||
|
||||
|
||||
8 -> 7 ;
|
||||
7 [label="7: Exit nested \n " color=yellow style=filled]
|
||||
|
||||
|
||||
6 [label="6: Start nested\nFormals: \nLocals: ref_from_ref:int & ref_from_val:int & a:int \n DECLARE_LOCALS(&return,&ref_from_ref,&ref_from_val,&a); [line 16]\n NULLIFY(&ref_from_ref,false); [line 16]\n NULLIFY(&ref_from_val,false); [line 16]\n " color=yellow style=filled]
|
||||
|
||||
|
||||
6 -> 10 ;
|
||||
5 [label="5: DeclStmt \n *&a:int =3 [line 11]\n " shape="box"]
|
||||
|
||||
|
||||
5 -> 4 ;
|
||||
4 [label="4: DeclStmt \n *&ref_from_val:int =&a [line 12]\n " shape="box"]
|
||||
|
||||
|
||||
4 -> 3 ;
|
||||
3 [label="3: DeclStmt \n n$0=*&ref_from_val:int & [line 13]\n *&ref_from_ref:int =n$0 [line 13]\n REMOVE_TEMPS(n$0); [line 13]\n NULLIFY(&ref_from_ref,false); [line 13]\n NULLIFY(&ref_from_val,false); [line 13]\n NULLIFY(&a,false); [line 13]\n APPLY_ABSTRACTION; [line 13]\n " shape="box"]
|
||||
|
||||
|
||||
3 -> 2 ;
|
||||
2 [label="2: Exit normal \n " color=yellow style=filled]
|
||||
|
||||
|
||||
1 [label="1: Start normal\nFormals: \nLocals: ref_from_ref:int & ref_from_val:int & a:int \n DECLARE_LOCALS(&return,&ref_from_ref,&ref_from_val,&a); [line 10]\n NULLIFY(&ref_from_ref,false); [line 10]\n NULLIFY(&ref_from_val,false); [line 10]\n " color=yellow style=filled]
|
||||
|
||||
|
||||
1 -> 5 ;
|
||||
}
|
@ -0,0 +1,57 @@
|
||||
/*
|
||||
* Copyright (c) 2013 - present Facebook, Inc.
|
||||
* All rights reserved.
|
||||
*
|
||||
* This source code is licensed under the BSD style license found in the
|
||||
* LICENSE file in the root directory of this source tree. An additional grant
|
||||
* of patent rights can be found in the PATENTS file in the same directory.
|
||||
*/
|
||||
|
||||
package frontend.cpp;
|
||||
|
||||
import org.junit.Rule;
|
||||
import org.junit.Test;
|
||||
|
||||
import java.io.IOException;
|
||||
|
||||
import utils.DebuggableTemporaryFolder;
|
||||
import utils.InferException;
|
||||
import utils.ClangFrontendUtils;
|
||||
|
||||
/**
|
||||
* Run C++ frontend on C code and compare it to .dot files produced by C frontend.
|
||||
*/
|
||||
public class NestedOperatorsTest {
|
||||
|
||||
String nestedOperatorsBasePath = "infer/tests/codetoanalyze/c/frontend/nestedoperators/";
|
||||
|
||||
@Rule
|
||||
public DebuggableTemporaryFolder folder = new DebuggableTemporaryFolder();
|
||||
|
||||
void frontendTest(String fileRelative) throws InterruptedException, IOException, InferException {
|
||||
ClangFrontendUtils.createAndCompareCppDotFiles(folder, nestedOperatorsBasePath + fileRelative);
|
||||
}
|
||||
|
||||
|
||||
@Test
|
||||
public void whenCaptureRunEnumThenDotFilesAreTheSame()
|
||||
throws InterruptedException, IOException, InferException {
|
||||
frontendTest("nestedassignment.c");
|
||||
}
|
||||
|
||||
@Test
|
||||
public void whenCaptureRunUnionThenDotFilesAreTheSame()
|
||||
throws InterruptedException, IOException, InferException {
|
||||
frontendTest("union.c");
|
||||
}
|
||||
|
||||
@Test
|
||||
public void whenCaptureRunAssignInConditionThenDotFilesAreTheSame()
|
||||
throws InterruptedException, IOException, InferException {
|
||||
// .dot file for cpp is slightly different (but semantically equivalent).
|
||||
// We need to have different dot file to compare against.
|
||||
// assign_in_condition.cpp is in fact pointing to assign_in_condition.c
|
||||
frontendTest("assign_in_condition.cpp");
|
||||
}
|
||||
|
||||
}
|
Loading…
Reference in new issue