[PATCH] D29748: [cxx1z-constexpr-lambda] Implement captures - thus completing implementation of constexpr lambdas.

2017-05-21 Thread Faisal Vali via Phabricator via cfe-commits
faisalv closed this revision.
faisalv added a comment.

Closed by commit https://reviews.llvm.org/rL295279


https://reviews.llvm.org/D29748



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


[PATCH] D29748: [cxx1z-constexpr-lambda] Implement captures - thus completing implementation of constexpr lambdas.

2017-02-14 Thread Richard Smith via Phabricator via cfe-commits
rsmith accepted this revision.
rsmith added inline comments.
This revision is now accepted and ready to land.



Comment at: lib/AST/ExprConstant.cpp:428-429
 
+llvm::DenseMap LambdaCaptureFields;
+FieldDecl *LambdaThisCaptureField;
+

I'm a little concerned that adding this to every `CallStackFrame` may have a 
nontrivial impact on the overall stack usage of deeply-recursing constexpr 
evaluataions. (I'd also like to cache this map rather than recomputing it 
repeatedly.) But let's try this and see how it goes; we can look into caching 
the map as a later change.



Comment at: lib/AST/ExprConstant.cpp:4194
+MD->getParent()->getCaptureFields(Frame.LambdaCaptureFields,
+  Frame.LambdaThisCaptureField);
   }

Indent.



Comment at: lib/AST/ExprConstant.cpp:5061
+  // ... then update it to refer to the field of the closure object
+  // that represents the capture.
+  if (!HandleLValueMember(Info, E, Result, FD))

```constexpr bool b = [&]{ return  }() ==  // should be accepted```

... is more what I was thinking.



Comment at: lib/AST/ExprConstant.cpp:5067-5071
+  APValue RVal;
+  if (!handleLValueToRValueConversion(Info, E, FD->getType(), Result,
+  RVal))
+return false;
+  Result.setFrom(Info.Ctx, RVal);

Too much indentation here.


https://reviews.llvm.org/D29748



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


[PATCH] D29748: [cxx1z-constexpr-lambda] Implement captures - thus completing implementation of constexpr lambdas.

2017-02-09 Thread Hubert Tong via Phabricator via cfe-commits
hubert.reinterpretcast added inline comments.



Comment at: lib/AST/ExprConstant.cpp:5061
+  APValue RVal;
+  // FIXME: We need to make sure we're passing the right type that
+  // maintains cv-qualifiers.

faisalv wrote:
> rsmith wrote:
> > faisalv wrote:
> > > I don't think we need this fixme - the type of the expression should be 
> > > correct - all other const checks for mutability have already been 
> > > performed, right?
> > When using `handleLValueToRValueConversion` to obtain the lvalue denoted by 
> > a reference, the type you pass should be the reference type itself 
> > (`FD->getType()`). This approach will give the wrong answer when using a 
> > captured volatile object:
> > ```
> > void f() {
> >   volatile int n;
> >   constexpr volatile int *p = [&]{ return  }(); // should be accepted
> > }
> > ```
> OK - but how is the address of a local variable a constant expression?
I guess this one is safer:
```
void f() {
  volatile int n;
  constexpr volatile int *p = [&]{ return false ?  : nullptr; }();
}
```


https://reviews.llvm.org/D29748



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


[PATCH] D29748: [cxx1z-constexpr-lambda] Implement captures - thus completing implementation of constexpr lambdas.

2017-02-09 Thread Faisal Vali via Phabricator via cfe-commits
faisalv added inline comments.



Comment at: lib/AST/ExprConstant.cpp:5061
+  APValue RVal;
+  // FIXME: We need to make sure we're passing the right type that
+  // maintains cv-qualifiers.

rsmith wrote:
> faisalv wrote:
> > I don't think we need this fixme - the type of the expression should be 
> > correct - all other const checks for mutability have already been 
> > performed, right?
> When using `handleLValueToRValueConversion` to obtain the lvalue denoted by a 
> reference, the type you pass should be the reference type itself 
> (`FD->getType()`). This approach will give the wrong answer when using a 
> captured volatile object:
> ```
> void f() {
>   volatile int n;
>   constexpr volatile int *p = [&]{ return  }(); // should be accepted
> }
> ```
OK - but how is the address of a local variable a constant expression?


https://reviews.llvm.org/D29748



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


[PATCH] D29748: [cxx1z-constexpr-lambda] Implement captures - thus completing implementation of constexpr lambdas.

2017-02-09 Thread Faisal Vali via Phabricator via cfe-commits
faisalv updated this revision to Diff 87943.
faisalv marked 6 inline comments as done.
faisalv added a comment.

Incorporated Richard's feedback and added comments.


https://reviews.llvm.org/D29748

Files:
  lib/AST/ExprConstant.cpp
  test/SemaCXX/cxx1z-constexpr-lambdas.cpp

Index: test/SemaCXX/cxx1z-constexpr-lambdas.cpp
===
--- test/SemaCXX/cxx1z-constexpr-lambdas.cpp
+++ test/SemaCXX/cxx1z-constexpr-lambdas.cpp
@@ -1,6 +1,6 @@
-// RUN: %clang_cc1 -std=c++1z -verify -fsyntax-only -fblocks %s
-// RUN: %clang_cc1 -std=c++1z -verify -fsyntax-only -fblocks -fdelayed-template-parsing %s 
-// RUN: %clang_cc1 -std=c++14 -verify -fsyntax-only -fblocks %s -DCPP14_AND_EARLIER
+// RUN: %clang_cc1 -std=c++1z -verify -fsyntax-only -fblocks %s -fcxx-exceptions
+// RUN: %clang_cc1 -std=c++1z -verify -fsyntax-only -fblocks -fdelayed-template-parsing %s -fcxx-exceptions
+// RUN: %clang_cc1 -std=c++14 -verify -fsyntax-only -fblocks %s -DCPP14_AND_EARLIER -fcxx-exceptions
 
 
 namespace test_lambda_is_literal {
@@ -157,18 +157,111 @@
 
 } // end ns1_simple_lambda
 
-namespace ns1_unimplemented {
-namespace ns1_captures {
+namespace test_captures_1 {
+namespace ns1 {
 constexpr auto f(int i) {
-  double d = 3.14;
-  auto L = [=](auto a) { //expected-note{{coming soon}}
-int Isz = i + d;
-return sizeof(i) + sizeof(a) + sizeof(d); 
+  struct S { int x; } s = { i * 2 };
+  auto L = [=](auto a) { 
+return i + s.x + a;
   };
   return L;
 }
-constexpr auto M = f(3);  //expected-error{{constant expression}} expected-note{{in call to}}
-} // end ns1_captures
+constexpr auto M = f(3);  
+
+static_assert(M(10) == 19);
+
+} // end test_captures_1::ns1
+
+namespace ns2 {
+
+constexpr auto foo(int n) {
+  auto L = [i = n] (auto N) mutable {
+if (!N(i)) throw "error";
+return [] {
+  return ++i;
+};
+  };
+  auto M = L([n](int p) { return p == n; });
+  M(); M();
+  L([n](int p) { return p == n + 2; });
+  
+  return L;
+}
+
+constexpr auto L = foo(3);
+
+} // end test_captures_1::ns2
+namespace ns3 {
+
+constexpr auto foo(int n) {
+  auto L = [i = n] (auto N) mutable {
+if (!N(i)) throw "error";
+return [] {
+  return [i]() mutable {
+return ++i;
+  };
+};
+  };
+  auto M = L([n](int p) { return p == n; });
+  M()(); M()();
+  L([n](int p) { return p == n; });
+  
+  return L;
+}
+
+constexpr auto L = foo(3);
+} // end test_captures_1::ns3
+
+namespace ns2_capture_this_byval {
+struct S {
+  int s;
+  constexpr S(int s) : s{s} { }
+  constexpr auto f(S o) {
+return [*this,o] (auto a) { return s + o.s + a.s; };
+  }
+};
+
+constexpr auto L = S{5}.f(S{10});
+static_assert(L(S{100}) == 115);
+} // end test_captures_1::ns2_capture_this_byval
+
+namespace ns2_capture_this_byref {
+
+struct S {
+  int s;
+  constexpr S(int s) : s{s} { }
+  constexpr auto f() const {
+return [this] { return s; };
+  }
+};
+
+constexpr S SObj{5};
+constexpr auto L = SObj.f();
+constexpr int I = L();
+static_assert(I == 5);
+
+} // end ns2_capture_this_byref
+
+} // end test_captures_1
+
+namespace test_capture_array {
+namespace ns1 {
+constexpr auto f(int I) {
+  int arr[] = { I, I *2, I * 3 };
+  auto L1 = [&] (auto a) { return arr[a]; };
+  int r = L1(2);
+  struct X { int x, y; };
+  return [=](auto a) { return X{arr[a],r}; };
+}
+constexpr auto L = f(3);
+static_assert(L(0).x == 3);
+static_assert(L(0).y == 9);
+static_assert(L(1).x == 6);
+static_assert(L(1).y == 9);
+} // end ns1
+
+} // end test_capture_array
+namespace ns1_unimplemented {
 } // end ns1_unimplemented 
 
 } // end ns test_lambda_is_cce
Index: lib/AST/ExprConstant.cpp
===
--- lib/AST/ExprConstant.cpp
+++ lib/AST/ExprConstant.cpp
@@ -425,6 +425,9 @@
 /// Index - The call index of this call.
 unsigned Index;
 
+llvm::DenseMap LambdaCaptureFields;
+FieldDecl *LambdaThisCaptureField;
+
 CallStackFrame(EvalInfo , SourceLocation CallLoc,
const FunctionDecl *Callee, const LValue *This,
APValue *Arguments);
@@ -2279,6 +2282,10 @@
   return true;
 }
 
+static bool handleLValueToRValueConversion(EvalInfo , const Expr *Conv,
+   QualType Type, const LValue ,
+   APValue );
+
 /// Try to evaluate the initializer for a variable declaration.
 ///
 /// \param Info   Information about the ongoing evaluation.
@@ -2290,6 +2297,7 @@
 static bool evaluateVarDeclInit(EvalInfo , const Expr *E,
 const VarDecl *VD, CallStackFrame *Frame,
 APValue *) {
+
   // If this is a parameter to an active constexpr function call, perform
   // argument substitution.
   if (const ParmVarDecl *PVD = dyn_cast(VD)) {
@@ -4180,6 +4188,10 @@
   return false;
 This->moveInto(Result);
 return true;
+  } else if (MD && 

[PATCH] D29748: [cxx1z-constexpr-lambda] Implement captures - thus completing implementation of constexpr lambdas.

2017-02-09 Thread Richard Smith via Phabricator via cfe-commits
rsmith added inline comments.



Comment at: lib/AST/ExprConstant.cpp:5061
+  APValue RVal;
+  // FIXME: We need to make sure we're passing the right type that
+  // maintains cv-qualifiers.

faisalv wrote:
> I don't think we need this fixme - the type of the expression should be 
> correct - all other const checks for mutability have already been performed, 
> right?
When using `handleLValueToRValueConversion` to obtain the lvalue denoted by a 
reference, the type you pass should be the reference type itself 
(`FD->getType()`). This approach will give the wrong answer when using a 
captured volatile object:
```
void f() {
  volatile int n;
  constexpr volatile int *p = [&]{ return  }(); // should be accepted
}
```



Comment at: lib/AST/ExprConstant.cpp:5066-5068
+  assert(RVal.isLValue() && "Reference captures through their "
+"corresponding field members must refer to 
"
+"lvalues (VarDecls or FieldDecls)");

I don't see why this assert is correct. If we initialize a reference with a 
(constant-folded) dereferenced integer cast to pointer type, the value will 
have integer representation. Just remove the assert?



Comment at: lib/AST/ExprConstant.cpp:5473-5474
+  
+  if (HandleLValueMember(Info, E, Result,
+ Info.CurrentCall->LambdaThisCaptureField)) {
+if (Info.CurrentCall->LambdaThisCaptureField->getType()

Please use early-exit style (`if (!HandleLValueMember(...)) return false;`) 
here to reduce indentation and make it clearer that you only return false if a 
diagnostic has already been produced.



Comment at: lib/AST/ExprConstant.cpp:6338-6339
+// occurred.
+if (!CurFieldInit)
+  return false;
+

Returning `false` without producing a diagnostic (for the VLA case) is not OK. 
You should at least produce the basic "not a constant expression" note here.


Repository:
  rL LLVM

https://reviews.llvm.org/D29748



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


[PATCH] D29748: [cxx1z-constexpr-lambda] Implement captures - thus completing implementation of constexpr lambdas.

2017-02-08 Thread Faisal Vali via Phabricator via cfe-commits
faisalv added inline comments.



Comment at: lib/AST/ExprConstant.cpp:5061
+  APValue RVal;
+  // FIXME: We need to make sure we're passing the right type that
+  // maintains cv-qualifiers.

I don't think we need this fixme - the type of the expression should be correct 
- all other const checks for mutability have already been performed, right?



Comment at: lib/AST/ExprConstant.cpp:5486
+  }
+  //Info.FFDiag(E);
+  return false;

I need to delete this comment...


Repository:
  rL LLVM

https://reviews.llvm.org/D29748



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


[PATCH] D29748: [cxx1z-constexpr-lambda] Implement captures - thus completing implementation of constexpr lambdas.

2017-02-08 Thread Faisal Vali via Phabricator via cfe-commits
faisalv created this revision.
faisalv added a project: clang-c.
Herald added a subscriber: EricWF.

This patch attempts to enable evaluation of all forms of captures (however 
deeply nested) within constexpr lambdas.

Appreciate the feedback.

Thanks!


Repository:
  rL LLVM

https://reviews.llvm.org/D29748

Files:
  lib/AST/ExprConstant.cpp
  test/SemaCXX/cxx1z-constexpr-lambdas.cpp

Index: test/SemaCXX/cxx1z-constexpr-lambdas.cpp
===
--- test/SemaCXX/cxx1z-constexpr-lambdas.cpp
+++ test/SemaCXX/cxx1z-constexpr-lambdas.cpp
@@ -1,6 +1,6 @@
-// RUN: %clang_cc1 -std=c++1z -verify -fsyntax-only -fblocks %s
-// RUN: %clang_cc1 -std=c++1z -verify -fsyntax-only -fblocks -fdelayed-template-parsing %s 
-// RUN: %clang_cc1 -std=c++14 -verify -fsyntax-only -fblocks %s -DCPP14_AND_EARLIER
+// RUN: %clang_cc1 -std=c++1z -verify -fsyntax-only -fblocks %s -fcxx-exceptions
+// RUN: %clang_cc1 -std=c++1z -verify -fsyntax-only -fblocks -fdelayed-template-parsing %s -fcxx-exceptions
+// RUN: %clang_cc1 -std=c++14 -verify -fsyntax-only -fblocks %s -DCPP14_AND_EARLIER -fcxx-exceptions
 
 
 namespace test_lambda_is_literal {
@@ -157,18 +157,111 @@
 
 } // end ns1_simple_lambda
 
-namespace ns1_unimplemented {
-namespace ns1_captures {
+namespace test_captures_1 {
+namespace ns1 {
 constexpr auto f(int i) {
-  double d = 3.14;
-  auto L = [=](auto a) { //expected-note{{coming soon}}
-int Isz = i + d;
-return sizeof(i) + sizeof(a) + sizeof(d); 
+  struct S { int x; } s = { i * 2 };
+  auto L = [=](auto a) { 
+return i + s.x + a;
   };
   return L;
 }
-constexpr auto M = f(3);  //expected-error{{constant expression}} expected-note{{in call to}}
-} // end ns1_captures
+constexpr auto M = f(3);  
+
+static_assert(M(10) == 19);
+
+} // end test_captures_1::ns1
+
+namespace ns2 {
+
+constexpr auto foo(int n) {
+  auto L = [i = n] (auto N) mutable {
+if (!N(i)) throw "error";
+return [] {
+  return ++i;
+};
+  };
+  auto M = L([n](int p) { return p == n; });
+  M(); M();
+  L([n](int p) { return p == n + 2; });
+  
+  return L;
+}
+
+constexpr auto L = foo(3);
+
+} // end test_captures_1::ns2
+namespace ns3 {
+
+constexpr auto foo(int n) {
+  auto L = [i = n] (auto N) mutable {
+if (!N(i)) throw "error";
+return [] {
+  return [i]() mutable {
+return ++i;
+  };
+};
+  };
+  auto M = L([n](int p) { return p == n; });
+  M()(); M()();
+  L([n](int p) { return p == n; });
+  
+  return L;
+}
+
+constexpr auto L = foo(3);
+} // end test_captures_1::ns3
+
+namespace ns2_capture_this_byval {
+struct S {
+  int s;
+  constexpr S(int s) : s{s} { }
+  constexpr auto f(S o) {
+return [*this,o] (auto a) { return s + o.s + a.s; };
+  }
+};
+
+constexpr auto L = S{5}.f(S{10});
+static_assert(L(S{100}) == 115);
+} // end test_captures_1::ns2_capture_this_byval
+
+namespace ns2_capture_this_byref {
+
+struct S {
+  int s;
+  constexpr S(int s) : s{s} { }
+  constexpr auto f() const {
+return [this] { return s; };
+  }
+};
+
+constexpr S SObj{5};
+constexpr auto L = SObj.f();
+constexpr int I = L();
+static_assert(I == 5);
+
+} // end ns2_capture_this_byref
+
+} // end test_captures_1
+
+namespace test_capture_array {
+namespace ns1 {
+constexpr auto f(int I) {
+  int arr[] = { I, I *2, I * 3 };
+  auto L1 = [&] (auto a) { return arr[a]; };
+  int r = L1(2);
+  struct X { int x, y; };
+  return [=](auto a) { return X{arr[a],r}; };
+}
+constexpr auto L = f(3);
+static_assert(L(0).x == 3);
+static_assert(L(0).y == 9);
+static_assert(L(1).x == 6);
+static_assert(L(1).y == 9);
+} // end ns1
+
+} // end test_capture_array
+namespace ns1_unimplemented {
 } // end ns1_unimplemented 
 
 } // end ns test_lambda_is_cce
Index: lib/AST/ExprConstant.cpp
===
--- lib/AST/ExprConstant.cpp
+++ lib/AST/ExprConstant.cpp
@@ -425,6 +425,9 @@
 /// Index - The call index of this call.
 unsigned Index;
 
+llvm::DenseMap LambdaCaptureFields;
+FieldDecl *LambdaThisCaptureField;
+
 CallStackFrame(EvalInfo , SourceLocation CallLoc,
const FunctionDecl *Callee, const LValue *This,
APValue *Arguments);
@@ -2279,6 +2282,10 @@
   return true;
 }
 
+static bool handleLValueToRValueConversion(EvalInfo , const Expr *Conv,
+   QualType Type, const LValue ,
+   APValue );
+
 /// Try to evaluate the initializer for a variable declaration.
 ///
 /// \param Info   Information about the ongoing evaluation.
@@ -2290,6 +2297,7 @@
 static bool evaluateVarDeclInit(EvalInfo , const Expr *E,
 const VarDecl *VD, CallStackFrame *Frame,
 APValue *) {
+
   // If this is a parameter to an active constexpr function call, perform
   // argument substitution.
   if (const ParmVarDecl *PVD = dyn_cast(VD)) {
@@