[PATCH] D36101: Fix usage of right shift operator in fold expressions

2017-08-28 Thread Blitz Rakete via Phabricator via cfe-commits
Rakete updated this revision to Diff 113020.
Rakete added a comment.

Updated test to use the -std=c++17 option + friendly ping


https://reviews.llvm.org/D36101

Files:
  lib/Parse/ParseExpr.cpp
  test/CXX/expr/expr.prim/expr.prim.fold/p2.cpp


Index: test/CXX/expr/expr.prim/expr.prim.fold/p2.cpp
===
--- test/CXX/expr/expr.prim/expr.prim.fold/p2.cpp
+++ test/CXX/expr/expr.prim/expr.prim.fold/p2.cpp
@@ -0,0 +1,12 @@
+// RUN: %clang_cc1 -std=c++17 -verify %s
+
+// PR32563
+template
+constexpr int right_shift(int value, Ts... args) {
+  return (value >> ... >> args); // expected-no-diagnostics
+}
+
+void test_folds() {
+  static_assert(right_shift(10, 2) == 2);
+}
+
Index: lib/Parse/ParseExpr.cpp
===
--- lib/Parse/ParseExpr.cpp
+++ lib/Parse/ParseExpr.cpp
@@ -270,7 +270,7 @@
   return Level > prec::Unknown && Level != prec::Conditional;
 }
 static bool isFoldOperator(tok::TokenKind Kind) {
-  return isFoldOperator(getBinOpPrecedence(Kind, false, true));
+  return isFoldOperator(getBinOpPrecedence(Kind, true, true));
 }
 
 /// \brief Parse a binary expression that starts with \p LHS and has a


Index: test/CXX/expr/expr.prim/expr.prim.fold/p2.cpp
===
--- test/CXX/expr/expr.prim/expr.prim.fold/p2.cpp
+++ test/CXX/expr/expr.prim/expr.prim.fold/p2.cpp
@@ -0,0 +1,12 @@
+// RUN: %clang_cc1 -std=c++17 -verify %s
+
+// PR32563
+template
+constexpr int right_shift(int value, Ts... args) {
+  return (value >> ... >> args); // expected-no-diagnostics
+}
+
+void test_folds() {
+  static_assert(right_shift(10, 2) == 2);
+}
+
Index: lib/Parse/ParseExpr.cpp
===
--- lib/Parse/ParseExpr.cpp
+++ lib/Parse/ParseExpr.cpp
@@ -270,7 +270,7 @@
   return Level > prec::Unknown && Level != prec::Conditional;
 }
 static bool isFoldOperator(tok::TokenKind Kind) {
-  return isFoldOperator(getBinOpPrecedence(Kind, false, true));
+  return isFoldOperator(getBinOpPrecedence(Kind, true, true));
 }
 
 /// \brief Parse a binary expression that starts with \p LHS and has a
___
cfe-commits mailing list
cfe-commits@lists.llvm.org
http://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits


[PATCH] D37442: [C++17] Disallow lambdas in template parameters (PR33696).

2017-09-04 Thread Blitz Rakete via Phabricator via cfe-commits
Rakete created this revision.

This revision disallows lambdas in template parameters, as reported in PR33696.


https://reviews.llvm.org/D37442

Files:
  include/clang/Basic/DiagnosticSemaKinds.td
  include/clang/Sema/Sema.h
  lib/Parse/ParseTemplate.cpp
  lib/Sema/Sema.cpp
  lib/Sema/SemaExpr.cpp
  test/CXX/expr/expr.prim/expr.prim.lambda/p2-template-parameter.cpp

Index: test/CXX/expr/expr.prim/expr.prim.lambda/p2-template-parameter.cpp
===
--- test/CXX/expr/expr.prim/expr.prim.lambda/p2-template-parameter.cpp
+++ test/CXX/expr/expr.prim/expr.prim.lambda/p2-template-parameter.cpp
@@ -0,0 +1,8 @@
+// RUN: %clang_cc1 -std=c++17 %s -verify
+
+template struct Nothing {};
+
+void pr33696() {
+Nothing<[]() { return 0; }()> nothing; // expected-error{{a lambda expression cannot appear in this context}}
+}
+
Index: lib/Sema/SemaExpr.cpp
===
--- lib/Sema/SemaExpr.cpp
+++ lib/Sema/SemaExpr.cpp
@@ -13355,9 +13355,10 @@
 void
 Sema::PushExpressionEvaluationContext(ExpressionEvaluationContext NewContext,
   Decl *LambdaContextDecl,
-  bool IsDecltype) {
+  bool IsDecltype,
+  bool IsLambdaValid) {
   ExprEvalContexts.emplace_back(NewContext, ExprCleanupObjects.size(), Cleanup,
-LambdaContextDecl, IsDecltype);
+LambdaContextDecl, IsDecltype, IsLambdaValid);
   Cleanup.reset();
   if (!MaybeODRUseExprs.empty())
 std::swap(MaybeODRUseExprs, ExprEvalContexts.back().SavedMaybeODRUseExprs);
@@ -13366,9 +13367,11 @@
 void
 Sema::PushExpressionEvaluationContext(ExpressionEvaluationContext NewContext,
   ReuseLambdaContextDecl_t,
-  bool IsDecltype) {
+  bool IsDecltype,
+  bool IsLambdaValid) {
   Decl *ClosureContextDecl = ExprEvalContexts.back().ManglingContextDecl;
-  PushExpressionEvaluationContext(NewContext, ClosureContextDecl, IsDecltype);
+  PushExpressionEvaluationContext(NewContext, ClosureContextDecl, IsDecltype,
+  IsLambdaValid);
 }
 
 void Sema::PopExpressionEvaluationContext() {
@@ -13376,7 +13379,8 @@
   unsigned NumTypos = Rec.NumTypos;
 
   if (!Rec.Lambdas.empty()) {
-if (Rec.isUnevaluated() || Rec.isConstantEvaluated()) {
+if (!Rec.IsLambdaValid || Rec.isUnevaluated() ||
+(Rec.isConstantEvaluated() && !getLangOpts().CPlusPlus1z)) {
   unsigned D;
   if (Rec.isUnevaluated()) {
 // C++11 [expr.prim.lambda]p2:
@@ -13383,23 +13387,21 @@
 //   A lambda-expression shall not appear in an unevaluated operand
 //   (Clause 5).
 D = diag::err_lambda_unevaluated_operand;
-  } else {
+  } else if (Rec.isConstantEvaluated() && !getLangOpts().CPlusPlus1z) {
 // C++1y [expr.const]p2:
 //   A conditional-expression e is a core constant expression unless the
 //   evaluation of e, following the rules of the abstract machine, would
 //   evaluate [...] a lambda-expression.
 D = diag::err_lambda_in_constant_expression;
-  }
+  } else if (!Rec.IsLambdaValid) {
+// C++17 [expr.prim.lambda]p2:
+// A lambda-expression shall not appear [...] in a template-argument.
+D = diag::err_lambda_in_invalid_context;
+  } else
+llvm_unreachable("Couldn't infer lambda error message.");
 
-  // C++1z allows lambda expressions as core constant expressions.
-  // FIXME: In C++1z, reinstate the restrictions on lambda expressions (CWG
-  // 1607) from appearing within template-arguments and array-bounds that
-  // are part of function-signatures.  Be mindful that P0315 (Lambdas in
-  // unevaluated contexts) might lift some of these restrictions in a 
-  // future version.
-  if (!Rec.isConstantEvaluated() || !getLangOpts().CPlusPlus1z)
-for (const auto *L : Rec.Lambdas)
-  Diag(L->getLocStart(), D);
+  for (const auto *L : Rec.Lambdas)
+Diag(L->getLocStart(), D);
 } else {
   // Mark the capture expressions odr-used. This was deferred
   // during lambda expression creation.
Index: lib/Sema/Sema.cpp
===
--- lib/Sema/Sema.cpp
+++ lib/Sema/Sema.cpp
@@ -159,7 +159,7 @@
 
   ExprEvalContexts.emplace_back(
   ExpressionEvaluationContext::PotentiallyEvaluated, 0, CleanupInfo{},
-  nullptr, false);
+  nullptr, false, true);
 
   FunctionScopes.push_back(new FunctionScopeInfo(Diags));
 
Index: lib/Parse/ParseTemplate.cpp
===
--- lib/Parse/ParseTemplate.cpp
+++ lib/Parse/ParseTemplate.cpp

[PATCH] D37442: [C++17] Disallow lambdas in template parameters (PR33696).

2017-09-07 Thread Blitz Rakete via Phabricator via cfe-commits
Rakete updated this revision to Diff 114204.
Rakete added a comment.

Good idea! Updated diff :)


https://reviews.llvm.org/D37442

Files:
  include/clang/Basic/DiagnosticSemaKinds.td
  include/clang/Sema/Sema.h
  lib/Parse/ParseDecl.cpp
  lib/Parse/ParseDeclCXX.cpp
  lib/Parse/ParseStmt.cpp
  lib/Parse/ParseTemplate.cpp
  lib/Sema/Sema.cpp
  lib/Sema/SemaExpr.cpp
  lib/Sema/SemaExprCXX.cpp
  lib/Sema/TreeTransform.h
  test/CXX/expr/expr.prim/expr.prim.lambda/p2-template-parameter.cpp

Index: test/CXX/expr/expr.prim/expr.prim.lambda/p2-template-parameter.cpp
===
--- test/CXX/expr/expr.prim/expr.prim.lambda/p2-template-parameter.cpp
+++ test/CXX/expr/expr.prim/expr.prim.lambda/p2-template-parameter.cpp
@@ -0,0 +1,7 @@
+// RUN: %clang_cc1 -std=c++17 %s -verify
+
+template struct Nothing {};
+
+void pr33696() {
+Nothing<[]() { return 0; }()> nothing; // expected-error{{a lambda expression cannot appear in this context}}
+}
Index: lib/Sema/TreeTransform.h
===
--- lib/Sema/TreeTransform.h
+++ lib/Sema/TreeTransform.h
@@ -5450,7 +5450,7 @@
   // decltype expressions are not potentially evaluated contexts
   EnterExpressionEvaluationContext Unevaluated(
   SemaRef, Sema::ExpressionEvaluationContext::Unevaluated, nullptr,
-  /*IsDecltype=*/true);
+  Sema::ExpressionType::Decltype);
 
   ExprResult E = getDerived().TransformExpr(T->getUnderlyingExpr());
   if (E.isInvalid())
Index: lib/Sema/SemaExprCXX.cpp
===
--- lib/Sema/SemaExprCXX.cpp
+++ lib/Sema/SemaExprCXX.cpp
@@ -6146,7 +6146,7 @@
   if (RD->isInvalidDecl() || RD->isDependentContext())
 return E;
 
-  bool IsDecltype = ExprEvalContexts.back().IsDecltype;
+  bool IsDecltype = ExprEvalContexts.back().Type == ExpressionType::Decltype;
   CXXDestructorDecl *Destructor = IsDecltype ? nullptr : LookupDestructor(RD);
 
   if (Destructor) {
@@ -6229,7 +6229,8 @@
 /// are omitted for the 'topmost' call in the decltype expression. If the
 /// topmost call bound a temporary, strip that temporary off the expression.
 ExprResult Sema::ActOnDecltypeExpression(Expr *E) {
-  assert(ExprEvalContexts.back().IsDecltype && "not in a decltype expression");
+  assert(ExprEvalContexts.back().Type == ExpressionType::Decltype &&
+ "not in a decltype expression");
 
   // C++11 [expr.call]p11:
   //   If a function call is a prvalue of object type,
@@ -6271,7 +6272,7 @@
 TopBind = nullptr;
 
   // Disable the special decltype handling now.
-  ExprEvalContexts.back().IsDecltype = false;
+  ExprEvalContexts.back().Type = ExpressionType::Other;
 
   // In MS mode, don't perform any extra checking of call return types within a
   // decltype expression.
Index: lib/Sema/SemaExpr.cpp
===
--- lib/Sema/SemaExpr.cpp
+++ lib/Sema/SemaExpr.cpp
@@ -13355,9 +13355,9 @@
 void
 Sema::PushExpressionEvaluationContext(ExpressionEvaluationContext NewContext,
   Decl *LambdaContextDecl,
-  bool IsDecltype) {
+  ExpressionType Type) {
   ExprEvalContexts.emplace_back(NewContext, ExprCleanupObjects.size(), Cleanup,
-LambdaContextDecl, IsDecltype);
+LambdaContextDecl, Type);
   Cleanup.reset();
   if (!MaybeODRUseExprs.empty())
 std::swap(MaybeODRUseExprs, ExprEvalContexts.back().SavedMaybeODRUseExprs);
@@ -13366,9 +13366,9 @@
 void
 Sema::PushExpressionEvaluationContext(ExpressionEvaluationContext NewContext,
   ReuseLambdaContextDecl_t,
-  bool IsDecltype) {
+  ExpressionType Type) {
   Decl *ClosureContextDecl = ExprEvalContexts.back().ManglingContextDecl;
-  PushExpressionEvaluationContext(NewContext, ClosureContextDecl, IsDecltype);
+  PushExpressionEvaluationContext(NewContext, ClosureContextDecl, Type);
 }
 
 void Sema::PopExpressionEvaluationContext() {
@@ -13376,7 +13376,8 @@
   unsigned NumTypos = Rec.NumTypos;
 
   if (!Rec.Lambdas.empty()) {
-if (Rec.isUnevaluated() || Rec.isConstantEvaluated()) {
+if (Rec.Type == ExpressionType::TemplateParameter || Rec.isUnevaluated() ||
+(Rec.isConstantEvaluated() && !getLangOpts().CPlusPlus1z)) {
   unsigned D;
   if (Rec.isUnevaluated()) {
 // C++11 [expr.prim.lambda]p2:
@@ -13383,23 +13384,21 @@
 //   A lambda-expression shall not appear in an unevaluated operand
 //   (Clause 5).
 D = diag::err_lambda_unevaluated_operand;
-  } else {
+  } else if (Rec.isConstantEvaluated() && !getLangOpts().CPlusPlus1z) {
 // C++1y [expr.const]p2:
 //   A conditional-expression e is a core constant expression unless the
  

[PATCH] D36527: Implemented P0428R2 - Familiar template syntax for generic lambdas

2017-09-09 Thread Blitz Rakete via Phabricator via cfe-commits
Rakete added a comment.

> Is that a problem?

I don't think so, because `shouldVisitImplicitCode()` doesn't mean that it only 
visits implicit code, it's not `onlyVisitImplicitCode()` :) In fact, I would be 
surprised if the template parameters were only visited once.




Comment at: lib/AST/ExprCXX.cpp:21
 #include "clang/Basic/IdentifierTable.h"
+#include "llvm/ADT/STLExtras.h"
 using namespace clang;

You don't need this header.



Comment at: lib/AST/ExprCXX.cpp:1010
+  return std::count_if(List->begin(), List->end(),
+   [](const NamedDecl *D) { return !D->isImplicit(); });
 }

You could store the lambda in a variable instead of having two times the same 
exact lambda expression.



Comment at: lib/Sema/SemaLambda.cpp:840
+  "template param scope");
+KnownDependent = TemplateParamScope->getParent()
+   ->getTemplateParamParent() != nullptr;

I think you should add an `assert` to verify that `getParent()` doesn't return 
`nullptr`, just to be safe from UB.



Comment at: unittests/AST/StmtPrinterTest.cpp:126
+ const T &NodeMatch, StringRef ExpectedPrinted) {
+  std::vector Args {
+"-std=c++98",

LLVM style guide says that if you are using a braced-init-list to initialize an 
object, you have to use an `=`.


https://reviews.llvm.org/D36527



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


[PATCH] D37667: [C++14][Sema] Disallow decltype(auto) deduction for lambdas

2017-09-10 Thread Blitz Rakete via Phabricator via cfe-commits
Rakete created this revision.

`decltype(auto) lambda = []{};` is currently allowed by clang, gcc and MSVC, 
but it is actually not valid, because `decltype([]{})` (which is how the type 
of `lambda` is deduced) is ill-formed, I think. I honestly could argue both 
ways (and I did once), but the fact that `decltype(auto) list = {0,1};` is 
already rejected by all three, it seems like the most sensible way is to 
disallow it for lambdas too.


https://reviews.llvm.org/D37667

Files:
  include/clang/Basic/DiagnosticSemaKinds.td
  lib/Sema/SemaTemplateDeduction.cpp
  test/CXX/dcl.dcl/dcl.spec/dcl.type/dcl.spec.auto/p7-1y.cpp


Index: test/CXX/dcl.dcl/dcl.spec/dcl.type/dcl.spec.auto/p7-1y.cpp
===
--- test/CXX/dcl.dcl/dcl.spec/dcl.type/dcl.spec.auto/p7-1y.cpp
+++ test/CXX/dcl.dcl/dcl.spec/dcl.type/dcl.spec.auto/p7-1y.cpp
@@ -96,3 +96,10 @@
 
 auto init_list_1() { return { 1, 2, 3 }; } // expected-error {{cannot deduce 
return type from initializer list}}
 decltype(auto) init_list_2() { return { 1, 2, 3 }; } // expected-error 
{{cannot deduce return type from initializer list}}
+
+auto auto_lambda() { return []{}; }
+decltype(auto) decltype_lambda() { return []{}; } // expected-error {{cannot 
deduce 'decltype(auto)' from lambda}}
+
+auto AutoLambda = []{};
+decltype(auto) DecltypeLambda = []{}; // expected-error {{cannot deduce 
'decltype(auto)' from lambda}}
+
Index: lib/Sema/SemaTemplateDeduction.cpp
===
--- lib/Sema/SemaTemplateDeduction.cpp
+++ lib/Sema/SemaTemplateDeduction.cpp
@@ -4314,6 +4314,9 @@
   if (isa(Init)) {
 Diag(Init->getLocStart(), diag::err_decltype_auto_initializer_list);
 return DAR_FailedAlreadyDiagnosed;
+  } else if (isa(Init)) {
+Diag(Init->getLocStart(), diag::err_decltype_auto_lambda);
+return DAR_FailedAlreadyDiagnosed;
   }
 
   QualType Deduced = BuildDecltypeType(Init, Init->getLocStart(), false);
Index: include/clang/Basic/DiagnosticSemaKinds.td
===
--- include/clang/Basic/DiagnosticSemaKinds.td
+++ include/clang/Basic/DiagnosticSemaKinds.td
@@ -2021,6 +2021,8 @@
   "cannot form %select{pointer to|reference to|array of}0 'decltype(auto)'">;
 def err_decltype_auto_initializer_list : Error<
   "cannot deduce 'decltype(auto)' from initializer list">;
+def err_decltype_auto_lambda : Error<
+  "cannot deduce 'decltype(auto)' from lambda">;
 
 // C++17 deduced class template specialization types
 def err_deduced_class_template_compound_type : Error<


Index: test/CXX/dcl.dcl/dcl.spec/dcl.type/dcl.spec.auto/p7-1y.cpp
===
--- test/CXX/dcl.dcl/dcl.spec/dcl.type/dcl.spec.auto/p7-1y.cpp
+++ test/CXX/dcl.dcl/dcl.spec/dcl.type/dcl.spec.auto/p7-1y.cpp
@@ -96,3 +96,10 @@
 
 auto init_list_1() { return { 1, 2, 3 }; } // expected-error {{cannot deduce return type from initializer list}}
 decltype(auto) init_list_2() { return { 1, 2, 3 }; } // expected-error {{cannot deduce return type from initializer list}}
+
+auto auto_lambda() { return []{}; }
+decltype(auto) decltype_lambda() { return []{}; } // expected-error {{cannot deduce 'decltype(auto)' from lambda}}
+
+auto AutoLambda = []{};
+decltype(auto) DecltypeLambda = []{}; // expected-error {{cannot deduce 'decltype(auto)' from lambda}}
+
Index: lib/Sema/SemaTemplateDeduction.cpp
===
--- lib/Sema/SemaTemplateDeduction.cpp
+++ lib/Sema/SemaTemplateDeduction.cpp
@@ -4314,6 +4314,9 @@
   if (isa(Init)) {
 Diag(Init->getLocStart(), diag::err_decltype_auto_initializer_list);
 return DAR_FailedAlreadyDiagnosed;
+  } else if (isa(Init)) {
+Diag(Init->getLocStart(), diag::err_decltype_auto_lambda);
+return DAR_FailedAlreadyDiagnosed;
   }
 
   QualType Deduced = BuildDecltypeType(Init, Init->getLocStart(), false);
Index: include/clang/Basic/DiagnosticSemaKinds.td
===
--- include/clang/Basic/DiagnosticSemaKinds.td
+++ include/clang/Basic/DiagnosticSemaKinds.td
@@ -2021,6 +2021,8 @@
   "cannot form %select{pointer to|reference to|array of}0 'decltype(auto)'">;
 def err_decltype_auto_initializer_list : Error<
   "cannot deduce 'decltype(auto)' from initializer list">;
+def err_decltype_auto_lambda : Error<
+  "cannot deduce 'decltype(auto)' from lambda">;
 
 // C++17 deduced class template specialization types
 def err_deduced_class_template_compound_type : Error<
___
cfe-commits mailing list
cfe-commits@lists.llvm.org
http://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits


[PATCH] D37667: [C++14][Sema] Disallow decltype(auto) deduction for lambdas

2017-09-11 Thread Blitz Rakete via Phabricator via cfe-commits
Rakete abandoned this revision.
Rakete added a comment.

Agreed. Closing this.


https://reviews.llvm.org/D37667



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


[PATCH] D36101: Fix usage of right shift operator in fold expressions

2017-07-31 Thread Blitz Rakete via Phabricator via cfe-commits
Rakete created this revision.

The right shift operator was not seen as a valid operator in a fold expression, 
which is PR32563.


https://reviews.llvm.org/D36101

Files:
  lib/Parse/ParseExpr.cpp
  test/CXX/expr/expr.prim/expr.prim.fold/p2.cpp


Index: test/CXX/expr/expr.prim/expr.prim.fold/p2.cpp
===
--- test/CXX/expr/expr.prim/expr.prim.fold/p2.cpp
+++ test/CXX/expr/expr.prim/expr.prim.fold/p2.cpp
@@ -0,0 +1,12 @@
+// RUN: %clang_cc1 -std=c++1z -verify %s
+
+// PR32563
+template
+constexpr int right_shift(int value, Ts... args) {
+  return (value >> ... >> args); // expected-no-diagnostics
+}
+
+void test_folds() {
+  static_assert(right_shift(10, 2) == 2);
+}
+
Index: lib/Parse/ParseExpr.cpp
===
--- lib/Parse/ParseExpr.cpp
+++ lib/Parse/ParseExpr.cpp
@@ -270,7 +270,7 @@
   return Level > prec::Unknown && Level != prec::Conditional;
 }
 static bool isFoldOperator(tok::TokenKind Kind) {
-  return isFoldOperator(getBinOpPrecedence(Kind, false, true));
+  return isFoldOperator(getBinOpPrecedence(Kind, true, true));
 }
 
 /// \brief Parse a binary expression that starts with \p LHS and has a


Index: test/CXX/expr/expr.prim/expr.prim.fold/p2.cpp
===
--- test/CXX/expr/expr.prim/expr.prim.fold/p2.cpp
+++ test/CXX/expr/expr.prim/expr.prim.fold/p2.cpp
@@ -0,0 +1,12 @@
+// RUN: %clang_cc1 -std=c++1z -verify %s
+
+// PR32563
+template
+constexpr int right_shift(int value, Ts... args) {
+  return (value >> ... >> args); // expected-no-diagnostics
+}
+
+void test_folds() {
+  static_assert(right_shift(10, 2) == 2);
+}
+
Index: lib/Parse/ParseExpr.cpp
===
--- lib/Parse/ParseExpr.cpp
+++ lib/Parse/ParseExpr.cpp
@@ -270,7 +270,7 @@
   return Level > prec::Unknown && Level != prec::Conditional;
 }
 static bool isFoldOperator(tok::TokenKind Kind) {
-  return isFoldOperator(getBinOpPrecedence(Kind, false, true));
+  return isFoldOperator(getBinOpPrecedence(Kind, true, true));
 }
 
 /// \brief Parse a binary expression that starts with \p LHS and has a
___
cfe-commits mailing list
cfe-commits@lists.llvm.org
http://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits


[PATCH] D36357: Added a better diagnostic when using the delete operator with lambdas

2017-08-05 Thread Blitz Rakete via Phabricator via cfe-commits
Rakete created this revision.

This adds a new error for missing parentheses around lambdas in delete 
operators.

  int main() {
delete []() { return new int(); }();
  }

This will result in:

  test.cpp:2:10: error: missing parentheses around lambda expression
delete []() { return new int(); }();
   ^~~
  1 error generated.




https://reviews.llvm.org/D36357

Files:
  include/clang/Basic/DiagnosticParseKinds.td
  lib/Parse/ParseExprCXX.cpp
  test/Parser/cxx0x-lambda-expressions.cpp
  test/SemaCXX/new-delete-0x.cpp


Index: test/SemaCXX/new-delete-0x.cpp
===
--- test/SemaCXX/new-delete-0x.cpp
+++ test/SemaCXX/new-delete-0x.cpp
@@ -34,6 +34,5 @@
 void bad_deletes()
 {
   // 'delete []' is always array delete, per [expr.delete]p1.
-  // FIXME: Give a better diagnostic.
-  delete []{ return (int*)0; }(); // expected-error {{expected expression}}
+  delete []{ return (int*)0; }(); // expected-error{{missing parentheses 
around lambda expression}}
 }
Index: test/Parser/cxx0x-lambda-expressions.cpp
===
--- test/Parser/cxx0x-lambda-expressions.cpp
+++ test/Parser/cxx0x-lambda-expressions.cpp
@@ -53,7 +53,7 @@
   void delete_lambda(int *p) {
 delete [] p;
 delete [] (int*) { new int }; // ok, compound-literal, not lambda
-delete [] { return new int; } (); // expected-error{{expected expression}}
+delete [] { return new int; } (); // expected-error{{missing parentheses 
around lambda expression}}
 delete [&] { return new int; } (); // ok, lambda
   }
 
Index: lib/Parse/ParseExprCXX.cpp
===
--- lib/Parse/ParseExprCXX.cpp
+++ lib/Parse/ParseExprCXX.cpp
@@ -2884,15 +2884,39 @@
 //   [Footnote: A lambda expression with a lambda-introducer that consists
 //  of empty square brackets can follow the delete keyword if
 //  the lambda expression is enclosed in parentheses.]
-// FIXME: Produce a better diagnostic if the '[]' is unambiguously a
-//lambda-introducer.
-ArrayDelete = true;
-BalancedDelimiterTracker T(*this, tok::l_square);
+TentativeParsingAction TPA(*this);
 
-T.consumeOpen();
-T.consumeClose();
-if (T.getCloseLocation().isInvalid())
-  return ExprError();
+// Basic lookahead to check if we have a lambda expression. If we
+// encounter two braces with a semicolon, we can be pretty sure
+// that this is a lambda, not say a compound literal. 
+if (!SkipUntil(tok::l_brace, SkipUntilFlags::StopAtSemi) ||
+(NextToken().isNot(tok::r_brace) && !SkipUntil(tok::semi)) ||
+!SkipUntil(tok::r_brace, SkipUntilFlags::StopAtSemi)) {
+  TPA.Revert();
+  ArrayDelete = true;
+  BalancedDelimiterTracker T(*this, tok::l_square);
+
+  T.consumeOpen();
+  T.consumeClose();
+  if (T.getCloseLocation().isInvalid())
+return ExprError();
+} else {
+  TPA.Revert();
+
+  // Warn if the non-capturing lambda isn't surrounded by parenthesis
+  // to disambiguate it from 'delete[]'. 
+  ExprResult Lambda = TryParseLambdaExpression();
+  if (!Lambda.isInvalid()) {
+SourceLocation StartLoc = Lambda.get()->getLocStart();
+Diag(StartLoc, diag::err_lambda_after_array_delete)
+  << SourceRange(StartLoc, Lambda.get()->getLocEnd());
+
+// Evaluate any postfix expressions used on the lambda.
+Lambda = ParsePostfixExpressionSuffix(Lambda);
+return Actions.ActOnCXXDelete(Start, UseGlobal, /*ArrayForm=*/false,
+  Lambda.get());
+  }
+}
   }
 
   ExprResult Operand(ParseCastExpression(false));
Index: include/clang/Basic/DiagnosticParseKinds.td
===
--- include/clang/Basic/DiagnosticParseKinds.td
+++ include/clang/Basic/DiagnosticParseKinds.td
@@ -99,6 +99,8 @@
   InGroup, DefaultIgnore;
 def ext_alignof_expr : ExtWarn<
   "%0 applied to an expression is a GNU extension">, 
InGroup;
+def err_lambda_after_array_delete : Error<
+  "missing parentheses around lambda expression">;
 
 def warn_microsoft_dependent_exists : Warning<
   "dependent %select{__if_not_exists|__if_exists}0 declarations are ignored">, 


Index: test/SemaCXX/new-delete-0x.cpp
===
--- test/SemaCXX/new-delete-0x.cpp
+++ test/SemaCXX/new-delete-0x.cpp
@@ -34,6 +34,5 @@
 void bad_deletes()
 {
   // 'delete []' is always array delete, per [expr.delete]p1.
-  // FIXME: Give a better diagnostic.
-  delete []{ return (int*)0; }(); // expected-error {{expected expression}}
+  delete []{ return (int*)0; }(); // expected-error{{missing parentheses around lambda expression}}
 }
Index: test/Parser/cxx0x-lambda-expressions.cpp
==

[PATCH] D36101: Fix usage of right shift operator in fold expressions

2017-08-08 Thread Blitz Rakete via Phabricator via cfe-commits
Rakete added a comment.

Ping?


https://reviews.llvm.org/D36101



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


[PATCH] D36855: Fixed pointer to const& member function on rvalues, P0704r1

2017-08-17 Thread Blitz Rakete via Phabricator via cfe-commits
Rakete created this revision.

This patch allows pointer to const& member functions on rvalues for C++20, and 
as an extension for prior versions. This is P0704r1 
.


https://reviews.llvm.org/D36855

Files:
  include/clang/Basic/DiagnosticGroups.td
  include/clang/Basic/DiagnosticSemaKinds.td
  lib/Sema/SemaExprCXX.cpp
  www/cxx_status.html

Index: www/cxx_status.html
===
--- www/cxx_status.html
+++ www/cxx_status.html
@@ -777,13 +777,12 @@
 
 C++2a implementation status
 
-Clang does not yet support any of the proposed features of
-
+Clang has experimental support for some proposed features of
 the C++ standard following C++17, provisionally named C++2a.
 Note that support for these features may change or be removed without notice,
 as the draft C++2a standard evolves.
 
-
+You can use Clang in C++2a mode with the -std=c++2a option.
 
 
 List of features and minimum Clang version with support
@@ -803,7 +802,7 @@
 
   const&-qualified pointers to members
   http://wg21.link/p0704r1";>P0704R1
-  No
+  SVN
 
 
   Allow lambda-capture [=, this]
Index: lib/Sema/SemaExprCXX.cpp
===
--- lib/Sema/SemaExprCXX.cpp
+++ lib/Sema/SemaExprCXX.cpp
@@ -5175,9 +5175,16 @@
   break;
 
 case RQ_LValue:
-  if (!isIndirect && !LHS.get()->Classify(Context).isLValue())
-Diag(Loc, diag::err_pointer_to_member_oper_value_classify)
-  << RHSType << 1 << LHS.get()->getSourceRange();
+  if (!isIndirect && !LHS.get()->Classify(Context).isLValue()) {
+// C++2a allows functions with ref-qualifier & if they are also 'const'.
+if (Proto->isConst())
+  Diag(Loc, getLangOpts().CPlusPlus2a
+? diag::warn_cxx17_compat_pointer_to_const_ref_member_on_rvalue
+: diag::ext_pointer_to_const_ref_member_on_rvalue);
+else
+  Diag(Loc, diag::err_pointer_to_member_oper_value_classify)
+  << RHSType << 1 << LHS.get()->getSourceRange();
+  }
   break;
 
 case RQ_RValue:
Index: include/clang/Basic/DiagnosticSemaKinds.td
===
--- include/clang/Basic/DiagnosticSemaKinds.td
+++ include/clang/Basic/DiagnosticSemaKinds.td
@@ -4088,6 +4088,13 @@
 def err_pointer_to_member_oper_value_classify: Error<
   "pointer-to-member function type %0 can only be called on an "
   "%select{rvalue|lvalue}1">;
+def ext_pointer_to_const_ref_member_on_rvalue : ExtWarn<
+  "pointer-to-member to const& function on an rvalue is a C++2a extension">,
+  InGroup;
+def warn_cxx17_compat_pointer_to_const_ref_member_on_rvalue : Warning<
+  "pointer-to-member function for const& member function on rvalues is "
+  "incompatible with C++ standards before C++2a">,
+  InGroup, DefaultIgnore;
 def ext_ms_deref_template_argument: ExtWarn<
   "non-type template argument containing a dereference operation is a "
   "Microsoft extension">, InGroup;
Index: include/clang/Basic/DiagnosticGroups.td
===
--- include/clang/Basic/DiagnosticGroups.td
+++ include/clang/Basic/DiagnosticGroups.td
@@ -169,6 +169,9 @@
 def CXXPre1zCompatPedantic : DiagGroup<"c++98-c++11-c++14-compat-pedantic",
[CXXPre1zCompat]>;
 
+// Warnings for C++2a code which is not compatible with prior C++ standards.
+def CXXPre2aCompat : DiagGroup<"c++98-c++11-c++14-c++17-compat">;
+
 def CXX98CompatBindToTemporaryCopy :
   DiagGroup<"c++98-compat-bind-to-temporary-copy">;
 def CXX98CompatLocalTypeTemplateArgs :
@@ -180,7 +183,8 @@
 [CXX98CompatLocalTypeTemplateArgs,
  CXX98CompatUnnamedTypeTemplateArgs,
  CXXPre14Compat,
- CXXPre1zCompat]>;
+ CXXPre1zCompat,
+ CXXPre2aCompat]>;
 // Warnings for C++11 features which are Extensions in C++98 mode.
 def CXX98CompatPedantic : DiagGroup<"c++98-compat-pedantic",
 [CXX98Compat,
@@ -211,7 +215,8 @@
  CXX11CompatReservedUserDefinedLiteral,
  CXX11CompatDeprecatedWritableStr,
  CXXPre14Compat,
- CXXPre1zCompat]>;
+ CXXPre1zCompat,
+ CXXPre2aCompat]>;
 def : DiagGroup<"c++0x-compat", [CXX11Compat]>;
 def CXX11CompatPedantic : DiagGroup<"c++11-compat-pedantic",
 [CXXPre14CompatPedantic,
@@ -784,9 +789,14 @@
 // earlier C++ versions.
 def CXX17 : DiagGroup<"c++17-extensions">;
 
+// A warning group for warnings about using C++2a features as extensions in
+// earlier

[PATCH] D36855: Fixed pointer to const& member function on rvalues, P0704r1

2017-08-17 Thread Blitz Rakete via Phabricator via cfe-commits
Rakete updated this revision to Diff 111602.
Rakete added a comment.

Thanks! Agreed, your wording is better than mine :)


https://reviews.llvm.org/D36855

Files:
  include/clang/Basic/DiagnosticGroups.td
  include/clang/Basic/DiagnosticSemaKinds.td
  lib/Sema/SemaExprCXX.cpp
  test/SemaCXX/cxx2a-pointer-to-const-ref-member.cpp
  www/cxx_status.html

Index: www/cxx_status.html
===
--- www/cxx_status.html
+++ www/cxx_status.html
@@ -777,13 +777,12 @@
 
 C++2a implementation status
 
-Clang does not yet support any of the proposed features of
-
+Clang has experimental support for some proposed features of
 the C++ standard following C++17, provisionally named C++2a.
 Note that support for these features may change or be removed without notice,
 as the draft C++2a standard evolves.
 
-
+You can use Clang in C++2a mode with the -std=c++2a option.
 
 
 List of features and minimum Clang version with support
@@ -803,7 +802,7 @@
 
   const&-qualified pointers to members
   http://wg21.link/p0704r1";>P0704R1
-  No
+  SVN
 
 
   Allow lambda-capture [=, this]
Index: test/SemaCXX/cxx2a-pointer-to-const-ref-member.cpp
===
--- test/SemaCXX/cxx2a-pointer-to-const-ref-member.cpp
+++ test/SemaCXX/cxx2a-pointer-to-const-ref-member.cpp
@@ -0,0 +1,14 @@
+// RUN: %clang_cc1 -std=c++2a %s -verify
+
+struct X {
+  void ref() & {}
+  void cref() const& {}
+};
+
+void test() {
+  X{}.ref(); // expected-error{{cannot initialize object parameter of type 'X' with an expression of type 'X'}}
+  X{}.cref(); // expected-no-error
+
+  (X{}.*&X::ref)(); // expected-error{{pointer-to-member function type 'void (X::*)() &' can only be called on an lvalue}}
+  (X{}.*&X::cref)(); // expected-no-error
+}
Index: lib/Sema/SemaExprCXX.cpp
===
--- lib/Sema/SemaExprCXX.cpp
+++ lib/Sema/SemaExprCXX.cpp
@@ -5175,9 +5175,16 @@
   break;
 
 case RQ_LValue:
-  if (!isIndirect && !LHS.get()->Classify(Context).isLValue())
-Diag(Loc, diag::err_pointer_to_member_oper_value_classify)
-  << RHSType << 1 << LHS.get()->getSourceRange();
+  if (!isIndirect && !LHS.get()->Classify(Context).isLValue()) {
+// C++2a allows functions with ref-qualifier & if they are also 'const'.
+if (Proto->isConst())
+  Diag(Loc, getLangOpts().CPlusPlus2a
+? diag::warn_cxx17_compat_pointer_to_const_ref_member_on_rvalue
+: diag::ext_pointer_to_const_ref_member_on_rvalue);
+else
+  Diag(Loc, diag::err_pointer_to_member_oper_value_classify)
+  << RHSType << 1 << LHS.get()->getSourceRange();
+  }
   break;
 
 case RQ_RValue:
Index: include/clang/Basic/DiagnosticSemaKinds.td
===
--- include/clang/Basic/DiagnosticSemaKinds.td
+++ include/clang/Basic/DiagnosticSemaKinds.td
@@ -4088,6 +4088,13 @@
 def err_pointer_to_member_oper_value_classify: Error<
   "pointer-to-member function type %0 can only be called on an "
   "%select{rvalue|lvalue}1">;
+def ext_pointer_to_const_ref_member_on_rvalue : Extension<
+  "invoking a pointer to a 'const &' member function on an rvalue is a C++2a extension">,
+  InGroup, SFINAEFailure;
+def warn_cxx17_compat_pointer_to_const_ref_member_on_rvalue : Warning<
+  "pointer-to-member function for const& member function on rvalues is "
+  "incompatible with C++ standards before C++2a">,
+  InGroup, DefaultIgnore;
 def ext_ms_deref_template_argument: ExtWarn<
   "non-type template argument containing a dereference operation is a "
   "Microsoft extension">, InGroup;
Index: include/clang/Basic/DiagnosticGroups.td
===
--- include/clang/Basic/DiagnosticGroups.td
+++ include/clang/Basic/DiagnosticGroups.td
@@ -169,6 +169,9 @@
 def CXXPre1zCompatPedantic : DiagGroup<"c++98-c++11-c++14-compat-pedantic",
[CXXPre1zCompat]>;
 
+// Warnings for C++2a code which is not compatible with prior C++ standards.
+def CXXPre2aCompat : DiagGroup<"c++98-c++11-c++14-c++17-compat">;
+
 def CXX98CompatBindToTemporaryCopy :
   DiagGroup<"c++98-compat-bind-to-temporary-copy">;
 def CXX98CompatLocalTypeTemplateArgs :
@@ -180,7 +183,8 @@
 [CXX98CompatLocalTypeTemplateArgs,
  CXX98CompatUnnamedTypeTemplateArgs,
  CXXPre14Compat,
- CXXPre1zCompat]>;
+ CXXPre1zCompat,
+ CXXPre2aCompat]>;
 // Warnings for C++11 features which are Extensions in C++98 mode.
 def CXX98CompatPedantic : DiagGroup<"c++98-compat-pedantic",
 [CXX98Compat,
@@ -211,7 +215,8 @@
   

[PATCH] D36855: Fixed pointer to const& member function on rvalues, P0704r1

2017-08-18 Thread Blitz Rakete via Phabricator via cfe-commits
Rakete updated this revision to Diff 111719.
Rakete marked 3 inline comments as done.
Rakete added a comment.

Yes please.


https://reviews.llvm.org/D36855

Files:
  include/clang/Basic/DiagnosticGroups.td
  include/clang/Basic/DiagnosticSemaKinds.td
  lib/Sema/SemaExprCXX.cpp
  test/SemaCXX/cxx2a-pointer-to-const-ref-member.cpp
  www/cxx_status.html

Index: www/cxx_status.html
===
--- www/cxx_status.html
+++ www/cxx_status.html
@@ -777,13 +777,12 @@
 
 C++2a implementation status
 
-Clang does not yet support any of the proposed features of
-
+Clang has experimental support for some proposed features of
 the C++ standard following C++17, provisionally named C++2a.
 Note that support for these features may change or be removed without notice,
 as the draft C++2a standard evolves.
 
-
+You can use Clang in C++2a mode with the -std=c++2a option.
 
 
 List of features and minimum Clang version with support
@@ -803,7 +802,7 @@
 
   const&-qualified pointers to members
   http://wg21.link/p0704r1";>P0704R1
-  No
+  SVN
 
 
   Allow lambda-capture [=, this]
Index: test/SemaCXX/cxx2a-pointer-to-const-ref-member.cpp
===
--- test/SemaCXX/cxx2a-pointer-to-const-ref-member.cpp
+++ test/SemaCXX/cxx2a-pointer-to-const-ref-member.cpp
@@ -0,0 +1,14 @@
+// RUN: %clang_cc1 -std=c++2a %s -verify
+
+struct X {
+  void ref() & {}
+  void cref() const& {}
+};
+
+void test() {
+  X{}.ref(); // expected-error{{cannot initialize object parameter of type 'X' with an expression of type 'X'}}
+  X{}.cref(); // expected-no-error
+
+  (X{}.*&X::ref)(); // expected-error{{pointer-to-member function type 'void (X::*)() &' can only be called on an lvalue}}
+  (X{}.*&X::cref)(); // expected-no-error
+}
Index: lib/Sema/SemaExprCXX.cpp
===
--- lib/Sema/SemaExprCXX.cpp
+++ lib/Sema/SemaExprCXX.cpp
@@ -5175,9 +5175,16 @@
   break;
 
 case RQ_LValue:
-  if (!isIndirect && !LHS.get()->Classify(Context).isLValue())
-Diag(Loc, diag::err_pointer_to_member_oper_value_classify)
-  << RHSType << 1 << LHS.get()->getSourceRange();
+  if (!isIndirect && !LHS.get()->Classify(Context).isLValue()) {
+// C++2a allows functions with ref-qualifier & if they are also 'const'.
+if (Proto->isConst())
+  Diag(Loc, getLangOpts().CPlusPlus2a
+? diag::warn_cxx17_compat_pointer_to_const_ref_member_on_rvalue
+: diag::ext_pointer_to_const_ref_member_on_rvalue);
+else
+  Diag(Loc, diag::err_pointer_to_member_oper_value_classify)
+  << RHSType << 1 << LHS.get()->getSourceRange();
+  }
   break;
 
 case RQ_RValue:
Index: include/clang/Basic/DiagnosticSemaKinds.td
===
--- include/clang/Basic/DiagnosticSemaKinds.td
+++ include/clang/Basic/DiagnosticSemaKinds.td
@@ -4088,6 +4088,13 @@
 def err_pointer_to_member_oper_value_classify: Error<
   "pointer-to-member function type %0 can only be called on an "
   "%select{rvalue|lvalue}1">;
+def ext_pointer_to_const_ref_member_on_rvalue : Extension<
+  "invoking a pointer to a 'const &' member function on an rvalue is a C++2a extension">,
+  InGroup;
+def warn_cxx17_compat_pointer_to_const_ref_member_on_rvalue : Warning<
+  "invoking a pointer to a 'const &' member function on an rvalue is "
+  "incompatible with C++ standards before C++2a">,
+  InGroup, DefaultIgnore, SFINAEFailure;
 def ext_ms_deref_template_argument: ExtWarn<
   "non-type template argument containing a dereference operation is a "
   "Microsoft extension">, InGroup;
Index: include/clang/Basic/DiagnosticGroups.td
===
--- include/clang/Basic/DiagnosticGroups.td
+++ include/clang/Basic/DiagnosticGroups.td
@@ -169,6 +169,11 @@
 def CXXPre1zCompatPedantic : DiagGroup<"c++98-c++11-c++14-compat-pedantic",
[CXXPre1zCompat]>;
 
+// Warnings for C++2a code which is not compatible with prior C++ standards.
+def CXXPre2aCompat : DiagGroup<"c++98-c++11-c++14-c++17-compat">;
+def CXXPre2aCompatPedantic :
+  DiagGroup<"c++98-c++11-c++14-c++17-compat-pedantic", [CXXPre2aCompat]>;
+
 def CXX98CompatBindToTemporaryCopy :
   DiagGroup<"c++98-compat-bind-to-temporary-copy">;
 def CXX98CompatLocalTypeTemplateArgs :
@@ -180,7 +185,8 @@
 [CXX98CompatLocalTypeTemplateArgs,
  CXX98CompatUnnamedTypeTemplateArgs,
  CXXPre14Compat,
- CXXPre1zCompat]>;
+ CXXPre1zCompat,
+ CXXPre2aCompat]>;
 // Warnings for C++11 features which are Extensions in C++98 mode.
 def CXX98CompatPedantic : Diag

[PATCH] D36855: Fixed pointer to const& member function on rvalues, P0704r1

2017-08-18 Thread Blitz Rakete via Phabricator via cfe-commits
Rakete updated this revision to Diff 111800.
Rakete added a comment.

Rebased because another commit already added the definitions of the C++20 
groups.


https://reviews.llvm.org/D36855

Files:
  include/clang/Basic/DiagnosticSemaKinds.td
  lib/Sema/SemaExprCXX.cpp
  test/SemaCXX/cxx2a-pointer-to-const-ref-member.cpp


Index: test/SemaCXX/cxx2a-pointer-to-const-ref-member.cpp
===
--- test/SemaCXX/cxx2a-pointer-to-const-ref-member.cpp
+++ test/SemaCXX/cxx2a-pointer-to-const-ref-member.cpp
@@ -0,0 +1,14 @@
+// RUN: %clang_cc1 -std=c++2a %s -verify
+
+struct X {
+  void ref() & {}
+  void cref() const& {}
+};
+
+void test() {
+  X{}.ref(); // expected-error{{cannot initialize object parameter of type 'X' 
with an expression of type 'X'}}
+  X{}.cref(); // expected-no-error
+
+  (X{}.*&X::ref)(); // expected-error{{pointer-to-member function type 'void 
(X::*)() &' can only be called on an lvalue}}
+  (X{}.*&X::cref)(); // expected-no-error
+}
Index: lib/Sema/SemaExprCXX.cpp
===
--- lib/Sema/SemaExprCXX.cpp
+++ lib/Sema/SemaExprCXX.cpp
@@ -5175,9 +5175,16 @@
   break;
 
 case RQ_LValue:
-  if (!isIndirect && !LHS.get()->Classify(Context).isLValue())
-Diag(Loc, diag::err_pointer_to_member_oper_value_classify)
-  << RHSType << 1 << LHS.get()->getSourceRange();
+  if (!isIndirect && !LHS.get()->Classify(Context).isLValue()) {
+// C++2a allows functions with ref-qualifier & if they are also 
'const'.
+if (Proto->isConst())
+  Diag(Loc, getLangOpts().CPlusPlus2a
+? 
diag::warn_cxx17_compat_pointer_to_const_ref_member_on_rvalue
+: diag::ext_pointer_to_const_ref_member_on_rvalue);
+else
+  Diag(Loc, diag::err_pointer_to_member_oper_value_classify)
+  << RHSType << 1 << LHS.get()->getSourceRange();
+  }
   break;
 
 case RQ_RValue:
Index: include/clang/Basic/DiagnosticSemaKinds.td
===
--- include/clang/Basic/DiagnosticSemaKinds.td
+++ include/clang/Basic/DiagnosticSemaKinds.td
@@ -4088,6 +4088,13 @@
 def err_pointer_to_member_oper_value_classify: Error<
   "pointer-to-member function type %0 can only be called on an "
   "%select{rvalue|lvalue}1">;
+def ext_pointer_to_const_ref_member_on_rvalue : Extension<
+  "invoking a pointer to a 'const &' member function on an rvalue is a C++2a 
extension">,
+  InGroup;
+def warn_cxx17_compat_pointer_to_const_ref_member_on_rvalue : Warning<
+  "invoking a pointer to a 'const &' member function on an rvalue is "
+  "incompatible with C++ standards before C++2a">,
+  InGroup, DefaultIgnore, SFINAEFailure;
 def ext_ms_deref_template_argument: ExtWarn<
   "non-type template argument containing a dereference operation is a "
   "Microsoft extension">, InGroup;


Index: test/SemaCXX/cxx2a-pointer-to-const-ref-member.cpp
===
--- test/SemaCXX/cxx2a-pointer-to-const-ref-member.cpp
+++ test/SemaCXX/cxx2a-pointer-to-const-ref-member.cpp
@@ -0,0 +1,14 @@
+// RUN: %clang_cc1 -std=c++2a %s -verify
+
+struct X {
+  void ref() & {}
+  void cref() const& {}
+};
+
+void test() {
+  X{}.ref(); // expected-error{{cannot initialize object parameter of type 'X' with an expression of type 'X'}}
+  X{}.cref(); // expected-no-error
+
+  (X{}.*&X::ref)(); // expected-error{{pointer-to-member function type 'void (X::*)() &' can only be called on an lvalue}}
+  (X{}.*&X::cref)(); // expected-no-error
+}
Index: lib/Sema/SemaExprCXX.cpp
===
--- lib/Sema/SemaExprCXX.cpp
+++ lib/Sema/SemaExprCXX.cpp
@@ -5175,9 +5175,16 @@
   break;
 
 case RQ_LValue:
-  if (!isIndirect && !LHS.get()->Classify(Context).isLValue())
-Diag(Loc, diag::err_pointer_to_member_oper_value_classify)
-  << RHSType << 1 << LHS.get()->getSourceRange();
+  if (!isIndirect && !LHS.get()->Classify(Context).isLValue()) {
+// C++2a allows functions with ref-qualifier & if they are also 'const'.
+if (Proto->isConst())
+  Diag(Loc, getLangOpts().CPlusPlus2a
+? diag::warn_cxx17_compat_pointer_to_const_ref_member_on_rvalue
+: diag::ext_pointer_to_const_ref_member_on_rvalue);
+else
+  Diag(Loc, diag::err_pointer_to_member_oper_value_classify)
+  << RHSType << 1 << LHS.get()->getSourceRange();
+  }
   break;
 
 case RQ_RValue:
Index: include/clang/Basic/DiagnosticSemaKinds.td
===
--- include/clang/Basic/DiagnosticSemaKinds.td
+++ include/clang/Basic/DiagnosticSemaKinds.td
@@ -4088,6 +4088,13 @@
 def err_pointer_to_member_oper_value_classify: Error<
   "pointer-to-member function type

[PATCH] D36855: Fixed pointer to const& member function on rvalues, P0704r1

2017-08-18 Thread Blitz Rakete via Phabricator via cfe-commits
Rakete updated this revision to Diff 111801.

https://reviews.llvm.org/D36855

Files:
  include/clang/Basic/DiagnosticSemaKinds.td
  lib/Sema/SemaExprCXX.cpp
  test/SemaCXX/cxx2a-pointer-to-const-ref-member.cpp


Index: test/SemaCXX/cxx2a-pointer-to-const-ref-member.cpp
===
--- test/SemaCXX/cxx2a-pointer-to-const-ref-member.cpp
+++ test/SemaCXX/cxx2a-pointer-to-const-ref-member.cpp
@@ -0,0 +1,14 @@
+// RUN: %clang_cc1 -std=c++2a %s -verify
+
+struct X {
+  void ref() & {}
+  void cref() const& {}
+};
+
+void test() {
+  X{}.ref(); // expected-error{{cannot initialize object parameter of type 'X' 
with an expression of type 'X'}}
+  X{}.cref(); // expected-no-error
+
+  (X{}.*&X::ref)(); // expected-error{{pointer-to-member function type 'void 
(X::*)() &' can only be called on an lvalue}}
+  (X{}.*&X::cref)(); // expected-no-error
+}
Index: lib/Sema/SemaExprCXX.cpp
===
--- lib/Sema/SemaExprCXX.cpp
+++ lib/Sema/SemaExprCXX.cpp
@@ -5175,9 +5175,16 @@
   break;
 
 case RQ_LValue:
-  if (!isIndirect && !LHS.get()->Classify(Context).isLValue())
-Diag(Loc, diag::err_pointer_to_member_oper_value_classify)
-  << RHSType << 1 << LHS.get()->getSourceRange();
+  if (!isIndirect && !LHS.get()->Classify(Context).isLValue()) {
+// C++2a allows functions with ref-qualifier & if they are also 
'const'.
+if (Proto->isConst())
+  Diag(Loc, getLangOpts().CPlusPlus2a
+? 
diag::warn_cxx17_compat_pointer_to_const_ref_member_on_rvalue
+: diag::ext_pointer_to_const_ref_member_on_rvalue);
+else
+  Diag(Loc, diag::err_pointer_to_member_oper_value_classify)
+  << RHSType << 1 << LHS.get()->getSourceRange();
+  }
   break;
 
 case RQ_RValue:
Index: include/clang/Basic/DiagnosticSemaKinds.td
===
--- include/clang/Basic/DiagnosticSemaKinds.td
+++ include/clang/Basic/DiagnosticSemaKinds.td
@@ -4088,6 +4088,13 @@
 def err_pointer_to_member_oper_value_classify: Error<
   "pointer-to-member function type %0 can only be called on an "
   "%select{rvalue|lvalue}1">;
+def ext_pointer_to_const_ref_member_on_rvalue : Extension<
+  "invoking a pointer to a 'const &' member function on an rvalue is a C++2a 
extension">,
+  InGroup, SFINAEFailure;
+def warn_cxx17_compat_pointer_to_const_ref_member_on_rvalue : Warning<
+  "invoking a pointer to a 'const &' member function on an rvalue is "
+  "incompatible with C++ standards before C++2a">,
+  InGroup, DefaultIgnore;
 def ext_ms_deref_template_argument: ExtWarn<
   "non-type template argument containing a dereference operation is a "
   "Microsoft extension">, InGroup;


Index: test/SemaCXX/cxx2a-pointer-to-const-ref-member.cpp
===
--- test/SemaCXX/cxx2a-pointer-to-const-ref-member.cpp
+++ test/SemaCXX/cxx2a-pointer-to-const-ref-member.cpp
@@ -0,0 +1,14 @@
+// RUN: %clang_cc1 -std=c++2a %s -verify
+
+struct X {
+  void ref() & {}
+  void cref() const& {}
+};
+
+void test() {
+  X{}.ref(); // expected-error{{cannot initialize object parameter of type 'X' with an expression of type 'X'}}
+  X{}.cref(); // expected-no-error
+
+  (X{}.*&X::ref)(); // expected-error{{pointer-to-member function type 'void (X::*)() &' can only be called on an lvalue}}
+  (X{}.*&X::cref)(); // expected-no-error
+}
Index: lib/Sema/SemaExprCXX.cpp
===
--- lib/Sema/SemaExprCXX.cpp
+++ lib/Sema/SemaExprCXX.cpp
@@ -5175,9 +5175,16 @@
   break;
 
 case RQ_LValue:
-  if (!isIndirect && !LHS.get()->Classify(Context).isLValue())
-Diag(Loc, diag::err_pointer_to_member_oper_value_classify)
-  << RHSType << 1 << LHS.get()->getSourceRange();
+  if (!isIndirect && !LHS.get()->Classify(Context).isLValue()) {
+// C++2a allows functions with ref-qualifier & if they are also 'const'.
+if (Proto->isConst())
+  Diag(Loc, getLangOpts().CPlusPlus2a
+? diag::warn_cxx17_compat_pointer_to_const_ref_member_on_rvalue
+: diag::ext_pointer_to_const_ref_member_on_rvalue);
+else
+  Diag(Loc, diag::err_pointer_to_member_oper_value_classify)
+  << RHSType << 1 << LHS.get()->getSourceRange();
+  }
   break;
 
 case RQ_RValue:
Index: include/clang/Basic/DiagnosticSemaKinds.td
===
--- include/clang/Basic/DiagnosticSemaKinds.td
+++ include/clang/Basic/DiagnosticSemaKinds.td
@@ -4088,6 +4088,13 @@
 def err_pointer_to_member_oper_value_classify: Error<
   "pointer-to-member function type %0 can only be called on an "
   "%select{rvalue|lvalue}1">;
+def ext_pointer_to_const_ref_member_on_rvalue : Ex

[PATCH] D36855: Fixed pointer to const& member function on rvalues, P0704r1

2017-08-19 Thread Blitz Rakete via Phabricator via cfe-commits
Rakete updated this revision to Diff 111840.
Rakete marked 2 inline comments as done.
Rakete added a comment.

Update entry on the C++ status page.


https://reviews.llvm.org/D36855

Files:
  include/clang/Basic/DiagnosticSemaKinds.td
  lib/Sema/SemaExprCXX.cpp
  test/SemaCXX/cxx2a-pointer-to-const-ref-member.cpp
  www/cxx_status.html


Index: www/cxx_status.html
===
--- www/cxx_status.html
+++ www/cxx_status.html
@@ -802,7 +802,7 @@
 
   const&-qualified pointers to members
   http://wg21.link/p0704r1";>P0704R1
-  No
+  SVN
 
 
   Allow lambda-capture [=, this]
Index: test/SemaCXX/cxx2a-pointer-to-const-ref-member.cpp
===
--- test/SemaCXX/cxx2a-pointer-to-const-ref-member.cpp
+++ test/SemaCXX/cxx2a-pointer-to-const-ref-member.cpp
@@ -0,0 +1,14 @@
+// RUN: %clang_cc1 -std=c++2a %s -verify
+
+struct X {
+  void ref() & {}
+  void cref() const& {}
+};
+
+void test() {
+  X{}.ref(); // expected-error{{cannot initialize object parameter of type 'X' 
with an expression of type 'X'}}
+  X{}.cref(); // expected-no-error
+
+  (X{}.*&X::ref)(); // expected-error{{pointer-to-member function type 'void 
(X::*)() &' can only be called on an lvalue}}
+  (X{}.*&X::cref)(); // expected-no-error
+}
Index: lib/Sema/SemaExprCXX.cpp
===
--- lib/Sema/SemaExprCXX.cpp
+++ lib/Sema/SemaExprCXX.cpp
@@ -5175,9 +5175,16 @@
   break;
 
 case RQ_LValue:
-  if (!isIndirect && !LHS.get()->Classify(Context).isLValue())
-Diag(Loc, diag::err_pointer_to_member_oper_value_classify)
-  << RHSType << 1 << LHS.get()->getSourceRange();
+  if (!isIndirect && !LHS.get()->Classify(Context).isLValue()) {
+// C++2a allows functions with ref-qualifier & if they are also 
'const'.
+if (Proto->isConst())
+  Diag(Loc, getLangOpts().CPlusPlus2a
+? 
diag::warn_cxx17_compat_pointer_to_const_ref_member_on_rvalue
+: diag::ext_pointer_to_const_ref_member_on_rvalue);
+else
+  Diag(Loc, diag::err_pointer_to_member_oper_value_classify)
+  << RHSType << 1 << LHS.get()->getSourceRange();
+  }
   break;
 
 case RQ_RValue:
Index: include/clang/Basic/DiagnosticSemaKinds.td
===
--- include/clang/Basic/DiagnosticSemaKinds.td
+++ include/clang/Basic/DiagnosticSemaKinds.td
@@ -4088,6 +4088,13 @@
 def err_pointer_to_member_oper_value_classify: Error<
   "pointer-to-member function type %0 can only be called on an "
   "%select{rvalue|lvalue}1">;
+def ext_pointer_to_const_ref_member_on_rvalue : Extension<
+  "invoking a pointer to a 'const &' member function on an rvalue is a C++2a 
extension">,
+  InGroup, SFINAEFailure;
+def warn_cxx17_compat_pointer_to_const_ref_member_on_rvalue : Warning<
+  "invoking a pointer to a 'const &' member function on an rvalue is "
+  "incompatible with C++ standards before C++2a">,
+  InGroup, DefaultIgnore;
 def ext_ms_deref_template_argument: ExtWarn<
   "non-type template argument containing a dereference operation is a "
   "Microsoft extension">, InGroup;


Index: www/cxx_status.html
===
--- www/cxx_status.html
+++ www/cxx_status.html
@@ -802,7 +802,7 @@
 
   const&-qualified pointers to members
   http://wg21.link/p0704r1";>P0704R1
-  No
+  SVN
 
 
   Allow lambda-capture [=, this]
Index: test/SemaCXX/cxx2a-pointer-to-const-ref-member.cpp
===
--- test/SemaCXX/cxx2a-pointer-to-const-ref-member.cpp
+++ test/SemaCXX/cxx2a-pointer-to-const-ref-member.cpp
@@ -0,0 +1,14 @@
+// RUN: %clang_cc1 -std=c++2a %s -verify
+
+struct X {
+  void ref() & {}
+  void cref() const& {}
+};
+
+void test() {
+  X{}.ref(); // expected-error{{cannot initialize object parameter of type 'X' with an expression of type 'X'}}
+  X{}.cref(); // expected-no-error
+
+  (X{}.*&X::ref)(); // expected-error{{pointer-to-member function type 'void (X::*)() &' can only be called on an lvalue}}
+  (X{}.*&X::cref)(); // expected-no-error
+}
Index: lib/Sema/SemaExprCXX.cpp
===
--- lib/Sema/SemaExprCXX.cpp
+++ lib/Sema/SemaExprCXX.cpp
@@ -5175,9 +5175,16 @@
   break;
 
 case RQ_LValue:
-  if (!isIndirect && !LHS.get()->Classify(Context).isLValue())
-Diag(Loc, diag::err_pointer_to_member_oper_value_classify)
-  << RHSType << 1 << LHS.get()->getSourceRange();
+  if (!isIndirect && !LHS.get()->Classify(Context).isLValue()) {
+// C++2a allows functions with ref-qualifier & if they are also 'const'.
+if (Proto->isConst())
+  Diag(Loc, getLangOpts().CPlusPlus2a
+  

[PATCH] D36357: Added a better diagnostic when using the delete operator with lambdas

2017-08-21 Thread Blitz Rakete via Phabricator via cfe-commits
Rakete updated this revision to Diff 112103.
Rakete added a comment.

Rebased and friendly ping.


https://reviews.llvm.org/D36357

Files:
  include/clang/Basic/DiagnosticParseKinds.td
  lib/Parse/ParseExprCXX.cpp
  test/Parser/cxx0x-lambda-expressions.cpp
  test/SemaCXX/new-delete-0x.cpp


Index: test/SemaCXX/new-delete-0x.cpp
===
--- test/SemaCXX/new-delete-0x.cpp
+++ test/SemaCXX/new-delete-0x.cpp
@@ -34,6 +34,5 @@
 void bad_deletes()
 {
   // 'delete []' is always array delete, per [expr.delete]p1.
-  // FIXME: Give a better diagnostic.
-  delete []{ return (int*)0; }(); // expected-error {{expected expression}}
+  delete []{ return (int*)0; }(); // expected-error{{missing parentheses 
around lambda expression}}
 }
Index: test/Parser/cxx0x-lambda-expressions.cpp
===
--- test/Parser/cxx0x-lambda-expressions.cpp
+++ test/Parser/cxx0x-lambda-expressions.cpp
@@ -53,7 +53,7 @@
   void delete_lambda(int *p) {
 delete [] p;
 delete [] (int*) { new int }; // ok, compound-literal, not lambda
-delete [] { return new int; } (); // expected-error{{expected expression}}
+delete [] { return new int; } (); // expected-error{{missing parentheses 
around lambda expression}}
 delete [&] { return new int; } (); // ok, lambda
   }
 
Index: lib/Parse/ParseExprCXX.cpp
===
--- lib/Parse/ParseExprCXX.cpp
+++ lib/Parse/ParseExprCXX.cpp
@@ -2885,15 +2885,39 @@
 //   [Footnote: A lambda expression with a lambda-introducer that consists
 //  of empty square brackets can follow the delete keyword if
 //  the lambda expression is enclosed in parentheses.]
-// FIXME: Produce a better diagnostic if the '[]' is unambiguously a
-//lambda-introducer.
-ArrayDelete = true;
-BalancedDelimiterTracker T(*this, tok::l_square);
+TentativeParsingAction TPA(*this);
 
-T.consumeOpen();
-T.consumeClose();
-if (T.getCloseLocation().isInvalid())
-  return ExprError();
+// Basic lookahead to check if we have a lambda expression. If we
+// encounter two braces with a semicolon, we can be pretty sure
+// that this is a lambda, not say a compound literal. 
+if (!SkipUntil(tok::l_brace, SkipUntilFlags::StopAtSemi) ||
+(NextToken().isNot(tok::r_brace) && !SkipUntil(tok::semi)) ||
+!SkipUntil(tok::r_brace, SkipUntilFlags::StopAtSemi)) {
+  TPA.Revert();
+  ArrayDelete = true;
+  BalancedDelimiterTracker T(*this, tok::l_square);
+
+  T.consumeOpen();
+  T.consumeClose();
+  if (T.getCloseLocation().isInvalid())
+return ExprError();
+} else {
+  TPA.Revert();
+
+  // Warn if the non-capturing lambda isn't surrounded by parenthesis
+  // to disambiguate it from 'delete[]'.
+  ExprResult Lambda = TryParseLambdaExpression();
+  if (!Lambda.isInvalid()) {
+SourceLocation StartLoc = Lambda.get()->getLocStart();
+Diag(StartLoc, diag::err_lambda_after_array_delete)
+  << SourceRange(StartLoc, Lambda.get()->getLocEnd());
+
+// Evaluate any postfix expressions used on the lambda.
+Lambda = ParsePostfixExpressionSuffix(Lambda);
+return Actions.ActOnCXXDelete(Start, UseGlobal, /*ArrayForm=*/false,
+  Lambda.get());
+  }
+}
   }
 
   ExprResult Operand(ParseCastExpression(false));
Index: include/clang/Basic/DiagnosticParseKinds.td
===
--- include/clang/Basic/DiagnosticParseKinds.td
+++ include/clang/Basic/DiagnosticParseKinds.td
@@ -99,6 +99,8 @@
   InGroup, DefaultIgnore;
 def ext_alignof_expr : ExtWarn<
   "%0 applied to an expression is a GNU extension">, 
InGroup;
+def err_lambda_after_array_delete : Error<
+  "missing parentheses around lambda expression">;
 
 def warn_microsoft_dependent_exists : Warning<
   "dependent %select{__if_not_exists|__if_exists}0 declarations are ignored">, 


Index: test/SemaCXX/new-delete-0x.cpp
===
--- test/SemaCXX/new-delete-0x.cpp
+++ test/SemaCXX/new-delete-0x.cpp
@@ -34,6 +34,5 @@
 void bad_deletes()
 {
   // 'delete []' is always array delete, per [expr.delete]p1.
-  // FIXME: Give a better diagnostic.
-  delete []{ return (int*)0; }(); // expected-error {{expected expression}}
+  delete []{ return (int*)0; }(); // expected-error{{missing parentheses around lambda expression}}
 }
Index: test/Parser/cxx0x-lambda-expressions.cpp
===
--- test/Parser/cxx0x-lambda-expressions.cpp
+++ test/Parser/cxx0x-lambda-expressions.cpp
@@ -53,7 +53,7 @@
   void delete_lambda(int *p) {
 delete [] p;
 delete [] (int*) { new int }; // ok, compound-literal, not lambda
-delete []