[PATCH] D42498: [ExprConstant] Fix crash when initialize an indirect field with another field.

2018-02-23 Thread Volodymyr Sapsai via Phabricator via cfe-commits
vsapsai added a comment.

Thanks for the review. Explicit `this` usage is a good test, added it.

Checked that it happened to work with my previous approach because initializer 
was `CXXDefaultInitExpr` with expression

  ImplicitCastExpr 0x7fe966808c40 'void *' 
  `-CXXThisExpr 0x7fe966808c28 'struct A::(anonymous at file.cc:3:5) *' this


Repository:
  rL LLVM

https://reviews.llvm.org/D42498



___
cfe-commits mailing list
cfe-commits@lists.llvm.org
http://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits


[PATCH] D42498: [ExprConstant] Fix crash when initialize an indirect field with another field.

2018-02-23 Thread Volodymyr Sapsai via Phabricator via cfe-commits
This revision was automatically updated to reflect the committed changes.
Closed by commit rL325997: [ExprConstant] Fix crash when initialize an indirect 
field with another field. (authored by vsapsai, committed by ).
Herald added a subscriber: llvm-commits.

Changed prior to commit:
  https://reviews.llvm.org/D42498?vs=135708=135726#toc

Repository:
  rL LLVM

https://reviews.llvm.org/D42498

Files:
  cfe/trunk/lib/AST/ExprConstant.cpp
  cfe/trunk/test/SemaCXX/constant-expression-cxx1y.cpp

Index: cfe/trunk/test/SemaCXX/constant-expression-cxx1y.cpp
===
--- cfe/trunk/test/SemaCXX/constant-expression-cxx1y.cpp
+++ cfe/trunk/test/SemaCXX/constant-expression-cxx1y.cpp
@@ -1045,3 +1045,57 @@
   constexpr B b;
   constexpr int p = b.n; // expected-error {{constant expression}} expected-note {{mutable}}
 }
+
+namespace IndirectFields {
+
+// Reference indirect field.
+struct A {
+  struct {
+union {
+  int x = x = 3; // expected-note {{outside its lifetime}}
+};
+  };
+  constexpr A() {}
+};
+static_assert(A().x == 3, ""); // expected-error{{not an integral constant expression}} expected-note{{in call to 'A()'}}
+
+// Reference another indirect field, with different 'this'.
+struct B {
+  struct {
+union {
+  int x = 3;
+};
+int y = x;
+  };
+  constexpr B() {}
+};
+static_assert(B().y == 3, "");
+
+// Nested evaluation of indirect field initializers.
+struct C {
+  union {
+int x = 1;
+  };
+};
+struct D {
+  struct {
+C c;
+int y = c.x + 1;
+  };
+};
+static_assert(D().y == 2, "");
+
+// Explicit 'this'.
+struct E {
+  int n = 0;
+  struct {
+void *x = this;
+  };
+  void *y = this;
+};
+constexpr E e1 = E();
+static_assert(e1.x != e1.y, "");
+constexpr E e2 = E{0};
+static_assert(e2.x != e2.y, "");
+
+} // namespace IndirectFields
Index: cfe/trunk/lib/AST/ExprConstant.cpp
===
--- cfe/trunk/lib/AST/ExprConstant.cpp
+++ cfe/trunk/lib/AST/ExprConstant.cpp
@@ -4383,6 +4383,7 @@
 #endif
   for (const auto *I : Definition->inits()) {
 LValue Subobject = This;
+LValue SubobjectParent = This;
 APValue *Value = 
 
 // Determine the subobject to initialize.
@@ -4413,7 +4414,8 @@
 } else if (IndirectFieldDecl *IFD = I->getIndirectMember()) {
   // Walk the indirect field decl's chain to find the object to initialize,
   // and make sure we've initialized every step along it.
-  for (auto *C : IFD->chain()) {
+  auto IndirectFieldChain = IFD->chain();
+  for (auto *C : IndirectFieldChain) {
 FD = cast(C);
 CXXRecordDecl *CD = cast(FD->getParent());
 // Switch the union field if it differs. This happens if we had
@@ -4429,6 +4431,10 @@
 *Value = APValue(APValue::UninitStruct(), CD->getNumBases(),
  std::distance(CD->field_begin(), CD->field_end()));
 }
+// Store Subobject as its parent before updating it for the last element
+// in the chain.
+if (C == IndirectFieldChain.back())
+  SubobjectParent = Subobject;
 if (!HandleLValueMember(Info, I->getInit(), Subobject, FD))
   return false;
 if (CD->isUnion())
@@ -4440,10 +4446,16 @@
   llvm_unreachable("unknown base initializer kind");
 }
 
+// Need to override This for implicit field initializers as in this case
+// This refers to innermost anonymous struct/union containing initializer,
+// not to currently constructed class.
+const Expr *Init = I->getInit();
+ThisOverrideRAII ThisOverride(*Info.CurrentCall, ,
+  isa(Init));
 FullExpressionRAII InitScope(Info);
-if (!EvaluateInPlace(*Value, Info, Subobject, I->getInit()) ||
-(FD && FD->isBitField() && !truncateBitfieldValue(Info, I->getInit(),
-  *Value, FD))) {
+if (!EvaluateInPlace(*Value, Info, Subobject, Init) ||
+(FD && FD->isBitField() &&
+ !truncateBitfieldValue(Info, Init, *Value, FD))) {
   // If we're checking for a potential constant expression, evaluate all
   // initializers even if some of them fail.
   if (!Info.noteFailure())
___
cfe-commits mailing list
cfe-commits@lists.llvm.org
http://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits


[PATCH] D42498: [ExprConstant] Fix crash when initialize an indirect field with another field.

2018-02-23 Thread Volodymyr Sapsai via Phabricator via cfe-commits
This revision was automatically updated to reflect the committed changes.
Closed by commit rC325997: [ExprConstant] Fix crash when initialize an indirect 
field with another field. (authored by vsapsai, committed by ).

Changed prior to commit:
  https://reviews.llvm.org/D42498?vs=135708=135725#toc

Repository:
  rL LLVM

https://reviews.llvm.org/D42498

Files:
  lib/AST/ExprConstant.cpp
  test/SemaCXX/constant-expression-cxx1y.cpp

Index: test/SemaCXX/constant-expression-cxx1y.cpp
===
--- test/SemaCXX/constant-expression-cxx1y.cpp
+++ test/SemaCXX/constant-expression-cxx1y.cpp
@@ -1045,3 +1045,57 @@
   constexpr B b;
   constexpr int p = b.n; // expected-error {{constant expression}} expected-note {{mutable}}
 }
+
+namespace IndirectFields {
+
+// Reference indirect field.
+struct A {
+  struct {
+union {
+  int x = x = 3; // expected-note {{outside its lifetime}}
+};
+  };
+  constexpr A() {}
+};
+static_assert(A().x == 3, ""); // expected-error{{not an integral constant expression}} expected-note{{in call to 'A()'}}
+
+// Reference another indirect field, with different 'this'.
+struct B {
+  struct {
+union {
+  int x = 3;
+};
+int y = x;
+  };
+  constexpr B() {}
+};
+static_assert(B().y == 3, "");
+
+// Nested evaluation of indirect field initializers.
+struct C {
+  union {
+int x = 1;
+  };
+};
+struct D {
+  struct {
+C c;
+int y = c.x + 1;
+  };
+};
+static_assert(D().y == 2, "");
+
+// Explicit 'this'.
+struct E {
+  int n = 0;
+  struct {
+void *x = this;
+  };
+  void *y = this;
+};
+constexpr E e1 = E();
+static_assert(e1.x != e1.y, "");
+constexpr E e2 = E{0};
+static_assert(e2.x != e2.y, "");
+
+} // namespace IndirectFields
Index: lib/AST/ExprConstant.cpp
===
--- lib/AST/ExprConstant.cpp
+++ lib/AST/ExprConstant.cpp
@@ -4383,6 +4383,7 @@
 #endif
   for (const auto *I : Definition->inits()) {
 LValue Subobject = This;
+LValue SubobjectParent = This;
 APValue *Value = 
 
 // Determine the subobject to initialize.
@@ -4413,7 +4414,8 @@
 } else if (IndirectFieldDecl *IFD = I->getIndirectMember()) {
   // Walk the indirect field decl's chain to find the object to initialize,
   // and make sure we've initialized every step along it.
-  for (auto *C : IFD->chain()) {
+  auto IndirectFieldChain = IFD->chain();
+  for (auto *C : IndirectFieldChain) {
 FD = cast(C);
 CXXRecordDecl *CD = cast(FD->getParent());
 // Switch the union field if it differs. This happens if we had
@@ -4429,6 +4431,10 @@
 *Value = APValue(APValue::UninitStruct(), CD->getNumBases(),
  std::distance(CD->field_begin(), CD->field_end()));
 }
+// Store Subobject as its parent before updating it for the last element
+// in the chain.
+if (C == IndirectFieldChain.back())
+  SubobjectParent = Subobject;
 if (!HandleLValueMember(Info, I->getInit(), Subobject, FD))
   return false;
 if (CD->isUnion())
@@ -4440,10 +4446,16 @@
   llvm_unreachable("unknown base initializer kind");
 }
 
+// Need to override This for implicit field initializers as in this case
+// This refers to innermost anonymous struct/union containing initializer,
+// not to currently constructed class.
+const Expr *Init = I->getInit();
+ThisOverrideRAII ThisOverride(*Info.CurrentCall, ,
+  isa(Init));
 FullExpressionRAII InitScope(Info);
-if (!EvaluateInPlace(*Value, Info, Subobject, I->getInit()) ||
-(FD && FD->isBitField() && !truncateBitfieldValue(Info, I->getInit(),
-  *Value, FD))) {
+if (!EvaluateInPlace(*Value, Info, Subobject, Init) ||
+(FD && FD->isBitField() &&
+ !truncateBitfieldValue(Info, Init, *Value, FD))) {
   // If we're checking for a potential constant expression, evaluate all
   // initializers even if some of them fail.
   if (!Info.noteFailure())
___
cfe-commits mailing list
cfe-commits@lists.llvm.org
http://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits


[PATCH] D42498: [ExprConstant] Fix crash when initialize an indirect field with another field.

2018-02-23 Thread Richard Smith - zygoloid via Phabricator via cfe-commits
rsmith accepted this revision.
rsmith added a comment.
This revision is now accepted and ready to land.

Looks good, thanks!

In https://reviews.llvm.org/D42498#1015419, @vsapsai wrote:

> In https://reviews.llvm.org/D42498#1007028, @rsmith wrote:
>
> > […] your approach will still go wrong if the `This` pointer is used in 
> > other ways, such as an explicit mention of `this` or a member function call.
>
>
> I wasn't able to find a failing test case. Maybe I misunderstood you but in 
> my testing functions declared in named structs had correct `This` pointer and 
> in anonymous structs functions cannot be declared.


Here's a testcase that fails today:

  struct A { int n = 0; struct { void *p = this; }; void *q = this; };
  constexpr A a = A();
  static_assert(a.p != a.q, ""); // fails today, should pass
  
  constexpr A b = A{0};
  static_assert(b.p != b.q, ""); // passes today

With the previous approach of fixing up the `This` value only in class member 
access, the above testcase would presumably still fail. I expect it to pass 
with your new approach.


https://reviews.llvm.org/D42498



___
cfe-commits mailing list
cfe-commits@lists.llvm.org
http://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits


[PATCH] D42498: [ExprConstant] Fix crash when initialize an indirect field with another field.

2018-02-23 Thread Volodymyr Sapsai via Phabricator via cfe-commits
vsapsai updated this revision to Diff 135708.
vsapsai added a comment.

- Override `This` for indirect field initializer more like it is done for 
`InitListExpr`.

I rebased my changes, so the diff between different versions can be noisy.


https://reviews.llvm.org/D42498

Files:
  clang/lib/AST/ExprConstant.cpp
  clang/test/SemaCXX/constant-expression-cxx1y.cpp

Index: clang/test/SemaCXX/constant-expression-cxx1y.cpp
===
--- clang/test/SemaCXX/constant-expression-cxx1y.cpp
+++ clang/test/SemaCXX/constant-expression-cxx1y.cpp
@@ -1044,3 +1044,44 @@
   constexpr B b;
   constexpr int p = b.n; // expected-error {{constant expression}} expected-note {{mutable}}
 }
+
+namespace IndirectFields {
+
+// Reference indirect field.
+struct A {
+  struct {
+union {
+  int x = x = 3; // expected-note {{outside its lifetime}}
+};
+  };
+  constexpr A() {}
+};
+static_assert(A().x == 3, ""); // expected-error{{not an integral constant expression}} expected-note{{in call to 'A()'}}
+
+// Reference another indirect field, with different 'this'.
+struct B {
+  struct {
+union {
+  int x = 3;
+};
+int y = x;
+  };
+  constexpr B() {}
+};
+static_assert(B().y == 3, "");
+
+// Nested evaluation of indirect field initializers.
+struct C {
+  union {
+int x = 1;
+  };
+};
+struct D {
+  struct {
+C c;
+int y = c.x + 1;
+  };
+};
+static_assert(D().y == 2, "");
+
+} // namespace IndirectFields
Index: clang/lib/AST/ExprConstant.cpp
===
--- clang/lib/AST/ExprConstant.cpp
+++ clang/lib/AST/ExprConstant.cpp
@@ -4383,6 +4383,7 @@
 #endif
   for (const auto *I : Definition->inits()) {
 LValue Subobject = This;
+LValue SubobjectParent = This;
 APValue *Value = 
 
 // Determine the subobject to initialize.
@@ -4413,7 +4414,8 @@
 } else if (IndirectFieldDecl *IFD = I->getIndirectMember()) {
   // Walk the indirect field decl's chain to find the object to initialize,
   // and make sure we've initialized every step along it.
-  for (auto *C : IFD->chain()) {
+  auto IndirectFieldChain = IFD->chain();
+  for (auto *C : IndirectFieldChain) {
 FD = cast(C);
 CXXRecordDecl *CD = cast(FD->getParent());
 // Switch the union field if it differs. This happens if we had
@@ -4429,6 +4431,10 @@
 *Value = APValue(APValue::UninitStruct(), CD->getNumBases(),
  std::distance(CD->field_begin(), CD->field_end()));
 }
+// Store Subobject as its parent before updating it for the last element
+// in the chain.
+if (C == IndirectFieldChain.back())
+  SubobjectParent = Subobject;
 if (!HandleLValueMember(Info, I->getInit(), Subobject, FD))
   return false;
 if (CD->isUnion())
@@ -4440,10 +4446,16 @@
   llvm_unreachable("unknown base initializer kind");
 }
 
+// Need to override This for implicit field initializers as in this case
+// This refers to innermost anonymous struct/union containing initializer,
+// not to currently constructed class.
+const Expr *Init = I->getInit();
+ThisOverrideRAII ThisOverride(*Info.CurrentCall, ,
+  isa(Init));
 FullExpressionRAII InitScope(Info);
-if (!EvaluateInPlace(*Value, Info, Subobject, I->getInit()) ||
-(FD && FD->isBitField() && !truncateBitfieldValue(Info, I->getInit(),
-  *Value, FD))) {
+if (!EvaluateInPlace(*Value, Info, Subobject, Init) ||
+(FD && FD->isBitField() &&
+ !truncateBitfieldValue(Info, Init, *Value, FD))) {
   // If we're checking for a potential constant expression, evaluate all
   // initializers even if some of them fail.
   if (!Info.noteFailure())
___
cfe-commits mailing list
cfe-commits@lists.llvm.org
http://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits


[PATCH] D42498: [ExprConstant] Fix crash when initialize an indirect field with another field.

2018-02-21 Thread Volodymyr Sapsai via Phabricator via cfe-commits
vsapsai added a comment.

Thanks for response, Richard. I'll look into using `CXXDefaultInitExpr`.

As for

In https://reviews.llvm.org/D42498#1007028, @rsmith wrote:

> […] your approach will still go wrong if the `This` pointer is used in other 
> ways, such as an explicit mention of `this` or a member function call.


I wasn't able to find a failing test case. Maybe I misunderstood you but in my 
testing functions declared in named structs had correct `This` pointer and in 
anonymous structs functions cannot be declared.


https://reviews.llvm.org/D42498



___
cfe-commits mailing list
cfe-commits@lists.llvm.org
http://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits


[PATCH] D42498: [ExprConstant] Fix crash when initialize an indirect field with another field.

2018-02-13 Thread Richard Smith - zygoloid via Phabricator via cfe-commits
rsmith added a comment.

Please handle this by temporarily updating the `This` pointer appropriately 
when evaluating the `CXXDefaultInitExpr` rather than trying to work around the 
`This` value being wrong later (your approach will still go wrong if the `This` 
pointer is used in other ways, such as an explicit mention of `this` or a 
member function call). You can refer to how we do this in CodeGen: look for 
`CodeGenFunction::CXXDefaultInitExprScope` and 
`CodeGenFunction::FieldConstructionScope`.


https://reviews.llvm.org/D42498



___
cfe-commits mailing list
cfe-commits@lists.llvm.org
http://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits


[PATCH] D42498: [ExprConstant] Fix crash when initialize an indirect field with another field.

2018-02-13 Thread Volodymyr Sapsai via Phabricator via cfe-commits
vsapsai added a comment.
Herald added a subscriber: jkorous-apple.

Ping.


https://reviews.llvm.org/D42498



___
cfe-commits mailing list
cfe-commits@lists.llvm.org
http://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits


[PATCH] D42498: [ExprConstant] Fix crash when initialize an indirect field with another field.

2018-01-24 Thread Volodymyr Sapsai via Phabricator via cfe-commits
vsapsai created this revision.
vsapsai added reviewers: rsmith, efriedma.

When indirect field is initialized with another field, you have
MemberExpr with CXXThisExpr that corresponds to the field's immediate
anonymous parent. But 'this' was referring to the non-anonymous parent.
So when we were building LValue Designator, it was incorrect as it had
wrong starting point. Usage of such designator would cause unexpected
APValue changes and crashes.

The fix is in adjusting 'this' for indirect fields from non-anonymous
parent to the field's immediate parent.

Discovered by OSS-Fuzz:
https://bugs.chromium.org/p/oss-fuzz/issues/detail?id=4985

rdar://problem/36359187


https://reviews.llvm.org/D42498

Files:
  clang/lib/AST/ExprConstant.cpp
  clang/test/SemaCXX/constant-expression-cxx1y.cpp

Index: clang/test/SemaCXX/constant-expression-cxx1y.cpp
===
--- clang/test/SemaCXX/constant-expression-cxx1y.cpp
+++ clang/test/SemaCXX/constant-expression-cxx1y.cpp
@@ -1021,3 +1021,44 @@
 }
 static_assert(evalNested(), "");
 } // namespace PR19741
+
+namespace IndirectFields {
+
+// Reference indirect field.
+struct A {
+  struct {
+union {
+  int x = x = 3; // expected-note {{outside its lifetime}}
+};
+  };
+  constexpr A() {}
+};
+static_assert(A().x == 3, ""); // expected-error{{not an integral constant expression}} expected-note{{in call to 'A()'}}
+
+// Reference another indirect field, with different 'this'.
+struct B {
+  struct {
+union {
+  int x = 3;
+};
+int y = x;
+  };
+  constexpr B() {}
+};
+static_assert(B().y == 3, "");
+
+// Nested evaluation of indirect field initializers.
+struct C {
+  union {
+int x = 1;
+  };
+};
+struct D {
+  struct {
+C c;
+int y = c.x + 1;
+  };
+};
+static_assert(D().y == 2, "");
+
+} // namespace IndirectFields
Index: clang/lib/AST/ExprConstant.cpp
===
--- clang/lib/AST/ExprConstant.cpp
+++ clang/lib/AST/ExprConstant.cpp
@@ -449,6 +449,9 @@
 /// Index - The call index of this call.
 unsigned Index;
 
+/// IndirectField - The indirect field being evaluated.
+const IndirectFieldDecl *IndirectField = nullptr;
+
 // FIXME: Adding this to every 'CallStackFrame' may have a nontrivial impact
 // on the overall stack usage of deeply-recursing constexpr evaluataions.
 // (We should cache this map rather than recomputing it repeatedly.)
@@ -4370,6 +4373,7 @@
   for (const auto *I : Definition->inits()) {
 LValue Subobject = This;
 APValue *Value = 
+Frame.IndirectField = nullptr;
 
 // Determine the subobject to initialize.
 FieldDecl *FD = nullptr;
@@ -4399,6 +4403,7 @@
 } else if (IndirectFieldDecl *IFD = I->getIndirectMember()) {
   // Walk the indirect field decl's chain to find the object to initialize,
   // and make sure we've initialized every step along it.
+  Frame.IndirectField = IFD;
   for (auto *C : IFD->chain()) {
 FD = cast(C);
 CXXRecordDecl *CD = cast(FD->getParent());
@@ -4437,6 +4442,7 @@
   Success = false;
 }
   }
+  Frame.IndirectField = nullptr;
 
   return Success &&
  EvaluateStmt(Ret, Info, Definition->getBody()) != ESR_Failed;
@@ -5612,6 +5618,20 @@
 
 Result.setFrom(Info.Ctx, RVal);
   }
+} else if (Info.CurrentCall->IndirectField) {
+  // Fields of anonymous structs/unions can refer to other fields. In this
+  // case the 'this' expression corresponds to anonymous struct/union but
+  // Info.CurrentCall->This corresponds to the field's non-anonymous parent.
+  for (auto *C : Info.CurrentCall->IndirectField->chain()) {
+const FieldDecl *FD = cast(C);
+if (!FD->isImplicit()) {
+  assert(E->getType()->getPointeeCXXRecordDecl() == FD->getParent() &&
+ "Should adjust LValue to refer to the same 'this'");
+  break;
+}
+if (!HandleLValueMember(Info, E, Result, FD))
+  return false;
+  }
 }
 return true;
   }
___
cfe-commits mailing list
cfe-commits@lists.llvm.org
http://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits