================
@@ -0,0 +1,362 @@
+// RUN: %clang_cc1 -mllvm 
-debug-only=ExperimentalLifetimeAnalysis,LifetimeFacts,LifetimeDataflow 
-Wreturn-stack-address-cfg %s 2>&1 | FileCheck %s
+
+struct MyObj {
+  int id;
+  ~MyObj() {} // Non-trivial destructor
+};
+
+// Simple Local Variable Address and Return
+// CHECK-LABEL: Function: return_local_addr
+MyObj* return_local_addr() {
+  MyObj x {10};
+  MyObj* p = &x;
+// CHECK: Block B{{[0-9]+}}:
+// CHECK:   Issue (LoanID: [[L_X:[0-9]+]], OriginID: [[O_ADDR_X:[0-9]+]])
+// CHECK:   AssignOrigin (DestID: [[O_P:[0-9]+]], SrcID: [[O_ADDR_X]])
+  return p;
+// CHECK:   AssignOrigin (DestID: [[O_RET_VAL:[0-9]+]], SrcID: [[O_P]])
+// CHECK:   ReturnOfOrigin (OriginID: [[O_RET_VAL]])
+// CHECK:   Expire (LoanID: [[L_X]])
+}
+// CHECK: Dataflow results:
+
+// CHECK-DAG: Origin [[O_ADDR_X]] contains Loan [[L_X]]
+// CHECK-DAG: Origin [[O_P]] contains Loan [[L_X]]
+// CHECK-DAG: Origin [[O_RET_VAL]] contains Loan [[L_X]]
+
+
+// Pointer Assignment and Return
+// CHECK-LABEL: Function: assign_and_return_local_addr
+// CHECK-NEXT: Block B{{[0-9]+}}:
+MyObj* assign_and_return_local_addr() {
+  MyObj y{20};
+  MyObj* ptr1 = &y;
+// CHECK: Issue (LoanID: [[L_Y:[0-9]+]], OriginID: [[O_ADDR_Y:[0-9]+]])
+// CHECK: AssignOrigin (DestID: [[O_PTR1:[0-9]+]], SrcID: [[O_ADDR_Y]])
+  MyObj* ptr2 = ptr1;
+// CHECK: AssignOrigin (DestID: [[O_PTR1_RVAL:[0-9]+]], SrcID: [[O_PTR1]])
+// CHECK: AssignOrigin (DestID: [[O_PTR2:[0-9]+]], SrcID: [[O_PTR1_RVAL]])
+  ptr2 = ptr1;
+// CHECK: AssignOrigin (DestID: [[O_PTR1_RVAL_2:[0-9]+]], SrcID: [[O_PTR1]])
+// CHECK: AssignOrigin (DestID: [[O_PTR2]], SrcID: [[O_PTR1_RVAL_2]])
+  ptr2 = ptr2; // Self assignment.
+// CHECK: AssignOrigin (DestID: [[O_PTR2_RVAL:[0-9]+]], SrcID: [[O_PTR2]])
+// CHECK: AssignOrigin (DestID: [[O_PTR2]], SrcID: [[O_PTR2_RVAL]])
+  return ptr2;
+// CHECK: AssignOrigin (DestID: [[O_PTR2_RVAL_2:[0-9]+]], SrcID: [[O_PTR2]])
+// CHECK: ReturnOfOrigin (OriginID: [[O_PTR2_RVAL_2]])
+// CHECK: Expire (LoanID: [[L_Y]])
+}
+// CHECK: Dataflow results:
+
+// CHECK-DAG: Origin [[O_ADDR_Y]] contains Loan [[L_Y]]
+// CHECK-DAG: Origin [[O_PTR1]] contains Loan [[L_Y]]
+// CHECK-DAG: Origin [[O_PTR2]] contains Loan [[L_Y]]
+// CHECK-DAG: Origin [[O_PTR1_RVAL]] contains Loan [[L_Y]]
+// CHECK-DAG: Origin [[O_PTR1_RVAL_2]] contains Loan [[L_Y]]
+// CHECK-DAG: Origin [[O_PTR2_RVAL]] contains Loan [[L_Y]]
+// CHECK-DAG: Origin [[O_PTR2_RVAL_2]] contains Loan [[L_Y]]
+
+
+// Return of Non-Pointer Type
+// CHECK-LABEL: Function: return_int_val
+// CHECK-NEXT: Block B{{[0-9]+}}:
+int return_int_val() {
+  int x = 10;
+  return x;
+}
+// CHECK-NEXT: End of Block
+// CHECK: Dataflow results:
+
+// CHECK:  <empty>
+
+
+// Loan Expiration (Automatic Variable, C++)
+// CHECK-LABEL: Function: loan_expires_cpp
+// CHECK-NEXT: Block B{{[0-9]+}}:
+void loan_expires_cpp() {
+  MyObj obj{1};
+  MyObj* pObj = &obj;
+// CHECK: Issue (LoanID: [[L_OBJ:[0-9]+]], OriginID: [[O_ADDR_OBJ:[0-9]+]])
+// CHECK: AssignOrigin (DestID: [[O_POBJ:[0-9]+]], SrcID: [[O_ADDR_OBJ]])
+// CHECK: Expire (LoanID: [[L_OBJ]])
+}
+// CHECK: Dataflow results:
+
+// CHECK-DAG: Origin [[O_ADDR_OBJ]] contains Loan [[L_OBJ]]
+// CHECK-DAG: Origin [[O_POBJ]] contains Loan [[L_OBJ]]
+
+
+// FIXME: No expire for Trivial Destructors
+// CHECK-LABEL: Function: loan_expires_trivial
+// CHECK-NEXT: Block B{{[0-9]+}}:
+void loan_expires_trivial() {
+  int trivial_obj = 1;
+  int* pTrivialObj = &trivial_obj;
+// CHECK: Issue (LoanID: [[L_TRIVIAL_OBJ:[0-9]+]], OriginID: 
[[O_ADDR_TRIVIAL_OBJ:[0-9]+]])
+// CHECK: AssignOrigin (DestID: [[O_PTOBJ:[0-9]+]], SrcID: 
[[O_ADDR_TRIVIAL_OBJ]])
+// CHECK-NOT: Expire (LoanID: [[L_TRIVIAL_OBJ]])
+// CHECK-NEXT: End of Block
+  // FIXME: Add check for Expire once trivial destructors are handled for 
expiration.
+}
+// CHECK: Dataflow results:
+
+// CHECK-DAG: Origin [[O_ADDR_TRIVIAL_OBJ]] contains Loan [[L_TRIVIAL_OBJ]]
+// CHECK-DAG: Origin [[O_PTOBJ]] contains Loan [[L_TRIVIAL_OBJ]]
+
+
+// CHECK-LABEL: Function: conditional
+void conditional(bool condition) {
+  int a = 5;
+  int b = 10;
+  int* p = nullptr;
+
+  if (condition)
+    p = &a;
+  // CHECK: Issue (LoanID: [[L_A:[0-9]+]], OriginID: [[O_ADDR_A:[0-9]+]])
+  // CHECK: AssignOrigin (DestID: [[O_P:[0-9]+]], SrcID: [[O_ADDR_A]])
+  else
+    p = &b;
+  // CHECK: Issue (LoanID: [[L_B:[0-9]+]], OriginID: [[O_ADDR_B:[0-9]+]])
+  // CHECK: AssignOrigin (DestID: [[O_P]], SrcID: [[O_ADDR_B]])
+}
----------------
Xazax-hun wrote:

Could you add a test case where we have `int *q = p;` after the branch? I am 
curios what facts are generated and how it is handled by the dataflow analysis. 

https://github.com/llvm/llvm-project/pull/142313
_______________________________________________
cfe-commits mailing list
cfe-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits

Reply via email to