[PATCH] D53847: [C++2a] P0634r3: Down with typename!

2019-05-27 Thread Nicolas Lesser via Phabricator via cfe-commits
Rakete marked an inline comment as done.
Rakete added inline comments.



Comment at: clang/lib/Sema/SemaTemplate.cpp:3377-3379
   // FIXME: This is not quite correct recovery as we don't transform SS
   // into the corresponding dependent form (and we don't diagnose missing
   // 'template' keywords within SS as a result).

rsmith wrote:
> Rakete wrote:
> > Rakete wrote:
> > > rsmith wrote:
> > > > This FIXME is concerning. Is this a problem with this patch? (Is the 
> > > > FIXME wrong now?)
> > > Yes you're right, I believe it not longer applies due to the change in 
> > > ParseDecl.cpp in ParseDeclarationSpecifiers.
> > Although I'm not that sure I fully understand what that comments alludes to.
> The example would be something like this:
> 
> ```
> template struct X {
>   template struct Y { Y(); using V = int; };
>   template typename Y::V f();
> };
> template template
> X::Y::V X::f() {} 
> ```
> 
> Clang trunk today points out that the `typename` keyword is missing on the 
> final line, but fails to point out that the `template` keyword is also 
> missing. The reason is that in the case where that construct is valid:
> 
> ```
> template template
> X::Y::Y() {}
> ```
> 
> ... we are "entering the context" of the //nested-name-specifier//, which 
> means we don't need a `template` keyword.
> 
> If the FIXME is fixed, then we should diagnose the missing `template` in the 
> above program.
> 
> Also, because we don't rebuild the //nested-name-specifier// as a dependent 
> nested name specifier in this case, we fail to match it against the 
> declaration in the class, so in my example above, we also produce an 
> "out-of-line definition does not match" error.
> 
> 
> A closely-related issue can be seen in an example such as:
> 
> ```
> template struct X {
>   template struct Y { Y(); typedef void V; }; 
>   template typename Y::V::W f();
> };
> template template
> X::template Y::V::W X::f() { return 0; } 
> ```
> 
> Here, we produce a completely bogus error:
> 
> ```
> :6:13: error: 'X::Y::V' (aka 'void') is not a class, namespace, or 
> enumeration
> X::template Y::V::W X::f() { return 0; } 
> ^
> ```
> 
> ... because we parse this in "entering context" mode and so resolve 
> `X::Y::V` to the type in the primary template (that is, `void`). That's 
> wrong: we should defer resolving this name to a type until we know what `T` 
> and `U` are, or until we know that we're *actually* entering the context. 
> Specifically, the above program can be extended as follows:
> 
> ```
> template<> template<> struct X::Y {
>   struct V { using W = int; };
> };
> void call(X x) { x.f(); } // OK, f returns int
> ```
> 
> The above program should be accepted by this patch, if the FIXME is indeed 
> now fixed. Please add it as a testcase :)
Oh ok, got it thanks. So no, the program is still not accepted in clang, and a 
pretty dumb side effect of it is that 

```
template struct X {
  template struct Y { Y(); using V = int; };
  template typename Y::V f();
};
template template
X::Y::V X::f() {}
```

is accepted without the diagnostic for the missing `template`. :(


Repository:
  rG LLVM Github Monorepo

CHANGES SINCE LAST ACTION
  https://reviews.llvm.org/D53847/new/

https://reviews.llvm.org/D53847



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


[PATCH] D53847: [C++2a] P0634r3: Down with typename!

2019-05-22 Thread Nicolas Lesser via Phabricator via cfe-commits
Rakete marked an inline comment as done.
Rakete added inline comments.



Comment at: clang/lib/Sema/SemaTemplate.cpp:3377-3379
   // FIXME: This is not quite correct recovery as we don't transform SS
   // into the corresponding dependent form (and we don't diagnose missing
   // 'template' keywords within SS as a result).

Rakete wrote:
> rsmith wrote:
> > This FIXME is concerning. Is this a problem with this patch? (Is the FIXME 
> > wrong now?)
> Yes you're right, I believe it not longer applies due to the change in 
> ParseDecl.cpp in ParseDeclarationSpecifiers.
Although I'm not that sure I fully understand what that comments alludes to.


Repository:
  rG LLVM Github Monorepo

CHANGES SINCE LAST ACTION
  https://reviews.llvm.org/D53847/new/

https://reviews.llvm.org/D53847



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


[PATCH] D53847: [C++2a] P0634r3: Down with typename!

2019-05-22 Thread Nicolas Lesser via Phabricator via cfe-commits
Rakete added inline comments.



Comment at: clang/lib/Parse/ParseDecl.cpp:4321
+ isCXXDeclarationSpecifier(ITC_Never, TPResult::True) !=
+ TPResult::True) ||
+(!getLangOpts().CPlusPlus && !isDeclarationSpecifier(ITC_Yes))) {

rsmith wrote:
> It seems like a wording oversight that we don't assume `typename` in an 
> //enum-base//. Probably would be good to raise this on the core reflector.
Do you know why this isn't allowed in `operator` ids?



Comment at: clang/lib/Parse/ParseDecl.cpp:5100-5101
   bool IsConstructor = false;
-  if (isDeclarationSpecifier())
+  if (isDeclarationSpecifier(ITC_Never))
 IsConstructor = true;
   else if (Tok.is(tok::identifier) ||

rsmith wrote:
> Oh, this could be a problem.
> 
> If this *is* a constructor declaration, then this is implicit typename 
> context: this is either a "//parameter-declaration// in a 
> //member-declaration//" ([temp.res]/5.2.3) or a "//parameter-declaration// in 
> a //declarator// of a function or function template declaration whose 
> //declarator-id// is qualified". But if it's *not* a constructor declaration, 
> then this is either the //declarator-id// of a declaration or the 
> //nested-name-specifier// of a pointer-to-member declarator:
> 
> ```
> template
> struct C {
>   C(T::type); // implicit typename context
>   friend C (T::fn)(); // not implicit typename context, declarator-id of 
> friend declaration
>   C(T::type::*x)[3]; // not implicit typename context, pointer-to-member type
> };
> ```
> 
> I think we need to use `ITC_Yes` here, in order to correctly disambiguate the 
> first example above. Please add tests for the other two cases to make sure 
> this doesn't break them -- but I'm worried this **will** break the second 
> case, because it will incorrectly annotate `T::fn` as a type.
Yeah it does the break the second. Would just checking whether a `friend` is 
there be good enough? clang doesn't seem to actively propose to add  a friend 
if there's one missing, so if we add a `IsFriend` parameter and then check if 
it is set than always return `false`, it should work. Is that acceptable? It 
would break the nice error message you get if you write `friend C(int);`, but 
if we restrict it when `isDeclarationSpecifier` return false (with `Never`) 
would that be better (that's what I'm doing right now)?

Another solution would be to tentatively parse the whole thing, but that can be 
pretty expensive I believe.



Comment at: clang/lib/Sema/SemaTemplate.cpp:3377-3379
   // FIXME: This is not quite correct recovery as we don't transform SS
   // into the corresponding dependent form (and we don't diagnose missing
   // 'template' keywords within SS as a result).

rsmith wrote:
> This FIXME is concerning. Is this a problem with this patch? (Is the FIXME 
> wrong now?)
Yes you're right, I believe it not longer applies due to the change in 
ParseDecl.cpp in ParseDeclarationSpecifiers.


Repository:
  rG LLVM Github Monorepo

CHANGES SINCE LAST ACTION
  https://reviews.llvm.org/D53847/new/

https://reviews.llvm.org/D53847



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


[PATCH] D53847: [C++2a] P0634r3: Down with typename!

2019-05-22 Thread Nicolas Lesser via Phabricator via cfe-commits
Rakete updated this revision to Diff 200767.
Rakete marked 11 inline comments as done.
Rakete added a comment.

- rebased
- addressed review comments


Repository:
  rG LLVM Github Monorepo

CHANGES SINCE LAST ACTION
  https://reviews.llvm.org/D53847/new/

https://reviews.llvm.org/D53847

Files:
  clang/include/clang/Basic/DiagnosticSemaKinds.td
  clang/include/clang/Parse/Parser.h
  clang/include/clang/Sema/DeclSpec.h
  clang/include/clang/Sema/Sema.h
  clang/lib/Parse/ParseDecl.cpp
  clang/lib/Parse/ParseDeclCXX.cpp
  clang/lib/Parse/ParseExpr.cpp
  clang/lib/Parse/ParseExprCXX.cpp
  clang/lib/Parse/ParseTemplate.cpp
  clang/lib/Parse/ParseTentative.cpp
  clang/lib/Parse/Parser.cpp
  clang/lib/Sema/DeclSpec.cpp
  clang/lib/Sema/Sema.cpp
  clang/lib/Sema/SemaDecl.cpp
  clang/lib/Sema/SemaTemplate.cpp
  clang/test/CXX/basic/basic.lookup/basic.lookup.qual/class.qual/p2.cpp
  clang/test/CXX/drs/dr1xx.cpp
  clang/test/CXX/drs/dr2xx.cpp
  clang/test/CXX/drs/dr4xx.cpp
  clang/test/CXX/drs/dr5xx.cpp
  clang/test/CXX/temp/temp.res/p3.cpp
  clang/test/CXX/temp/temp.res/p5.cpp
  clang/test/CXX/temp/temp.res/temp.dep/temp.dep.type/p1.cpp
  clang/test/FixIt/fixit.cpp
  clang/test/Parser/cxx-member-initializers.cpp
  clang/test/SemaCXX/MicrosoftCompatibility.cpp
  clang/test/SemaCXX/MicrosoftExtensions.cpp
  clang/test/SemaCXX/MicrosoftSuper.cpp
  clang/test/SemaCXX/unknown-type-name.cpp
  clang/test/SemaTemplate/alias-templates.cpp
  clang/test/SemaTemplate/typename-specifier-3.cpp

Index: clang/test/SemaTemplate/typename-specifier-3.cpp
===
--- clang/test/SemaTemplate/typename-specifier-3.cpp
+++ clang/test/SemaTemplate/typename-specifier-3.cpp
@@ -27,7 +27,7 @@
   typedef int arg;
 };
 struct C {
-  typedef B::X x; // expected-error {{missing 'typename'}}
+  typedef B::X x; // expected-warning {{missing 'typename'}}
 };
   };
 
Index: clang/test/SemaTemplate/alias-templates.cpp
===
--- clang/test/SemaTemplate/alias-templates.cpp
+++ clang/test/SemaTemplate/alias-templates.cpp
@@ -195,11 +195,10 @@
   struct base {
 template  struct derived;
   };
-  // FIXME: The diagnostics here are terrible.
   template 
-  using derived = base::template derived; // expected-error {{expected a type}} expected-error {{expected ';'}}
+  using derived = base::template derived; // expected-warning {{missing 'typename'}}
   template 
-  using derived2 = ::PR16904::base::template derived; // expected-error {{expected a type}} expected-error {{expected ';'}}
+  using derived2 = ::PR16904::base::template derived; // expected-warning {{missing 'typename'}}
 }
 
 namespace PR14858 {
Index: clang/test/SemaCXX/unknown-type-name.cpp
===
--- clang/test/SemaCXX/unknown-type-name.cpp
+++ clang/test/SemaCXX/unknown-type-name.cpp
@@ -36,15 +36,15 @@
 
   static int n;
   static type m;
-  static int h(T::type, int); // expected-error{{missing 'typename'}}
-  static int h(T::type x, char); // expected-error{{missing 'typename'}}
+  static int h(T::type, int); // expected-warning{{implicit 'typename' is a C++2a extension}}
+  static int h(T::type x, char); // expected-warning{{implicit 'typename' is a C++2a extension}}
 };
 
 template
-A::type g(T t) { return t; } // expected-error{{missing 'typename'}}
+A::type g(T t) { return t; } // expected-warning{{implicit 'typename' is a C++2a extension}}
 
 template
-A::type A::f() { return type(); } // expected-error{{missing 'typename'}}
+A::type A::f() { return type(); } // expected-warning{{implicit 'typename' is a C++2a extension}}
 
 template
 void f(T::type) { } // expected-error{{missing 'typename'}}
@@ -84,11 +84,11 @@
 
 template int A::n(T::value); // ok
 template
-A::type // expected-error{{missing 'typename'}}
+A::type // expected-warning {{implicit 'typename' is a C++2a extension}}
 A::m(T::value, 0); // ok
 
-template int A::h(T::type, int) {} // expected-error{{missing 'typename'}}
-template int A::h(T::type x, char) {} // expected-error{{missing 'typename'}}
+template int A::h(T::type, int) {} // expected-warning{{implicit 'typename' is a C++2a extension}}
+template int A::h(T::type x, char) {} // expected-warning{{implicit 'typename' is a C++2a extension}}
 
 template int h(T::type, int); // expected-error{{missing 'typename'}}
 template int h(T::type x, char); // expected-error{{missing 'typename'}}
@@ -116,4 +116,5 @@
 // FIXME: We know which type specifier should have been specified here. Provide
 //a fix-it to add 'typename A::type'
 template
-A::g() { } // expected-error{{requires a type specifier}}
+A::g() { } // expected-error{{expected unqualified-id}}
+// expected-warning@-1{{implicit 'typename' is a C++2a extension}}
Index: clang/test/SemaCXX/MicrosoftSuper.cpp
===
--- clang/test/Se

[PATCH] D53847: [C++2a] P0634r3: Down with typename!

2019-05-21 Thread Nicolas Lesser via Phabricator via cfe-commits
Rakete updated this revision to Diff 200440.
Rakete added a comment.

Add support for implicit typenames of the form T::template U


Repository:
  rG LLVM Github Monorepo

CHANGES SINCE LAST ACTION
  https://reviews.llvm.org/D53847/new/

https://reviews.llvm.org/D53847

Files:
  clang/include/clang/Basic/DiagnosticSemaKinds.td
  clang/include/clang/Parse/Parser.h
  clang/include/clang/Sema/DeclSpec.h
  clang/include/clang/Sema/Sema.h
  clang/lib/Parse/ParseDecl.cpp
  clang/lib/Parse/ParseDeclCXX.cpp
  clang/lib/Parse/ParseExprCXX.cpp
  clang/lib/Parse/ParseTemplate.cpp
  clang/lib/Parse/ParseTentative.cpp
  clang/lib/Parse/Parser.cpp
  clang/lib/Sema/DeclSpec.cpp
  clang/lib/Sema/Sema.cpp
  clang/lib/Sema/SemaDecl.cpp
  clang/lib/Sema/SemaTemplate.cpp
  clang/test/CXX/basic/basic.lookup/basic.lookup.qual/class.qual/p2.cpp
  clang/test/CXX/drs/dr1xx.cpp
  clang/test/CXX/drs/dr2xx.cpp
  clang/test/CXX/drs/dr4xx.cpp
  clang/test/CXX/drs/dr5xx.cpp
  clang/test/CXX/temp/temp.res/p3.cpp
  clang/test/CXX/temp/temp.res/p5.cpp
  clang/test/CXX/temp/temp.res/temp.dep/temp.dep.type/p1.cpp
  clang/test/FixIt/fixit.cpp
  clang/test/Parser/cxx-member-initializers.cpp
  clang/test/Parser/editor-placeholder-recovery.cpp
  clang/test/SemaCXX/MicrosoftCompatibility.cpp
  clang/test/SemaCXX/MicrosoftExtensions.cpp
  clang/test/SemaCXX/MicrosoftSuper.cpp
  clang/test/SemaCXX/unknown-type-name.cpp
  clang/test/SemaTemplate/alias-templates.cpp
  clang/test/SemaTemplate/typename-specifier-3.cpp

Index: clang/test/SemaTemplate/typename-specifier-3.cpp
===
--- clang/test/SemaTemplate/typename-specifier-3.cpp
+++ clang/test/SemaTemplate/typename-specifier-3.cpp
@@ -27,7 +27,7 @@
   typedef int arg;
 };
 struct C {
-  typedef B::X x; // expected-error {{missing 'typename'}}
+  typedef B::X x; // expected-warning {{missing 'typename'}}
 };
   };
 
Index: clang/test/SemaTemplate/alias-templates.cpp
===
--- clang/test/SemaTemplate/alias-templates.cpp
+++ clang/test/SemaTemplate/alias-templates.cpp
@@ -195,11 +195,10 @@
   struct base {
 template  struct derived;
   };
-  // FIXME: The diagnostics here are terrible.
   template 
-  using derived = base::template derived; // expected-error {{expected a type}} expected-error {{expected ';'}}
+  using derived = base::template derived; // expected-warning {{missing 'typename'}}
   template 
-  using derived2 = ::PR16904::base::template derived; // expected-error {{expected a type}} expected-error {{expected ';'}}
+  using derived2 = ::PR16904::base::template derived; // expected-warning {{missing 'typename'}}
 }
 
 namespace PR14858 {
Index: clang/test/SemaCXX/unknown-type-name.cpp
===
--- clang/test/SemaCXX/unknown-type-name.cpp
+++ clang/test/SemaCXX/unknown-type-name.cpp
@@ -36,15 +36,15 @@
 
   static int n;
   static type m;
-  static int h(T::type, int); // expected-error{{missing 'typename'}}
-  static int h(T::type x, char); // expected-error{{missing 'typename'}}
+  static int h(T::type, int); // expected-warning{{implicit 'typename' is a C++2a extension}}
+  static int h(T::type x, char); // expected-warning{{implicit 'typename' is a C++2a extension}}
 };
 
 template
-A::type g(T t) { return t; } // expected-error{{missing 'typename'}}
+A::type g(T t) { return t; } // expected-warning{{implicit 'typename' is a C++2a extension}}
 
 template
-A::type A::f() { return type(); } // expected-error{{missing 'typename'}}
+A::type A::f() { return type(); } // expected-warning{{implicit 'typename' is a C++2a extension}}
 
 template
 void f(T::type) { } // expected-error{{missing 'typename'}}
@@ -72,9 +72,7 @@
 
 int *p;
 
-// FIXME: We should assume that 'undeclared' is a type, not a parameter name
-//here, and produce an 'unknown type name' diagnostic instead.
-int f1(undeclared, int); // expected-error{{requires a type specifier}}
+int f1(undeclared, int); // expected-error{{unknown type name 'undeclared'}}
 
 int f2(undeclared, 0); // expected-error{{undeclared identifier}}
 
@@ -86,11 +84,11 @@
 
 template int A::n(T::value); // ok
 template
-A::type // expected-error{{missing 'typename'}}
+A::type // expected-warning {{implicit 'typename' is a C++2a extension}}
 A::m(T::value, 0); // ok
 
-template int A::h(T::type, int) {} // expected-error{{missing 'typename'}}
-template int A::h(T::type x, char) {} // expected-error{{missing 'typename'}}
+template int A::h(T::type, int) {} // expected-warning{{implicit 'typename' is a C++2a extension}}
+template int A::h(T::type x, char) {} // expected-warning{{implicit 'typename' is a C++2a extension}}
 
 template int h(T::type, int); // expected-error{{missing 'typename'}}
 template int h(T::type x, char); // expected-error{{missing 'typename'}}
@@ -118,4 +116,5 @@
 // FIXME: We know which type specifier should have

[PATCH] D53847: [C++2a] P0634r3: Down with typename!

2019-05-21 Thread Nicolas Lesser via Phabricator via cfe-commits
Rakete marked an inline comment as done.
Rakete added inline comments.



Comment at: clang/lib/Parse/ParseDecl.cpp:4859
 // recurse to handle whatever we get.
-if (TryAnnotateTypeOrScopeToken())
+if (TryAnnotateTypeOrScopeToken(!getCurScope()->isTemplateParamScope()))
   return true;

rsmith wrote:
> This seems surprising to me; I'd expect to have an implicit `typename` here 
> approximately when not `DisambiguatingWithExpression`. Also basing this off 
> the scope seems wrong, as we can switch into and out of implicit `typename` 
> contexts multiple times within a scope. Eg, in `template T::template U>` we get an implicit `typename` for `T::template U` but 
> not for `T::V` despite them being in the same scope.
> 
> Should the callers of this function be passing in an "implicit `typename`" 
> flag?
Seems like `template >` isn't accepted as a 
context with an implicit typename (for the `T::template`). I'll look into it :)


Repository:
  rG LLVM Github Monorepo

CHANGES SINCE LAST ACTION
  https://reviews.llvm.org/D53847/new/

https://reviews.llvm.org/D53847



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


[PATCH] D53847: [C++2a] P0634r3: Down with typename!

2019-05-21 Thread Nicolas Lesser via Phabricator via cfe-commits
Rakete updated this revision to Diff 200423.
Rakete marked 10 inline comments as done.
Rakete added a comment.

- Addressed review comments


Repository:
  rG LLVM Github Monorepo

CHANGES SINCE LAST ACTION
  https://reviews.llvm.org/D53847/new/

https://reviews.llvm.org/D53847

Files:
  clang/include/clang/Basic/DiagnosticSemaKinds.td
  clang/include/clang/Parse/Parser.h
  clang/include/clang/Sema/DeclSpec.h
  clang/include/clang/Sema/Sema.h
  clang/lib/Parse/ParseDecl.cpp
  clang/lib/Parse/ParseDeclCXX.cpp
  clang/lib/Parse/ParseExprCXX.cpp
  clang/lib/Parse/ParseTemplate.cpp
  clang/lib/Parse/ParseTentative.cpp
  clang/lib/Parse/Parser.cpp
  clang/lib/Sema/DeclSpec.cpp
  clang/lib/Sema/Sema.cpp
  clang/lib/Sema/SemaDecl.cpp
  clang/lib/Sema/SemaTemplate.cpp
  clang/test/CXX/drs/dr1xx.cpp
  clang/test/CXX/drs/dr2xx.cpp
  clang/test/CXX/drs/dr4xx.cpp
  clang/test/CXX/drs/dr5xx.cpp
  clang/test/CXX/temp/temp.res/p5.cpp
  clang/test/CXX/temp/temp.res/temp.dep/temp.dep.type/p1.cpp
  clang/test/FixIt/fixit.cpp
  clang/test/Parser/cxx-member-initializers.cpp
  clang/test/Parser/editor-placeholder-recovery.cpp
  clang/test/SemaCXX/MicrosoftCompatibility.cpp
  clang/test/SemaCXX/MicrosoftExtensions.cpp
  clang/test/SemaCXX/MicrosoftSuper.cpp
  clang/test/SemaCXX/unknown-type-name.cpp

Index: clang/test/SemaCXX/unknown-type-name.cpp
===
--- clang/test/SemaCXX/unknown-type-name.cpp
+++ clang/test/SemaCXX/unknown-type-name.cpp
@@ -36,15 +36,15 @@
 
   static int n;
   static type m;
-  static int h(T::type, int); // expected-error{{missing 'typename'}}
-  static int h(T::type x, char); // expected-error{{missing 'typename'}}
+  static int h(T::type, int); // expected-warning{{implicit 'typename' is a C++2a extension}}
+  static int h(T::type x, char); // expected-warning{{implicit 'typename' is a C++2a extension}}
 };
 
 template
-A::type g(T t) { return t; } // expected-error{{missing 'typename'}}
+A::type g(T t) { return t; } // expected-warning{{implicit 'typename' is a C++2a extension}}
 
 template
-A::type A::f() { return type(); } // expected-error{{missing 'typename'}}
+A::type A::f() { return type(); } // expected-warning{{implicit 'typename' is a C++2a extension}}
 
 template
 void f(T::type) { } // expected-error{{missing 'typename'}}
@@ -72,9 +72,7 @@
 
 int *p;
 
-// FIXME: We should assume that 'undeclared' is a type, not a parameter name
-//here, and produce an 'unknown type name' diagnostic instead.
-int f1(undeclared, int); // expected-error{{requires a type specifier}}
+int f1(undeclared, int); // expected-error{{unknown type name 'undeclared'}}
 
 int f2(undeclared, 0); // expected-error{{undeclared identifier}}
 
@@ -86,11 +84,11 @@
 
 template int A::n(T::value); // ok
 template
-A::type // expected-error{{missing 'typename'}}
+A::type // expected-warning {{implicit 'typename' is a C++2a extension}}
 A::m(T::value, 0); // ok
 
-template int A::h(T::type, int) {} // expected-error{{missing 'typename'}}
-template int A::h(T::type x, char) {} // expected-error{{missing 'typename'}}
+template int A::h(T::type, int) {} // expected-warning{{implicit 'typename' is a C++2a extension}}
+template int A::h(T::type x, char) {} // expected-warning{{implicit 'typename' is a C++2a extension}}
 
 template int h(T::type, int); // expected-error{{missing 'typename'}}
 template int h(T::type x, char); // expected-error{{missing 'typename'}}
@@ -118,4 +116,5 @@
 // FIXME: We know which type specifier should have been specified here. Provide
 //a fix-it to add 'typename A::type'
 template
-A::g() { } // expected-error{{requires a type specifier}}
+A::g() { } // expected-error{{expected unqualified-id}}
+// expected-warning@-1{{implicit 'typename' is a C++2a extension}}
Index: clang/test/SemaCXX/MicrosoftSuper.cpp
===
--- clang/test/SemaCXX/MicrosoftSuper.cpp
+++ clang/test/SemaCXX/MicrosoftSuper.cpp
@@ -108,8 +108,8 @@
   typename __super::XXX a;
   typedef typename __super::XXX b;
 
-  __super::XXX c; // expected-error {{missing 'typename'}}
-  typedef __super::XXX d; // expected-error {{missing 'typename'}}
+  __super::XXX c; // expected-warning {{implicit 'typename' is a C++2a extension}}
+  typedef __super::XXX d; // expected-warning {{implicit 'typename' is a C++2a extension}}
 
   void foo() {
 typename __super::XXX e;
@@ -127,8 +127,8 @@
   typename __super::XXX a;
   typedef typename __super::XXX b;
 
-  __super::XXX c; // expected-error {{missing 'typename'}}
-  typedef __super::XXX d; // expected-error {{missing 'typename'}}
+  __super::XXX c; // expected-warning {{implicit 'typename' is a C++2a extension}}
+  typedef __super::XXX d; // expected-warning {{implicit 'typename' is a C++2a extension}}
 
   void foo() {
 typename __super::XXX e;
Index: clang/test/SemaCXX/MicrosoftExtensions.cpp

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

2019-05-19 Thread Nicolas Lesser via Phabricator via cfe-commits
This revision was automatically updated to reflect the committed changes.
Closed by commit rL361119: Added a better diagnostic when using the delete 
operator with lambdas (authored by Rakete, committed by ).
Herald added a project: LLVM.
Herald added a subscriber: llvm-commits.

Changed prior to commit:
  https://reviews.llvm.org/D36357?vs=199566&id=200180#toc

Repository:
  rL LLVM

CHANGES SINCE LAST ACTION
  https://reviews.llvm.org/D36357/new/

https://reviews.llvm.org/D36357

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

Index: cfe/trunk/lib/Parse/ParseExprCXX.cpp
===
--- cfe/trunk/lib/Parse/ParseExprCXX.cpp
+++ cfe/trunk/lib/Parse/ParseExprCXX.cpp
@@ -3034,8 +3034,58 @@
 //   [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.
+
+const Token Next = GetLookAheadToken(2);
+
+// Basic lookahead to check if we have a lambda expression.
+if (Next.isOneOf(tok::l_brace, tok::less) ||
+(Next.is(tok::l_paren) &&
+ (GetLookAheadToken(3).is(tok::r_paren) ||
+  (GetLookAheadToken(3).is(tok::identifier) &&
+   GetLookAheadToken(4).is(tok::identifier) {
+  TentativeParsingAction TPA(*this);
+  SourceLocation LSquareLoc = Tok.getLocation();
+  SourceLocation RSquareLoc = NextToken().getLocation();
+
+  // SkipUntil can't skip pairs of ; don't emit a FixIt in this
+  // case.
+  SkipUntil({tok::l_brace, tok::less}, StopBeforeMatch);
+  SourceLocation RBraceLoc;
+  bool EmitFixIt = false;
+  if (TryConsumeToken(tok::l_brace)) {
+SkipUntil(tok::r_brace, StopBeforeMatch);
+RBraceLoc = Tok.getLocation();
+EmitFixIt = true;
+  }
+
+  TPA.Revert();
+
+  if (EmitFixIt)
+Diag(Start, diag::err_lambda_after_delete)
+<< SourceRange(Start, RSquareLoc)
+<< FixItHint::CreateInsertion(LSquareLoc, "(")
+<< FixItHint::CreateInsertion(
+   Lexer::getLocForEndOfToken(
+   RBraceLoc, 0, Actions.getSourceManager(), getLangOpts()),
+   ")");
+  else
+Diag(Start, diag::err_lambda_after_delete)
+<< SourceRange(Start, RSquareLoc);
+
+  // Warn that the non-capturing lambda isn't surrounded by parentheses
+  // to disambiguate it from 'delete[]'.
+  ExprResult Lambda = ParseLambdaExpression();
+  if (Lambda.isInvalid())
+return ExprError();
+
+  // Evaluate any postfix expressions used on the lambda.
+  Lambda = ParsePostfixExpressionSuffix(Lambda);
+  if (Lambda.isInvalid())
+return ExprError();
+  return Actions.ActOnCXXDelete(Start, UseGlobal, /*ArrayForm=*/false,
+Lambda.get());
+}
+
 ArrayDelete = true;
 BalancedDelimiterTracker T(*this, tok::l_square);
 
Index: cfe/trunk/include/clang/Basic/DiagnosticParseKinds.td
===
--- cfe/trunk/include/clang/Basic/DiagnosticParseKinds.td
+++ cfe/trunk/include/clang/Basic/DiagnosticParseKinds.td
@@ -109,6 +109,8 @@
   InGroup, DefaultIgnore;
 def ext_alignof_expr : ExtWarn<
   "%0 applied to an expression is a GNU extension">, InGroup;
+def err_lambda_after_delete : Error<
+  "'[]' after delete interpreted as 'delete[]'; add parentheses to treat this as a lambda-expression">;
 
 def warn_microsoft_dependent_exists : Warning<
   "dependent %select{__if_not_exists|__if_exists}0 declarations are ignored">,
Index: cfe/trunk/test/SemaCXX/new-delete-0x.cpp
===
--- cfe/trunk/test/SemaCXX/new-delete-0x.cpp
+++ cfe/trunk/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 {{'[]' after delete interpreted as 'delete[]'}}
 }
Index: cfe/trunk/test/FixIt/fixit-cxx0x.cpp
===
--- cfe/trunk/test/FixIt/fixit-cxx0x.cpp
+++ cfe/trunk/test/FixIt/fixit-cxx0x.cpp
@@ -58,6 +58,9 @@
   (void)[&, i, i]{ }; // expected-error{{'i' can appear only once in a capture list}}
   (void)[] mutable { }; // expected-error{{lambda requires '()' before 'mutable'}}
   (void)[] -> int { }; // expected-error{{lambda requires '()' before return 

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

2019-05-15 Thread Nicolas Lesser via Phabricator via cfe-commits
Rakete updated this revision to Diff 199565.
Rakete added a comment.

- Fix crash with invalid postfix expr
- Don't emit FixIt when using <


Repository:
  rG LLVM Github Monorepo

CHANGES SINCE LAST ACTION
  https://reviews.llvm.org/D36357/new/

https://reviews.llvm.org/D36357

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

Index: clang/test/SemaCXX/new-delete-0x.cpp
===
--- clang/test/SemaCXX/new-delete-0x.cpp
+++ clang/test/SemaCXX/new-delete-0x.cpp
@@ -34,6 +34,6 @@
 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 {{'[]' after delete interpreted as 'delete[]'}}
 }
+
Index: clang/test/Parser/cxx0x-lambda-expressions.cpp
===
--- clang/test/Parser/cxx0x-lambda-expressions.cpp
+++ clang/test/Parser/cxx0x-lambda-expressions.cpp
@@ -1,4 +1,5 @@
 // RUN: %clang_cc1 -fsyntax-only -Wno-unused-value -verify -std=c++11 %s
+// RUN: %clang_cc1 -fsyntax-only -Wno-unused-value -verify -std=c++2a %s
 
 enum E { e };
 
@@ -43,31 +44,57 @@
 int a4[1] = {[&b] = 1 }; // expected-error{{integral constant expression must have integral or unscoped enumeration type, not 'const int *'}}
 int a5[3] = { []{return 0;}() };
 int a6[1] = {[this] = 1 }; // expected-error{{integral constant expression must have integral or unscoped enumeration type, not 'C *'}}
-int a7[1] = {[d(0)] { return d; } ()}; // expected-warning{{extension}}
-int a8[1] = {[d = 0] { return d; } ()}; // expected-warning{{extension}}
+int a7[1] = {[d(0)] { return d; } ()};
+int a8[1] = {[d = 0] { return d; } ()};
+int a10[1] = {[id(0)] { return id; } ()};
+#if __cplusplus <= 201103L
+// expected-warning@-4{{extension}}
+// expected-warning@-4{{extension}}
+// expected-warning@-4{{extension}}
+#endif
 int a9[1] = {[d = 0] = 1}; // expected-error{{is not an integral constant expression}}
-int a10[1] = {[id(0)] { return id; } ()}; // expected-warning{{extension}}
+#if __cplusplus >= 201402L
+// expected-note@-2{{constant expression cannot modify an object that is visible outside that expression}}
+#endif
 int a11[1] = {[id(0)] = 1};
   }
 
   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 {{'[]' after delete interpreted as 'delete[]'}}
 delete [&] { return new int; } (); // ok, lambda
+
+delete []() { return new int; }(); // expected-error{{'[]' after delete interpreted as 'delete[]'}}
+delete [](E Enum) { return new int((int)Enum); }(e); // expected-error{{'[]' after delete interpreted as 'delete[]'}}
+#if __cplusplus > 201703L
+delete []() { return new int; }(); // expected-error{{'[]' after delete interpreted as 'delete[]'}}
+#endif
   }
 
   // We support init-captures in C++11 as an extension.
   int z;
   void init_capture() {
-[n(0)] () mutable -> int { return ++n; }; // expected-warning{{extension}}
-[n{0}] { return; }; // expected-warning{{extension}}
-[n = 0] { return ++n; }; // expected-error {{captured by copy in a non-mutable}} expected-warning{{extension}}
-[n = {0}] { return; }; // expected-error {{}} expected-warning{{extension}}
-[a([&b = z]{})](){}; // expected-warning 2{{extension}}
+[n(0)] () mutable -> int { return ++n; };
+[n{0}] { return; };
+[a([&b = z]{})](){};
+[n = 0] { return ++n; }; // expected-error {{captured by copy in a non-mutable}}
+[n = {0}] { return; }; // expected-error {{}}
+#if __cplusplus <= 201103L
+// expected-warning@-6{{extension}}
+// expected-warning@-6{{extension}}
+// expected-warning@-6{{extension}}
+// expected-warning@-7{{extension}}
+// expected-warning@-7{{extension}}
+// expected-warning@-7{{extension}}
+#endif
 
 int x = 4;
-auto y = [&r = x, x = x + 1]() -> int { // expected-warning 2{{extension}}
+auto y = [&r = x, x = x + 1]() -> int {
+#if __cplusplus <= 201103L
+  // expected-warning@-2{{extension}}
+  // expected-warning@-3{{extension}}
+#endif
   r += 2;
   return x + 2;
 } ();
Index: clang/test/FixIt/fixit-cxx0x.cpp
===
--- clang/test/FixIt/fixit-cxx0x.cpp
+++ clang/test/FixIt/fixit-cxx0x.cpp
@@ -58,6 +58,9 @@
   (void)[&, i, i]{ }; // expected-error{{'i' can appear only once in a capture list}}
   (void)[] mutable { }; // expected-error{{lambda requires '()' befo

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

2019-05-15 Thread Nicolas Lesser via Phabricator via cfe-commits
Rakete updated this revision to Diff 199566.
Rakete added a comment.

- Use TryConsumeToken


Repository:
  rG LLVM Github Monorepo

CHANGES SINCE LAST ACTION
  https://reviews.llvm.org/D36357/new/

https://reviews.llvm.org/D36357

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

Index: clang/test/SemaCXX/new-delete-0x.cpp
===
--- clang/test/SemaCXX/new-delete-0x.cpp
+++ clang/test/SemaCXX/new-delete-0x.cpp
@@ -34,6 +34,6 @@
 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 {{'[]' after delete interpreted as 'delete[]'}}
 }
+
Index: clang/test/Parser/cxx0x-lambda-expressions.cpp
===
--- clang/test/Parser/cxx0x-lambda-expressions.cpp
+++ clang/test/Parser/cxx0x-lambda-expressions.cpp
@@ -1,4 +1,5 @@
 // RUN: %clang_cc1 -fsyntax-only -Wno-unused-value -verify -std=c++11 %s
+// RUN: %clang_cc1 -fsyntax-only -Wno-unused-value -verify -std=c++2a %s
 
 enum E { e };
 
@@ -43,31 +44,57 @@
 int a4[1] = {[&b] = 1 }; // expected-error{{integral constant expression must have integral or unscoped enumeration type, not 'const int *'}}
 int a5[3] = { []{return 0;}() };
 int a6[1] = {[this] = 1 }; // expected-error{{integral constant expression must have integral or unscoped enumeration type, not 'C *'}}
-int a7[1] = {[d(0)] { return d; } ()}; // expected-warning{{extension}}
-int a8[1] = {[d = 0] { return d; } ()}; // expected-warning{{extension}}
+int a7[1] = {[d(0)] { return d; } ()};
+int a8[1] = {[d = 0] { return d; } ()};
+int a10[1] = {[id(0)] { return id; } ()};
+#if __cplusplus <= 201103L
+// expected-warning@-4{{extension}}
+// expected-warning@-4{{extension}}
+// expected-warning@-4{{extension}}
+#endif
 int a9[1] = {[d = 0] = 1}; // expected-error{{is not an integral constant expression}}
-int a10[1] = {[id(0)] { return id; } ()}; // expected-warning{{extension}}
+#if __cplusplus >= 201402L
+// expected-note@-2{{constant expression cannot modify an object that is visible outside that expression}}
+#endif
 int a11[1] = {[id(0)] = 1};
   }
 
   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 {{'[]' after delete interpreted as 'delete[]'}}
 delete [&] { return new int; } (); // ok, lambda
+
+delete []() { return new int; }(); // expected-error{{'[]' after delete interpreted as 'delete[]'}}
+delete [](E Enum) { return new int((int)Enum); }(e); // expected-error{{'[]' after delete interpreted as 'delete[]'}}
+#if __cplusplus > 201703L
+delete []() { return new int; }(); // expected-error{{'[]' after delete interpreted as 'delete[]'}}
+#endif
   }
 
   // We support init-captures in C++11 as an extension.
   int z;
   void init_capture() {
-[n(0)] () mutable -> int { return ++n; }; // expected-warning{{extension}}
-[n{0}] { return; }; // expected-warning{{extension}}
-[n = 0] { return ++n; }; // expected-error {{captured by copy in a non-mutable}} expected-warning{{extension}}
-[n = {0}] { return; }; // expected-error {{}} expected-warning{{extension}}
-[a([&b = z]{})](){}; // expected-warning 2{{extension}}
+[n(0)] () mutable -> int { return ++n; };
+[n{0}] { return; };
+[a([&b = z]{})](){};
+[n = 0] { return ++n; }; // expected-error {{captured by copy in a non-mutable}}
+[n = {0}] { return; }; // expected-error {{}}
+#if __cplusplus <= 201103L
+// expected-warning@-6{{extension}}
+// expected-warning@-6{{extension}}
+// expected-warning@-6{{extension}}
+// expected-warning@-7{{extension}}
+// expected-warning@-7{{extension}}
+// expected-warning@-7{{extension}}
+#endif
 
 int x = 4;
-auto y = [&r = x, x = x + 1]() -> int { // expected-warning 2{{extension}}
+auto y = [&r = x, x = x + 1]() -> int {
+#if __cplusplus <= 201103L
+  // expected-warning@-2{{extension}}
+  // expected-warning@-3{{extension}}
+#endif
   r += 2;
   return x + 2;
 } ();
Index: clang/test/FixIt/fixit-cxx0x.cpp
===
--- clang/test/FixIt/fixit-cxx0x.cpp
+++ clang/test/FixIt/fixit-cxx0x.cpp
@@ -58,6 +58,9 @@
   (void)[&, i, i]{ }; // expected-error{{'i' can appear only once in a capture list}}
   (void)[] mutable { }; // expected-error{{lambda requires '()' before 'mutable'}}
   (void)[] -> int { }; // expect

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

2019-05-14 Thread Nicolas Lesser via Phabricator via cfe-commits
Rakete updated this revision to Diff 199528.
Rakete marked an inline comment as done.
Rakete added a comment.

Nevermind, seems to be working fine even with.


Repository:
  rG LLVM Github Monorepo

CHANGES SINCE LAST ACTION
  https://reviews.llvm.org/D36357/new/

https://reviews.llvm.org/D36357

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

Index: clang/test/SemaCXX/new-delete-0x.cpp
===
--- clang/test/SemaCXX/new-delete-0x.cpp
+++ clang/test/SemaCXX/new-delete-0x.cpp
@@ -34,6 +34,6 @@
 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 {{'[]' after delete interpreted as 'delete[]'}}
 }
+
Index: clang/test/Parser/cxx0x-lambda-expressions.cpp
===
--- clang/test/Parser/cxx0x-lambda-expressions.cpp
+++ clang/test/Parser/cxx0x-lambda-expressions.cpp
@@ -1,4 +1,5 @@
 // RUN: %clang_cc1 -fsyntax-only -Wno-unused-value -verify -std=c++11 %s
+// RUN: %clang_cc1 -fsyntax-only -Wno-unused-value -verify -std=c++2a %s
 
 enum E { e };
 
@@ -43,31 +44,57 @@
 int a4[1] = {[&b] = 1 }; // expected-error{{integral constant expression must have integral or unscoped enumeration type, not 'const int *'}}
 int a5[3] = { []{return 0;}() };
 int a6[1] = {[this] = 1 }; // expected-error{{integral constant expression must have integral or unscoped enumeration type, not 'C *'}}
-int a7[1] = {[d(0)] { return d; } ()}; // expected-warning{{extension}}
-int a8[1] = {[d = 0] { return d; } ()}; // expected-warning{{extension}}
+int a7[1] = {[d(0)] { return d; } ()};
+int a8[1] = {[d = 0] { return d; } ()};
+int a10[1] = {[id(0)] { return id; } ()};
+#if __cplusplus <= 201103L
+// expected-warning@-4{{extension}}
+// expected-warning@-4{{extension}}
+// expected-warning@-4{{extension}}
+#endif
 int a9[1] = {[d = 0] = 1}; // expected-error{{is not an integral constant expression}}
-int a10[1] = {[id(0)] { return id; } ()}; // expected-warning{{extension}}
+#if __cplusplus >= 201402L
+// expected-note@-2{{constant expression cannot modify an object that is visible outside that expression}}
+#endif
 int a11[1] = {[id(0)] = 1};
   }
 
   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 {{'[]' after delete interpreted as 'delete[]'}}
 delete [&] { return new int; } (); // ok, lambda
+
+delete []() { return new int; }(); // expected-error{{'[]' after delete interpreted as 'delete[]'}}
+delete [](E Enum) { return new int((int)Enum); }(e); // expected-error{{'[]' after delete interpreted as 'delete[]'}}
+#if __cplusplus > 201703L
+delete []() { return new int; }(); // expected-error{{'[]' after delete interpreted as 'delete[]'}}
+#endif
   }
 
   // We support init-captures in C++11 as an extension.
   int z;
   void init_capture() {
-[n(0)] () mutable -> int { return ++n; }; // expected-warning{{extension}}
-[n{0}] { return; }; // expected-warning{{extension}}
-[n = 0] { return ++n; }; // expected-error {{captured by copy in a non-mutable}} expected-warning{{extension}}
-[n = {0}] { return; }; // expected-error {{}} expected-warning{{extension}}
-[a([&b = z]{})](){}; // expected-warning 2{{extension}}
+[n(0)] () mutable -> int { return ++n; };
+[n{0}] { return; };
+[a([&b = z]{})](){};
+[n = 0] { return ++n; }; // expected-error {{captured by copy in a non-mutable}}
+[n = {0}] { return; }; // expected-error {{}}
+#if __cplusplus <= 201103L
+// expected-warning@-6{{extension}}
+// expected-warning@-6{{extension}}
+// expected-warning@-6{{extension}}
+// expected-warning@-7{{extension}}
+// expected-warning@-7{{extension}}
+// expected-warning@-7{{extension}}
+#endif
 
 int x = 4;
-auto y = [&r = x, x = x + 1]() -> int { // expected-warning 2{{extension}}
+auto y = [&r = x, x = x + 1]() -> int {
+#if __cplusplus <= 201103L
+  // expected-warning@-2{{extension}}
+  // expected-warning@-3{{extension}}
+#endif
   r += 2;
   return x + 2;
 } ();
Index: clang/test/FixIt/fixit-cxx0x.cpp
===
--- clang/test/FixIt/fixit-cxx0x.cpp
+++ clang/test/FixIt/fixit-cxx0x.cpp
@@ -58,6 +58,9 @@
   (void)[&, i, i]{ }; // expected-error{{'i' can appear only once in a capture list}}
   (void)[] mutable { }; // expected-error{{lam

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

2019-05-14 Thread Nicolas Lesser via Phabricator via cfe-commits
Rakete marked 2 inline comments as done.
Rakete added a comment.

In D36357#1501961 , @rsmith wrote:

> In D36357#1500949 , @Rakete 
> wrote:
>
> > How should I do this? Do I just skip to the next `}`, or also take into 
> > account  any additional scopes? Also does this mean that I skip and then 
> > revert, because that seems pretty expensive?
>
>
> It would be a little expensive, yes, but we'd only be doing it on codepaths 
> where we're producing an error -- for an ill-formed program, it's OK to take 
> more time in order to produce a better diagnostic. Skipping to the next `}` 
> won't work, because `SkipUntil` will skip over pairs of brace-balanced tokens 
> (so you'll skip past the `}` you're looking for), but skipping until the next 
> `{` and then skipping to the `}` after it should work.


Hmm wouldn't this interact badly with `{}` in initializers?

  [] {};
  [](int = {0}) = {};






Comment at: clang/lib/Parse/ParseExprCXX.cpp:2996
+   GetLookAheadToken(4).is(tok::identifier) {
+  SourceLocation RightBracketLock = NextToken().getLocation();
+  // Warn if the non-capturing lambda isn't surrounded by parenthesis

rsmith wrote:
> rsmith wrote:
> > `RightBracketLock` -> `RSquareLoc`
> > 
> > (Our convention is to use `Loc` for "location" and to avoid the word 
> > "bracket" because it means different things in different English dialects 
> > -- usually `[]` in US English and usually `()` in UK English.)
> `Lock` -> `Loc`. There's no `k` in "location" =)
No idea how that k managed to sneak in :)


Repository:
  rG LLVM Github Monorepo

CHANGES SINCE LAST ACTION
  https://reviews.llvm.org/D36357/new/

https://reviews.llvm.org/D36357



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


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

2019-05-14 Thread Nicolas Lesser via Phabricator via cfe-commits
Rakete updated this revision to Diff 199380.
Rakete added a comment.

- Addressed review comments


Repository:
  rG LLVM Github Monorepo

CHANGES SINCE LAST ACTION
  https://reviews.llvm.org/D36357/new/

https://reviews.llvm.org/D36357

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

Index: clang/test/SemaCXX/new-delete-0x.cpp
===
--- clang/test/SemaCXX/new-delete-0x.cpp
+++ clang/test/SemaCXX/new-delete-0x.cpp
@@ -34,6 +34,6 @@
 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 {{'[]' after delete interpreted as 'delete[]'}}
 }
+
Index: clang/test/Parser/cxx0x-lambda-expressions.cpp
===
--- clang/test/Parser/cxx0x-lambda-expressions.cpp
+++ clang/test/Parser/cxx0x-lambda-expressions.cpp
@@ -1,4 +1,5 @@
 // RUN: %clang_cc1 -fsyntax-only -Wno-unused-value -verify -std=c++11 %s
+// RUN: %clang_cc1 -fsyntax-only -Wno-unused-value -verify -std=c++2a %s
 
 enum E { e };
 
@@ -53,8 +54,14 @@
   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 {{'[]' after delete interpreted as 'delete[]'}}
 delete [&] { return new int; } (); // ok, lambda
+
+delete []() { return new int; }(); // expected-error{{'[]' after delete interpreted as 'delete[]'}}
+delete [](E Enum) { return new int((int)Enum); }(e); // expected-error{{'[]' after delete interpreted as 'delete[]'}}
+#if __cplusplus > 201703L
+delete [] { return new int; }(); // expected-error{{'[]' after delete interpreted as 'delete[]'}}
+#endif
   }
 
   // We support init-captures in C++11 as an extension.
Index: clang/test/FixIt/fixit-cxx0x.cpp
===
--- clang/test/FixIt/fixit-cxx0x.cpp
+++ clang/test/FixIt/fixit-cxx0x.cpp
@@ -58,6 +58,9 @@
   (void)[&, i, i]{ }; // expected-error{{'i' can appear only once in a capture list}}
   (void)[] mutable { }; // expected-error{{lambda requires '()' before 'mutable'}}
   (void)[] -> int { }; // expected-error{{lambda requires '()' before return type}}
+
+  delete []() { return new int; }(); // expected-error{{'[]' after delete interpreted as 'delete[]'}}
+  delete [] { return new int; }(); // expected-error{{'[]' after delete interpreted as 'delete[]'}}
 }
 
 #define bar "bar"
Index: clang/lib/Parse/ParseExprCXX.cpp
===
--- clang/lib/Parse/ParseExprCXX.cpp
+++ clang/lib/Parse/ParseExprCXX.cpp
@@ -2984,8 +2984,38 @@
 //   [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.
+
+const Token Next = GetLookAheadToken(2);
+
+// Basic lookahead to check if we have a lambda expression.
+if (Next.isOneOf(tok::l_brace, tok::less) ||
+(Next.is(tok::l_paren) &&
+ (GetLookAheadToken(3).is(tok::r_paren) ||
+  (GetLookAheadToken(3).is(tok::identifier) &&
+   GetLookAheadToken(4).is(tok::identifier) {
+  SourceLocation RSquareLock = NextToken().getLocation();
+  // Warn that the non-capturing lambda isn't surrounded by parentheses
+  // to disambiguate it from 'delete[]'.
+  ExprResult Lambda = ParseLambdaExpression();
+  if (Lambda.isInvalid())
+return ExprError();
+
+  SourceLocation StartLoc = Lambda.get()->getBeginLoc();
+  Diag(Start, diag::err_lambda_after_delete)
+  << SourceRange(Start, RSquareLock)
+  << FixItHint::CreateInsertion(StartLoc, "(")
+  << FixItHint::CreateInsertion(
+ Lexer::getLocForEndOfToken(Lambda.get()->getEndLoc(), 0,
+Actions.getSourceManager(),
+getLangOpts()),
+ ")");
+
+  // Evaluate any postfix expressions used on the lambda.
+  Lambda = ParsePostfixExpressionSuffix(Lambda);
+  return Actions.ActOnCXXDelete(Start, UseGlobal, /*ArrayForm=*/false,
+Lambda.get());
+}
+
 ArrayDelete = true;
 BalancedDelimiterTracker T(*this, tok::l_square);
 
Index: clang/include/clang/Basic/DiagnosticParseKinds.td

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

2019-05-14 Thread Nicolas Lesser via Phabricator via cfe-commits
Rakete marked 3 inline comments as done.
Rakete added a comment.

> we could perform a tentative parse and skip to the } of the lambda.

How should I do this? Do I just skip to the next `}`, or also take into account 
 any additional scopes? Also does this mean that I skip and then revert, 
because that seems pretty expensive?


Repository:
  rG LLVM Github Monorepo

CHANGES SINCE LAST ACTION
  https://reviews.llvm.org/D36357/new/

https://reviews.llvm.org/D36357



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


[PATCH] D60934: [clang] adding explicit(bool) from c++2a

2019-05-06 Thread Nicolas Lesser via Phabricator via cfe-commits
Rakete added a comment.

@Tyker This broke the Chromium build, could you investigate please? 
http://lists.llvm.org/pipermail/cfe-commits/Week-of-Mon-20190506/270340.html


Repository:
  rC Clang

CHANGES SINCE LAST ACTION
  https://reviews.llvm.org/D60934/new/

https://reviews.llvm.org/D60934



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


[PATCH] D61556: [clang] fixing -ast-print for variadic parameter pack in lambda capture

2019-05-05 Thread Nicolas Lesser via Phabricator via cfe-commits
Rakete added a comment.

You might want to consider getting commit access 
.


Repository:
  rC Clang

CHANGES SINCE LAST ACTION
  https://reviews.llvm.org/D61556/new/

https://reviews.llvm.org/D61556



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


[PATCH] D61556: [clang] fixing -ast-print for variadic parameter pack in lambda capture

2019-05-05 Thread Nicolas Lesser via Phabricator via cfe-commits
This revision was automatically updated to reflect the committed changes.
Closed by commit rC359980: [clang] fixing -ast-print for variadic parameter 
pack in lambda capture (authored by Rakete, committed by ).

Changed prior to commit:
  https://reviews.llvm.org/D61556?vs=198155&id=198172#toc

Repository:
  rC Clang

CHANGES SINCE LAST ACTION
  https://reviews.llvm.org/D61556/new/

https://reviews.llvm.org/D61556

Files:
  lib/AST/StmtPrinter.cpp
  test/AST/ast-printer-lambda.cpp


Index: lib/AST/StmtPrinter.cpp
===
--- lib/AST/StmtPrinter.cpp
+++ lib/AST/StmtPrinter.cpp
@@ -1895,6 +1895,9 @@
   llvm_unreachable("VLA type in explicit captures.");
 }
 
+if (C->isPackExpansion())
+  OS << "...";
+
 if (Node->isInitCapture(C))
   PrintExpr(C->getCapturedVar()->getInit());
   }
Index: test/AST/ast-printer-lambda.cpp
===
--- test/AST/ast-printer-lambda.cpp
+++ test/AST/ast-printer-lambda.cpp
@@ -0,0 +1,36 @@
+// RUN: %clang_cc1 -ast-print -std=c++17 %s | FileCheck %s
+
+struct S {
+template
+void test1(int i, T... t) {
+{
+  auto lambda = [i]{};
+  //CHECK: [i] {
+}
+{
+  auto lambda = [=]{};
+  //CHECK: [=] {
+}
+{
+  auto lambda = [&]{};
+  //CHECK: [&] {
+}
+{
+  auto lambda = [t..., i]{};
+  //CHECK: [t..., i] {
+}
+{
+  auto lambda = [&t...]{};
+  //CHECK: [&t...] {
+}
+{
+  auto lambda = [this, &t...]{};
+  //CHECK: [this, &t...] {
+}
+{
+  auto lambda = [t..., this]{};
+  //CHECK: [t..., this] {
+}
+}
+
+};
\ No newline at end of file


Index: lib/AST/StmtPrinter.cpp
===
--- lib/AST/StmtPrinter.cpp
+++ lib/AST/StmtPrinter.cpp
@@ -1895,6 +1895,9 @@
   llvm_unreachable("VLA type in explicit captures.");
 }
 
+if (C->isPackExpansion())
+  OS << "...";
+
 if (Node->isInitCapture(C))
   PrintExpr(C->getCapturedVar()->getInit());
   }
Index: test/AST/ast-printer-lambda.cpp
===
--- test/AST/ast-printer-lambda.cpp
+++ test/AST/ast-printer-lambda.cpp
@@ -0,0 +1,36 @@
+// RUN: %clang_cc1 -ast-print -std=c++17 %s | FileCheck %s
+
+struct S {
+template
+void test1(int i, T... t) {
+{
+  auto lambda = [i]{};
+  //CHECK: [i] {
+}
+{
+  auto lambda = [=]{};
+  //CHECK: [=] {
+}
+{
+  auto lambda = [&]{};
+  //CHECK: [&] {
+}
+{
+  auto lambda = [t..., i]{};
+  //CHECK: [t..., i] {
+}
+{
+  auto lambda = [&t...]{};
+  //CHECK: [&t...] {
+}
+{
+  auto lambda = [this, &t...]{};
+  //CHECK: [this, &t...] {
+}
+{
+  auto lambda = [t..., this]{};
+  //CHECK: [t..., this] {
+}
+}
+
+};
\ No newline at end of file
___
cfe-commits mailing list
cfe-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits


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

2019-05-05 Thread Nicolas Lesser via Phabricator via cfe-commits
Rakete added a comment.

Is this also okay?

  main.cpp:2:9: warning: lambda expressions are incompatible with C++98 
[-Wc++98-compat]
delete[] { return new int; }
  ^
  main.cpp:2:3: error: '[]' after delete interpreted as 'delete[]'; add 
parentheses to treat this as a lambda-expression
delete[] { return new int; }
^~~~
  ( )


Repository:
  rG LLVM Github Monorepo

CHANGES SINCE LAST ACTION
  https://reviews.llvm.org/D36357/new/

https://reviews.llvm.org/D36357



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


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

2019-05-05 Thread Nicolas Lesser via Phabricator via cfe-commits
Rakete added a comment.

@rsmith One last question: The fixit diagnostic seems to be inconsistent with 
the rest?

  main.cpp:2:3: error: '[]' after delete interpreted as 'delete[]'
delete[] { return new int; }
^~~~
  ( )

Shouldn't the `^~~` be starting at the `[]`?


Repository:
  rG LLVM Github Monorepo

CHANGES SINCE LAST ACTION
  https://reviews.llvm.org/D36357/new/

https://reviews.llvm.org/D36357



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


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

2019-05-04 Thread Nicolas Lesser via Phabricator via cfe-commits
Rakete updated this revision to Diff 198142.
Rakete added a comment.

friendly ping :)


Repository:
  rG LLVM Github Monorepo

CHANGES SINCE LAST ACTION
  https://reviews.llvm.org/D36357/new/

https://reviews.llvm.org/D36357

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

Index: clang/test/SemaCXX/new-delete-0x.cpp
===
--- clang/test/SemaCXX/new-delete-0x.cpp
+++ clang/test/SemaCXX/new-delete-0x.cpp
@@ -34,6 +34,6 @@
 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 {{'[]' after delete interpreted as 'delete[]'}}
 }
+
Index: clang/test/Parser/cxx0x-lambda-expressions.cpp
===
--- clang/test/Parser/cxx0x-lambda-expressions.cpp
+++ clang/test/Parser/cxx0x-lambda-expressions.cpp
@@ -53,8 +53,11 @@
   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 {{'[]' after delete interpreted as 'delete[]'}}
 delete [&] { return new int; } (); // ok, lambda
+
+delete []() { return new int; }(); // expected-error{{'[]' after delete interpreted as 'delete[]'}}
+delete [](E Enum) { return new int((int)Enum); }(e); // expected-error{{'[]' after delete interpreted as 'delete[]'}}
   }
 
   // We support init-captures in C++11 as an extension.
Index: clang/test/FixIt/fixit-cxx0x.cpp
===
--- clang/test/FixIt/fixit-cxx0x.cpp
+++ clang/test/FixIt/fixit-cxx0x.cpp
@@ -58,6 +58,9 @@
   (void)[&, i, i]{ }; // expected-error{{'i' can appear only once in a capture list}}
   (void)[] mutable { }; // expected-error{{lambda requires '()' before 'mutable'}}
   (void)[] -> int { }; // expected-error{{lambda requires '()' before return type}}
+
+  delete []() { return new int; }(); // expected-error{{'[]' after delete interpreted as 'delete[]'}}
+  delete [] { return new int; }(); // expected-error{{'[]' after delete interpreted as 'delete[]'}}
 }
 
 #define bar "bar"
Index: clang/lib/Parse/ParseExprCXX.cpp
===
--- clang/lib/Parse/ParseExprCXX.cpp
+++ clang/lib/Parse/ParseExprCXX.cpp
@@ -2984,8 +2984,38 @@
 //   [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.
+
+const Token Next = GetLookAheadToken(2);
+
+// Basic lookahead to check if we have a lambda expression.
+if (Next.isOneOf(tok::l_brace, tok::less) ||
+(Next.is(tok::l_paren) &&
+ (GetLookAheadToken(3).is(tok::r_paren) ||
+  (GetLookAheadToken(3).is(tok::identifier) &&
+   GetLookAheadToken(4).is(tok::identifier) {
+  SourceLocation RightBracketLock = NextToken().getLocation();
+  // Warn if the non-capturing lambda isn't surrounded by parenthesis
+  // to disambiguate it from 'delete[]'.
+  ExprResult Lambda = ParseLambdaExpression();
+  if (Lambda.isInvalid())
+return ExprError();
+
+  SourceLocation StartLoc = Lambda.get()->getBeginLoc();
+  Diag(Start, diag::err_lambda_after_delete)
+  << SourceRange(Start, RightBracketLock)
+  << FixItHint::CreateInsertion(StartLoc, "(")
+  << FixItHint::CreateInsertion(
+ Lexer::getLocForEndOfToken(Lambda.get()->getEndLoc(), 0,
+Actions.getSourceManager(),
+getLangOpts()),
+ ")");
+
+  // Evaluate any postfix expressions used on the lambda.
+  Lambda = ParsePostfixExpressionSuffix(Lambda);
+  return Actions.ActOnCXXDelete(Start, UseGlobal, /*ArrayForm=*/false,
+Lambda.get());
+}
+
 ArrayDelete = true;
 BalancedDelimiterTracker T(*this, tok::l_square);
 
Index: clang/include/clang/Basic/DiagnosticParseKinds.td
===
--- clang/include/clang/Basic/DiagnosticParseKinds.td
+++ clang/include/clang/Basic/DiagnosticParseKinds.td
@@ -105,6 +105,8 @@
   InGroup, DefaultIgnore;
 def ext_alignof_expr : ExtWarn<
   "%0 applied to an expression is a GNU extension">, InGroup;
+def err_lambda_after

[PATCH] D53847: [C++2a] P0634r3: Down with typename!

2019-05-04 Thread Nicolas Lesser via Phabricator via cfe-commits
Rakete updated this revision to Diff 198139.
Rakete added a comment.

Don't leak memory and friendly ping :)


Repository:
  rG LLVM Github Monorepo

CHANGES SINCE LAST ACTION
  https://reviews.llvm.org/D53847/new/

https://reviews.llvm.org/D53847

Files:
  clang/include/clang/Basic/DiagnosticSemaKinds.td
  clang/include/clang/Parse/Parser.h
  clang/include/clang/Sema/DeclSpec.h
  clang/include/clang/Sema/Sema.h
  clang/lib/Parse/ParseDecl.cpp
  clang/lib/Parse/ParseDeclCXX.cpp
  clang/lib/Parse/ParseExprCXX.cpp
  clang/lib/Parse/ParseTemplate.cpp
  clang/lib/Parse/ParseTentative.cpp
  clang/lib/Parse/Parser.cpp
  clang/lib/Sema/DeclSpec.cpp
  clang/lib/Sema/Sema.cpp
  clang/lib/Sema/SemaDecl.cpp
  clang/lib/Sema/SemaTemplate.cpp
  clang/test/CXX/drs/dr1xx.cpp
  clang/test/CXX/drs/dr2xx.cpp
  clang/test/CXX/drs/dr4xx.cpp
  clang/test/CXX/drs/dr5xx.cpp
  clang/test/CXX/temp/temp.res/p5.cpp
  clang/test/CXX/temp/temp.res/temp.dep/temp.dep.type/p1.cpp
  clang/test/FixIt/fixit.cpp
  clang/test/Parser/cxx-member-initializers.cpp
  clang/test/Parser/editor-placeholder-recovery.cpp
  clang/test/SemaCXX/MicrosoftCompatibility.cpp
  clang/test/SemaCXX/MicrosoftExtensions.cpp
  clang/test/SemaCXX/MicrosoftSuper.cpp
  clang/test/SemaCXX/unknown-type-name.cpp

Index: clang/test/SemaCXX/unknown-type-name.cpp
===
--- clang/test/SemaCXX/unknown-type-name.cpp
+++ clang/test/SemaCXX/unknown-type-name.cpp
@@ -36,15 +36,15 @@
 
   static int n;
   static type m;
-  static int h(T::type, int); // expected-error{{missing 'typename'}}
-  static int h(T::type x, char); // expected-error{{missing 'typename'}}
+  static int h(T::type, int); // expected-warning{{implicit 'typename' is a C++2a extension}}
+  static int h(T::type x, char); // expected-warning{{implicit 'typename' is a C++2a extension}}
 };
 
 template
-A::type g(T t) { return t; } // expected-error{{missing 'typename'}}
+A::type g(T t) { return t; } // expected-warning{{implicit 'typename' is a C++2a extension}}
 
 template
-A::type A::f() { return type(); } // expected-error{{missing 'typename'}}
+A::type A::f() { return type(); } // expected-warning{{implicit 'typename' is a C++2a extension}}
 
 template
 void f(T::type) { } // expected-error{{missing 'typename'}}
@@ -72,9 +72,7 @@
 
 int *p;
 
-// FIXME: We should assume that 'undeclared' is a type, not a parameter name
-//here, and produce an 'unknown type name' diagnostic instead.
-int f1(undeclared, int); // expected-error{{requires a type specifier}}
+int f1(undeclared, int); // expected-error{{unknown type name 'undeclared'}}
 
 int f2(undeclared, 0); // expected-error{{undeclared identifier}}
 
@@ -86,11 +84,11 @@
 
 template int A::n(T::value); // ok
 template
-A::type // expected-error{{missing 'typename'}}
+A::type // expected-warning {{implicit 'typename' is a C++2a extension}}
 A::m(T::value, 0); // ok
 
-template int A::h(T::type, int) {} // expected-error{{missing 'typename'}}
-template int A::h(T::type x, char) {} // expected-error{{missing 'typename'}}
+template int A::h(T::type, int) {} // expected-warning{{implicit 'typename' is a C++2a extension}}
+template int A::h(T::type x, char) {} // expected-warning{{implicit 'typename' is a C++2a extension}}
 
 template int h(T::type, int); // expected-error{{missing 'typename'}}
 template int h(T::type x, char); // expected-error{{missing 'typename'}}
@@ -118,4 +116,5 @@
 // FIXME: We know which type specifier should have been specified here. Provide
 //a fix-it to add 'typename A::type'
 template
-A::g() { } // expected-error{{requires a type specifier}}
+A::g() { } // expected-error{{expected unqualified-id}}
+// expected-warning@-1{{implicit 'typename' is a C++2a extension}}
Index: clang/test/SemaCXX/MicrosoftSuper.cpp
===
--- clang/test/SemaCXX/MicrosoftSuper.cpp
+++ clang/test/SemaCXX/MicrosoftSuper.cpp
@@ -108,8 +108,8 @@
   typename __super::XXX a;
   typedef typename __super::XXX b;
 
-  __super::XXX c; // expected-error {{missing 'typename'}}
-  typedef __super::XXX d; // expected-error {{missing 'typename'}}
+  __super::XXX c; // expected-warning {{implicit 'typename' is a C++2a extension}}
+  typedef __super::XXX d; // expected-warning {{implicit 'typename' is a C++2a extension}}
 
   void foo() {
 typename __super::XXX e;
@@ -127,8 +127,8 @@
   typename __super::XXX a;
   typedef typename __super::XXX b;
 
-  __super::XXX c; // expected-error {{missing 'typename'}}
-  typedef __super::XXX d; // expected-error {{missing 'typename'}}
+  __super::XXX c; // expected-warning {{implicit 'typename' is a C++2a extension}}
+  typedef __super::XXX d; // expected-warning {{implicit 'typename' is a C++2a extension}}
 
   void foo() {
 typename __super::XXX e;
Index: clang/test/SemaCXX/MicrosoftExtensions.cpp
===

[PATCH] D61522: Added an assertion to constant evaluation enty points that prohibits dependent expressions

2019-05-03 Thread Nicolas Lesser via Phabricator via cfe-commits
Rakete added a comment.

Can you add tests for the bugs you fixed? thanks


Repository:
  rG LLVM Github Monorepo

CHANGES SINCE LAST ACTION
  https://reviews.llvm.org/D61522/new/

https://reviews.llvm.org/D61522



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


[PATCH] D60934: [clang] adding explicit(bool) from c++2a

2019-05-01 Thread Nicolas Lesser via Phabricator via cfe-commits
Rakete added inline comments.



Comment at: clang/include/clang/AST/DeclCXX.h:2579
+assert(
+!ES.getExpr() ||
+CXXConstructorDeclBits.HasTrailingExplicitSpecifier &&

Tyker wrote:
> Rakete wrote:
> > Your or needs parens or the disambiguation is wrong.
> i don't understand. but there is no need for disambiguation, `a && true == a` 
> so this will work regardless of operator priority.
Yeah sorry you're right, I meant that the parens are needed to shut up -Wparens 
warning about disambiguation.



Comment at: clang/include/clang/Serialization/ASTReader.h:2435
+uint64_t Kind = readInt();
+bool hasExpr = Kind & 0x1;
+Kind = Kind >> 1;

Tyker wrote:
> Rakete wrote:
> > same here.
> what is the issue
> For consistency with nearby code, please name this variable starting with a 
> capital letter.


CHANGES SINCE LAST ACTION
  https://reviews.llvm.org/D60934/new/

https://reviews.llvm.org/D60934



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


[PATCH] D60934: [clang] adding explicit(bool) from c++2a

2019-04-30 Thread Nicolas Lesser via Phabricator via cfe-commits
Rakete added inline comments.



Comment at: clang/include/clang/AST/DeclCXX.h:2579
+assert(
+!ES.getExpr() ||
+CXXConstructorDeclBits.HasTrailingExplicitSpecifier &&

Your or needs parens or the disambiguation is wrong.



Comment at: clang/include/clang/Serialization/ASTReader.h:2435
+uint64_t Kind = readInt();
+bool hasExpr = Kind & 0x1;
+Kind = Kind >> 1;

same here.



Comment at: clang/lib/Sema/DeclSpec.cpp:952
+  ExplicitSpec.getExpr()) &&
+ "invalide ExplicitSpecifier");
   // 'explicit explicit' is ok, but warn as this is likely not what the user

typo.



Comment at: clang/test/CXX/temp/temp.deduct.guide/p1.cpp:74
 virtual A(int(&)[28]) -> A; // expected-error {{'virtual' can only appear 
on non-static member functions}}
-const A(int(&)[28]) -> A; // expected-error {{deduction guide cannot be 
declared 'const'}}
+const A(int(&)[31]) -> A; // expected-error {{deduction guide cannot be 
declared 'const'}}
 

Is there a reason why you changed this?


CHANGES SINCE LAST ACTION
  https://reviews.llvm.org/D60934/new/

https://reviews.llvm.org/D60934



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


[PATCH] D60934: [clang] adding explicit(bool) from c++2a

2019-04-25 Thread Nicolas Lesser via Phabricator via cfe-commits
Rakete added a comment.

Thanks for working on this! :)




Comment at: clang/lib/Parse/ParseDecl.cpp:3533
+  if (ExplicitExpr.isInvalid()) {
+Diag(ParenLoc, diag::note_explicit_bool_breaking_change_cxx2a)
+<< FixItHint::CreateReplacement(

This is a useful diagnostic but you'll need to fix (a lot) of false positives:

```
template  struct Foo { explicit(T{} +) Foo(); };
```

gets me:

```
main.cpp:1:50: error: expected expression
template  struct Foo { explicit(T{} +) Foo(); };
 ^
main.cpp:1:44: note: this expression is parsed as explicit(bool) since C++2a
template  struct Foo { explicit(T{} +) Foo(); };
   ^
   explicit(true)
```

Fixit hints should only be used when it is 100% the right fix that works, 
always.



Comment at: clang/lib/Parse/ParseDecl.cpp:3534
+Diag(ParenLoc, diag::note_explicit_bool_breaking_change_cxx2a)
+<< FixItHint::CreateReplacement(
+   SourceRange(ExplicitLoc, ExplicitLoc.getLocWithOffset(

FixIt Hints also need tests :)



Comment at: clang/lib/Sema/DeclSpec.cpp:952
+  assert((ExplicitState != ESF_unresolved || ExplicitExpr) &&
+ "ExplicitExpr can't be null if the state is ESF_resolved_false or "
+ "ESF_unresolved");

The comment seems to explain something else than the code.



Comment at: clang/lib/Sema/DeclSpec.cpp:956
   // intended.
-  if (FS_explicit_specified) {
+  // TODO : it is unclear how to handle multiple explicit(bool) specifiers.
+  if (hasExplicitSpecifier()) {

We accept `explicit explicit`, but we really shouldn't accept 
`explicit(some-expr) explicit(some-other-expr)`. That would just be confusing. 
`explicit explicit(some-expr)` is also borderline.



Comment at: clang/lib/Sema/DeclSpec.cpp:1316
 FixItHint Hint = FixItHint::CreateRemoval(SCLoc);
 S.Diag(SCLoc, diag::err_friend_decl_spec)
   << Keyword << Hint;

Please change this warning so that the whole *explicit-specifier* is underlined 
(or even change the text for conditional explicit):

```
main.cpp:1:36: error: 'explicit' can only be applied to a constructor or 
conversion function
template  struct Foo { explicit(false) void foo(); };
   ^~~~
1 error generated.
```

This will also fix the FixIt Hint.



Comment at: clang/lib/Sema/SemaDeclCXX.cpp:8641
   // C++0x explicit conversion operators.
-  if (DS.isExplicitSpecified())
+  if (DS.hasExplicitSpecifier())
 Diag(DS.getExplicitSpecLoc(),

You should amend the diagnostic, because as of right now `explicit(true)` is 
being diagnosed as C++11 feature.



Comment at: clang/lib/Sema/SemaDeclCXX.cpp:10870
+  ExprResult Converted =
+  CheckBooleanCondition(Loc, ExplicitExpr, /*isConstexpr=*/true);
+  if (Converted.isInvalid())

This assumes that we are in a [constexpr] if, leading to errors like this:

```
int a;
template  struct Foo { explicit(a) Foo(); };
```

```
main.cpp:2:45: error: constexpr if condition is not a constant expression
template  struct Foo { explicit(a) Foo(); };
^
```



Comment at: clang/lib/Sema/SemaDeclCXX.cpp:10876-10881
+return Converted;
+  }
+
+  llvm::APSInt Result;
+  Converted = VerifyIntegerConstantExpression(
+  Converted.get(), &Result, diag::err_noexcept_needs_constant_expression,

Wrong diagnostic.



Comment at: clang/lib/Sema/SemaOverload.cpp:10359
+  default:
+llvm_unreachable("invalide Decl");
+  }

typo.




Comment at: clang/lib/Sema/SemaOverload.cpp:10361
+  }
+  assert(ESI.getPointer() && "null expression should be handled before");
+  S.Diag(Cand->Function->getLocation(),

This fires for an instantiation dependent (but not value dependent) explicit 
specifier that is invalid:

```
template  struct Foo { explicit((T{}, false)) Foo(int); };

int main() { Foo f = 1; }
```



Comment at: clang/test/SemaCXX/cxx2a-compat.cpp:46
+#if __cplusplus <= 201703L
+// expected-warning@-3 {{this expression would be parsed as explicit(bool) in 
C++2a}}
+#if defined(__cpp_conditional_explicit)

would -> will



Comment at: clang/test/SemaCXX/cxx2a-compat.cpp:51
+#else
+// expected-error@-8 {{does not refer to a value}}
+// expected-error@-9 {{expected member name or ';'}}

A fixit hint for this would be great. Also it would be nice if there was a 
nicer error message.


CHANGES SINCE LAST ACTION
  https://reviews.llvm.org/D60934/new/

https://reviews.llvm.org/D60934



___
cfe-comm

[PATCH] D59900: [Sema] Fix a crash when nonnull checking

2019-03-28 Thread Nicolas Lesser via Phabricator via cfe-commits
Rakete accepted this revision.
Rakete added a comment.
This revision is now accepted and ready to land.

Otherwise LGTM.




Comment at: clang/test/SemaTemplate/decltype.cpp:1
+// RUN: %clang_cc1 -std=c++11 -fsyntax-only -verify %s
+// no crash & no diag

test/SemaCXX/nonnull.cpp would be a better place to put this test.



Comment at: clang/test/SemaTemplate/decltype.cpp:2
+// RUN: %clang_cc1 -std=c++11 -fsyntax-only -verify %s
+// no crash & no diag
+

This is redundant :)



Comment at: clang/test/SemaTemplate/decltype.cpp:4
+
+// expected-no-diagnostics
+template 

If you move the test as above you can drop this line.


Repository:
  rG LLVM Github Monorepo

CHANGES SINCE LAST ACTION
  https://reviews.llvm.org/D59900/new/

https://reviews.llvm.org/D59900



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


[PATCH] D59754: [Sema] Add c++2a designated initializer warnings

2019-03-26 Thread Nicolas Lesser via Phabricator via cfe-commits
Rakete added inline comments.



Comment at: clang/lib/Sema/SemaInit.cpp:2044
+ : std::distance(RD->field_begin(), RD->field_end());
+  if (VerifyOnly && (LastIdx >= NextIdx || HasNonDesignatedInit) &&
+  SemaRef.getLangOpts().CPlusPlus2a)

hintonda wrote:
> Rakete wrote:
> > `!VerifyOnly` and braces please.
> Will commit this change as soon as check-clang finishes, but not sure I grok 
> the VerityOnly/!VerifyOnly criteria.  Could you help me out? 
`VerifyOnly` is used if you only want to verify and not actually generate any 
diagnostics or actually do anything that would commit to that change. So only 
generate the warning if `!VerifyOnly`.


Repository:
  rG LLVM Github Monorepo

CHANGES SINCE LAST ACTION
  https://reviews.llvm.org/D59754/new/

https://reviews.llvm.org/D59754



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


[PATCH] D59754: [Sema] Add c++2a designated initializer warnings

2019-03-25 Thread Nicolas Lesser via Phabricator via cfe-commits
Rakete added inline comments.



Comment at: clang/test/SemaCXX/cxx2a-initializer-aggregates.cpp:30
+// out of order designators
+A a1 = {.y = 1, .x = 2}; // expected-warning {{designated initializers are a 
C99 feature}}
+

hintonda wrote:
> lebedev.ri wrote:
> > hintonda wrote:
> > > Rakete wrote:
> > > > Those warnings are misleading, since C++20 does have designated 
> > > > initializers; they just don't support some stuff that C99 does. It 
> > > > would be better  IMO if you could separate them. As in, the above 
> > > > should give you: `out-of-order designated initializers are a C99 
> > > > feature` or something like that.
> > > I think that would be a good idea as well, but wanted to get advise first.
> > > As in, the above should give you: out-of-order designated initializers 
> > > are a C99 feature or something like that.
> > 
> > I suppose also the question is, whether to error-out, or support them as an 
> > extension?
> > 
> Although most of them seem fine, the nested ones can be problematic.  Please 
> see https://reviews.llvm.org/D17407 for a proposal on how to fix them.
> I suppose also the question is, whether to error-out, or support them as an 
> extension?

Yes that's true. gcc doesn't support them at all in C++, and it seems like we 
accept it as well, but only for C classes (constructors make clang crash).

But making it an error now breaks backwards compatibility. So I think the best 
solution is to accept it for now, as an extension.


Repository:
  rG LLVM Github Monorepo

CHANGES SINCE LAST ACTION
  https://reviews.llvm.org/D59754/new/

https://reviews.llvm.org/D59754



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


[PATCH] D59754: [Sema] Add c++2a designated initializer warnings

2019-03-25 Thread Nicolas Lesser via Phabricator via cfe-commits
Rakete added inline comments.



Comment at: clang/lib/Sema/SemaInit.cpp:2017
 
+  auto LastIdx = Field != FieldEnd
+ ? Field->getFieldIndex()

Can `Field` ever be `FieldEnd` at this point?



Comment at: clang/lib/Sema/SemaInit.cpp:2044
+ : std::distance(RD->field_begin(), RD->field_end());
+  if (VerifyOnly && (LastIdx >= NextIdx || HasNonDesignatedInit) &&
+  SemaRef.getLangOpts().CPlusPlus2a)

`!VerifyOnly` and braces please.



Comment at: clang/lib/Sema/SemaInit.cpp:2065
+// Warn on mixed designators in C++20
+if (VerifyOnly && HasDesignatedInit && SemaRef.getLangOpts().CPlusPlus2a)
+  SemaRef.Diag(Init->getBeginLoc(), diag::ext_designated_init)

Same here. It should be `!VerifyOnly`. Also braces for the if statement.



Comment at: clang/lib/Sema/SemaInit.cpp:3087
   if (!getLangOpts().C99)
-Diag(DIE->getBeginLoc(), diag::ext_designated_init)
-<< DIE->getSourceRange();
+// Warn on nested and array designators in C++20
+if (!getLangOpts().CPlusPlus2a || Desig.getNumDesignators() > 1 ||

Missing dot.



Comment at: clang/lib/Sema/SemaInit.cpp:3089
+if (!getLangOpts().CPlusPlus2a || Desig.getNumDesignators() > 1 ||
+HasArrayDesignator)
+  Diag(DIE->getBeginLoc(), diag::ext_designated_init)

Braces.



Comment at: clang/test/SemaCXX/cxx2a-initializer-aggregates.cpp:30
+// out of order designators
+A a1 = {.y = 1, .x = 2}; // expected-warning {{designated initializers are a 
C99 feature}}
+

Those warnings are misleading, since C++20 does have designated initializers; 
they just don't support some stuff that C99 does. It would be better  IMO if 
you could separate them. As in, the above should give you: `out-of-order 
designated initializers are a C99 feature` or something like that.


Repository:
  rG LLVM Github Monorepo

CHANGES SINCE LAST ACTION
  https://reviews.llvm.org/D59754/new/

https://reviews.llvm.org/D59754



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


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

2019-03-13 Thread Nicolas Lesser via Phabricator via cfe-commits
Rakete updated this revision to Diff 190435.
Rakete added a comment.

Rebase + friendly ping :).


Repository:
  rG LLVM Github Monorepo

CHANGES SINCE LAST ACTION
  https://reviews.llvm.org/D36357/new/

https://reviews.llvm.org/D36357

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

Index: clang/test/SemaCXX/new-delete-0x.cpp
===
--- clang/test/SemaCXX/new-delete-0x.cpp
+++ clang/test/SemaCXX/new-delete-0x.cpp
@@ -34,6 +34,6 @@
 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 {{'[]' after delete interpreted as 'delete[]'}}
 }
+
Index: clang/test/Parser/cxx0x-lambda-expressions.cpp
===
--- clang/test/Parser/cxx0x-lambda-expressions.cpp
+++ clang/test/Parser/cxx0x-lambda-expressions.cpp
@@ -53,8 +53,11 @@
   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 {{'[]' after delete interpreted as 'delete[]'}}
 delete [&] { return new int; } (); // ok, lambda
+
+delete []() { return new int; }(); // expected-error{{'[]' after delete interpreted as 'delete[]'}}
+delete [](E Enum) { return new int((int)Enum); }(e); // expected-error{{'[]' after delete interpreted as 'delete[]'}}
   }
 
   // We support init-captures in C++11 as an extension.
Index: clang/test/FixIt/fixit-cxx0x.cpp
===
--- clang/test/FixIt/fixit-cxx0x.cpp
+++ clang/test/FixIt/fixit-cxx0x.cpp
@@ -58,6 +58,9 @@
   (void)[&, i, i]{ }; // expected-error{{'i' can appear only once in a capture list}}
   (void)[] mutable { }; // expected-error{{lambda requires '()' before 'mutable'}}
   (void)[] -> int { }; // expected-error{{lambda requires '()' before return type}}
+
+  delete []() { return new int; }(); // expected-error{{'[]' after delete interpreted as 'delete[]'}}
+  delete [] { return new int; }(); // expected-error{{'[]' after delete interpreted as 'delete[]'}}
 }
 
 #define bar "bar"
Index: clang/lib/Parse/ParseExprCXX.cpp
===
--- clang/lib/Parse/ParseExprCXX.cpp
+++ clang/lib/Parse/ParseExprCXX.cpp
@@ -2984,8 +2984,38 @@
 //   [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.
+
+const Token Next = GetLookAheadToken(2);
+
+// Basic lookahead to check if we have a lambda expression.
+if (Next.isOneOf(tok::l_brace, tok::less) ||
+(Next.is(tok::l_paren) &&
+ (GetLookAheadToken(3).is(tok::r_paren) ||
+  (GetLookAheadToken(3).is(tok::identifier) &&
+   GetLookAheadToken(4).is(tok::identifier) {
+  SourceLocation RightBracketLock = NextToken().getLocation();
+  // Warn if the non-capturing lambda isn't surrounded by parenthesis
+  // to disambiguate it from 'delete[]'.
+  ExprResult Lambda = ParseLambdaExpression();
+  if (Lambda.isInvalid())
+return ExprError();
+
+  SourceLocation StartLoc = Lambda.get()->getBeginLoc();
+  Diag(Start, diag::err_lambda_after_delete)
+  << SourceRange(Start, RightBracketLock)
+  << FixItHint::CreateInsertion(StartLoc, "(")
+  << FixItHint::CreateInsertion(
+ Lexer::getLocForEndOfToken(Lambda.get()->getEndLoc(), 0,
+Actions.getSourceManager(),
+getLangOpts()),
+ ")");
+
+  // Evaluate any postfix expressions used on the lambda.
+  Lambda = ParsePostfixExpressionSuffix(Lambda);
+  return Actions.ActOnCXXDelete(Start, UseGlobal, /*ArrayForm=*/false,
+Lambda.get());
+}
+
 ArrayDelete = true;
 BalancedDelimiterTracker T(*this, tok::l_square);
 
Index: clang/include/clang/Basic/DiagnosticParseKinds.td
===
--- clang/include/clang/Basic/DiagnosticParseKinds.td
+++ clang/include/clang/Basic/DiagnosticParseKinds.td
@@ -105,6 +105,8 @@
   InGroup, DefaultIgnore;
 def ext_alignof_expr : ExtWarn<
   "%0 applied to an expression is a GNU extension">, InGroup;
+def err_la

[PATCH] D53847: [C++2a] P0634r3: Down with typename!

2019-03-10 Thread Nicolas Lesser via Phabricator via cfe-commits
Rakete updated this revision to Diff 190013.
Rakete added a comment.

Don't relookup the qualified-id and use the cached one instead if possible.


Repository:
  rG LLVM Github Monorepo

CHANGES SINCE LAST ACTION
  https://reviews.llvm.org/D53847/new/

https://reviews.llvm.org/D53847

Files:
  clang/include/clang/Basic/DiagnosticSemaKinds.td
  clang/include/clang/Parse/Parser.h
  clang/include/clang/Sema/DeclSpec.h
  clang/include/clang/Sema/Sema.h
  clang/lib/Parse/ParseDecl.cpp
  clang/lib/Parse/ParseDeclCXX.cpp
  clang/lib/Parse/ParseExprCXX.cpp
  clang/lib/Parse/ParseTemplate.cpp
  clang/lib/Parse/ParseTentative.cpp
  clang/lib/Parse/Parser.cpp
  clang/lib/Sema/DeclSpec.cpp
  clang/lib/Sema/Sema.cpp
  clang/lib/Sema/SemaDecl.cpp
  clang/lib/Sema/SemaTemplate.cpp
  clang/test/CXX/drs/dr1xx.cpp
  clang/test/CXX/drs/dr2xx.cpp
  clang/test/CXX/drs/dr4xx.cpp
  clang/test/CXX/drs/dr5xx.cpp
  clang/test/CXX/temp/temp.res/p5.cpp
  clang/test/CXX/temp/temp.res/temp.dep/temp.dep.type/p1.cpp
  clang/test/FixIt/fixit.cpp
  clang/test/Parser/cxx-member-initializers.cpp
  clang/test/Parser/editor-placeholder-recovery.cpp
  clang/test/SemaCXX/MicrosoftCompatibility.cpp
  clang/test/SemaCXX/MicrosoftExtensions.cpp
  clang/test/SemaCXX/MicrosoftSuper.cpp
  clang/test/SemaCXX/unknown-type-name.cpp

Index: clang/test/SemaCXX/unknown-type-name.cpp
===
--- clang/test/SemaCXX/unknown-type-name.cpp
+++ clang/test/SemaCXX/unknown-type-name.cpp
@@ -36,15 +36,15 @@
 
   static int n;
   static type m;
-  static int h(T::type, int); // expected-error{{missing 'typename'}}
-  static int h(T::type x, char); // expected-error{{missing 'typename'}}
+  static int h(T::type, int); // expected-warning{{implicit 'typename' is a C++2a extension}}
+  static int h(T::type x, char); // expected-warning{{implicit 'typename' is a C++2a extension}}
 };
 
 template
-A::type g(T t) { return t; } // expected-error{{missing 'typename'}}
+A::type g(T t) { return t; } // expected-warning{{implicit 'typename' is a C++2a extension}}
 
 template
-A::type A::f() { return type(); } // expected-error{{missing 'typename'}}
+A::type A::f() { return type(); } // expected-warning{{implicit 'typename' is a C++2a extension}}
 
 template
 void f(T::type) { } // expected-error{{missing 'typename'}}
@@ -72,9 +72,7 @@
 
 int *p;
 
-// FIXME: We should assume that 'undeclared' is a type, not a parameter name
-//here, and produce an 'unknown type name' diagnostic instead.
-int f1(undeclared, int); // expected-error{{requires a type specifier}}
+int f1(undeclared, int); // expected-error{{unknown type name 'undeclared'}}
 
 int f2(undeclared, 0); // expected-error{{undeclared identifier}}
 
@@ -86,11 +84,11 @@
 
 template int A::n(T::value); // ok
 template
-A::type // expected-error{{missing 'typename'}}
+A::type // expected-warning {{implicit 'typename' is a C++2a extension}}
 A::m(T::value, 0); // ok
 
-template int A::h(T::type, int) {} // expected-error{{missing 'typename'}}
-template int A::h(T::type x, char) {} // expected-error{{missing 'typename'}}
+template int A::h(T::type, int) {} // expected-warning{{implicit 'typename' is a C++2a extension}}
+template int A::h(T::type x, char) {} // expected-warning{{implicit 'typename' is a C++2a extension}}
 
 template int h(T::type, int); // expected-error{{missing 'typename'}}
 template int h(T::type x, char); // expected-error{{missing 'typename'}}
@@ -118,4 +116,5 @@
 // FIXME: We know which type specifier should have been specified here. Provide
 //a fix-it to add 'typename A::type'
 template
-A::g() { } // expected-error{{requires a type specifier}}
+A::g() { } // expected-error{{expected unqualified-id}}
+// expected-warning@-1{{implicit 'typename' is a C++2a extension}}
Index: clang/test/SemaCXX/MicrosoftSuper.cpp
===
--- clang/test/SemaCXX/MicrosoftSuper.cpp
+++ clang/test/SemaCXX/MicrosoftSuper.cpp
@@ -108,8 +108,8 @@
   typename __super::XXX a;
   typedef typename __super::XXX b;
 
-  __super::XXX c; // expected-error {{missing 'typename'}}
-  typedef __super::XXX d; // expected-error {{missing 'typename'}}
+  __super::XXX c; // expected-warning {{implicit 'typename' is a C++2a extension}}
+  typedef __super::XXX d; // expected-warning {{implicit 'typename' is a C++2a extension}}
 
   void foo() {
 typename __super::XXX e;
@@ -127,8 +127,8 @@
   typename __super::XXX a;
   typedef typename __super::XXX b;
 
-  __super::XXX c; // expected-error {{missing 'typename'}}
-  typedef __super::XXX d; // expected-error {{missing 'typename'}}
+  __super::XXX c; // expected-warning {{implicit 'typename' is a C++2a extension}}
+  typedef __super::XXX d; // expected-warning {{implicit 'typename' is a C++2a extension}}
 
   void foo() {
 typename __super::XXX e;
Index: clang/test/SemaCXX/MicrosoftExtensions.cpp
==

[PATCH] D53847: [C++2a] P0634r3: Down with typename!

2019-03-10 Thread Nicolas Lesser via Phabricator via cfe-commits
Rakete added a comment.

rsmith:

> Some thoughts on this:
> 
> - Can this be unified with the lookup code in HandleDeclarator? This is 
> really the same lookup, repeated in two places.

What I wrote:

> I don't think so, because HandleDeclarator is called after having already 
> parsed the function declaration. I cached it now, but the cleanest solution 
> that I could think of is to use new. Is this appropriate? Or do you have an 
> alternative suggestion?

Maybe a `llvm::Optional` is more appropriate?

> - It'd be nice to cache this lookup, rather than performing it three times 
> (once when disambiguating a parenthesized initializer from a function 
> declaration, once when we're about to parse a parameter-declaration-clause, 
> and once in HandleDeclarator after parsing completes -- though at least 
> that's reduced to two lookups if you make the change I suggested in 
> ParseParameterDeclarationClause)

Hmm let me see what I can do about that.

> - If we don't do the caching, what happens if lookup fails due to ambiguity? 
> Do we get the same error multiple times (once for each time we perform the 
> lookup)?


Repository:
  rG LLVM Github Monorepo

CHANGES SINCE LAST ACTION
  https://reviews.llvm.org/D53847/new/

https://reviews.llvm.org/D53847



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


[PATCH] D53847: [C++2a] P0634r3: Down with typename!

2019-03-10 Thread Nicolas Lesser via Phabricator via cfe-commits
Rakete updated this revision to Diff 190012.
Rakete added a comment.
Herald added a subscriber: jdoerfert.
Herald added a project: clang.

Fix a bug where `T::value` inside a functional cast in a template argument 
would be interpreted as a function type.

Also added the missing test file that got lost in a previous revision for some 
reason. :)


Repository:
  rG LLVM Github Monorepo

CHANGES SINCE LAST ACTION
  https://reviews.llvm.org/D53847/new/

https://reviews.llvm.org/D53847

Files:
  clang/include/clang/Basic/DiagnosticSemaKinds.td
  clang/include/clang/Parse/Parser.h
  clang/include/clang/Sema/DeclSpec.h
  clang/include/clang/Sema/Sema.h
  clang/lib/Parse/ParseDecl.cpp
  clang/lib/Parse/ParseDeclCXX.cpp
  clang/lib/Parse/ParseExprCXX.cpp
  clang/lib/Parse/ParseTemplate.cpp
  clang/lib/Parse/ParseTentative.cpp
  clang/lib/Parse/Parser.cpp
  clang/lib/Sema/DeclSpec.cpp
  clang/lib/Sema/Sema.cpp
  clang/lib/Sema/SemaDecl.cpp
  clang/lib/Sema/SemaTemplate.cpp
  clang/test/CXX/drs/dr1xx.cpp
  clang/test/CXX/drs/dr2xx.cpp
  clang/test/CXX/drs/dr4xx.cpp
  clang/test/CXX/drs/dr5xx.cpp
  clang/test/CXX/temp/temp.res/p5.cpp
  clang/test/CXX/temp/temp.res/temp.dep/temp.dep.type/p1.cpp
  clang/test/FixIt/fixit.cpp
  clang/test/Parser/cxx-member-initializers.cpp
  clang/test/Parser/editor-placeholder-recovery.cpp
  clang/test/SemaCXX/MicrosoftCompatibility.cpp
  clang/test/SemaCXX/MicrosoftExtensions.cpp
  clang/test/SemaCXX/MicrosoftSuper.cpp
  clang/test/SemaCXX/unknown-type-name.cpp

Index: clang/test/SemaCXX/unknown-type-name.cpp
===
--- clang/test/SemaCXX/unknown-type-name.cpp
+++ clang/test/SemaCXX/unknown-type-name.cpp
@@ -36,15 +36,15 @@
 
   static int n;
   static type m;
-  static int h(T::type, int); // expected-error{{missing 'typename'}}
-  static int h(T::type x, char); // expected-error{{missing 'typename'}}
+  static int h(T::type, int); // expected-warning{{implicit 'typename' is a C++2a extension}}
+  static int h(T::type x, char); // expected-warning{{implicit 'typename' is a C++2a extension}}
 };
 
 template
-A::type g(T t) { return t; } // expected-error{{missing 'typename'}}
+A::type g(T t) { return t; } // expected-warning{{implicit 'typename' is a C++2a extension}}
 
 template
-A::type A::f() { return type(); } // expected-error{{missing 'typename'}}
+A::type A::f() { return type(); } // expected-warning{{implicit 'typename' is a C++2a extension}}
 
 template
 void f(T::type) { } // expected-error{{missing 'typename'}}
@@ -72,9 +72,7 @@
 
 int *p;
 
-// FIXME: We should assume that 'undeclared' is a type, not a parameter name
-//here, and produce an 'unknown type name' diagnostic instead.
-int f1(undeclared, int); // expected-error{{requires a type specifier}}
+int f1(undeclared, int); // expected-error{{unknown type name 'undeclared'}}
 
 int f2(undeclared, 0); // expected-error{{undeclared identifier}}
 
@@ -86,11 +84,11 @@
 
 template int A::n(T::value); // ok
 template
-A::type // expected-error{{missing 'typename'}}
+A::type // expected-warning {{implicit 'typename' is a C++2a extension}}
 A::m(T::value, 0); // ok
 
-template int A::h(T::type, int) {} // expected-error{{missing 'typename'}}
-template int A::h(T::type x, char) {} // expected-error{{missing 'typename'}}
+template int A::h(T::type, int) {} // expected-warning{{implicit 'typename' is a C++2a extension}}
+template int A::h(T::type x, char) {} // expected-warning{{implicit 'typename' is a C++2a extension}}
 
 template int h(T::type, int); // expected-error{{missing 'typename'}}
 template int h(T::type x, char); // expected-error{{missing 'typename'}}
@@ -118,4 +116,5 @@
 // FIXME: We know which type specifier should have been specified here. Provide
 //a fix-it to add 'typename A::type'
 template
-A::g() { } // expected-error{{requires a type specifier}}
+A::g() { } // expected-error{{expected unqualified-id}}
+// expected-warning@-1{{implicit 'typename' is a C++2a extension}}
Index: clang/test/SemaCXX/MicrosoftSuper.cpp
===
--- clang/test/SemaCXX/MicrosoftSuper.cpp
+++ clang/test/SemaCXX/MicrosoftSuper.cpp
@@ -108,8 +108,8 @@
   typename __super::XXX a;
   typedef typename __super::XXX b;
 
-  __super::XXX c; // expected-error {{missing 'typename'}}
-  typedef __super::XXX d; // expected-error {{missing 'typename'}}
+  __super::XXX c; // expected-warning {{implicit 'typename' is a C++2a extension}}
+  typedef __super::XXX d; // expected-warning {{implicit 'typename' is a C++2a extension}}
 
   void foo() {
 typename __super::XXX e;
@@ -127,8 +127,8 @@
   typename __super::XXX a;
   typedef typename __super::XXX b;
 
-  __super::XXX c; // expected-error {{missing 'typename'}}
-  typedef __super::XXX d; // expected-error {{missing 'typename'}}
+  __super::XXX c; // expected-warning {{implicit 'typename' is a C++2a extension}}
+  typedef

[PATCH] D57540: [C++17] Don't crash while diagnosing different access specifier of a deduction guide.

2019-02-18 Thread Nicolas Lesser via Phabricator via cfe-commits
Rakete abandoned this revision.
Rakete added a comment.
Herald added a subscriber: jdoerfert.

This revision has been superseded :)


Repository:
  rC Clang

CHANGES SINCE LAST ACTION
  https://reviews.llvm.org/D57540/new/

https://reviews.llvm.org/D57540



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


[PATCH] D57540: [C++17] Don't crash while diagnosing different access specifier of a deduction guide.

2019-02-02 Thread Nicolas Lesser via Phabricator via cfe-commits
Rakete marked an inline comment as done.
Rakete added inline comments.



Comment at: test/SemaCXX/cxx1z-class-template-argument-deduction.cpp:360-361
+  struct Type {
+Typo(); // expected-error{{deduction guide must be declared in the same 
scope}}
+// expected-error@-1{{deduction guide declaration without trailing return 
type}}
+  };

aaron.ballman wrote:
> These errors are pretty unfortunate -- they don't really help the user to 
> understand what's gone wrong here. They're an improvement over the crash, but 
> I think we should try to make the errors more useful if we can.
> 
> Why is `Typo()` being treated as a deduction guide? Perhaps we could look to 
> see if there is a `->` before making that determination?
> Perhaps we could look to see if there is a -> before making that 
> determination?

Yes that would be possible. The diagnostic would change for the following code:

```
template 
struct Foo {};

Foo();// -> Foo; 
// currently: deduction guide missing ->
// after: C++ requires type specifier for every declaration
```

Is that acceptable? Or I guess I could restrict this to partial deduction 
guides in classes.


Repository:
  rC Clang

CHANGES SINCE LAST ACTION
  https://reviews.llvm.org/D57540/new/

https://reviews.llvm.org/D57540



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


[PATCH] D57540: [C++17] Don't crash while diagnosing different access specifier of a deduction guide.

2019-01-31 Thread Nicolas Lesser via Phabricator via cfe-commits
Rakete created this revision.
Rakete added a reviewer: rsmith.

This fixes PR40552 by not showing the diagnostic that complains about different 
access specifiers, since the template does not have one.


Repository:
  rC Clang

https://reviews.llvm.org/D57540

Files:
  lib/Sema/SemaDeclCXX.cpp
  test/SemaCXX/cxx1z-class-template-argument-deduction.cpp


Index: test/SemaCXX/cxx1z-class-template-argument-deduction.cpp
===
--- test/SemaCXX/cxx1z-class-template-argument-deduction.cpp
+++ test/SemaCXX/cxx1z-class-template-argument-deduction.cpp
@@ -353,6 +353,13 @@
 template Protected(T) -> Protected; // expected-error 
{{different access}}
 template Private(T) -> Private; // expected-error 
{{different access}}
   };
+
+  // PR40552
+  template  struct Typo {}; // expected-note{{template is declared 
here}}
+  struct Type {
+Typo(); // expected-error{{deduction guide must be declared in the same 
scope}}
+// expected-error@-1{{deduction guide declaration without trailing return 
type}}
+  };
 }
 
 namespace rdar41903969 {
Index: lib/Sema/SemaDeclCXX.cpp
===
--- lib/Sema/SemaDeclCXX.cpp
+++ lib/Sema/SemaDeclCXX.cpp
@@ -3175,7 +3175,7 @@
 //   declared] with the same access [as the template].
 if (auto *DG = dyn_cast(NonTemplateMember)) {
   auto *TD = DG->getDeducedTemplate();
-  if (AS != TD->getAccess()) {
+  if (AS != TD->getAccess() && TD->getAccess() != AS_none) {
 Diag(DG->getBeginLoc(), diag::err_deduction_guide_wrong_access);
 Diag(TD->getBeginLoc(), diag::note_deduction_guide_template_access)
 << TD->getAccess();


Index: test/SemaCXX/cxx1z-class-template-argument-deduction.cpp
===
--- test/SemaCXX/cxx1z-class-template-argument-deduction.cpp
+++ test/SemaCXX/cxx1z-class-template-argument-deduction.cpp
@@ -353,6 +353,13 @@
 template Protected(T) -> Protected; // expected-error {{different access}}
 template Private(T) -> Private; // expected-error {{different access}}
   };
+
+  // PR40552
+  template  struct Typo {}; // expected-note{{template is declared here}}
+  struct Type {
+Typo(); // expected-error{{deduction guide must be declared in the same scope}}
+// expected-error@-1{{deduction guide declaration without trailing return type}}
+  };
 }
 
 namespace rdar41903969 {
Index: lib/Sema/SemaDeclCXX.cpp
===
--- lib/Sema/SemaDeclCXX.cpp
+++ lib/Sema/SemaDeclCXX.cpp
@@ -3175,7 +3175,7 @@
 //   declared] with the same access [as the template].
 if (auto *DG = dyn_cast(NonTemplateMember)) {
   auto *TD = DG->getDeducedTemplate();
-  if (AS != TD->getAccess()) {
+  if (AS != TD->getAccess() && TD->getAccess() != AS_none) {
 Diag(DG->getBeginLoc(), diag::err_deduction_guide_wrong_access);
 Diag(TD->getBeginLoc(), diag::note_deduction_guide_template_access)
 << TD->getAccess();
___
cfe-commits mailing list
cfe-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits


[PATCH] D56974: [SemaCXX] Fix ICE with structure bindings to members of template

2019-01-27 Thread Nicolas Lesser via Phabricator via cfe-commits
Rakete added a comment.

Backporting to 8.0.0 is possibly possible, you'll need to ping Hans. I don't 
know about previous versions though.


Repository:
  rL LLVM

CHANGES SINCE LAST ACTION
  https://reviews.llvm.org/D56974/new/

https://reviews.llvm.org/D56974



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


[PATCH] D56974: [SemaCXX] Fix ICE with structure bindings to members of template

2019-01-27 Thread Nicolas Lesser via Phabricator via cfe-commits
This revision was automatically updated to reflect the committed changes.
Closed by commit rL352323: [SemaCXX] Fix ICE with structure bindings to members 
of template (authored by Rakete, committed by ).
Herald added a subscriber: llvm-commits.

Changed prior to commit:
  https://reviews.llvm.org/D56974?vs=182695&id=183761#toc

Repository:
  rL LLVM

CHANGES SINCE LAST ACTION
  https://reviews.llvm.org/D56974/new/

https://reviews.llvm.org/D56974

Files:
  cfe/trunk/lib/Sema/SemaDeclCXX.cpp
  cfe/trunk/test/SemaCXX/cxx1z-decomposition.cpp


Index: cfe/trunk/test/SemaCXX/cxx1z-decomposition.cpp
===
--- cfe/trunk/test/SemaCXX/cxx1z-decomposition.cpp
+++ cfe/trunk/test/SemaCXX/cxx1z-decomposition.cpp
@@ -81,4 +81,21 @@
   void f() { static auto [a] = *this; } // expected-error {{cannot be declared 
'static'}}
 };
 
+namespace instantiate_template {
+
+template 
+struct pair {
+  T1 a;
+  T2 b;
+};
+
+const pair &f1();
+
+int f2() {
+  const auto &[a, b] = f1();
+  return a + b;
+}
+
+} // namespace instantiate_template
+
 // FIXME: by-value array copies
Index: cfe/trunk/lib/Sema/SemaDeclCXX.cpp
===
--- cfe/trunk/lib/Sema/SemaDeclCXX.cpp
+++ cfe/trunk/lib/Sema/SemaDeclCXX.cpp
@@ -1300,6 +1300,10 @@
 static bool checkMemberDecomposition(Sema &S, ArrayRef Bindings,
  ValueDecl *Src, QualType DecompType,
  const CXXRecordDecl *OrigRD) {
+  if (S.RequireCompleteType(Src->getLocation(), DecompType,
+diag::err_incomplete_type))
+return true;
+
   CXXCastPath BasePath;
   DeclAccessPair BasePair =
   findDecomposableBaseClass(S, Src->getLocation(), OrigRD, BasePath);


Index: cfe/trunk/test/SemaCXX/cxx1z-decomposition.cpp
===
--- cfe/trunk/test/SemaCXX/cxx1z-decomposition.cpp
+++ cfe/trunk/test/SemaCXX/cxx1z-decomposition.cpp
@@ -81,4 +81,21 @@
   void f() { static auto [a] = *this; } // expected-error {{cannot be declared 'static'}}
 };
 
+namespace instantiate_template {
+
+template 
+struct pair {
+  T1 a;
+  T2 b;
+};
+
+const pair &f1();
+
+int f2() {
+  const auto &[a, b] = f1();
+  return a + b;
+}
+
+} // namespace instantiate_template
+
 // FIXME: by-value array copies
Index: cfe/trunk/lib/Sema/SemaDeclCXX.cpp
===
--- cfe/trunk/lib/Sema/SemaDeclCXX.cpp
+++ cfe/trunk/lib/Sema/SemaDeclCXX.cpp
@@ -1300,6 +1300,10 @@
 static bool checkMemberDecomposition(Sema &S, ArrayRef Bindings,
  ValueDecl *Src, QualType DecompType,
  const CXXRecordDecl *OrigRD) {
+  if (S.RequireCompleteType(Src->getLocation(), DecompType,
+diag::err_incomplete_type))
+return true;
+
   CXXCastPath BasePath;
   DeclAccessPair BasePair =
   findDecomposableBaseClass(S, Src->getLocation(), OrigRD, BasePath);
___
cfe-commits mailing list
cfe-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits


[PATCH] D56974: [SemaCXX] Fix ICE with structure bindings to members of template

2019-01-20 Thread Nicolas Lesser via Phabricator via cfe-commits
Rakete added a comment.

Yeah, seems like we don't instantiate `pair` at all in that specific 
case. LGTM but you might want to wait for someone else to confirm.


Repository:
  rC Clang

CHANGES SINCE LAST ACTION
  https://reviews.llvm.org/D56974/new/

https://reviews.llvm.org/D56974



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


[PATCH] D50766: Fix false positive unsequenced access and modification warning in array subscript expression.

2019-01-10 Thread Nicolas Lesser via Phabricator via cfe-commits
This revision was automatically updated to reflect the committed changes.
Closed by commit rC350874: Fix false positive unsequenced access and 
modification warning in array… (authored by Rakete, committed by ).

Repository:
  rC Clang

CHANGES SINCE LAST ACTION
  https://reviews.llvm.org/D50766/new/

https://reviews.llvm.org/D50766

Files:
  lib/Sema/SemaChecking.cpp
  test/SemaCXX/warn-unsequenced-cxx17.cpp
  test/SemaCXX/warn-unsequenced.cpp


Index: test/SemaCXX/warn-unsequenced.cpp
===
--- test/SemaCXX/warn-unsequenced.cpp
+++ test/SemaCXX/warn-unsequenced.cpp
@@ -81,6 +81,7 @@
   int *p = xs;
   a = *(a++, p); // ok
   a = a++ && a; // ok
+  p[(long long unsigned)(p = 0)]; // expected-warning {{unsequenced 
modification and access to 'p'}}
 
   A *q = &agg1;
   (q = &agg2)->y = q->x; // expected-warning {{unsequenced modification and 
access to 'q'}}
Index: test/SemaCXX/warn-unsequenced-cxx17.cpp
===
--- test/SemaCXX/warn-unsequenced-cxx17.cpp
+++ test/SemaCXX/warn-unsequenced-cxx17.cpp
@@ -0,0 +1,8 @@
+// RUN: %clang_cc1 -fsyntax-only -verify -std=c++17 -Wno-unused %s
+
+void test() {
+  int xs[10];
+  int *p = xs;
+  // expected-no-diagnostics
+  p[(long long unsigned)(p = 0)]; // ok
+}
Index: lib/Sema/SemaChecking.cpp
===
--- lib/Sema/SemaChecking.cpp
+++ lib/Sema/SemaChecking.cpp
@@ -11908,30 +11908,42 @@
   notePostUse(O, E);
   }
 
-  void VisitBinComma(BinaryOperator *BO) {
-// C++11 [expr.comma]p1:
-//   Every value computation and side effect associated with the left
-//   expression is sequenced before every value computation and side
-//   effect associated with the right expression.
-SequenceTree::Seq LHS = Tree.allocate(Region);
-SequenceTree::Seq RHS = Tree.allocate(Region);
+  void VisitSequencedExpressions(Expr *SequencedBefore, Expr *SequencedAfter) {
+SequenceTree::Seq BeforeRegion = Tree.allocate(Region);
+SequenceTree::Seq AfterRegion = Tree.allocate(Region);
 SequenceTree::Seq OldRegion = Region;
 
 {
-  SequencedSubexpression SeqLHS(*this);
-  Region = LHS;
-  Visit(BO->getLHS());
+  SequencedSubexpression SeqBefore(*this);
+  Region = BeforeRegion;
+  Visit(SequencedBefore);
 }
 
-Region = RHS;
-Visit(BO->getRHS());
+Region = AfterRegion;
+Visit(SequencedAfter);
 
 Region = OldRegion;
 
-// Forget that LHS and RHS are sequenced. They are both unsequenced
-// with respect to other stuff.
-Tree.merge(LHS);
-Tree.merge(RHS);
+Tree.merge(BeforeRegion);
+Tree.merge(AfterRegion);
+  }
+
+  void VisitArraySubscriptExpr(ArraySubscriptExpr *ASE) {
+// C++17 [expr.sub]p1:
+//   The expression E1[E2] is identical (by definition) to *((E1)+(E2)). 
The
+//   expression E1 is sequenced before the expression E2.
+if (SemaRef.getLangOpts().CPlusPlus17)
+  VisitSequencedExpressions(ASE->getLHS(), ASE->getRHS());
+else
+  Base::VisitStmt(ASE);
+  }
+
+  void VisitBinComma(BinaryOperator *BO) {
+// C++11 [expr.comma]p1:
+//   Every value computation and side effect associated with the left
+//   expression is sequenced before every value computation and side
+//   effect associated with the right expression.
+VisitSequencedExpressions(BO->getLHS(), BO->getRHS());
   }
 
   void VisitBinAssign(BinaryOperator *BO) {


Index: test/SemaCXX/warn-unsequenced.cpp
===
--- test/SemaCXX/warn-unsequenced.cpp
+++ test/SemaCXX/warn-unsequenced.cpp
@@ -81,6 +81,7 @@
   int *p = xs;
   a = *(a++, p); // ok
   a = a++ && a; // ok
+  p[(long long unsigned)(p = 0)]; // expected-warning {{unsequenced modification and access to 'p'}}
 
   A *q = &agg1;
   (q = &agg2)->y = q->x; // expected-warning {{unsequenced modification and access to 'q'}}
Index: test/SemaCXX/warn-unsequenced-cxx17.cpp
===
--- test/SemaCXX/warn-unsequenced-cxx17.cpp
+++ test/SemaCXX/warn-unsequenced-cxx17.cpp
@@ -0,0 +1,8 @@
+// RUN: %clang_cc1 -fsyntax-only -verify -std=c++17 -Wno-unused %s
+
+void test() {
+  int xs[10];
+  int *p = xs;
+  // expected-no-diagnostics
+  p[(long long unsigned)(p = 0)]; // ok
+}
Index: lib/Sema/SemaChecking.cpp
===
--- lib/Sema/SemaChecking.cpp
+++ lib/Sema/SemaChecking.cpp
@@ -11908,30 +11908,42 @@
   notePostUse(O, E);
   }
 
-  void VisitBinComma(BinaryOperator *BO) {
-// C++11 [expr.comma]p1:
-//   Every value computation and side effect associated with the left
-//   expression is sequenced before every value computation and side
-//   effect associated with the right expression.
-SequenceTree::Seq LHS = Tree.allocate(Region);
-SequenceTre

[PATCH] D55039: [sema] Warn of mangling change if function parameters are noexcept.

2018-12-18 Thread Nicolas Lesser via Phabricator via cfe-commits
Rakete added a comment.

Apart from the comments I think your patch LGTM, but I'll let someone else hav 
the final say.




Comment at: lib/Sema/SemaDecl.cpp:10266
   auto *FPT = NewFD->getType()->castAs();
-  bool AnyNoexcept = HasNoexcept(FPT->getReturnType());
-  for (QualType T : FPT->param_types())
-AnyNoexcept |= HasNoexcept(T);
-  if (AnyNoexcept)
+  if (hasNoexcept(FPT->getReturnType()) ||
+  llvm::any_of(FPT->param_types(),

mattd wrote:
> mattd wrote:
> > Rakete wrote:
> > > What you're doing here is a subset of what `hasNoexcept` is doing for 
> > > function types. Do you think it would make sense to use 
> > > `!FPT->isNothrow() && hasNoexcept(NewFW->getType())` or something like 
> > > that?
> > Thanks for the comments @Rakete.
> > 
> > I do see the similarity and was trying to implement a solution to take 
> > advantage of that.  However, I was running into trouble on assert/debug 
> > builds.  `llvm_unreachable`, called in `FunctionProtoType::canThrow`, will 
> > trigger on FunctionProtoType instances that have not yet had their 
> > exception-spec type evaluated.  `canThrow` is called on behalf of 
> > `isNothrow`.  Some of the test cases will fail in assert/debug builds if we 
> > place a call to to `FPT->isNothrow` here. 
> > 
> > The original code avoided this assertion by not calling `isNothrow` on FPT 
> > here, but instead just evaluating the return and parameter types of FPT.  I 
> > made this patch similar to what was already in place, but with the more  
> > thorough check in `hasNoexcept.`  I'd be pleased to remove this 
> > duplication/similarity if I can avoid this assertion.
> I just got back into looking at this issue.  Given that I was unable to 
> implement `!FPT->isNoThrow() && hasNoexcept(NewFW->getType())` without 
> triggering an assertion (discussed in my reply immediately above), is there 
> anything we should be doing differently here?  The change, as it sits now 
> (with the duplication), seems to work fine.
I think it's fine.



Comment at: lib/Sema/SemaDecl.cpp:10268
+  llvm::any_of(FPT->param_types(),
+   [](QualType Q) { return hasNoexcept(Q); })) {
 Diag(NewFD->getLocation(),

Rakete wrote:
> Same, that lambda is unnecessary.
You marked this comment as done but the lambda is still there :).


CHANGES SINCE LAST ACTION
  https://reviews.llvm.org/D55039/new/

https://reviews.llvm.org/D55039



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


[PATCH] D53847: [C++2a] P0634r3: Down with typename!

2018-12-14 Thread Nicolas Lesser via Phabricator via cfe-commits
Rakete updated this revision to Diff 178289.
Rakete added a comment.

@rsmith do you have any more comments?

ping/rebase.


Repository:
  rC Clang

CHANGES SINCE LAST ACTION
  https://reviews.llvm.org/D53847/new/

https://reviews.llvm.org/D53847

Files:
  include/clang/Basic/DiagnosticSemaKinds.td
  include/clang/Parse/Parser.h
  include/clang/Sema/DeclSpec.h
  include/clang/Sema/Sema.h
  lib/Parse/ParseDecl.cpp
  lib/Parse/ParseDeclCXX.cpp
  lib/Parse/ParseExprCXX.cpp
  lib/Parse/ParseTemplate.cpp
  lib/Parse/ParseTentative.cpp
  lib/Parse/Parser.cpp
  lib/Sema/DeclSpec.cpp
  lib/Sema/Sema.cpp
  lib/Sema/SemaDecl.cpp
  lib/Sema/SemaTemplate.cpp
  test/CXX/drs/dr1xx.cpp
  test/CXX/drs/dr2xx.cpp
  test/CXX/drs/dr4xx.cpp
  test/CXX/drs/dr5xx.cpp
  test/CXX/temp/temp.res/temp.dep/temp.dep.type/p1.cpp
  test/FixIt/fixit.cpp
  test/Parser/cxx-member-initializers.cpp
  test/Parser/editor-placeholder-recovery.cpp
  test/SemaCXX/MicrosoftCompatibility.cpp
  test/SemaCXX/MicrosoftExtensions.cpp
  test/SemaCXX/MicrosoftSuper.cpp
  test/SemaCXX/unknown-type-name.cpp

Index: test/SemaCXX/unknown-type-name.cpp
===
--- test/SemaCXX/unknown-type-name.cpp
+++ test/SemaCXX/unknown-type-name.cpp
@@ -36,15 +36,15 @@
 
   static int n;
   static type m;
-  static int h(T::type, int); // expected-error{{missing 'typename'}}
-  static int h(T::type x, char); // expected-error{{missing 'typename'}}
+  static int h(T::type, int); // expected-warning{{implicit 'typename' is a C++2a extension}}
+  static int h(T::type x, char); // expected-warning{{implicit 'typename' is a C++2a extension}}
 };
 
 template
-A::type g(T t) { return t; } // expected-error{{missing 'typename'}}
+A::type g(T t) { return t; } // expected-warning{{implicit 'typename' is a C++2a extension}}
 
 template
-A::type A::f() { return type(); } // expected-error{{missing 'typename'}}
+A::type A::f() { return type(); } // expected-warning{{implicit 'typename' is a C++2a extension}}
 
 template
 void f(T::type) { } // expected-error{{missing 'typename'}}
@@ -72,9 +72,7 @@
 
 int *p;
 
-// FIXME: We should assume that 'undeclared' is a type, not a parameter name
-//here, and produce an 'unknown type name' diagnostic instead.
-int f1(undeclared, int); // expected-error{{requires a type specifier}}
+int f1(undeclared, int); // expected-error{{unknown type name 'undeclared'}}
 
 int f2(undeclared, 0); // expected-error{{undeclared identifier}}
 
@@ -86,11 +84,11 @@
 
 template int A::n(T::value); // ok
 template
-A::type // expected-error{{missing 'typename'}}
+A::type // expected-warning {{implicit 'typename' is a C++2a extension}}
 A::m(T::value, 0); // ok
 
-template int A::h(T::type, int) {} // expected-error{{missing 'typename'}}
-template int A::h(T::type x, char) {} // expected-error{{missing 'typename'}}
+template int A::h(T::type, int) {} // expected-warning{{implicit 'typename' is a C++2a extension}}
+template int A::h(T::type x, char) {} // expected-warning{{implicit 'typename' is a C++2a extension}}
 
 template int h(T::type, int); // expected-error{{missing 'typename'}}
 template int h(T::type x, char); // expected-error{{missing 'typename'}}
@@ -118,4 +116,5 @@
 // FIXME: We know which type specifier should have been specified here. Provide
 //a fix-it to add 'typename A::type'
 template
-A::g() { } // expected-error{{requires a type specifier}}
+A::g() { } // expected-error{{expected unqualified-id}}
+// expected-warning@-1{{implicit 'typename' is a C++2a extension}}
Index: test/SemaCXX/MicrosoftSuper.cpp
===
--- test/SemaCXX/MicrosoftSuper.cpp
+++ test/SemaCXX/MicrosoftSuper.cpp
@@ -108,8 +108,8 @@
   typename __super::XXX a;
   typedef typename __super::XXX b;
 
-  __super::XXX c; // expected-error {{missing 'typename'}}
-  typedef __super::XXX d; // expected-error {{missing 'typename'}}
+  __super::XXX c; // expected-warning {{implicit 'typename' is a C++2a extension}}
+  typedef __super::XXX d; // expected-warning {{implicit 'typename' is a C++2a extension}}
 
   void foo() {
 typename __super::XXX e;
@@ -127,8 +127,8 @@
   typename __super::XXX a;
   typedef typename __super::XXX b;
 
-  __super::XXX c; // expected-error {{missing 'typename'}}
-  typedef __super::XXX d; // expected-error {{missing 'typename'}}
+  __super::XXX c; // expected-warning {{implicit 'typename' is a C++2a extension}}
+  typedef __super::XXX d; // expected-warning {{implicit 'typename' is a C++2a extension}}
 
   void foo() {
 typename __super::XXX e;
Index: test/SemaCXX/MicrosoftExtensions.cpp
===
--- test/SemaCXX/MicrosoftExtensions.cpp
+++ test/SemaCXX/MicrosoftExtensions.cpp
@@ -526,7 +526,7 @@
 
 namespace PR32750 {
 template struct A {};
-template struct B : A> { A::C::D d; }; // expected-error {{missing 'typename' p

[PATCH] D53847: [C++2a] P0634r3: Down with typename!

2018-12-04 Thread Nicolas Lesser via Phabricator via cfe-commits
Rakete updated this revision to Diff 176554.
Rakete added a comment.

Rebase + friendly ping :)


Repository:
  rC Clang

CHANGES SINCE LAST ACTION
  https://reviews.llvm.org/D53847/new/

https://reviews.llvm.org/D53847

Files:
  include/clang/Basic/DiagnosticSemaKinds.td
  include/clang/Parse/Parser.h
  include/clang/Sema/DeclSpec.h
  include/clang/Sema/Sema.h
  lib/Parse/ParseDecl.cpp
  lib/Parse/ParseDeclCXX.cpp
  lib/Parse/ParseExprCXX.cpp
  lib/Parse/ParseTemplate.cpp
  lib/Parse/ParseTentative.cpp
  lib/Parse/Parser.cpp
  lib/Sema/DeclSpec.cpp
  lib/Sema/Sema.cpp
  lib/Sema/SemaDecl.cpp
  lib/Sema/SemaTemplate.cpp
  test/CXX/drs/dr1xx.cpp
  test/CXX/drs/dr2xx.cpp
  test/CXX/drs/dr4xx.cpp
  test/CXX/drs/dr5xx.cpp
  test/CXX/temp/temp.res/temp.dep/temp.dep.type/p1.cpp
  test/FixIt/fixit.cpp
  test/Parser/cxx-member-initializers.cpp
  test/Parser/editor-placeholder-recovery.cpp
  test/SemaCXX/MicrosoftCompatibility.cpp
  test/SemaCXX/MicrosoftExtensions.cpp
  test/SemaCXX/MicrosoftSuper.cpp
  test/SemaCXX/unknown-type-name.cpp

Index: test/SemaCXX/unknown-type-name.cpp
===
--- test/SemaCXX/unknown-type-name.cpp
+++ test/SemaCXX/unknown-type-name.cpp
@@ -36,15 +36,15 @@
 
   static int n;
   static type m;
-  static int h(T::type, int); // expected-error{{missing 'typename'}}
-  static int h(T::type x, char); // expected-error{{missing 'typename'}}
+  static int h(T::type, int); // expected-warning{{implicit 'typename' is a C++2a extension}}
+  static int h(T::type x, char); // expected-warning{{implicit 'typename' is a C++2a extension}}
 };
 
 template
-A::type g(T t) { return t; } // expected-error{{missing 'typename'}}
+A::type g(T t) { return t; } // expected-warning{{implicit 'typename' is a C++2a extension}}
 
 template
-A::type A::f() { return type(); } // expected-error{{missing 'typename'}}
+A::type A::f() { return type(); } // expected-warning{{implicit 'typename' is a C++2a extension}}
 
 template
 void f(T::type) { } // expected-error{{missing 'typename'}}
@@ -72,9 +72,7 @@
 
 int *p;
 
-// FIXME: We should assume that 'undeclared' is a type, not a parameter name
-//here, and produce an 'unknown type name' diagnostic instead.
-int f1(undeclared, int); // expected-error{{requires a type specifier}}
+int f1(undeclared, int); // expected-error{{unknown type name 'undeclared'}}
 
 int f2(undeclared, 0); // expected-error{{undeclared identifier}}
 
@@ -86,11 +84,11 @@
 
 template int A::n(T::value); // ok
 template
-A::type // expected-error{{missing 'typename'}}
+A::type // expected-warning {{implicit 'typename' is a C++2a extension}}
 A::m(T::value, 0); // ok
 
-template int A::h(T::type, int) {} // expected-error{{missing 'typename'}}
-template int A::h(T::type x, char) {} // expected-error{{missing 'typename'}}
+template int A::h(T::type, int) {} // expected-warning{{implicit 'typename' is a C++2a extension}}
+template int A::h(T::type x, char) {} // expected-warning{{implicit 'typename' is a C++2a extension}}
 
 template int h(T::type, int); // expected-error{{missing 'typename'}}
 template int h(T::type x, char); // expected-error{{missing 'typename'}}
@@ -118,4 +116,5 @@
 // FIXME: We know which type specifier should have been specified here. Provide
 //a fix-it to add 'typename A::type'
 template
-A::g() { } // expected-error{{requires a type specifier}}
+A::g() { } // expected-error{{expected unqualified-id}}
+// expected-warning@-1{{implicit 'typename' is a C++2a extension}}
Index: test/SemaCXX/MicrosoftSuper.cpp
===
--- test/SemaCXX/MicrosoftSuper.cpp
+++ test/SemaCXX/MicrosoftSuper.cpp
@@ -108,8 +108,8 @@
   typename __super::XXX a;
   typedef typename __super::XXX b;
 
-  __super::XXX c; // expected-error {{missing 'typename'}}
-  typedef __super::XXX d; // expected-error {{missing 'typename'}}
+  __super::XXX c; // expected-warning {{implicit 'typename' is a C++2a extension}}
+  typedef __super::XXX d; // expected-warning {{implicit 'typename' is a C++2a extension}}
 
   void foo() {
 typename __super::XXX e;
@@ -127,8 +127,8 @@
   typename __super::XXX a;
   typedef typename __super::XXX b;
 
-  __super::XXX c; // expected-error {{missing 'typename'}}
-  typedef __super::XXX d; // expected-error {{missing 'typename'}}
+  __super::XXX c; // expected-warning {{implicit 'typename' is a C++2a extension}}
+  typedef __super::XXX d; // expected-warning {{implicit 'typename' is a C++2a extension}}
 
   void foo() {
 typename __super::XXX e;
Index: test/SemaCXX/MicrosoftExtensions.cpp
===
--- test/SemaCXX/MicrosoftExtensions.cpp
+++ test/SemaCXX/MicrosoftExtensions.cpp
@@ -526,7 +526,7 @@
 
 namespace PR32750 {
 template struct A {};
-template struct B : A> { A::C::D d; }; // expected-error {{missing 'typename' prior to dependent type name

[PATCH] D55039: [sema] Warn of mangling change if function parameters are noexcept.

2018-12-03 Thread Nicolas Lesser via Phabricator via cfe-commits
Rakete added inline comments.



Comment at: lib/Sema/SemaDecl.cpp:9933
+llvm::any_of(FPT->param_types(),
+ [](QualType Q) { return hasNoexcept(Q); }))
+  return true;

You don't need this lambda.



Comment at: lib/Sema/SemaDecl.cpp:10266
   auto *FPT = NewFD->getType()->castAs();
-  bool AnyNoexcept = HasNoexcept(FPT->getReturnType());
-  for (QualType T : FPT->param_types())
-AnyNoexcept |= HasNoexcept(T);
-  if (AnyNoexcept)
+  if (hasNoexcept(FPT->getReturnType()) ||
+  llvm::any_of(FPT->param_types(),

What you're doing here is a subset of what `hasNoexcept` is doing for function 
types. Do you think it would make sense to use `!FPT->isNothrow() && 
hasNoexcept(NewFW->getType())` or something like that?



Comment at: lib/Sema/SemaDecl.cpp:10268
+  llvm::any_of(FPT->param_types(),
+   [](QualType Q) { return hasNoexcept(Q); })) {
 Diag(NewFD->getLocation(),

Same, that lambda is unnecessary.


CHANGES SINCE LAST ACTION
  https://reviews.llvm.org/D55039/new/

https://reviews.llvm.org/D55039



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


[PATCH] D55039: [sema] Warn of mangling change if function parameters are noexcept.

2018-11-28 Thread Nicolas Lesser via Phabricator via cfe-commits
Rakete added a comment.

You're missing the case of the function return type of a parameter.

  void f(void (*g())() noexcept); // no warning with trunk nor with your patch


CHANGES SINCE LAST ACTION
  https://reviews.llvm.org/D55039/new/

https://reviews.llvm.org/D55039



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


[PATCH] D53847: [C++2a] P0634r3: Down with typename!

2018-11-27 Thread Nicolas Lesser via Phabricator via cfe-commits
Rakete updated this revision to Diff 175553.
Rakete added a comment.

Rebase and friendly ping! :)


Repository:
  rC Clang

CHANGES SINCE LAST ACTION
  https://reviews.llvm.org/D53847/new/

https://reviews.llvm.org/D53847

Files:
  include/clang/Basic/DiagnosticSemaKinds.td
  include/clang/Parse/Parser.h
  include/clang/Sema/DeclSpec.h
  include/clang/Sema/Sema.h
  lib/Parse/ParseDecl.cpp
  lib/Parse/ParseDeclCXX.cpp
  lib/Parse/ParseExprCXX.cpp
  lib/Parse/ParseTemplate.cpp
  lib/Parse/ParseTentative.cpp
  lib/Parse/Parser.cpp
  lib/Sema/DeclSpec.cpp
  lib/Sema/Sema.cpp
  lib/Sema/SemaDecl.cpp
  lib/Sema/SemaTemplate.cpp
  test/CXX/drs/dr1xx.cpp
  test/CXX/drs/dr2xx.cpp
  test/CXX/drs/dr4xx.cpp
  test/CXX/drs/dr5xx.cpp
  test/CXX/temp/temp.res/temp.dep/temp.dep.type/p1.cpp
  test/FixIt/fixit.cpp
  test/Parser/cxx-member-initializers.cpp
  test/Parser/editor-placeholder-recovery.cpp
  test/SemaCXX/MicrosoftCompatibility.cpp
  test/SemaCXX/MicrosoftExtensions.cpp
  test/SemaCXX/MicrosoftSuper.cpp
  test/SemaCXX/unknown-type-name.cpp

Index: test/SemaCXX/unknown-type-name.cpp
===
--- test/SemaCXX/unknown-type-name.cpp
+++ test/SemaCXX/unknown-type-name.cpp
@@ -36,15 +36,15 @@
 
   static int n;
   static type m;
-  static int h(T::type, int); // expected-error{{missing 'typename'}}
-  static int h(T::type x, char); // expected-error{{missing 'typename'}}
+  static int h(T::type, int); // expected-warning{{implicit 'typename' is a C++2a extension}}
+  static int h(T::type x, char); // expected-warning{{implicit 'typename' is a C++2a extension}}
 };
 
 template
-A::type g(T t) { return t; } // expected-error{{missing 'typename'}}
+A::type g(T t) { return t; } // expected-warning{{implicit 'typename' is a C++2a extension}}
 
 template
-A::type A::f() { return type(); } // expected-error{{missing 'typename'}}
+A::type A::f() { return type(); } // expected-warning{{implicit 'typename' is a C++2a extension}}
 
 template
 void f(T::type) { } // expected-error{{missing 'typename'}}
@@ -72,9 +72,7 @@
 
 int *p;
 
-// FIXME: We should assume that 'undeclared' is a type, not a parameter name
-//here, and produce an 'unknown type name' diagnostic instead.
-int f1(undeclared, int); // expected-error{{requires a type specifier}}
+int f1(undeclared, int); // expected-error{{unknown type name 'undeclared'}}
 
 int f2(undeclared, 0); // expected-error{{undeclared identifier}}
 
@@ -86,11 +84,11 @@
 
 template int A::n(T::value); // ok
 template
-A::type // expected-error{{missing 'typename'}}
+A::type // expected-warning {{implicit 'typename' is a C++2a extension}}
 A::m(T::value, 0); // ok
 
-template int A::h(T::type, int) {} // expected-error{{missing 'typename'}}
-template int A::h(T::type x, char) {} // expected-error{{missing 'typename'}}
+template int A::h(T::type, int) {} // expected-warning{{implicit 'typename' is a C++2a extension}}
+template int A::h(T::type x, char) {} // expected-warning{{implicit 'typename' is a C++2a extension}}
 
 template int h(T::type, int); // expected-error{{missing 'typename'}}
 template int h(T::type x, char); // expected-error{{missing 'typename'}}
@@ -118,4 +116,5 @@
 // FIXME: We know which type specifier should have been specified here. Provide
 //a fix-it to add 'typename A::type'
 template
-A::g() { } // expected-error{{requires a type specifier}}
+A::g() { } // expected-error{{expected unqualified-id}}
+// expected-warning@-1{{implicit 'typename' is a C++2a extension}}
Index: test/SemaCXX/MicrosoftSuper.cpp
===
--- test/SemaCXX/MicrosoftSuper.cpp
+++ test/SemaCXX/MicrosoftSuper.cpp
@@ -108,8 +108,8 @@
   typename __super::XXX a;
   typedef typename __super::XXX b;
 
-  __super::XXX c; // expected-error {{missing 'typename'}}
-  typedef __super::XXX d; // expected-error {{missing 'typename'}}
+  __super::XXX c; // expected-warning {{implicit 'typename' is a C++2a extension}}
+  typedef __super::XXX d; // expected-warning {{implicit 'typename' is a C++2a extension}}
 
   void foo() {
 typename __super::XXX e;
@@ -127,8 +127,8 @@
   typename __super::XXX a;
   typedef typename __super::XXX b;
 
-  __super::XXX c; // expected-error {{missing 'typename'}}
-  typedef __super::XXX d; // expected-error {{missing 'typename'}}
+  __super::XXX c; // expected-warning {{implicit 'typename' is a C++2a extension}}
+  typedef __super::XXX d; // expected-warning {{implicit 'typename' is a C++2a extension}}
 
   void foo() {
 typename __super::XXX e;
Index: test/SemaCXX/MicrosoftExtensions.cpp
===
--- test/SemaCXX/MicrosoftExtensions.cpp
+++ test/SemaCXX/MicrosoftExtensions.cpp
@@ -526,7 +526,7 @@
 
 namespace PR32750 {
 template struct A {};
-template struct B : A> { A::C::D d; }; // expected-error {{missing 'typename' prior to dependent type n

[PATCH] D53847: [C++2a] P0634r3: Down with typename!

2018-11-14 Thread Nicolas Lesser via Phabricator via cfe-commits
Rakete added inline comments.



Comment at: include/clang/Parse/Parser.h:2119
   DeclSpecContext DSC = DeclSpecContext::DSC_normal,
-  LateParsedAttrList *LateAttrs = nullptr);
+  LateParsedAttrList *LateAttrs = nullptr) {
+return ParseDeclarationSpecifiers(DS, TemplateInfo, AS, DSC, LateAttrs,

Rakete wrote:
> This overload is unnecessary; I accidentally included it. I'll change it 
> later so that Phab doesn't lose the review comments.
Actually, it's less repetitive if I leave it. So I'll just leave it be.


Repository:
  rC Clang

https://reviews.llvm.org/D53847



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


[PATCH] D53847: [C++2a] P0634r3: Down with typename!

2018-11-14 Thread Nicolas Lesser via Phabricator via cfe-commits
Rakete added inline comments.



Comment at: lib/Sema/Sema.cpp:2006-2019
+bool Sema::isDeclaratorFunctionLike(const Declarator &D) {
+  assert(D.getCXXScopeSpec().isSet() &&
+ "can only be called for qualified names");
+  LookupResult LR(*this, D.getIdentifier(), D.getBeginLoc(), 
LookupOrdinaryName,
+  ForVisibleRedeclaration);
+  DeclContext *DC = computeDeclContext(D.getCXXScopeSpec());
+  if (!DC)

rsmith wrote:
> Some thoughts on this:
> 
>  * Can this be unified with the lookup code in `HandleDeclarator`? This is 
> really the same lookup, repeated in two places.
>  * It'd be nice to cache this lookup, rather than performing it three times 
> (once when disambiguating a parenthesized initializer from a function 
> declaration, once when we're about to parse a parameter-declaration-clause, 
> and once in `HandleDeclarator` after parsing completes -- though at least 
> that's reduced to two lookups if you make the change I suggested in 
> `ParseParameterDeclarationClause`)
>  * If we don't do the caching, what happens if lookup fails due to ambiguity? 
> Do we get the same error multiple times (once for each time we perform the 
> lookup)?
I don't think so, because `HandleDeclarator` is called after having already 
parsed the function declaration. I cached it now, but the cleanest solution 
that I could think of is to use `new`. Is this appropriate? Or do you have an 
alternative suggestion?


Repository:
  rC Clang

https://reviews.llvm.org/D53847



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


[PATCH] D53847: [C++2a] P0634r3: Down with typename!

2018-11-14 Thread Nicolas Lesser via Phabricator via cfe-commits
Rakete updated this revision to Diff 174158.
Rakete marked 11 inline comments as done.
Rakete added a comment.

Addressed review comments :)


Repository:
  rC Clang

https://reviews.llvm.org/D53847

Files:
  include/clang/Basic/DiagnosticSemaKinds.td
  include/clang/Parse/Parser.h
  include/clang/Sema/DeclSpec.h
  include/clang/Sema/Sema.h
  lib/Parse/ParseDecl.cpp
  lib/Parse/ParseDeclCXX.cpp
  lib/Parse/ParseExprCXX.cpp
  lib/Parse/ParseTemplate.cpp
  lib/Parse/ParseTentative.cpp
  lib/Parse/Parser.cpp
  lib/Sema/DeclSpec.cpp
  lib/Sema/Sema.cpp
  lib/Sema/SemaDecl.cpp
  lib/Sema/SemaTemplate.cpp
  test/CXX/drs/dr1xx.cpp
  test/CXX/drs/dr2xx.cpp
  test/CXX/drs/dr4xx.cpp
  test/CXX/drs/dr5xx.cpp
  test/CXX/temp/temp.res/temp.dep/temp.dep.type/p1.cpp
  test/FixIt/fixit.cpp
  test/Parser/cxx-member-initializers.cpp
  test/Parser/editor-placeholder-recovery.cpp
  test/SemaCXX/MicrosoftCompatibility.cpp
  test/SemaCXX/MicrosoftExtensions.cpp
  test/SemaCXX/MicrosoftSuper.cpp
  test/SemaCXX/unknown-type-name.cpp

Index: test/SemaCXX/unknown-type-name.cpp
===
--- test/SemaCXX/unknown-type-name.cpp
+++ test/SemaCXX/unknown-type-name.cpp
@@ -36,15 +36,15 @@
 
   static int n;
   static type m;
-  static int h(T::type, int); // expected-error{{missing 'typename'}}
-  static int h(T::type x, char); // expected-error{{missing 'typename'}}
+  static int h(T::type, int); // expected-warning{{implicit 'typename' is a C++2a extension}}
+  static int h(T::type x, char); // expected-warning{{implicit 'typename' is a C++2a extension}}
 };
 
 template
-A::type g(T t) { return t; } // expected-error{{missing 'typename'}}
+A::type g(T t) { return t; } // expected-warning{{implicit 'typename' is a C++2a extension}}
 
 template
-A::type A::f() { return type(); } // expected-error{{missing 'typename'}}
+A::type A::f() { return type(); } // expected-warning{{implicit 'typename' is a C++2a extension}}
 
 template
 void f(T::type) { } // expected-error{{missing 'typename'}}
@@ -72,9 +72,7 @@
 
 int *p;
 
-// FIXME: We should assume that 'undeclared' is a type, not a parameter name
-//here, and produce an 'unknown type name' diagnostic instead.
-int f1(undeclared, int); // expected-error{{requires a type specifier}}
+int f1(undeclared, int); // expected-error{{unknown type name 'undeclared'}}
 
 int f2(undeclared, 0); // expected-error{{undeclared identifier}}
 
@@ -86,11 +84,11 @@
 
 template int A::n(T::value); // ok
 template
-A::type // expected-error{{missing 'typename'}}
+A::type // expected-warning {{implicit 'typename' is a C++2a extension}}
 A::m(T::value, 0); // ok
 
-template int A::h(T::type, int) {} // expected-error{{missing 'typename'}}
-template int A::h(T::type x, char) {} // expected-error{{missing 'typename'}}
+template int A::h(T::type, int) {} // expected-warning{{implicit 'typename' is a C++2a extension}}
+template int A::h(T::type x, char) {} // expected-warning{{implicit 'typename' is a C++2a extension}}
 
 template int h(T::type, int); // expected-error{{missing 'typename'}}
 template int h(T::type x, char); // expected-error{{missing 'typename'}}
@@ -118,4 +116,5 @@
 // FIXME: We know which type specifier should have been specified here. Provide
 //a fix-it to add 'typename A::type'
 template
-A::g() { } // expected-error{{requires a type specifier}}
+A::g() { } // expected-error{{expected unqualified-id}}
+// expected-warning@-1{{implicit 'typename' is a C++2a extension}}
Index: test/SemaCXX/MicrosoftSuper.cpp
===
--- test/SemaCXX/MicrosoftSuper.cpp
+++ test/SemaCXX/MicrosoftSuper.cpp
@@ -108,8 +108,8 @@
   typename __super::XXX a;
   typedef typename __super::XXX b;
 
-  __super::XXX c; // expected-error {{missing 'typename'}}
-  typedef __super::XXX d; // expected-error {{missing 'typename'}}
+  __super::XXX c; // expected-warning {{implicit 'typename' is a C++2a extension}}
+  typedef __super::XXX d; // expected-warning {{implicit 'typename' is a C++2a extension}}
 
   void foo() {
 typename __super::XXX e;
@@ -127,8 +127,8 @@
   typename __super::XXX a;
   typedef typename __super::XXX b;
 
-  __super::XXX c; // expected-error {{missing 'typename'}}
-  typedef __super::XXX d; // expected-error {{missing 'typename'}}
+  __super::XXX c; // expected-warning {{implicit 'typename' is a C++2a extension}}
+  typedef __super::XXX d; // expected-warning {{implicit 'typename' is a C++2a extension}}
 
   void foo() {
 typename __super::XXX e;
Index: test/SemaCXX/MicrosoftExtensions.cpp
===
--- test/SemaCXX/MicrosoftExtensions.cpp
+++ test/SemaCXX/MicrosoftExtensions.cpp
@@ -526,7 +526,7 @@
 
 namespace PR32750 {
 template struct A {};
-template struct B : A> { A::C::D d; }; // expected-error {{missing 'typename' prior to dependent type name 'A::C::D'}}
+tem

[PATCH] D54414: [Sema] Make sure we substitute an instantiation-dependent default template parameter

2018-11-12 Thread Nicolas Lesser via Phabricator via cfe-commits
Rakete accepted this revision.
Rakete added a comment.
This revision is now accepted and ready to land.

LGTM, thanks :)




Comment at: clang/test/SemaCXX/alias-template.cpp:188
+template >
+int sfinae_me() { return 0; } // expected-note{{candidate template ignored: 
substitution failure}}
+

Very nit: The whole file has a space between the expected string and {{.


Repository:
  rC Clang

https://reviews.llvm.org/D54414



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


[PATCH] D53847: [C++2a] P0634r3: Down with typename!

2018-11-07 Thread Nicolas Lesser via Phabricator via cfe-commits
Rakete marked 9 inline comments as done.
Rakete added a comment.

I also found another diagnostic regression:

  template 
  T::type();

The previous error message was something with "nested name specifier does not 
refer to class ...". Now, the T::type part is interpreted as type and so we get 
a "expected unqualified-id" error message.




Comment at: include/clang/Parse/Parser.h:2119
   DeclSpecContext DSC = DeclSpecContext::DSC_normal,
-  LateParsedAttrList *LateAttrs = nullptr);
+  LateParsedAttrList *LateAttrs = nullptr) {
+return ParseDeclarationSpecifiers(DS, TemplateInfo, AS, DSC, LateAttrs,

This overload is unnecessary; I accidentally included it. I'll change it later 
so that Phab doesn't lose the review comments.



Comment at: include/clang/Parse/Parser.h:2054
+case DeclSpecContext::DSC_template_param:
+case DeclSpecContext::DSC_template_type_arg:
+case DeclSpecContext::DSC_normal:

rsmith wrote:
> This doesn't seem right to me. Doesn't this mean that `X` will change 
> from being a non-type template argument to being a type template argument?
> 
> Maybe that's a bug in the wording paper, though, since that context *is* a 
> /type-id/.
AFAIK no it won't, but I can't really tell if that's the right behavior or not. 
This patch doesn't touch the `X` case.



Comment at: test/SemaCXX/unknown-type-name.cpp:121-122
 template
-A::g() { } // expected-error{{requires a type specifier}}
+A::g() { } // expected-error{{expected unqualified-id}}
+// expected-warning@-1{{implicit 'typename' is a C++2a extension}}

rsmith wrote:
> rsmith wrote:
> > This is a diagnostic quality regression. Perhaps that's an inevitable 
> > consequence of P0634, but we should at least try to do better.
> This is marked "done" but doesn't seem to be done?
Oops, don't know why I did that. I can't figure out a way to fix this. I can 
implement a basic heuristic to detect some very basic cases like this one, but 
I don't think it's worth it.


Repository:
  rC Clang

https://reviews.llvm.org/D53847



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


[PATCH] D53847: [C++2a] P0634r3: Down with typename!

2018-11-07 Thread Nicolas Lesser via Phabricator via cfe-commits
Rakete updated this revision to Diff 173056.
Rakete added a comment.

Addressed review comments! :)


Repository:
  rC Clang

https://reviews.llvm.org/D53847

Files:
  include/clang/Basic/DiagnosticSemaKinds.td
  include/clang/Parse/Parser.h
  include/clang/Sema/Sema.h
  lib/Parse/ParseDecl.cpp
  lib/Parse/ParseDeclCXX.cpp
  lib/Parse/ParseExprCXX.cpp
  lib/Parse/ParseTentative.cpp
  lib/Parse/Parser.cpp
  lib/Sema/Sema.cpp
  lib/Sema/SemaDecl.cpp
  lib/Sema/SemaTemplate.cpp
  test/CXX/drs/dr1xx.cpp
  test/CXX/drs/dr2xx.cpp
  test/CXX/drs/dr4xx.cpp
  test/CXX/drs/dr5xx.cpp
  test/CXX/temp/temp.res/temp.dep/temp.dep.type/p1.cpp
  test/FixIt/fixit.cpp
  test/Parser/editor-placeholder-recovery.cpp
  test/SemaCXX/MicrosoftCompatibility.cpp
  test/SemaCXX/MicrosoftExtensions.cpp
  test/SemaCXX/MicrosoftSuper.cpp
  test/SemaCXX/unknown-type-name.cpp

Index: test/SemaCXX/unknown-type-name.cpp
===
--- test/SemaCXX/unknown-type-name.cpp
+++ test/SemaCXX/unknown-type-name.cpp
@@ -36,15 +36,15 @@
 
   static int n;
   static type m;
-  static int h(T::type, int); // expected-error{{missing 'typename'}}
-  static int h(T::type x, char); // expected-error{{missing 'typename'}}
+  static int h(T::type, int); // expected-warning{{implicit 'typename' is a C++2a extension}}
+  static int h(T::type x, char); // expected-warning{{implicit 'typename' is a C++2a extension}}
 };
 
 template
-A::type g(T t) { return t; } // expected-error{{missing 'typename'}}
+A::type g(T t) { return t; } // expected-warning{{implicit 'typename' is a C++2a extension}}
 
 template
-A::type A::f() { return type(); } // expected-error{{missing 'typename'}}
+A::type A::f() { return type(); } // expected-warning{{implicit 'typename' is a C++2a extension}}
 
 template
 void f(T::type) { } // expected-error{{missing 'typename'}}
@@ -72,9 +72,7 @@
 
 int *p;
 
-// FIXME: We should assume that 'undeclared' is a type, not a parameter name
-//here, and produce an 'unknown type name' diagnostic instead.
-int f1(undeclared, int); // expected-error{{requires a type specifier}}
+int f1(undeclared, int); // expected-error{{unknown type name 'undeclared'}}
 
 int f2(undeclared, 0); // expected-error{{undeclared identifier}}
 
@@ -86,11 +84,11 @@
 
 template int A::n(T::value); // ok
 template
-A::type // expected-error{{missing 'typename'}}
+A::type // expected-warning {{implicit 'typename' is a C++2a extension}}
 A::m(T::value, 0); // ok
 
-template int A::h(T::type, int) {} // expected-error{{missing 'typename'}}
-template int A::h(T::type x, char) {} // expected-error{{missing 'typename'}}
+template int A::h(T::type, int) {} // expected-warning{{implicit 'typename' is a C++2a extension}}
+template int A::h(T::type x, char) {} // expected-warning{{implicit 'typename' is a C++2a extension}}
 
 template int h(T::type, int); // expected-error{{missing 'typename'}}
 template int h(T::type x, char); // expected-error{{missing 'typename'}}
@@ -118,4 +116,5 @@
 // FIXME: We know which type specifier should have been specified here. Provide
 //a fix-it to add 'typename A::type'
 template
-A::g() { } // expected-error{{requires a type specifier}}
+A::g() { } // expected-error{{expected unqualified-id}}
+// expected-warning@-1{{implicit 'typename' is a C++2a extension}}
Index: test/SemaCXX/MicrosoftSuper.cpp
===
--- test/SemaCXX/MicrosoftSuper.cpp
+++ test/SemaCXX/MicrosoftSuper.cpp
@@ -108,8 +108,8 @@
   typename __super::XXX a;
   typedef typename __super::XXX b;
 
-  __super::XXX c; // expected-error {{missing 'typename'}}
-  typedef __super::XXX d; // expected-error {{missing 'typename'}}
+  __super::XXX c; // expected-warning {{implicit 'typename' is a C++2a extension}}
+  typedef __super::XXX d; // expected-warning {{implicit 'typename' is a C++2a extension}}
 
   void foo() {
 typename __super::XXX e;
@@ -127,8 +127,8 @@
   typename __super::XXX a;
   typedef typename __super::XXX b;
 
-  __super::XXX c; // expected-error {{missing 'typename'}}
-  typedef __super::XXX d; // expected-error {{missing 'typename'}}
+  __super::XXX c; // expected-warning {{implicit 'typename' is a C++2a extension}}
+  typedef __super::XXX d; // expected-warning {{implicit 'typename' is a C++2a extension}}
 
   void foo() {
 typename __super::XXX e;
Index: test/SemaCXX/MicrosoftExtensions.cpp
===
--- test/SemaCXX/MicrosoftExtensions.cpp
+++ test/SemaCXX/MicrosoftExtensions.cpp
@@ -526,7 +526,7 @@
 
 namespace PR32750 {
 template struct A {};
-template struct B : A> { A::C::D d; }; // expected-error {{missing 'typename' prior to dependent type name 'A::C::D'}}
+template struct B : A> { A::C::D d; }; // expected-warning {{implicit 'typename' is a C++2a extension}}
 }
 
 #else
Index: test/SemaCXX/MicrosoftCompatibility.cpp
=

[PATCH] D53847: [C++2a] P0634r3: Down with typename!

2018-11-01 Thread Nicolas Lesser via Phabricator via cfe-commits
Rakete updated this revision to Diff 172218.
Rakete added a comment.

I'm pretty sure I implemented the rules correctly now :)


Repository:
  rC Clang

https://reviews.llvm.org/D53847

Files:
  include/clang/Basic/DiagnosticSemaKinds.td
  include/clang/Parse/Parser.h
  include/clang/Sema/Sema.h
  lib/Parse/ParseDecl.cpp
  lib/Parse/ParseDeclCXX.cpp
  lib/Parse/ParseExprCXX.cpp
  lib/Parse/ParseTentative.cpp
  lib/Parse/Parser.cpp
  lib/Sema/SemaDecl.cpp
  lib/Sema/SemaTemplate.cpp
  test/CXX/drs/dr1xx.cpp
  test/CXX/drs/dr2xx.cpp
  test/CXX/drs/dr4xx.cpp
  test/CXX/drs/dr5xx.cpp
  test/CXX/temp/temp.res/p5.cpp
  test/CXX/temp/temp.res/temp.dep/temp.dep.type/p1.cpp
  test/FixIt/fixit.cpp
  test/SemaCXX/MicrosoftCompatibility.cpp
  test/SemaCXX/MicrosoftExtensions.cpp
  test/SemaCXX/MicrosoftSuper.cpp
  test/SemaCXX/unknown-type-name.cpp

Index: test/SemaCXX/unknown-type-name.cpp
===
--- test/SemaCXX/unknown-type-name.cpp
+++ test/SemaCXX/unknown-type-name.cpp
@@ -36,15 +36,15 @@
 
   static int n;
   static type m;
-  static int h(T::type, int); // expected-error{{missing 'typename'}}
-  static int h(T::type x, char); // expected-error{{missing 'typename'}}
+  static int h(T::type, int); // expected-warning{{implicit 'typename' is a C++2a extension}}
+  static int h(T::type x, char); // expected-warning{{implicit 'typename' is a C++2a extension}}
 };
 
 template
-A::type g(T t) { return t; } // expected-error{{missing 'typename'}}
+A::type g(T t) { return t; } // expected-warning{{implicit 'typename' is a C++2a extension}}
 
 template
-A::type A::f() { return type(); } // expected-error{{missing 'typename'}}
+A::type A::f() { return type(); } // expected-warning{{implicit 'typename' is a C++2a extension}}
 
 template
 void f(T::type) { } // expected-error{{missing 'typename'}}
@@ -86,11 +86,11 @@
 
 template int A::n(T::value); // ok
 template
-A::type // expected-error{{missing 'typename'}}
+A::type // expected-warning {{implicit 'typename' is a C++2a extension}}
 A::m(T::value, 0); // ok
 
-template int A::h(T::type, int) {} // expected-error{{missing 'typename'}}
-template int A::h(T::type x, char) {} // expected-error{{missing 'typename'}}
+template int A::h(T::type, int) {} // expected-warning{{implicit 'typename' is a C++2a extension}}
+template int A::h(T::type x, char) {} // expected-warning{{implicit 'typename' is a C++2a extension}}
 
 template int h(T::type, int); // expected-error{{missing 'typename'}}
 template int h(T::type x, char); // expected-error{{missing 'typename'}}
@@ -118,4 +118,5 @@
 // FIXME: We know which type specifier should have been specified here. Provide
 //a fix-it to add 'typename A::type'
 template
-A::g() { } // expected-error{{requires a type specifier}}
+A::g() { } // expected-error{{expected unqualified-id}}
+// expected-warning@-1{{implicit 'typename' is a C++2a extension}}
Index: test/SemaCXX/MicrosoftSuper.cpp
===
--- test/SemaCXX/MicrosoftSuper.cpp
+++ test/SemaCXX/MicrosoftSuper.cpp
@@ -108,8 +108,8 @@
   typename __super::XXX a;
   typedef typename __super::XXX b;
 
-  __super::XXX c; // expected-error {{missing 'typename'}}
-  typedef __super::XXX d; // expected-error {{missing 'typename'}}
+  __super::XXX c; // expected-warning {{implicit 'typename' is a C++2a extension}}
+  typedef __super::XXX d; // expected-warning {{implicit 'typename' is a C++2a extension}}
 
   void foo() {
 typename __super::XXX e;
@@ -127,8 +127,8 @@
   typename __super::XXX a;
   typedef typename __super::XXX b;
 
-  __super::XXX c; // expected-error {{missing 'typename'}}
-  typedef __super::XXX d; // expected-error {{missing 'typename'}}
+  __super::XXX c; // expected-warning {{implicit 'typename' is a C++2a extension}}
+  typedef __super::XXX d; // expected-warning {{implicit 'typename' is a C++2a extension}}
 
   void foo() {
 typename __super::XXX e;
Index: test/SemaCXX/MicrosoftExtensions.cpp
===
--- test/SemaCXX/MicrosoftExtensions.cpp
+++ test/SemaCXX/MicrosoftExtensions.cpp
@@ -526,7 +526,7 @@
 
 namespace PR32750 {
 template struct A {};
-template struct B : A> { A::C::D d; }; // expected-error {{missing 'typename' prior to dependent type name 'A::C::D'}}
+template struct B : A> { A::C::D d; }; // expected-warning {{implicit 'typename' is a C++2a extension}}
 }
 
 #else
Index: test/SemaCXX/MicrosoftCompatibility.cpp
===
--- test/SemaCXX/MicrosoftCompatibility.cpp
+++ test/SemaCXX/MicrosoftCompatibility.cpp
@@ -199,25 +199,25 @@
typedef B Base2;
typedef A Base3;
 
-   A::TYPE a1; // expected-warning {{missing 'typename' prior to dependent type name}}
-   Base1::TYPE a2; // expected-warning {{missing 'typename' prior to dependent type name}}
+   A::TYPE a1; // ex

[PATCH] D53847: [C++2a] P0634r3: Down with typename!

2018-11-01 Thread Nicolas Lesser via Phabricator via cfe-commits
Rakete added inline comments.



Comment at: test/SemaCXX/unknown-type-name.cpp:50
 template
-void f(T::type) { } // expected-error{{missing 'typename'}}
+void f(T::type) { } // expected-warning {{implicit 'typename' is a C++2a 
extension}}
 

rsmith wrote:
> Rakete wrote:
> > rsmith wrote:
> > > This is wrong.
> > > 
> > > ```
> > > template
> > > X f(T::type);
> > > ```
> > > 
> > > declares a variable template. This would be valid if the name `f` were a 
> > > //qualified-id//, and lookup for `f` found a function template, though.
> > > 
> > > (Same for the next 7 cases.)
> > I agree, but those are definitions, so the next 7 cases and this now are 
> > correct.
> I think you've misunderstood the rule. The rule that I think you're referring 
> to is:
> 
> "A qualified-id is assumed to name a type if it is a decl-specifier of the 
> decl-specifier-seq of a simple-declaration or a function-definition in 
> namespace scope"
> 
> But the decl-specifier-seq is just the type *before* the function name, not 
> the parameter's types. There is no special case for function definitions.
Oh I did! Thanks. Let me update my revision :)


Repository:
  rC Clang

https://reviews.llvm.org/D53847



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


[PATCH] D53847: [C++2a] P0634r3: Down with typename!

2018-11-01 Thread Nicolas Lesser via Phabricator via cfe-commits
Rakete updated this revision to Diff 172147.
Rakete marked an inline comment as done.
Rakete added a comment.

Remove spaces to be consistent.


Repository:
  rC Clang

https://reviews.llvm.org/D53847

Files:
  include/clang/Basic/DiagnosticSemaKinds.td
  include/clang/Parse/Parser.h
  include/clang/Sema/Scope.h
  include/clang/Sema/Sema.h
  lib/Parse/ParseDecl.cpp
  lib/Parse/ParseDeclCXX.cpp
  lib/Parse/ParseExprCXX.cpp
  lib/Parse/ParseTentative.cpp
  lib/Parse/Parser.cpp
  lib/Sema/SemaDecl.cpp
  lib/Sema/SemaLookup.cpp
  lib/Sema/SemaTemplate.cpp
  test/CXX/drs/dr1xx.cpp
  test/CXX/drs/dr2xx.cpp
  test/CXX/drs/dr4xx.cpp
  test/CXX/drs/dr5xx.cpp
  test/CXX/temp/temp.res/p5.cpp
  test/CXX/temp/temp.res/temp.dep/temp.dep.type/p1.cpp
  test/FixIt/fixit.cpp
  test/SemaCXX/MicrosoftCompatibility.cpp
  test/SemaCXX/MicrosoftExtensions.cpp
  test/SemaCXX/MicrosoftSuper.cpp
  test/SemaCXX/unknown-type-name.cpp

Index: test/SemaCXX/unknown-type-name.cpp
===
--- test/SemaCXX/unknown-type-name.cpp
+++ test/SemaCXX/unknown-type-name.cpp
@@ -36,39 +36,39 @@
 
   static int n;
   static type m;
-  static int h(T::type, int); // expected-error{{missing 'typename'}}
-  static int h(T::type x, char); // expected-error{{missing 'typename'}}
+  static int h(T::type, int); // expected-warning{{implicit 'typename' is a C++2a extension}}
+  static int h(T::type x, char); // expected-warning{{implicit 'typename' is a C++2a extension}}
 };
 
 template
-A::type g(T t) { return t; } // expected-error{{missing 'typename'}}
+A::type g(T t) { return t; } // expected-warning{{implicit 'typename' is a C++2a extension}}
 
 template
-A::type A::f() { return type(); } // expected-error{{missing 'typename'}}
+A::type A::f() { return type(); } // expected-warning{{implicit 'typename' is a C++2a extension}}
 
 template
-void f(T::type) { } // expected-error{{missing 'typename'}}
+void f(T::type) { } // expected-warning{{implicit 'typename' is a C++2a extension}}
 
 template
-void g(T::type x) { } // expected-error{{missing 'typename'}}
+void g(T::type x) { } // expected-warning{{implicit 'typename' is a C++2a extension}}
 
 template
-void f(T::type, int) { } // expected-error{{missing 'typename'}}
+void f(T::type, int) { } // expected-warning{{implicit 'typename' is a C++2a extension}}
 
 template
-void f(T::type x, char) { } // expected-error{{missing 'typename'}}
+void f(T::type x, char) { } // expected-warning{{implicit 'typename' is a C++2a extension}}
 
 template
-void f(int, T::type) { } // expected-error{{missing 'typename'}}
+void f(int, T::type) { } // expected-warning{{implicit 'typename' is a C++2a extension}}
 
 template
-void f(char, T::type x) { } // expected-error{{missing 'typename'}}
+void f(char, T::type x) { } // expected-warning{{implicit 'typename' is a C++2a extension}}
 
 template
-void f(int, T::type, int) { } // expected-error{{missing 'typename'}}
+void f(int, T::type, int) { } // expected-warning{{implicit 'typename' is a C++2a extension}}
 
 template
-void f(int, T::type x, char) { } // expected-error{{missing 'typename'}}
+void f(int, T::type x, char) { } // expected-warning{{implicit 'typename' is a C++2a extension}}
 
 int *p;
 
@@ -86,11 +86,11 @@
 
 template int A::n(T::value); // ok
 template
-A::type // expected-error{{missing 'typename'}}
+A::type // expected-warning {{implicit 'typename' is a C++2a extension}}
 A::m(T::value, 0); // ok
 
-template int A::h(T::type, int) {} // expected-error{{missing 'typename'}}
-template int A::h(T::type x, char) {} // expected-error{{missing 'typename'}}
+template int A::h(T::type, int) {} // expected-warning{{implicit 'typename' is a C++2a extension}}
+template int A::h(T::type x, char) {} // expected-warning{{implicit 'typename' is a C++2a extension}}
 
 template int h(T::type, int); // expected-error{{missing 'typename'}}
 template int h(T::type x, char); // expected-error{{missing 'typename'}}
@@ -100,7 +100,7 @@
 // expected-warning@-2 {{variable templates are a C++14 extension}}
 #endif
 template int junk2(T::junk) throw(); // expected-error{{missing 'typename'}}
-template int junk3(T::junk) = delete; // expected-error{{missing 'typename'}}
+template int junk3(T::junk) = delete; // expected-warning{{implicit 'typename' is a C++2a extension}}
 #if __cplusplus <= 199711L
 //expected-warning@-2 {{deleted function definitions are a C++11 extension}}
 #endif
@@ -118,4 +118,5 @@
 // FIXME: We know which type specifier should have been specified here. Provide
 //a fix-it to add 'typename A::type'
 template
-A::g() { } // expected-error{{requires a type specifier}}
+A::g() { } // expected-error{{expected unqualified-id}}
+// expected-warning@-1{{implicit 'typename' is a C++2a extension}}
Index: test/SemaCXX/MicrosoftSuper.cpp
===
--- test/SemaCXX/MicrosoftSuper.cpp
+++ test/SemaCXX/MicrosoftSuper.cpp
@@ -108,8 +108,8 @@
   

[PATCH] D53847: [C++2a] P0634r3: Down with typename!

2018-11-01 Thread Nicolas Lesser via Phabricator via cfe-commits
Rakete marked 7 inline comments as done.
Rakete added inline comments.



Comment at: lib/Parse/Parser.cpp:1778
+/*IsClassTemplateDeductionContext*/true,
+/*AllowImplicitTypename*/false)) {
   SourceLocation BeginLoc = Tok.getLocation();

rsmith wrote:
> Don't we need to sometimes allow an implicit typename here for correct 
> disambiguation?
This is done elsewhere now. :)



Comment at: test/SemaCXX/unknown-type-name.cpp:50
 template
-void f(T::type) { } // expected-error{{missing 'typename'}}
+void f(T::type) { } // expected-warning {{implicit 'typename' is a C++2a 
extension}}
 

rsmith wrote:
> This is wrong.
> 
> ```
> template
> X f(T::type);
> ```
> 
> declares a variable template. This would be valid if the name `f` were a 
> //qualified-id//, and lookup for `f` found a function template, though.
> 
> (Same for the next 7 cases.)
I agree, but those are definitions, so the next 7 cases and this now are 
correct.



Comment at: test/SemaCXX/unknown-type-name.cpp:102-103
 #endif
-template int junk2(T::junk) throw(); // expected-error{{missing 
'typename'}}
-template int junk3(T::junk) = delete; // expected-error{{missing 
'typename'}}
+template int junk2(T::junk) throw(); // expected-warning 
{{implicit 'typename' is a C++2a extension}}
+template int junk3(T::junk) = delete; // expected-warning 
{{implicit 'typename' is a C++2a extension}}
 #if __cplusplus <= 199711L

rsmith wrote:
> These two are incorrect.
Only the first one is incorrect (i.e. doesn't have implicit typename). The 
second one does, because it's a function definition.


Repository:
  rC Clang

https://reviews.llvm.org/D53847



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


[PATCH] D53847: [C++2a] P0634r3: Down with typename!

2018-11-01 Thread Nicolas Lesser via Phabricator via cfe-commits
Rakete updated this revision to Diff 172146.
Rakete marked 6 inline comments as done.
Rakete added a comment.

Addressed review comments! :)


Repository:
  rC Clang

https://reviews.llvm.org/D53847

Files:
  include/clang/Basic/DiagnosticSemaKinds.td
  include/clang/Parse/Parser.h
  include/clang/Sema/Scope.h
  include/clang/Sema/Sema.h
  lib/Parse/ParseDecl.cpp
  lib/Parse/ParseDeclCXX.cpp
  lib/Parse/ParseExprCXX.cpp
  lib/Parse/ParseTentative.cpp
  lib/Parse/Parser.cpp
  lib/Sema/SemaDecl.cpp
  lib/Sema/SemaLookup.cpp
  lib/Sema/SemaTemplate.cpp
  test/CXX/drs/dr1xx.cpp
  test/CXX/drs/dr2xx.cpp
  test/CXX/drs/dr4xx.cpp
  test/CXX/drs/dr5xx.cpp
  test/CXX/temp/temp.res/p5.cpp
  test/CXX/temp/temp.res/temp.dep/temp.dep.type/p1.cpp
  test/FixIt/fixit.cpp
  test/SemaCXX/MicrosoftCompatibility.cpp
  test/SemaCXX/MicrosoftExtensions.cpp
  test/SemaCXX/MicrosoftSuper.cpp
  test/SemaCXX/unknown-type-name.cpp

Index: test/SemaCXX/unknown-type-name.cpp
===
--- test/SemaCXX/unknown-type-name.cpp
+++ test/SemaCXX/unknown-type-name.cpp
@@ -36,39 +36,39 @@
 
   static int n;
   static type m;
-  static int h(T::type, int); // expected-error{{missing 'typename'}}
-  static int h(T::type x, char); // expected-error{{missing 'typename'}}
+  static int h(T::type, int); // expected-warning {{implicit 'typename' is a C++2a extension}}
+  static int h(T::type x, char); // expected-warning {{implicit 'typename' is a C++2a extension}}
 };
 
 template
-A::type g(T t) { return t; } // expected-error{{missing 'typename'}}
+A::type g(T t) { return t; } // expected-warning {{implicit 'typename' is a C++2a extension}}
 
 template
-A::type A::f() { return type(); } // expected-error{{missing 'typename'}}
+A::type A::f() { return type(); } // expected-warning {{implicit 'typename' is a C++2a extension}}
 
 template
-void f(T::type) { } // expected-error{{missing 'typename'}}
+void f(T::type) { } // expected-warning {{implicit 'typename' is a C++2a extension}}
 
 template
-void g(T::type x) { } // expected-error{{missing 'typename'}}
+void g(T::type x) { } // expected-warning {{implicit 'typename' is a C++2a extension}}
 
 template
-void f(T::type, int) { } // expected-error{{missing 'typename'}}
+void f(T::type, int) { } // expected-warning {{implicit 'typename' is a C++2a extension}}
 
 template
-void f(T::type x, char) { } // expected-error{{missing 'typename'}}
+void f(T::type x, char) { } // expected-warning {{implicit 'typename' is a C++2a extension}}
 
 template
-void f(int, T::type) { } // expected-error{{missing 'typename'}}
+void f(int, T::type) { } // expected-warning {{implicit 'typename' is a C++2a extension}}
 
 template
-void f(char, T::type x) { } // expected-error{{missing 'typename'}}
+void f(char, T::type x) { } // expected-warning {{implicit 'typename' is a C++2a extension}}
 
 template
-void f(int, T::type, int) { } // expected-error{{missing 'typename'}}
+void f(int, T::type, int) { } // expected-warning {{implicit 'typename' is a C++2a extension}}
 
 template
-void f(int, T::type x, char) { } // expected-error{{missing 'typename'}}
+void f(int, T::type x, char) { } // expected-warning {{implicit 'typename' is a C++2a extension}}
 
 int *p;
 
@@ -86,26 +86,26 @@
 
 template int A::n(T::value); // ok
 template
-A::type // expected-error{{missing 'typename'}}
+A::type // expected-warning {{implicit 'typename' is a C++2a extension}}
 A::m(T::value, 0); // ok
 
-template int A::h(T::type, int) {} // expected-error{{missing 'typename'}}
-template int A::h(T::type x, char) {} // expected-error{{missing 'typename'}}
+template int A::h(T::type, int) {} // expected-warning {{implicit 'typename' is a C++2a extension}}
+template int A::h(T::type x, char) {} // expected-warning {{implicit 'typename' is a C++2a extension}}
 
-template int h(T::type, int); // expected-error{{missing 'typename'}}
-template int h(T::type x, char); // expected-error{{missing 'typename'}}
+template int h(T::type, int); // expected-error {{missing 'typename'}}
+template int h(T::type x, char); // expected-error {{missing 'typename'}}
 
 template int junk1(T::junk);
 #if __cplusplus <= 201103L
 // expected-warning@-2 {{variable templates are a C++14 extension}}
 #endif
-template int junk2(T::junk) throw(); // expected-error{{missing 'typename'}}
-template int junk3(T::junk) = delete; // expected-error{{missing 'typename'}}
+template int junk2(T::junk) throw(); // expected-error {{missing 'typename'}}
+template int junk3(T::junk) = delete; // expected-warning {{implicit 'typename' is a C++2a extension}}
 #if __cplusplus <= 199711L
 //expected-warning@-2 {{deleted function definitions are a C++11 extension}}
 #endif
 
-template int junk4(T::junk j); // expected-error{{missing 'typename'}}
+template int junk4(T::junk j); // expected-error {{missing 'typename'}}
 
 // FIXME: We can tell this was intended to be a function because it does not
 //have a dependent nested na

[PATCH] D53847: [C++2a] P0634r3: Down with typename!

2018-10-29 Thread Nicolas Lesser via Phabricator via cfe-commits
Rakete updated this revision to Diff 171612.
Rakete added a comment.

Fix easy errors in tests that I missed by adding explicit template 
instantations.


Repository:
  rC Clang

https://reviews.llvm.org/D53847

Files:
  include/clang/Basic/DiagnosticSemaKinds.td
  include/clang/Sema/Sema.h
  lib/Parse/ParseDecl.cpp
  lib/Parse/ParseDeclCXX.cpp
  lib/Parse/Parser.cpp
  lib/Sema/SemaDecl.cpp
  test/CXX/drs/dr1xx.cpp
  test/CXX/drs/dr2xx.cpp
  test/CXX/drs/dr4xx.cpp
  test/CXX/drs/dr5xx.cpp
  test/CXX/temp/temp.res/p5.cpp
  test/CXX/temp/temp.res/temp.dep/temp.dep.type/p1.cpp
  test/FixIt/fixit.cpp
  test/SemaCXX/MicrosoftCompatibility.cpp
  test/SemaCXX/MicrosoftExtensions.cpp
  test/SemaCXX/MicrosoftSuper.cpp
  test/SemaCXX/PR11358.cpp
  test/SemaCXX/unknown-type-name.cpp

Index: test/SemaCXX/unknown-type-name.cpp
===
--- test/SemaCXX/unknown-type-name.cpp
+++ test/SemaCXX/unknown-type-name.cpp
@@ -36,39 +36,39 @@
 
   static int n;
   static type m;
-  static int h(T::type, int); // expected-error{{missing 'typename'}}
-  static int h(T::type x, char); // expected-error{{missing 'typename'}}
+  static int h(T::type, int); // expected-warning {{implicit 'typename' is a C++2a extension}}
+  static int h(T::type x, char); // expected-warning {{implicit 'typename' is a C++2a extension}}
 };
 
 template
-A::type g(T t) { return t; } // expected-error{{missing 'typename'}}
+A::type g(T t) { return t; } // expected-warning {{implicit 'typename' is a C++2a extension}}
 
 template
-A::type A::f() { return type(); } // expected-error{{missing 'typename'}}
+A::type A::f() { return type(); } // expected-warning {{implicit 'typename' is a C++2a extension}}
 
 template
-void f(T::type) { } // expected-error{{missing 'typename'}}
+void f(T::type) { } // expected-warning {{implicit 'typename' is a C++2a extension}}
 
 template
-void g(T::type x) { } // expected-error{{missing 'typename'}}
+void g(T::type x) { } // expected-warning {{implicit 'typename' is a C++2a extension}}
 
 template
-void f(T::type, int) { } // expected-error{{missing 'typename'}}
+void f(T::type, int) { } // expected-warning {{implicit 'typename' is a C++2a extension}}
 
 template
-void f(T::type x, char) { } // expected-error{{missing 'typename'}}
+void f(T::type x, char) { } // expected-warning {{implicit 'typename' is a C++2a extension}}
 
 template
-void f(int, T::type) { } // expected-error{{missing 'typename'}}
+void f(int, T::type) { } // expected-warning {{implicit 'typename' is a C++2a extension}}
 
 template
-void f(char, T::type x) { } // expected-error{{missing 'typename'}}
+void f(char, T::type x) { } // expected-warning {{implicit 'typename' is a C++2a extension}}
 
 template
-void f(int, T::type, int) { } // expected-error{{missing 'typename'}}
+void f(int, T::type, int) { } // expected-warning {{implicit 'typename' is a C++2a extension}}
 
 template
-void f(int, T::type x, char) { } // expected-error{{missing 'typename'}}
+void f(int, T::type x, char) { } // expected-warning {{implicit 'typename' is a C++2a extension}}
 
 int *p;
 
@@ -86,26 +86,26 @@
 
 template int A::n(T::value); // ok
 template
-A::type // expected-error{{missing 'typename'}}
+A::type // expected-warning {{implicit 'typename' is a C++2a extension}}
 A::m(T::value, 0); // ok
 
-template int A::h(T::type, int) {} // expected-error{{missing 'typename'}}
-template int A::h(T::type x, char) {} // expected-error{{missing 'typename'}}
+template int A::h(T::type, int) {} // expected-warning {{implicit 'typename' is a C++2a extension}}
+template int A::h(T::type x, char) {} // expected-warning {{implicit 'typename' is a C++2a extension}}
 
-template int h(T::type, int); // expected-error{{missing 'typename'}}
-template int h(T::type x, char); // expected-error{{missing 'typename'}}
+template int h(T::type, int); // expected-warning {{implicit 'typename' is a C++2a extension}}
+template int h(T::type x, char); // expected-warning {{implicit 'typename' is a C++2a extension}}
 
 template int junk1(T::junk);
 #if __cplusplus <= 201103L
 // expected-warning@-2 {{variable templates are a C++14 extension}}
 #endif
-template int junk2(T::junk) throw(); // expected-error{{missing 'typename'}}
-template int junk3(T::junk) = delete; // expected-error{{missing 'typename'}}
+template int junk2(T::junk) throw(); // expected-warning {{implicit 'typename' is a C++2a extension}}
+template int junk3(T::junk) = delete; // expected-warning {{implicit 'typename' is a C++2a extension}}
 #if __cplusplus <= 199711L
 //expected-warning@-2 {{deleted function definitions are a C++11 extension}}
 #endif
 
-template int junk4(T::junk j); // expected-error{{missing 'typename'}}
+template int junk4(T::junk j); // expected-warning {{implicit 'typename' is a C++2a extension}}
 
 // FIXME: We can tell this was intended to be a function because it does not
 //have a dependent nested name specifier.
@@ -118,4 +118,5 @@
 // FIXME

[PATCH] D53847: [C++2a] P0634r3: Down with typename!

2018-10-29 Thread Nicolas Lesser via Phabricator via cfe-commits
Rakete updated this revision to Diff 171609.
Rakete added a comment.

Remove unneeded -Wc++2a-compat flag in tests.


Repository:
  rC Clang

https://reviews.llvm.org/D53847

Files:
  include/clang/Basic/DiagnosticSemaKinds.td
  include/clang/Sema/Sema.h
  lib/Parse/ParseDecl.cpp
  lib/Parse/ParseDeclCXX.cpp
  lib/Parse/Parser.cpp
  lib/Sema/SemaDecl.cpp
  test/CXX/drs/dr1xx.cpp
  test/CXX/drs/dr2xx.cpp
  test/CXX/drs/dr4xx.cpp
  test/CXX/drs/dr5xx.cpp
  test/CXX/temp/temp.res/p5.cpp
  test/CXX/temp/temp.res/temp.dep/temp.dep.type/p1.cpp
  test/FixIt/fixit.cpp
  test/SemaCXX/MicrosoftCompatibility.cpp
  test/SemaCXX/MicrosoftExtensions.cpp
  test/SemaCXX/MicrosoftSuper.cpp
  test/SemaCXX/PR11358.cpp
  test/SemaCXX/unknown-type-name.cpp

Index: test/SemaCXX/unknown-type-name.cpp
===
--- test/SemaCXX/unknown-type-name.cpp
+++ test/SemaCXX/unknown-type-name.cpp
@@ -36,39 +36,39 @@
 
   static int n;
   static type m;
-  static int h(T::type, int); // expected-error{{missing 'typename'}}
-  static int h(T::type x, char); // expected-error{{missing 'typename'}}
+  static int h(T::type, int); // expected-warning {{implicit 'typename' is a C++2a extension}}
+  static int h(T::type x, char); // expected-warning {{implicit 'typename' is a C++2a extension}}
 };
 
 template
-A::type g(T t) { return t; } // expected-error{{missing 'typename'}}
+A::type g(T t) { return t; } // expected-warning {{implicit 'typename' is a C++2a extension}}
 
 template
-A::type A::f() { return type(); } // expected-error{{missing 'typename'}}
+A::type A::f() { return type(); } // expected-warning {{implicit 'typename' is a C++2a extension}}
 
 template
-void f(T::type) { } // expected-error{{missing 'typename'}}
+void f(T::type) { } // expected-warning {{implicit 'typename' is a C++2a extension}}
 
 template
-void g(T::type x) { } // expected-error{{missing 'typename'}}
+void g(T::type x) { } // expected-warning {{implicit 'typename' is a C++2a extension}}
 
 template
-void f(T::type, int) { } // expected-error{{missing 'typename'}}
+void f(T::type, int) { } // expected-warning {{implicit 'typename' is a C++2a extension}}
 
 template
-void f(T::type x, char) { } // expected-error{{missing 'typename'}}
+void f(T::type x, char) { } // expected-warning {{implicit 'typename' is a C++2a extension}}
 
 template
-void f(int, T::type) { } // expected-error{{missing 'typename'}}
+void f(int, T::type) { } // expected-warning {{implicit 'typename' is a C++2a extension}}
 
 template
-void f(char, T::type x) { } // expected-error{{missing 'typename'}}
+void f(char, T::type x) { } // expected-warning {{implicit 'typename' is a C++2a extension}}
 
 template
-void f(int, T::type, int) { } // expected-error{{missing 'typename'}}
+void f(int, T::type, int) { } // expected-warning {{implicit 'typename' is a C++2a extension}}
 
 template
-void f(int, T::type x, char) { } // expected-error{{missing 'typename'}}
+void f(int, T::type x, char) { } // expected-warning {{implicit 'typename' is a C++2a extension}}
 
 int *p;
 
@@ -86,26 +86,26 @@
 
 template int A::n(T::value); // ok
 template
-A::type // expected-error{{missing 'typename'}}
+A::type // expected-warning {{implicit 'typename' is a C++2a extension}}
 A::m(T::value, 0); // ok
 
-template int A::h(T::type, int) {} // expected-error{{missing 'typename'}}
-template int A::h(T::type x, char) {} // expected-error{{missing 'typename'}}
+template int A::h(T::type, int) {} // expected-warning {{implicit 'typename' is a C++2a extension}}
+template int A::h(T::type x, char) {} // expected-warning {{implicit 'typename' is a C++2a extension}}
 
-template int h(T::type, int); // expected-error{{missing 'typename'}}
-template int h(T::type x, char); // expected-error{{missing 'typename'}}
+template int h(T::type, int); // expected-warning {{implicit 'typename' is a C++2a extension}}
+template int h(T::type x, char); // expected-warning {{implicit 'typename' is a C++2a extension}}
 
 template int junk1(T::junk);
 #if __cplusplus <= 201103L
 // expected-warning@-2 {{variable templates are a C++14 extension}}
 #endif
-template int junk2(T::junk) throw(); // expected-error{{missing 'typename'}}
-template int junk3(T::junk) = delete; // expected-error{{missing 'typename'}}
+template int junk2(T::junk) throw(); // expected-warning {{implicit 'typename' is a C++2a extension}}
+template int junk3(T::junk) = delete; // expected-warning {{implicit 'typename' is a C++2a extension}}
 #if __cplusplus <= 199711L
 //expected-warning@-2 {{deleted function definitions are a C++11 extension}}
 #endif
 
-template int junk4(T::junk j); // expected-error{{missing 'typename'}}
+template int junk4(T::junk j); // expected-warning {{implicit 'typename' is a C++2a extension}}
 
 // FIXME: We can tell this was intended to be a function because it does not
 //have a dependent nested name specifier.
@@ -118,4 +118,5 @@
 // FIXME: We know which type specifier should

[PATCH] D53847: [C++2a] P0634r3: Down with typename!

2018-10-29 Thread Nicolas Lesser via Phabricator via cfe-commits
Rakete added inline comments.



Comment at: test/CXX/temp/temp.res/p5.cpp:71
+
+// FIXME: This is ok.
+template 

I think the below is well-formed according to the quote above, but I'm not sure 
I understand it correctly.


Repository:
  rC Clang

https://reviews.llvm.org/D53847



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


[PATCH] D53847: [C++2a] P0634r3: Down with typename!

2018-10-29 Thread Nicolas Lesser via Phabricator via cfe-commits
Rakete created this revision.
Rakete added a reviewer: rsmith.

This patch implements P0634r3 that removes the need for 'typename' in certain 
contexts.

For example,

  template 
  using foo = T::type; // ok

This is also allowed in previous language versions as an extension, because I 
think it's pretty useful. :)


Repository:
  rC Clang

https://reviews.llvm.org/D53847

Files:
  include/clang/Basic/DiagnosticSemaKinds.td
  include/clang/Sema/Sema.h
  lib/Parse/ParseDecl.cpp
  lib/Parse/ParseDeclCXX.cpp
  lib/Parse/Parser.cpp
  lib/Sema/SemaDecl.cpp
  test/CXX/drs/dr1xx.cpp
  test/CXX/drs/dr2xx.cpp
  test/CXX/drs/dr4xx.cpp
  test/CXX/drs/dr5xx.cpp
  test/CXX/temp/temp.res/p5.cpp
  test/CXX/temp/temp.res/temp.dep/temp.dep.type/p1.cpp
  test/FixIt/fixit.cpp
  test/SemaCXX/MicrosoftCompatibility.cpp
  test/SemaCXX/MicrosoftExtensions.cpp
  test/SemaCXX/MicrosoftSuper.cpp
  test/SemaCXX/PR11358.cpp
  test/SemaCXX/unknown-type-name.cpp

Index: test/SemaCXX/unknown-type-name.cpp
===
--- test/SemaCXX/unknown-type-name.cpp
+++ test/SemaCXX/unknown-type-name.cpp
@@ -1,6 +1,6 @@
-// RUN: %clang_cc1 -fsyntax-only -verify %s
-// RUN: %clang_cc1 -fsyntax-only -verify -std=c++98 %s
-// RUN: %clang_cc1 -fsyntax-only -verify -std=c++11 %s
+// RUN: %clang_cc1 -Wc++2a-compat -fsyntax-only -verify %s
+// RUN: %clang_cc1 -Wc++2a-compat -fsyntax-only -verify -std=c++98 %s
+// RUN: %clang_cc1 -Wc++2a-compat -fsyntax-only -verify -std=c++11 %s
 
 // PR3990
 namespace N {
@@ -36,39 +36,39 @@
 
   static int n;
   static type m;
-  static int h(T::type, int); // expected-error{{missing 'typename'}}
-  static int h(T::type x, char); // expected-error{{missing 'typename'}}
+  static int h(T::type, int); // expected-warning {{implicit 'typename' is a C++2a extension}}
+  static int h(T::type x, char); // expected-warning {{implicit 'typename' is a C++2a extension}}
 };
 
 template
-A::type g(T t) { return t; } // expected-error{{missing 'typename'}}
+A::type g(T t) { return t; } // expected-warning {{implicit 'typename' is a C++2a extension}}
 
 template
-A::type A::f() { return type(); } // expected-error{{missing 'typename'}}
+A::type A::f() { return type(); } // expected-warning {{implicit 'typename' is a C++2a extension}}
 
 template
-void f(T::type) { } // expected-error{{missing 'typename'}}
+void f(T::type) { } // expected-warning {{implicit 'typename' is a C++2a extension}}
 
 template
-void g(T::type x) { } // expected-error{{missing 'typename'}}
+void g(T::type x) { } // expected-warning {{implicit 'typename' is a C++2a extension}}
 
 template
-void f(T::type, int) { } // expected-error{{missing 'typename'}}
+void f(T::type, int) { } // expected-warning {{implicit 'typename' is a C++2a extension}}
 
 template
-void f(T::type x, char) { } // expected-error{{missing 'typename'}}
+void f(T::type x, char) { } // expected-warning {{implicit 'typename' is a C++2a extension}}
 
 template
-void f(int, T::type) { } // expected-error{{missing 'typename'}}
+void f(int, T::type) { } // expected-warning {{implicit 'typename' is a C++2a extension}}
 
 template
-void f(char, T::type x) { } // expected-error{{missing 'typename'}}
+void f(char, T::type x) { } // expected-warning {{implicit 'typename' is a C++2a extension}}
 
 template
-void f(int, T::type, int) { } // expected-error{{missing 'typename'}}
+void f(int, T::type, int) { } // expected-warning {{implicit 'typename' is a C++2a extension}}
 
 template
-void f(int, T::type x, char) { } // expected-error{{missing 'typename'}}
+void f(int, T::type x, char) { } // expected-warning {{implicit 'typename' is a C++2a extension}}
 
 int *p;
 
@@ -86,26 +86,26 @@
 
 template int A::n(T::value); // ok
 template
-A::type // expected-error{{missing 'typename'}}
+A::type // expected-warning {{implicit 'typename' is a C++2a extension}}
 A::m(T::value, 0); // ok
 
-template int A::h(T::type, int) {} // expected-error{{missing 'typename'}}
-template int A::h(T::type x, char) {} // expected-error{{missing 'typename'}}
+template int A::h(T::type, int) {} // expected-warning {{implicit 'typename' is a C++2a extension}}
+template int A::h(T::type x, char) {} // expected-warning {{implicit 'typename' is a C++2a extension}}
 
-template int h(T::type, int); // expected-error{{missing 'typename'}}
-template int h(T::type x, char); // expected-error{{missing 'typename'}}
+template int h(T::type, int); // expected-warning {{implicit 'typename' is a C++2a extension}}
+template int h(T::type x, char); // expected-warning {{implicit 'typename' is a C++2a extension}}
 
 template int junk1(T::junk);
 #if __cplusplus <= 201103L
 // expected-warning@-2 {{variable templates are a C++14 extension}}
 #endif
-template int junk2(T::junk) throw(); // expected-error{{missing 'typename'}}
-template int junk3(T::junk) = delete; // expected-error{{missing 'typename'}}
+template int junk2(T::junk) throw(); // expected-warning {{implicit 'typename' is a

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

2018-10-28 Thread Nicolas Lesser via Phabricator via cfe-commits
Rakete updated this revision to Diff 171421.
Rakete added a comment.

Rebase and friendly ping :)


Repository:
  rC Clang

https://reviews.llvm.org/D36357

Files:
  include/clang/Basic/DiagnosticParseKinds.td
  lib/Parse/ParseExprCXX.cpp
  test/FixIt/fixit-cxx0x.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,6 @@
 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 {{'[]' after delete interpreted as 'delete[]'}}
 }
+
Index: test/Parser/cxx0x-lambda-expressions.cpp
===
--- test/Parser/cxx0x-lambda-expressions.cpp
+++ test/Parser/cxx0x-lambda-expressions.cpp
@@ -53,8 +53,11 @@
   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 {{'[]' after delete interpreted as 'delete[]'}}
 delete [&] { return new int; } (); // ok, lambda
+
+delete []() { return new int; }(); // expected-error{{'[]' after delete interpreted as 'delete[]'}}
+delete [](E Enum) { return new int((int)Enum); }(e); // expected-error{{'[]' after delete interpreted as 'delete[]'}}
   }
 
   // We support init-captures in C++11 as an extension.
Index: test/FixIt/fixit-cxx0x.cpp
===
--- test/FixIt/fixit-cxx0x.cpp
+++ test/FixIt/fixit-cxx0x.cpp
@@ -58,6 +58,9 @@
   (void)[&, i, i]{ }; // expected-error{{'i' can appear only once in a capture list}}
   (void)[] mutable { }; // expected-error{{lambda requires '()' before 'mutable'}}
   (void)[] -> int { }; // expected-error{{lambda requires '()' before return type}}
+
+  delete []() { return new int; }(); // expected-error{{'[]' after delete interpreted as 'delete[]'}}
+  delete [] { return new int; }(); // expected-error{{'[]' after delete interpreted as 'delete[]'}}
 }
 
 #define bar "bar"
Index: lib/Parse/ParseExprCXX.cpp
===
--- lib/Parse/ParseExprCXX.cpp
+++ lib/Parse/ParseExprCXX.cpp
@@ -2976,8 +2976,38 @@
 //   [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.
+
+const Token Next = GetLookAheadToken(2);
+
+// Basic lookahead to check if we have a lambda expression.
+if (Next.isOneOf(tok::l_brace, tok::less) ||
+(Next.is(tok::l_paren) &&
+ (GetLookAheadToken(3).is(tok::r_paren) ||
+  (GetLookAheadToken(3).is(tok::identifier) &&
+   GetLookAheadToken(4).is(tok::identifier) {
+  SourceLocation RightBracketLock = NextToken().getLocation();
+  // Warn if the non-capturing lambda isn't surrounded by parenthesis
+  // to disambiguate it from 'delete[]'.
+  ExprResult Lambda = ParseLambdaExpression();
+  if (Lambda.isInvalid())
+return ExprError();
+
+  SourceLocation StartLoc = Lambda.get()->getBeginLoc();
+  Diag(Start, diag::err_lambda_after_delete)
+  << SourceRange(Start, RightBracketLock)
+  << FixItHint::CreateInsertion(StartLoc, "(")
+  << FixItHint::CreateInsertion(
+ Lexer::getLocForEndOfToken(Lambda.get()->getEndLoc(), 0,
+Actions.getSourceManager(),
+getLangOpts()),
+ ")");
+
+  // Evaluate any postfix expressions used on the lambda.
+  Lambda = ParsePostfixExpressionSuffix(Lambda);
+  return Actions.ActOnCXXDelete(Start, UseGlobal, /*ArrayForm=*/false,
+Lambda.get());
+}
+
 ArrayDelete = true;
 BalancedDelimiterTracker T(*this, tok::l_square);
 
Index: include/clang/Basic/DiagnosticParseKinds.td
===
--- include/clang/Basic/DiagnosticParseKinds.td
+++ include/clang/Basic/DiagnosticParseKinds.td
@@ -102,6 +102,8 @@
   InGroup, DefaultIgnore;
 def ext_alignof_expr : ExtWarn<
   "%0 applied to an expression is a GNU extension">, InGroup;
+def err_lambda_after_delete : Error<
+  "'[]' after delete interpreted as 'delete[]'">;
 
 def warn_microsoft_dependent_exists : Warning<
   "dependent %select{__if_not_exists|__if_exists}0 declarations are ign

[PATCH] D53595: [C++17] Reject shadowing of capture by parameter in lambda

2018-10-25 Thread Nicolas Lesser via Phabricator via cfe-commits
This revision was automatically updated to reflect the committed changes.
Closed by commit rC345308: [C++17] Reject shadowing of capture by parameter in 
lambda (authored by Rakete, committed by ).

Repository:
  rC Clang

https://reviews.llvm.org/D53595

Files:
  include/clang/Basic/DiagnosticSemaKinds.td
  include/clang/Sema/Sema.h
  lib/Sema/SemaLambda.cpp
  test/CXX/drs/dr22xx.cpp
  test/SemaCXX/warn-shadow-in-lambdas.cpp
  www/cxx_dr_status.html

Index: www/cxx_dr_status.html
===
--- www/cxx_dr_status.html
+++ www/cxx_dr_status.html
@@ -13081,7 +13081,7 @@
 http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_defects.html#2211";>2211
 C++17
 Hiding by lambda captures and parameters
-Unknown
+SVN
   
   
 http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_active.html#2212";>2212
Index: include/clang/Sema/Sema.h
===
--- include/clang/Sema/Sema.h
+++ include/clang/Sema/Sema.h
@@ -5580,7 +5580,9 @@
   void finishLambdaExplicitCaptures(sema::LambdaScopeInfo *LSI);
 
   /// Introduce the lambda parameters into scope.
-  void addLambdaParameters(CXXMethodDecl *CallOperator, Scope *CurScope);
+  void addLambdaParameters(
+  ArrayRef Captures,
+  CXXMethodDecl *CallOperator, Scope *CurScope);
 
   /// Deduce a block or lambda's return type based on the return
   /// statements present in the body.
Index: include/clang/Basic/DiagnosticSemaKinds.td
===
--- include/clang/Basic/DiagnosticSemaKinds.td
+++ include/clang/Basic/DiagnosticSemaKinds.td
@@ -6630,6 +6630,10 @@
   def ext_star_this_lambda_capture_cxx17 : ExtWarn<
 "capture of '*this' by copy is a C++17 extension">, InGroup;
 
+  // C++17 parameter shadows capture
+  def err_parameter_shadow_capture : Error<
+"a lambda parameter cannot shadow an explicitly captured entity">;
+
   // C++2a [=, this] captures.
   def warn_cxx17_compat_equals_this_lambda_capture : Warning<
 "explicit capture of 'this' with a capture default of '=' is incompatible "
Index: test/SemaCXX/warn-shadow-in-lambdas.cpp
===
--- test/SemaCXX/warn-shadow-in-lambdas.cpp
+++ test/SemaCXX/warn-shadow-in-lambdas.cpp
@@ -1,6 +1,7 @@
 // RUN: %clang_cc1 -std=c++14 -verify -fsyntax-only -Wshadow -D AVOID %s
 // RUN: %clang_cc1 -std=c++14 -verify -fsyntax-only -Wshadow -Wshadow-uncaptured-local %s
 // RUN: %clang_cc1 -std=c++14 -verify -fsyntax-only -Wshadow-all %s
+// RUN: %clang_cc1 -std=c++17 -verify -fsyntax-only -Wshadow-all %s
 
 void foo(int param) { // expected-note 1+ {{previous declaration is here}}
   int var = 0; // expected-note 1+ {{previous declaration is here}}
@@ -79,7 +80,7 @@
   int var = 1; // expected-warning {{declaration shadows a local variable}}
 };
 auto f2 = [param]   // expected-note {{variable 'param' is explicitly captured here}}
- (int param) { ; }; // expected-warning {{declaration shadows a local variable}}
+ (int param) { ; }; // expected-error {{a lambda parameter cannot shadow an explicitly captured entity}}
   }
 
   // Warn for variables defined in the capture list.
@@ -135,7 +136,7 @@
   auto g2 = [=](auto param) { ; }; // expected-warning {{declaration shadows a local variable}}
 #endif
   auto g3 = [param] // expected-note {{variable 'param' is explicitly captured here}}
-   (auto param) { ; }; // expected-warning {{declaration shadows a local variable}}
+   (auto param) { ; }; // expected-error {{a lambda parameter cannot shadow an explicitly captured entity}}
 }
 
 void avoidWarningWhenRedefining() {
Index: test/CXX/drs/dr22xx.cpp
===
--- test/CXX/drs/dr22xx.cpp
+++ test/CXX/drs/dr22xx.cpp
@@ -15,3 +15,14 @@
   const volatile unsigned i3 : 1;
 };
 }
+
+#if __cplusplus >= 201103L
+namespace dr2211 { // dr2211: 8
+void f() {
+  int a;
+  auto f = [a](int a) { (void)a; }; // expected-error {{a lambda parameter cannot shadow an explicitly captured entity}}
+  // expected-note@-1{{variable 'a' is explicitly captured here}}
+  auto g = [=](int a) { (void)a; };
+}
+}
+#endif
Index: lib/Sema/SemaLambda.cpp
===
--- lib/Sema/SemaLambda.cpp
+++ lib/Sema/SemaLambda.cpp
@@ -493,15 +493,29 @@
   LSI->finishedExplicitCaptures();
 }
 
-void Sema::addLambdaParameters(CXXMethodDecl *CallOperator, Scope *CurScope) {
+void Sema::addLambdaParameters(
+ArrayRef Captures,
+CXXMethodDecl *CallOperator, Scope *CurScope) {
   // Introduce our parameters into the function scope
   for (unsigned p = 0, NumParams = CallOperator->getNumParams();
p < NumParams; ++p) {
 ParmVarDecl *Param = CallOperator->getParamDecl(p);
 
 // If this has an identifier, add it to the scope stack.
 if (CurScope && Param->getIdentifier()) {

[PATCH] D53595: [C++17] Reject shadowing of capture by parameter in lambda

2018-10-25 Thread Nicolas Lesser via Phabricator via cfe-commits
Rakete updated this revision to Diff 171174.
Rakete added a comment.

Update DR list.


https://reviews.llvm.org/D53595

Files:
  include/clang/Basic/DiagnosticSemaKinds.td
  include/clang/Sema/Sema.h
  lib/Sema/SemaLambda.cpp
  test/CXX/drs/dr22xx.cpp
  test/SemaCXX/warn-shadow-in-lambdas.cpp
  www/cxx_dr_status.html

Index: www/cxx_dr_status.html
===
--- www/cxx_dr_status.html
+++ www/cxx_dr_status.html
@@ -13081,7 +13081,7 @@
 http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_defects.html#2211";>2211
 C++17
 Hiding by lambda captures and parameters
-Unknown
+SVN
   
   
 http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_active.html#2212";>2212
Index: test/SemaCXX/warn-shadow-in-lambdas.cpp
===
--- test/SemaCXX/warn-shadow-in-lambdas.cpp
+++ test/SemaCXX/warn-shadow-in-lambdas.cpp
@@ -1,6 +1,7 @@
 // RUN: %clang_cc1 -std=c++14 -verify -fsyntax-only -Wshadow -D AVOID %s
 // RUN: %clang_cc1 -std=c++14 -verify -fsyntax-only -Wshadow -Wshadow-uncaptured-local %s
 // RUN: %clang_cc1 -std=c++14 -verify -fsyntax-only -Wshadow-all %s
+// RUN: %clang_cc1 -std=c++17 -verify -fsyntax-only -Wshadow-all %s
 
 void foo(int param) { // expected-note 1+ {{previous declaration is here}}
   int var = 0; // expected-note 1+ {{previous declaration is here}}
@@ -79,7 +80,7 @@
   int var = 1; // expected-warning {{declaration shadows a local variable}}
 };
 auto f2 = [param]   // expected-note {{variable 'param' is explicitly captured here}}
- (int param) { ; }; // expected-warning {{declaration shadows a local variable}}
+ (int param) { ; }; // expected-error {{a lambda parameter cannot shadow an explicitly captured entity}}
   }
 
   // Warn for variables defined in the capture list.
@@ -135,7 +136,7 @@
   auto g2 = [=](auto param) { ; }; // expected-warning {{declaration shadows a local variable}}
 #endif
   auto g3 = [param] // expected-note {{variable 'param' is explicitly captured here}}
-   (auto param) { ; }; // expected-warning {{declaration shadows a local variable}}
+   (auto param) { ; }; // expected-error {{a lambda parameter cannot shadow an explicitly captured entity}}
 }
 
 void avoidWarningWhenRedefining() {
Index: test/CXX/drs/dr22xx.cpp
===
--- test/CXX/drs/dr22xx.cpp
+++ test/CXX/drs/dr22xx.cpp
@@ -15,3 +15,14 @@
   const volatile unsigned i3 : 1;
 };
 }
+
+#if __cplusplus >= 201103L
+namespace dr2211 { // dr2211: 8
+void f() {
+  int a;
+  auto f = [a](int a) { (void)a; }; // expected-error {{a lambda parameter cannot shadow an explicitly captured entity}}
+  // expected-note@-1{{variable 'a' is explicitly captured here}}
+  auto g = [=](int a) { (void)a; };
+}
+}
+#endif
Index: lib/Sema/SemaLambda.cpp
===
--- lib/Sema/SemaLambda.cpp
+++ lib/Sema/SemaLambda.cpp
@@ -493,7 +493,9 @@
   LSI->finishedExplicitCaptures();
 }
 
-void Sema::addLambdaParameters(CXXMethodDecl *CallOperator, Scope *CurScope) {
+void Sema::addLambdaParameters(
+ArrayRef Captures,
+CXXMethodDecl *CallOperator, Scope *CurScope) {
   // Introduce our parameters into the function scope
   for (unsigned p = 0, NumParams = CallOperator->getNumParams();
p < NumParams; ++p) {
@@ -501,7 +503,19 @@
 
 // If this has an identifier, add it to the scope stack.
 if (CurScope && Param->getIdentifier()) {
-  CheckShadow(CurScope, Param);
+  bool Error = false;
+  // Resolution of CWG 2211 in C++17 renders shadowing ill-formed, but we
+  // retroactively apply it.
+  for (const auto &Capture : Captures) {
+if (Capture.Id == Param->getIdentifier()) {
+  Error = true;
+  Diag(Param->getLocation(), diag::err_parameter_shadow_capture);
+  Diag(Capture.Loc, diag::note_var_explicitly_captured_here)
+  << Capture.Id << true;
+}
+  }
+  if (!Error)
+CheckShadow(CurScope, Param);
 
   PushOnScopeChains(Param, CurScope);
 }
@@ -1142,7 +1156,7 @@
   LSI->ContainsUnexpandedParameterPack = ContainsUnexpandedParameterPack;
 
   // Add lambda parameters into scope.
-  addLambdaParameters(Method, CurScope);
+  addLambdaParameters(Intro.Captures, Method, CurScope);
 
   // Enter a new evaluation context to insulate the lambda from any
   // cleanups from the enclosing full-expression.
Index: include/clang/Sema/Sema.h
===
--- include/clang/Sema/Sema.h
+++ include/clang/Sema/Sema.h
@@ -5580,7 +5580,9 @@
   void finishLambdaExplicitCaptures(sema::LambdaScopeInfo *LSI);
 
   /// Introduce the lambda parameters into scope.
-  void addLambdaParameters(CXXMethodDecl *CallOperator, Scope *CurScope);
+  void addLambdaParameters(
+  ArrayRef Captures,
+  CXXMethodDecl *CallOperator, Scope *

[PATCH] D53595: [C++17] Reject shadowing of capture by parameter in lambda

2018-10-25 Thread Nicolas Lesser via Phabricator via cfe-commits
Rakete added a comment.

In https://reviews.llvm.org/D53595#1276330, @rsmith wrote:

> In https://reviews.llvm.org/D53595#1273848, @Rakete wrote:
>
> > Addresed review comments :)
> >
> > I updated the dr status file but a lot of unrelated changes made it in. Is 
> > this okay?
>
>
> Please regenerate the file without your change and check that in as a 
> separate commit prior to this.


Why not afterwards? That way the DR is marked as resolved immediately.


Repository:
  rC Clang

https://reviews.llvm.org/D53595



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


[PATCH] D53595: [C++17] Reject shadowing of capture by parameter in lambda

2018-10-24 Thread Nicolas Lesser via Phabricator via cfe-commits
Rakete updated this revision to Diff 170828.
Rakete added a comment.

Addresed review comments :)

I updated the dr status file but a lot of unrelated changes made it in. Is this 
okay?


Repository:
  rC Clang

https://reviews.llvm.org/D53595

Files:
  include/clang/Basic/DiagnosticSemaKinds.td
  include/clang/Sema/Sema.h
  lib/Sema/SemaLambda.cpp
  test/CXX/drs/dr22xx.cpp
  test/SemaCXX/warn-shadow-in-lambdas.cpp
  www/cxx_dr_status.html

Index: www/cxx_dr_status.html
===
--- www/cxx_dr_status.html
+++ www/cxx_dr_status.html
@@ -7437,11 +7437,11 @@
 Brace elision in array temporary initialization
 Unknown
   
-  
-http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_active.html#1271";>1271
-drafting
+  
+http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_defects.html#1271";>1271
+DR
 Imprecise wording regarding dependent types
-Not resolved
+Unknown
   
   
 http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_closed.html#1272";>1272
@@ -11147,7 +11147,7 @@
   
   
 http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_active.html#1889";>1889
-open
+drafting
 Unclear effect of #pragma on conformance
 Not resolved
   
@@ -11170,8 +11170,8 @@
 Unknown
   
   
-http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_active.html#1893";>1893
-tentatively ready
+http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_defects.html#1893";>1893
+DR
 Function-style cast with braced-init-lists and empty pack expansions
 Unknown
   
@@ -11247,11 +11247,11 @@
 Dependent types and injected-class-names
 Unknown
   
-  
-http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_active.html#1906";>1906
-review
+  
+http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_closed.html#1906";>1906
+NAD
 Name lookup in member friend declaration
-Not resolved
+Unknown
   
   
 http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_active.html#1907";>1907
@@ -11272,8 +11272,8 @@
 Yes
   
   
-http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_active.html#1910";>1910
-tentatively ready
+http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_defects.html#1910";>1910
+DR
 “Shall” requirement applied to runtime behavior
 Unknown
   
@@ -11710,8 +11710,8 @@
 Unknown
   
   
-http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_active.html#1983";>1983
-tentatively ready
+http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_defects.html#1983";>1983
+DR
 Inappropriate use of virt-specifier
 Unknown
   
@@ -12166,8 +12166,8 @@
 Not resolved
   
   
-http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_active.html#2059";>2059
-tentatively ready
+http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_defects.html#2059";>2059
+DR
 Linkage and deduced return types
 Unknown
   
@@ -12298,8 +12298,8 @@
 Not resolved
   
   
-http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_active.html#2081";>2081
-tentatively ready
+http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_defects.html#2081";>2081
+DR
 Deduced return type in redeclaration or specialization of function template
 Unknown
   
@@ -12340,8 +12340,8 @@
 Not resolved
   
   
-http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_active.html#2088";>2088
-tentatively ready
+http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_defects.html#2088";>2088
+DR
 Late tiebreakers in partial ordering
 Unknown
   
@@ -12364,8 +12364,8 @@
 Unknown
   
   
-http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_active.html#2092";>2092
-tentatively ready
+http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_defects.html#2092";>2092
+DR
 Deduction failure and overload resolution
 Unknown
   
@@ -12796,8 +12796,8 @@
 Unknown
   
   
-http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_active.html#2164";>2164
-tentatively ready
+http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_defects.html#2164";>2164
+DR
 Name hiding and using-directives
 Unknown
   
@@ -12935,7 +12935,7 @@
   
   
 http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_active.html#2187";>2187
-open
+drafting
 Protected members and access via qualified-id
 Not resolved
   
@@ -13025,7 +13025,7 @@
   
   
 http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_active.html#2202";>2202
-open
+drafting
 When does default argument instantiation occur?
 Not resolved
   
@@ -13081,7 +13081,7 @@
 http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_defects.html#2211";>2211
 C++17
 Hiding by lambda captures and parameters
-Unknown
+SVN
   
   
 http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_active.html#2212";>2212
@@ -13127,7 +13127,7 @@
   
   
 http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_active.html#2219";>2219
-open
+drafting
 Dynamically-unreachable handlers
 Not resolved
   
@@ -13168,14 +13168,14 @@
 Un

[PATCH] D53595: [C++17] Reject shadowing of capture by parameter in lambda

2018-10-23 Thread Nicolas Lesser via Phabricator via cfe-commits
Rakete updated this revision to Diff 170757.
Rakete added a comment.

Use correct clang and version spelling.


Repository:
  rC Clang

https://reviews.llvm.org/D53595

Files:
  include/clang/Basic/DiagnosticSemaKinds.td
  include/clang/Sema/Sema.h
  lib/Sema/SemaLambda.cpp
  test/SemaCXX/warn-shadow-in-lambdas.cpp
  www/cxx_dr_status.html

Index: www/cxx_dr_status.html
===
--- www/cxx_dr_status.html
+++ www/cxx_dr_status.html
@@ -13081,7 +13081,7 @@
 http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_defects.html#2211";>2211
 C++17
 Hiding by lambda captures and parameters
-Unknown
+Clang 8
   
   
 http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_active.html#2212";>2212
Index: test/SemaCXX/warn-shadow-in-lambdas.cpp
===
--- test/SemaCXX/warn-shadow-in-lambdas.cpp
+++ test/SemaCXX/warn-shadow-in-lambdas.cpp
@@ -1,6 +1,7 @@
 // RUN: %clang_cc1 -std=c++14 -verify -fsyntax-only -Wshadow -D AVOID %s
 // RUN: %clang_cc1 -std=c++14 -verify -fsyntax-only -Wshadow -Wshadow-uncaptured-local %s
 // RUN: %clang_cc1 -std=c++14 -verify -fsyntax-only -Wshadow-all %s
+// RUN: %clang_cc1 -std=c++17 -verify -fsyntax-only -Wshadow-all %s
 
 void foo(int param) { // expected-note 1+ {{previous declaration is here}}
   int var = 0; // expected-note 1+ {{previous declaration is here}}
@@ -78,8 +79,15 @@
 auto f1 = [var] () { // expected-note {{variable 'var' is explicitly captured here}}
   int var = 1; // expected-warning {{declaration shadows a local variable}}
 };
-auto f2 = [param]   // expected-note {{variable 'param' is explicitly captured here}}
- (int param) { ; }; // expected-warning {{declaration shadows a local variable}}
+auto f2 = [param] 
+ (int param) { ; };
+#if __cplusplus < 201703L
+// expected-note@-3{{variable 'param' is explicitly captured here}}
+// expected-warning@-3{{a lambda parameter that shadows a capture is incompatible with C++ standards before C++17}}
+#else
+// expected-error@-5{{a lambda parameter cannot shadow an explicitly captured entity}}
+// expected-note@-7{{variable 'param' is explicitly captured here}}
+#endif
   }
 
   // Warn for variables defined in the capture list.
@@ -134,8 +142,16 @@
   auto g1 = [](auto param) { ; }; // expected-warning {{declaration shadows a local variable}}
   auto g2 = [=](auto param) { ; }; // expected-warning {{declaration shadows a local variable}}
 #endif
-  auto g3 = [param] // expected-note {{variable 'param' is explicitly captured here}}
-   (auto param) { ; }; // expected-warning {{declaration shadows a local variable}}
+  auto g3 = [param]
+   (auto param) { ; };
+#if __cplusplus < 201703L
+// expected-note@-3{{variable 'param' is explicitly captured here}}
+// expected-warning@-3{{a lambda parameter that shadows a capture is incompatible with C++ standards before C++17}}
+#else
+// expected-error@-5{{a lambda parameter cannot shadow an explicitly captured entity}}
+// expected-note@-7{{variable 'param' is explicitly captured here}}
+#endif
+
 }
 
 void avoidWarningWhenRedefining() {
@@ -145,3 +161,20 @@
 int b = 0; // expected-error {{redefinition of 'b'}}
   };
 }
+
+void parameterShadowCapture() {
+#if __cplusplus >= 201703L
+  int var = 1; // expected-note{{previous declaration is here}}
+  auto f1 = [var](int var) { return var; }; // expected-error{{a lambda parameter cannot shadow an explicitly captured entity}}
+  // expected-note@-1{{variable 'var' is explicitly captured here}}
+
+  auto f2 = [var = 1](int var) { return var; }; // expected-error{{a lambda parameter cannot shadow an explicitly captured entity}}
+  // expected-note@-1{{variable 'var' is explicitly captured here}}
+  // expected-error@-2{{reference to 'var' is ambiguous}}
+  // expected-note@-3{{candidate found by name lookup is 'var'}}
+  // expected-note@-4{{candidate found by name lookup is 'var'}}
+
+  auto f3 = [=](int var) { return var; };
+  // expected-warning@-1{{declaration shadows a local variable}}
+#endif
+}
Index: lib/Sema/SemaLambda.cpp
===
--- lib/Sema/SemaLambda.cpp
+++ lib/Sema/SemaLambda.cpp
@@ -493,15 +493,32 @@
   LSI->finishedExplicitCaptures();
 }
 
-void Sema::addLambdaParameters(CXXMethodDecl *CallOperator, Scope *CurScope) {
+void Sema::addLambdaParameters(
+const SmallVectorImpl &Captures,
+CXXMethodDecl *CallOperator, Scope *CurScope) {
   // Introduce our parameters into the function scope
   for (unsigned p = 0, NumParams = CallOperator->getNumParams();
p < NumParams; ++p) {
 ParmVarDecl *Param = CallOperator->getParamDecl(p);
 
 // If this has an identifier, add it to the scope stack.
 if (CurScope && Param->getIdentifier()) {
-  CheckShadow(CurScope, Param);
+  bool Error = false;
+  // Resolution of CWG 2211 in C++17 renders s

[PATCH] D53595: [C++17] Reject shadowing of capture by parameter in lambda

2018-10-23 Thread Nicolas Lesser via Phabricator via cfe-commits
Rakete updated this revision to Diff 170748.
Rakete added a comment.

Addressed review comments! :) Thanks


Repository:
  rC Clang

https://reviews.llvm.org/D53595

Files:
  include/clang/Basic/DiagnosticSemaKinds.td
  include/clang/Sema/Sema.h
  lib/Sema/SemaLambda.cpp
  test/SemaCXX/warn-shadow-in-lambdas.cpp
  www/cxx_dr_status.html

Index: www/cxx_dr_status.html
===
--- www/cxx_dr_status.html
+++ www/cxx_dr_status.html
@@ -13081,7 +13081,7 @@
 http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_defects.html#2211";>2211
 C++17
 Hiding by lambda captures and parameters
-Unknown
+clang 8.0
   
   
 http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_active.html#2212";>2212
Index: test/SemaCXX/warn-shadow-in-lambdas.cpp
===
--- test/SemaCXX/warn-shadow-in-lambdas.cpp
+++ test/SemaCXX/warn-shadow-in-lambdas.cpp
@@ -1,6 +1,7 @@
 // RUN: %clang_cc1 -std=c++14 -verify -fsyntax-only -Wshadow -D AVOID %s
 // RUN: %clang_cc1 -std=c++14 -verify -fsyntax-only -Wshadow -Wshadow-uncaptured-local %s
 // RUN: %clang_cc1 -std=c++14 -verify -fsyntax-only -Wshadow-all %s
+// RUN: %clang_cc1 -std=c++17 -verify -fsyntax-only -Wshadow-all %s
 
 void foo(int param) { // expected-note 1+ {{previous declaration is here}}
   int var = 0; // expected-note 1+ {{previous declaration is here}}
@@ -78,8 +79,15 @@
 auto f1 = [var] () { // expected-note {{variable 'var' is explicitly captured here}}
   int var = 1; // expected-warning {{declaration shadows a local variable}}
 };
-auto f2 = [param]   // expected-note {{variable 'param' is explicitly captured here}}
- (int param) { ; }; // expected-warning {{declaration shadows a local variable}}
+auto f2 = [param] 
+ (int param) { ; };
+#if __cplusplus < 201703L
+// expected-note@-3{{variable 'param' is explicitly captured here}}
+// expected-warning@-3{{a lambda parameter that shadows a capture is incompatible with C++ standards before C++17}}
+#else
+// expected-error@-5{{a lambda parameter cannot shadow an explicitly captured entity}}
+// expected-note@-7{{variable 'param' is explicitly captured here}}
+#endif
   }
 
   // Warn for variables defined in the capture list.
@@ -134,8 +142,16 @@
   auto g1 = [](auto param) { ; }; // expected-warning {{declaration shadows a local variable}}
   auto g2 = [=](auto param) { ; }; // expected-warning {{declaration shadows a local variable}}
 #endif
-  auto g3 = [param] // expected-note {{variable 'param' is explicitly captured here}}
-   (auto param) { ; }; // expected-warning {{declaration shadows a local variable}}
+  auto g3 = [param]
+   (auto param) { ; };
+#if __cplusplus < 201703L
+// expected-note@-3{{variable 'param' is explicitly captured here}}
+// expected-warning@-3{{a lambda parameter that shadows a capture is incompatible with C++ standards before C++17}}
+#else
+// expected-error@-5{{a lambda parameter cannot shadow an explicitly captured entity}}
+// expected-note@-7{{variable 'param' is explicitly captured here}}
+#endif
+
 }
 
 void avoidWarningWhenRedefining() {
@@ -145,3 +161,20 @@
 int b = 0; // expected-error {{redefinition of 'b'}}
   };
 }
+
+void parameterShadowCapture() {
+#if __cplusplus >= 201703L
+  int var = 1; // expected-note{{previous declaration is here}}
+  auto f1 = [var](int var) { return var; }; // expected-error{{a lambda parameter cannot shadow an explicitly captured entity}}
+  // expected-note@-1{{variable 'var' is explicitly captured here}}
+
+  auto f2 = [var = 1](int var) { return var; }; // expected-error{{a lambda parameter cannot shadow an explicitly captured entity}}
+  // expected-note@-1{{variable 'var' is explicitly captured here}}
+  // expected-error@-2{{reference to 'var' is ambiguous}}
+  // expected-note@-3{{candidate found by name lookup is 'var'}}
+  // expected-note@-4{{candidate found by name lookup is 'var'}}
+
+  auto f3 = [=](int var) { return var; };
+  // expected-warning@-1{{declaration shadows a local variable}}
+#endif
+}
Index: lib/Sema/SemaLambda.cpp
===
--- lib/Sema/SemaLambda.cpp
+++ lib/Sema/SemaLambda.cpp
@@ -493,15 +493,32 @@
   LSI->finishedExplicitCaptures();
 }
 
-void Sema::addLambdaParameters(CXXMethodDecl *CallOperator, Scope *CurScope) {
+void Sema::addLambdaParameters(
+const SmallVectorImpl &Captures,
+CXXMethodDecl *CallOperator, Scope *CurScope) {
   // Introduce our parameters into the function scope
   for (unsigned p = 0, NumParams = CallOperator->getNumParams();
p < NumParams; ++p) {
 ParmVarDecl *Param = CallOperator->getParamDecl(p);
 
 // If this has an identifier, add it to the scope stack.
 if (CurScope && Param->getIdentifier()) {
-  CheckShadow(CurScope, Param);
+  bool Error = false;
+  // Resolution of CWG 2211 in C++17 renders sh

[PATCH] D53595: [C++17] Reject shadowing of capture by parameter in lambda

2018-10-23 Thread Nicolas Lesser via Phabricator via cfe-commits
Rakete added inline comments.



Comment at: lib/Sema/SemaLambda.cpp:510
+for (const auto &Capture: Captures) {
+  if (Capture.Id && Capture.Id->getName() == Param->getName()) {
+Error = true;

erik.pilkington wrote:
> You should compare `IdentifierInfo`s here, rather than `StringRef`s.
`IdentifierInfo` doesn't have a compare equal or `operator==` function. How do 
you propose I do that? Do I add one?


Repository:
  rC Clang

https://reviews.llvm.org/D53595



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


[PATCH] D53595: [C++17] Reject shadowing of capture by parameter in lambda

2018-10-23 Thread Nicolas Lesser via Phabricator via cfe-commits
Rakete created this revision.
Rakete added a reviewer: rsmith.

This change rejects the shadowing of a capture by a parameter in lambdas in 
C++17.

  int main() {
int a;
auto f = [a](int a) { return a; };
  }

results in:

  main.cpp:3:20: error: a lambda parameter cannot shadow an explicitly captured 
entity
auto f = [a](int a) { return a; };
 ^
  main.cpp:3:13: note: variable a is explicitly captured here
auto f = [a](int a) { return a; };
  ^


Repository:
  rC Clang

https://reviews.llvm.org/D53595

Files:
  include/clang/Basic/DiagnosticSemaKinds.td
  include/clang/Sema/Sema.h
  lib/Sema/SemaLambda.cpp
  test/SemaCXX/warn-shadow-in-lambdas.cpp

Index: test/SemaCXX/warn-shadow-in-lambdas.cpp
===
--- test/SemaCXX/warn-shadow-in-lambdas.cpp
+++ test/SemaCXX/warn-shadow-in-lambdas.cpp
@@ -1,6 +1,7 @@
 // RUN: %clang_cc1 -std=c++14 -verify -fsyntax-only -Wshadow -D AVOID %s
 // RUN: %clang_cc1 -std=c++14 -verify -fsyntax-only -Wshadow -Wshadow-uncaptured-local %s
 // RUN: %clang_cc1 -std=c++14 -verify -fsyntax-only -Wshadow-all %s
+// RUN: %clang_cc1 -std=c++17 -verify -fsyntax-only -Wshadow-all %s
 
 void foo(int param) { // expected-note 1+ {{previous declaration is here}}
   int var = 0; // expected-note 1+ {{previous declaration is here}}
@@ -78,8 +79,15 @@
 auto f1 = [var] () { // expected-note {{variable 'var' is explicitly captured here}}
   int var = 1; // expected-warning {{declaration shadows a local variable}}
 };
-auto f2 = [param]   // expected-note {{variable 'param' is explicitly captured here}}
- (int param) { ; }; // expected-warning {{declaration shadows a local variable}}
+auto f2 = [param] 
+ (int param) { ; };
+#if __cplusplus < 201703L
+// expected-note@-3{{variable 'param' is explicitly captured here}}
+// expected-warning@-3{{declaration shadows a local variable}}
+#else
+// expected-error@-5{{a lambda parameter cannot shadow an explicitly captured entity}}
+// expected-note@-7{{variable param is explicitly captured here}}
+#endif
   }
 
   // Warn for variables defined in the capture list.
@@ -134,8 +142,16 @@
   auto g1 = [](auto param) { ; }; // expected-warning {{declaration shadows a local variable}}
   auto g2 = [=](auto param) { ; }; // expected-warning {{declaration shadows a local variable}}
 #endif
-  auto g3 = [param] // expected-note {{variable 'param' is explicitly captured here}}
-   (auto param) { ; }; // expected-warning {{declaration shadows a local variable}}
+  auto g3 = [param]
+   (auto param) { ; };
+#if __cplusplus < 201703L
+// expected-note@-3{{variable 'param' is explicitly captured here}}
+// expected-warning@-3{{declaration shadows a local variable}}
+#else
+// expected-error@-5{{a lambda parameter cannot shadow an explicitly captured entity}}
+// expected-note@-7{{variable param is explicitly captured here}}
+#endif
+
 }
 
 void avoidWarningWhenRedefining() {
@@ -145,3 +161,20 @@
 int b = 0; // expected-error {{redefinition of 'b'}}
   };
 }
+
+void parameterShadowCapture() {
+#if __cplusplus >= 201703L
+  int var = 1; // expected-note{{previous declaration is here}}
+  auto f1 = [var](int var) { return var; }; // expected-error{{a lambda parameter cannot shadow an explicitly captured entity}}
+  // expected-note@-1{{variable var is explicitly captured here}}
+
+  auto f2 = [var = 1](int var) { return var; }; // expected-error{{a lambda parameter cannot shadow an explicitly captured entity}}
+  // expected-note@-1{{variable var is explicitly captured here}}
+  // expected-error@-2{{reference to 'var' is ambiguous}}
+  // expected-note@-3{{candidate found by name lookup is 'var'}}
+  // expected-note@-4{{candidate found by name lookup is 'var'}}
+
+  auto f3 = [=](int var) { return var; };
+  // expected-warning@-1{{declaration shadows a local variable}}
+#endif
+}
Index: lib/Sema/SemaLambda.cpp
===
--- lib/Sema/SemaLambda.cpp
+++ lib/Sema/SemaLambda.cpp
@@ -493,15 +493,30 @@
   LSI->finishedExplicitCaptures();
 }
 
-void Sema::addLambdaParameters(CXXMethodDecl *CallOperator, Scope *CurScope) {
+void Sema::addLambdaParameters(
+const SmallVectorImpl &Captures,
+CXXMethodDecl *CallOperator, Scope *CurScope) {
   // Introduce our parameters into the function scope
   for (unsigned p = 0, NumParams = CallOperator->getNumParams();
p < NumParams; ++p) {
 ParmVarDecl *Param = CallOperator->getParamDecl(p);
 
 // If this has an identifier, add it to the scope stack.
 if (CurScope && Param->getIdentifier()) {
-  CheckShadow(CurScope, Param);
+  bool Error = false;
+  if (getLangOpts().CPlusPlus17) {
+// Resolution of CWG 2211 in C++17 renders shadowing ill-formed.
+for (const auto &Capture: Captures) {
+  if (Capture.Id && Capture.Id->getName() == Param->g

[PATCH] D52750: [Diagnostics] Check for integer overflow in array size expressions

2018-10-12 Thread Nicolas Lesser via Phabricator via cfe-commits
Rakete added a comment.

In https://reviews.llvm.org/D52750#1263466, @xbolva00 wrote:

> In https://reviews.llvm.org/D52750#1263461, @Rakete wrote:
>
> > This doesn't produce a warning in C++11 and up.
>
>
> But see Richard's comment: https://reviews.llvm.org/D52750#125175 so I am not 
> sure :/


I guess I can see why it makes sense to suppress the warning in those cases. 
Sorry.


https://reviews.llvm.org/D52750



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


[PATCH] D52750: [Diagnostics] Check for integer overflow in array size expressions

2018-10-12 Thread Nicolas Lesser via Phabricator via cfe-commits
Rakete added a comment.

This doesn't produce a warning in C++11 and up.


https://reviews.llvm.org/D52750



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


[PATCH] D52750: [Diagnostics] Check for integer overflow in array size expressions

2018-10-11 Thread Nicolas Lesser via Phabricator via cfe-commits
Rakete added a comment.

Nah, you don't even need to call `EvaluateForOverflow` I believe. :) Have a 
look overflow evaluation is done.


https://reviews.llvm.org/D52750



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


[PATCH] D52750: [Diagnostics] Check for integer overflow in array size expressions

2018-10-11 Thread Nicolas Lesser via Phabricator via cfe-commits
Rakete added a comment.

The array size is still evaluated twice. Try to incorporate the check in 
`Sema::VerifyIntegerConstantExpression`.


https://reviews.llvm.org/D52750



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


[PATCH] D50766: Fix false positive unsequenced access and modification warning in array subscript expression.

2018-10-11 Thread Nicolas Lesser via Phabricator via cfe-commits
Rakete added inline comments.



Comment at: test/SemaCXX/warn-unsequenced-cxx17.cpp:1
+// RUN: %clang_cc1 -fsyntax-only -verify -std=c++17 -Wno-unused %s
+

lebedev.ri wrote:
> One last-minute thought: this is only a positive test.
> You don't test what happens before C++17.
It is tested. Look at the diff for test/SemaCXX/warn-unsequenced.cpp :)
Or are you suggesting to merge the two files?


https://reviews.llvm.org/D50766



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


[PATCH] D50766: Fix false positive unsequenced access and modification warning in array subscript expression.

2018-10-10 Thread Nicolas Lesser via Phabricator via cfe-commits
Rakete accepted this revision.
Rakete added a comment.
This revision is now accepted and ready to land.

Nevermind my last comment, I was tired. LGTM


https://reviews.llvm.org/D50766



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


[PATCH] D50766: Fix false positive unsequenced access and modification warning in array subscript expression.

2018-10-10 Thread Nicolas Lesser via Phabricator via cfe-commits
Rakete added a comment.

Sorry, for some reason I didn't see your updates.

Can you add a test for C++17? Then your patch is good to go! :)


https://reviews.llvm.org/D50766



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


[PATCH] D52750: [Diagnostics] Check for integer overflow in array size expressions

2018-10-06 Thread Nicolas Lesser via Phabricator via cfe-commits
Rakete added inline comments.



Comment at: lib/Sema/SemaType.cpp:2232
+
+  if (isa(ArraySize))
+ArraySize->EvaluateForOverflow(Context);

What's up with this statement? Why is it needed? This won't handle overflows 
for unary expression for example.


https://reviews.llvm.org/D52750



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


[PATCH] D52791: [Diagnostics] Check for misleading pointer declarations

2018-10-03 Thread Nicolas Lesser via Phabricator via cfe-commits
Rakete added a comment.

There's a false positive.

  int **A, *B; // false positive: declaring a variable of type 'int *'; did you 
mean to declare a pointer?

And IMO this should also warn:

  int **A, B; // no warning currently


https://reviews.llvm.org/D52791



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


[PATCH] D50766: Fix false positive unsequenced access and modification warning in array subscript expression.

2018-08-26 Thread Nicolas Lesser via Phabricator via cfe-commits
Rakete added a comment.

> What do you think?

Good idea!




Comment at: test/SemaCXX/warn-unsequenced-cxx17.cpp:7
+  // expected-no-diagnostics
+  p[(long long unsigned)(p = 0)] // ok
+}

Oh no, you forgot a semicolon there! :)


https://reviews.llvm.org/D50766



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


[PATCH] D41284: [Concepts] Associated constraints infrastructure.

2018-08-18 Thread Nicolas Lesser via Phabricator via cfe-commits
Rakete added inline comments.



Comment at: 
test/CXX/concepts-ts/temp/temp.constr/temp.constr.decl/var-template-decl.cpp:10
+
+template  requires bool(U())
+int B::A = int(U());

Quuxplusone wrote:
> saar.raz wrote:
> > Quuxplusone wrote:
> > > For my own edification, could you explain whether, given
> > > 
> > > #define BOOL bool
> > > using typedef_for_bool = bool;
> > > 
> > > you'd expect to diagnose a redeclaration of `B::A` with associated 
> > > constraint
> > > 
> > > requires bool( U() )  // extra whitespace
> > > 
> > > or
> > > 
> > > requires BOOL(U())  // different spelling of `bool`
> > > 
> > > or
> > > 
> > > requires typedef_for_bool(U())  // different spelling of `bool`
> > > 
> > > ? My naive reading of N4762 temp.constr.atomic/2 says that none of these 
> > > constraints (on line 10) would be "identical" to the constraint on line 
> > > 6... but then I don't understand what's the salient difference between 
> > > line 10 (which apparently gives no error) and line 22 (which apparently 
> > > gives an error).
> > Line 22 has a not (!) operator in front of the bool(), I guess you missed 
> > that? 
> I saw the `!`... but I don't understand how the compiler "knows" that 
> `!bool(U())` is "different" from `bool(T())` in a way that doesn't equally 
> apply to `bool(U())`.
> 
> Or suppose the constraint on line 10 was `requires bool(U())==true`... would 
> that give a diagnostic?
`bool(T())` and `bool(U())` are identical because they have the same parameter 
mappings.

The "identical" requirement applies to the actual grammar composition of the 
expression, so `bool(T())` would be different to `bool(T()) == true`.

At least that's how I understand it.


Repository:
  rC Clang

https://reviews.llvm.org/D41284



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


[PATCH] D50766: Fix false positive unsequenced access and modification warning in array subscript expression.

2018-08-16 Thread Nicolas Lesser via Phabricator via cfe-commits
Rakete requested changes to this revision.
Rakete added a comment.
This revision now requires changes to proceed.

Your patch breaks a lot of stuff in the test suite. For example:

  void f() {
int A = 0;
(A++, A) = 1; // warning from this patch, but this is perfectly valid since 
forever.
  }

Also, you don't take into account the fact that the rule you mention was added 
in C++17. In versions prior to that (and C!), the warning is not a false 
positive.


https://reviews.llvm.org/D50766



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


[PATCH] D50119: Compiler support for P1144R0 "__is_trivially_relocatable(T)"

2018-08-16 Thread Nicolas Lesser via Phabricator via cfe-commits
Rakete added a comment.

It would be nice to be able to diagnose `X`:

  template 
  struct Foo {
struct [[trivially_relocatable]] X { // no warning
  X(X &&) = delete;
};
  };
  
  Foo f; // no warning
  static_assert(!__is_trivially_relocatable(Foo::X)); // ok

But otherwise, you might want to put the attribute in the `clang` namespace. 
LGTM then, but you'll want to wait for someone more senior than me to review 
(and possibly accept) it.


Repository:
  rC Clang

https://reviews.llvm.org/D50119



___
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

2018-08-08 Thread Nicolas Lesser via Phabricator via cfe-commits
Rakete updated this revision to Diff 159832.
Rakete added a comment.

Rebase + friendly ping :)


Repository:
  rC Clang

https://reviews.llvm.org/D36357

Files:
  include/clang/Basic/DiagnosticParseKinds.td
  lib/Parse/ParseExprCXX.cpp
  test/FixIt/fixit-cxx0x.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,6 @@
 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 {{'[]' after delete interpreted as 'delete[]'}}
 }
+
Index: test/Parser/cxx0x-lambda-expressions.cpp
===
--- test/Parser/cxx0x-lambda-expressions.cpp
+++ test/Parser/cxx0x-lambda-expressions.cpp
@@ -53,8 +53,11 @@
   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 {{'[]' after delete interpreted as 'delete[]'}}
 delete [&] { return new int; } (); // ok, lambda
+
+delete []() { return new int; }(); // expected-error{{'[]' after delete interpreted as 'delete[]'}}
+delete [](E Enum) { return new int((int)Enum); }(e); // expected-error{{'[]' after delete interpreted as 'delete[]'}}
   }
 
   // We support init-captures in C++11 as an extension.
Index: test/FixIt/fixit-cxx0x.cpp
===
--- test/FixIt/fixit-cxx0x.cpp
+++ test/FixIt/fixit-cxx0x.cpp
@@ -58,6 +58,9 @@
   (void)[&, i, i]{ }; // expected-error{{'i' can appear only once in a capture list}}
   (void)[] mutable { }; // expected-error{{lambda requires '()' before 'mutable'}}
   (void)[] -> int { }; // expected-error{{lambda requires '()' before return type}}
+
+  delete []() { return new int; }(); // expected-error{{'[]' after delete interpreted as 'delete[]'}}
+  delete [] { return new int; }(); // expected-error{{'[]' after delete interpreted as 'delete[]'}}
 }
 
 #define bar "bar"
Index: lib/Parse/ParseExprCXX.cpp
===
--- lib/Parse/ParseExprCXX.cpp
+++ lib/Parse/ParseExprCXX.cpp
@@ -2946,8 +2946,38 @@
 //   [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.
+
+const Token Next = GetLookAheadToken(2);
+
+// Basic lookahead to check if we have a lambda expression.
+if (Next.isOneOf(tok::l_brace, tok::less) ||
+(Next.is(tok::l_paren) &&
+ (GetLookAheadToken(3).is(tok::r_paren) ||
+  (GetLookAheadToken(3).is(tok::identifier) &&
+   GetLookAheadToken(4).is(tok::identifier) {
+  SourceLocation RightBracketLock = NextToken().getLocation();
+  // Warn if the non-capturing lambda isn't surrounded by parenthesis
+  // to disambiguate it from 'delete[]'.
+  ExprResult Lambda = ParseLambdaExpression();
+  if (Lambda.isInvalid())
+return ExprError();
+
+  SourceLocation StartLoc = Lambda.get()->getLocStart();
+  Diag(Start, diag::err_lambda_after_delete)
+  << SourceRange(Start, RightBracketLock)
+  << FixItHint::CreateInsertion(StartLoc, "(")
+  << FixItHint::CreateInsertion(
+ Lexer::getLocForEndOfToken(Lambda.get()->getLocEnd(), 0,
+Actions.getSourceManager(),
+getLangOpts()),
+ ")");
+
+  // Evaluate any postfix expressions used on the lambda.
+  Lambda = ParsePostfixExpressionSuffix(Lambda);
+  return Actions.ActOnCXXDelete(Start, UseGlobal, /*ArrayForm=*/false,
+Lambda.get());
+}
+
 ArrayDelete = true;
 BalancedDelimiterTracker T(*this, tok::l_square);
 
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_delete : Error<
+  "'[]' after delete interpreted as 'delete[]'">;
 
 def warn_microsoft_dependent_exists : Warning<
   "dependent %select{__if_not_exists|__if_exists}0 declarations are ignored

[PATCH] D50291: [C++] Delay checking of constexpr-ness for special members.

2018-08-03 Thread Nicolas Lesser via Phabricator via cfe-commits
Rakete updated this revision to Diff 159160.
Rakete added a comment.

Add missing test cases. :)


Repository:
  rC Clang

https://reviews.llvm.org/D50291

Files:
  include/clang/Sema/Sema.h
  lib/Sema/SemaDeclCXX.cpp
  test/CXX/special/class.copy/p10.cpp

Index: test/CXX/special/class.copy/p10.cpp
===
--- /dev/null
+++ test/CXX/special/class.copy/p10.cpp
@@ -0,0 +1,25 @@
+// RUN: %clang_cc1 -std=c++14 -fsyntax-only -verify %s
+// expected-no-diagnostics
+
+// The implicitly-defined copy/move assignment operator is constexpr if
+// - X is a literal type, and
+// - [...]
+//
+// PR38143: Order of defaulted special members matters.
+struct X {
+  constexpr X() = default;
+  constexpr X(const X &) = default;
+  constexpr X &operator=(const X &) = default;
+  ~X() = default;
+  constexpr X(X &&) = default;
+  constexpr X &operator=(X &&) = default;
+};
+
+struct Y {
+  constexpr Y &operator=(const Y &) = default;
+  constexpr Y &operator=(Y &&) = default;
+  constexpr Y() = default;
+  constexpr Y(const Y &) = default;
+  ~Y() = default;
+  constexpr Y(Y &&) = default;
+};
Index: lib/Sema/SemaDeclCXX.cpp
===
--- lib/Sema/SemaDeclCXX.cpp
+++ lib/Sema/SemaDeclCXX.cpp
@@ -6020,6 +6020,7 @@
 
   bool HasMethodWithOverrideControl = false,
HasOverridingMethodWithoutOverrideControl = false;
+  CXXMethodDecl *CopyAssignment = nullptr, *MoveAssignment = nullptr;
   if (!Record->isDependentType()) {
 for (auto *M : Record->methods()) {
   // See if a method overloads virtual methods in a base
@@ -6049,6 +6050,11 @@
 }
   }
 
+  if (CSM == CXXCopyAssignment)
+CopyAssignment = M;
+  else if (CSM == CXXMoveAssignment)
+MoveAssignment = M;
+
   // Set triviality for the purpose of calls if this is a user-provided
   // copy/move constructor or destructor.
   if ((CSM == CXXCopyConstructor || CSM == CXXMoveConstructor ||
@@ -6071,6 +6077,22 @@
 }
   }
 }
+
+// Now we can decide whether the special members are constexpr.
+auto ActOnSpecialMember = [this, &Record](CXXMethodDecl *MD) {
+  if (!MD->isInvalidDecl() && MD->isExplicitlyDefaulted()) {
+CheckExplicitlyDefaultedSpecialMemberConstexpr(MD);
+Record->finishedDefaultedOrDeletedMember(MD);
+  }
+};
+for (auto *M : Record->ctors())
+  ActOnSpecialMember(M);
+if (CopyAssignment)
+  ActOnSpecialMember(CopyAssignment);
+if (MoveAssignment)
+  ActOnSpecialMember(MoveAssignment);
+if (CXXDestructorDecl *CD = Record->getDestructor())
+  ActOnSpecialMember(CD);
   }
 
   if (HasMethodWithOverrideControl &&
@@ -6532,20 +6554,8 @@
   // C++11 [dcl.fct.def.default]p2:
   //   An explicitly-defaulted function may be declared constexpr only if it
   //   would have been implicitly declared as constexpr,
-  // Do not apply this rule to members of class templates, since core issue 1358
-  // makes such functions always instantiate to constexpr functions. For
-  // functions which cannot be constexpr (for non-constructors in C++11 and for
-  // destructors in C++1y), this is checked elsewhere.
-  bool Constexpr = defaultedSpecialMemberIsConstexpr(*this, RD, CSM,
- HasConstParam);
-  if ((getLangOpts().CPlusPlus14 ? !isa(MD)
- : isa(MD)) &&
-  MD->isConstexpr() && !Constexpr &&
-  MD->getTemplatedKind() == FunctionDecl::TK_NonTemplate) {
-Diag(MD->getLocStart(), diag::err_incorrect_defaulted_constexpr) << CSM;
-// FIXME: Explain why the special member can't be constexpr.
-HadError = true;
-  }
+  // We need to delay this, because at this point we may not have enough
+  // information to determine if MD is really constexpr or not.
 
   //   and may have an explicit exception-specification only if it is compatible
   //   with the exception-specification on the implicit declaration.
@@ -6568,8 +6578,6 @@
   if (First) {
 //  -- it is implicitly considered to be constexpr if the implicit
 // definition would be,
-MD->setConstexpr(Constexpr);
-
 //  -- it is implicitly considered to have the same exception-specification
 // as if it had been implicitly declared,
 FunctionProtoType::ExtProtoInfo EPI = Type->getExtProtoInfo();
@@ -6598,6 +6606,39 @@
 MD->setInvalidDecl();
 }
 
+void Sema::CheckExplicitlyDefaultedSpecialMemberConstexpr(CXXMethodDecl *MD) {
+  CXXSpecialMember CSM = getSpecialMember(MD);
+  assert(MD && MD->isExplicitlyDefaulted() && CSM != CXXInvalid &&
+ "not an explicitly-defaulted special member");
+
+  const FunctionProtoType *Type = MD->getType()->getAs();
+
+  unsigned ExpectedParams =
+  CSM != CXXDefaultConstructor && CSM != CXXDestructor;
+  QualType ArgType = ExpectedParams ? Type->getParamType(0) : QualType();
+
+  bool HasConstParam = Expec

[PATCH] D50291: [C++] Delay checking of constexpr-ness for special members.

2018-08-03 Thread Nicolas Lesser via Phabricator via cfe-commits
Rakete created this revision.
Rakete added a reviewer: rsmith.

Specific class layouts meant that the constexpr-ness of a special member could 
only be decided after every special member was seen. However, this was at odds 
with the implementation, which checked the constexpr-ness for each special 
member in the order in which they were declared (hence that the bug only occurs 
when special members are ordered in a specific order).

This patch moves the checking of constexpr-ness after evaluating each special 
member.
This fixes https://llvm.org/pr38143


Repository:
  rC Clang

https://reviews.llvm.org/D50291

Files:
  include/clang/Sema/Sema.h
  lib/Sema/SemaDeclCXX.cpp

Index: lib/Sema/SemaDeclCXX.cpp
===
--- lib/Sema/SemaDeclCXX.cpp
+++ lib/Sema/SemaDeclCXX.cpp
@@ -6020,6 +6020,7 @@
 
   bool HasMethodWithOverrideControl = false,
HasOverridingMethodWithoutOverrideControl = false;
+  CXXMethodDecl *CopyAssignment = nullptr, *MoveAssignment = nullptr;
   if (!Record->isDependentType()) {
 for (auto *M : Record->methods()) {
   // See if a method overloads virtual methods in a base
@@ -6049,6 +6050,11 @@
 }
   }
 
+  if (CSM == CXXCopyAssignment)
+CopyAssignment = M;
+  else if (CSM == CXXMoveAssignment)
+MoveAssignment = M;
+
   // Set triviality for the purpose of calls if this is a user-provided
   // copy/move constructor or destructor.
   if ((CSM == CXXCopyConstructor || CSM == CXXMoveConstructor ||
@@ -6071,6 +6077,22 @@
 }
   }
 }
+
+// Now we can decide whether the special members are constexpr.
+auto ActOnSpecialMember = [this, &Record](CXXMethodDecl *MD) {
+  if (!MD->isInvalidDecl() && MD->isExplicitlyDefaulted()) {
+CheckExplicitlyDefaultedSpecialMemberConstexpr(MD);
+Record->finishedDefaultedOrDeletedMember(MD);
+  }
+};
+for (auto *M : Record->ctors())
+  ActOnSpecialMember(M);
+if (CopyAssignment)
+  ActOnSpecialMember(CopyAssignment);
+if (MoveAssignment)
+  ActOnSpecialMember(MoveAssignment);
+if (CXXDestructorDecl *CD = Record->getDestructor())
+  ActOnSpecialMember(CD);
   }
 
   if (HasMethodWithOverrideControl &&
@@ -6532,20 +6554,8 @@
   // C++11 [dcl.fct.def.default]p2:
   //   An explicitly-defaulted function may be declared constexpr only if it
   //   would have been implicitly declared as constexpr,
-  // Do not apply this rule to members of class templates, since core issue 1358
-  // makes such functions always instantiate to constexpr functions. For
-  // functions which cannot be constexpr (for non-constructors in C++11 and for
-  // destructors in C++1y), this is checked elsewhere.
-  bool Constexpr = defaultedSpecialMemberIsConstexpr(*this, RD, CSM,
- HasConstParam);
-  if ((getLangOpts().CPlusPlus14 ? !isa(MD)
- : isa(MD)) &&
-  MD->isConstexpr() && !Constexpr &&
-  MD->getTemplatedKind() == FunctionDecl::TK_NonTemplate) {
-Diag(MD->getLocStart(), diag::err_incorrect_defaulted_constexpr) << CSM;
-// FIXME: Explain why the special member can't be constexpr.
-HadError = true;
-  }
+  // We need to delay this, because at this point we may not have enough
+  // information to determine if MD is really constexpr or not.
 
   //   and may have an explicit exception-specification only if it is compatible
   //   with the exception-specification on the implicit declaration.
@@ -6568,8 +6578,6 @@
   if (First) {
 //  -- it is implicitly considered to be constexpr if the implicit
 // definition would be,
-MD->setConstexpr(Constexpr);
-
 //  -- it is implicitly considered to have the same exception-specification
 // as if it had been implicitly declared,
 FunctionProtoType::ExtProtoInfo EPI = Type->getExtProtoInfo();
@@ -6598,6 +6606,39 @@
 MD->setInvalidDecl();
 }
 
+void Sema::CheckExplicitlyDefaultedSpecialMemberConstexpr(CXXMethodDecl *MD) {
+  CXXSpecialMember CSM = getSpecialMember(MD);
+  assert(MD && MD->isExplicitlyDefaulted() && CSM != CXXInvalid &&
+ "not an explicitly-defaulted special member");
+
+  const FunctionProtoType *Type = MD->getType()->getAs();
+
+  unsigned ExpectedParams =
+  CSM != CXXDefaultConstructor && CSM != CXXDestructor;
+  QualType ArgType = ExpectedParams ? Type->getParamType(0) : QualType();
+
+  bool HasConstParam = ExpectedParams && ArgType->isReferenceType() &&
+   ArgType->getPointeeType().isConstQualified();
+
+  // Do not apply this rule to members of class templates, since core issue 1358
+  // makes such functions always instantiate to constexpr functions. For
+  // functions which cannot be constexpr (for non-constructors in C++11 and for
+  // destructors in C++1y), this is checked elsewhere.
+  bool Constexpr = defaultedSpecialMemberIsConstexpr(*this,

[PATCH] D50119: Compiler support for P1144R0 "__is_trivially_relocatable(T)"

2018-08-02 Thread Nicolas Lesser via Phabricator via cfe-commits
Rakete added a reviewer: Rakete.
Rakete added inline comments.



Comment at: lib/Sema/SemaDeclCXX.cpp:6091
 
+  for (auto *F : Record->fields()) {
+if (F->isMutable()) {

Quuxplusone wrote:
> Rakete wrote:
> > Can you move this in `ActOnFields`? That way we avoid two iterations of the 
> > fields.
> Done. Btw, I notice that `ActOnFields` spends a lot of time doing 
> `dyn_cast(Record)` over and over. If I had commit privs, I'd 
> refactor it to compute `CXXRecordDecl *CXXRecord = 
> dyn_cast_or_null(Record);` once at the very top of the 
> function, and then use `CXXRecord` throughout.
Done. :) Thanks



Comment at: lib/Sema/SemaDeclCXX.cpp:6174
+  Record->hasAttr() &&
+  !isTemplateInstantiation(Record->getTemplateSpecializationKind())) {
+if (Record->getDefinition() && !Record->isDependentContext() &&

Quuxplusone wrote:
> Rakete wrote:
> > The call to `isTemplateInstantiation` is wrong. Consider:
> > 
> > ```
> > template
> > struct [[trivially_relocatable]] A {
> >   T t;
> > };
> > 
> > struct X {
> >   X() = default;
> >   X(X &&) = delete;
> > };
> > 
> > A d;
> > static_assert(!__is_trivially_relocatable(decltype(d))); // oops, fires
> > ```
> > 
> > There is also no diagnostic saying that `A` cannot be marked 
> > `[[trivially_relocatable]]`.
> The absence of any diagnostics is intentional. We're saying that `A` is 
> trivially relocatable except-of-course-when-it's-not-relocatable-at-all, 
> similar to how templates currently work with `constexpr`.
> 
> However, the fact that `__is_trivially_relocatable(A)` when 
> `!__is_constructible(A, A&&)` does seem like a bug. I should probably 
> move the `isTemplateInstantiation` check down to control just the diagnostic, 
> eh?
Yes, good idea.


Repository:
  rC Clang

https://reviews.llvm.org/D50119



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


[PATCH] D50119: Compiler support for P1144R0 "__is_trivially_relocatable(T)"

2018-08-02 Thread Nicolas Lesser via Phabricator via cfe-commits
Rakete added inline comments.



Comment at: lib/Sema/SemaDeclCXX.cpp:6174
+  Record->hasAttr() &&
+  !isTemplateInstantiation(Record->getTemplateSpecializationKind())) {
+if (Record->getDefinition() && !Record->isDependentContext() &&

The call to `isTemplateInstantiation` is wrong. Consider:

```
template
struct [[trivially_relocatable]] A {
  T t;
};

struct X {
  X() = default;
  X(X &&) = delete;
};

A d;
static_assert(!__is_trivially_relocatable(decltype(d))); // oops, fires
```

There is also no diagnostic saying that `A` cannot be marked 
`[[trivially_relocatable]]`.



Comment at: lib/Sema/SemaDeclCXX.cpp:6176
+if (Record->getDefinition() && !Record->isDependentContext() &&
+!Record->isBeingDefined()) {
+  // Check that the destructor is non-deleted.

`Record` is never being defined at this point, even for templates. It also 
always has a definition AFAIK.


Repository:
  rC Clang

https://reviews.llvm.org/D50119



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


[PATCH] D50119: Compiler support for P1144R0 "__is_trivially_relocatable(T)"

2018-08-02 Thread Nicolas Lesser via Phabricator via cfe-commits
Rakete added inline comments.



Comment at: lib/Sema/SemaDeclCXX.cpp:6187
+Record->dropAttr();
+  } else if (Record->needsImplicitMoveConstructor() &&
+ Record->defaultedMoveConstructorIsDeleted()) {

Rakete wrote:
> Quuxplusone wrote:
> > Rakete wrote:
> > > This is dead code. `Record` never needs an implicit move constructor at 
> > > this point, because either 1) it never did or 2) it was defined above by 
> > > `LookupSpecialMember`.
> > Confirmed that this code is never hit; and removed. Just for my own 
> > information: you're saying that the call to `LookupSpecialMember` on line 
> > 6179, even though it's looking up the //destructor//, will actually cause 
> > all the `needsImplicitFootor` flags to get resolved? And so also I guess I 
> > should never have been looking at those flags directly; I should have 
> > handled this case by calling `LookupSpecialMember` like I do on line 6196. 
> > Is that basically correct?
> No, not the 6179 one, but the one before it 6163. Yeah you could have :)
Sorry for the noise, that isn't it because of the if statement right before 
6163 :/. I was wrong...

Every implicit constructor is already defined before the call to 
`CheckCompletedCXXClass` (except if it's a template), so `needsImplicitFootor` 
is always `false`. This means that you can drop the if statement right before 
6163, because it's always true.

I'm 99% sure of the previous paragraph. :)



Comment at: lib/Sema/SemaDeclCXX.cpp:6091
 
+  for (auto *F : Record->fields()) {
+if (F->isMutable()) {

Can you move this in `ActOnFields`? That way we avoid two iterations of the 
fields.


Repository:
  rC Clang

https://reviews.llvm.org/D50119



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


[PATCH] D50119: Compiler support for P1144R0 "__is_trivially_relocatable(T)"

2018-08-02 Thread Nicolas Lesser via Phabricator via cfe-commits
Rakete added inline comments.



Comment at: lib/Sema/SemaDeclCXX.cpp:6187
+Record->dropAttr();
+  } else if (Record->needsImplicitMoveConstructor() &&
+ Record->defaultedMoveConstructorIsDeleted()) {

Quuxplusone wrote:
> Rakete wrote:
> > This is dead code. `Record` never needs an implicit move constructor at 
> > this point, because either 1) it never did or 2) it was defined above by 
> > `LookupSpecialMember`.
> Confirmed that this code is never hit; and removed. Just for my own 
> information: you're saying that the call to `LookupSpecialMember` on line 
> 6179, even though it's looking up the //destructor//, will actually cause all 
> the `needsImplicitFootor` flags to get resolved? And so also I guess I should 
> never have been looking at those flags directly; I should have handled this 
> case by calling `LookupSpecialMember` like I do on line 6196. Is that 
> basically correct?
No, not the 6179 one, but the one before it 6163. Yeah you could have :)


Repository:
  rC Clang

https://reviews.llvm.org/D50119



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


[PATCH] D50119: Compiler support for P1144R0 "__is_trivially_relocatable(T)"

2018-08-01 Thread Nicolas Lesser via Phabricator via cfe-commits
Rakete added inline comments.



Comment at: compiler-explorer-llvm-commit.sh:1
+# This is the commit of LLVM that we're currently based on.
+git reset --hard 1fa19f68007cd126a04448093c171f40e556087e

What's this file? A mistake?



Comment at: include/clang/AST/DeclCXX.h:471
 
+/// True when this class's bases and fields are all trivially relocatable,
+/// and the class itself has a defaulted move constructor and a defaulted

That comment misses a "or is a reference".



Comment at: include/clang/Basic/DiagnosticSemaKinds.td:2942
+  "not %select{move-constructible|destructible}2"
+  >;
+

Quuxplusone wrote:
> > Might be useful to add a note explaining why the type isn't trivially 
> > relocatable instead of the general "because it is not destructible".
> 
> You mean, like, a series of notes pointing at "because its base class B is 
> not destructible... because B's destructor is defined as deleted here"?  I 
> agree that might be helpful, but since it only happens when the programmer is 
> messing around with the attribute anyway, I wouldn't want to do anything too 
> innovative or LoC-consuming. I'd cut and paste ~10 lines of code from 
> somewhere else that already does something like that if you point me at it, 
> but otherwise I think it's not worth the number of extra codepaths that would 
> need to be tested.
Fair enough.



Comment at: include/clang/Sema/Sema.h:4304
 
+  bool IsTriviallyRelocatableType(QualType QT) const;
+

Quuxplusone wrote:
> Rakete wrote:
> > Any reason why this is a free function? Should be a member function of 
> > `QualType`.
> `class QualType` is defined in `AST/`, whereas all the C++-specific 
> TriviallyRelocatable stuff is currently confined to `Sema/`. My impression 
> was that I should try to preserve that separation, even if it meant being 
> ugly right here. I agree that this is a stupid hack, and would love to get 
> rid of it, but I think I need some guidance as to how much mixing of `AST` 
> and `Sema` is permitted.
Nah, it's fine. There are lots of C++ specific things in AST/, because the AST 
nodes represent C++-y stuff. Trivially copyable is also part of `QualType`, 
even though it's C++ specific.



Comment at: lib/Sema/SemaDecl.cpp:15823
 CXXRecord->setImplicitDestructorIsDeleted();
+CXXRecord->setIsNotNaturallyTriviallyRelocatable();
 SetDeclDeleted(Dtor, CXXRecord->getLocation());

You don't need this. This is already handled by `CheckCompleteCXXClass`.



Comment at: lib/Sema/SemaDeclAttr.cpp:6481
 break;
+  case ParsedAttr::AT_TriviallyRelocatable:
+handleTriviallyRelocatableAttr(S, D, AL);

Why is this attribute under "Microsoft Attributes"? ;)



Comment at: lib/Sema/SemaDeclCXX.cpp:6166
+if (SMOR.getKind() != SpecialMemberOverloadResult::Success ||
+!SMOR.getMethod()->isDefaulted()) {
+  Record->setIsNotNaturallyTriviallyRelocatable();

Extra braces.



Comment at: lib/Sema/SemaDeclCXX.cpp:6187
+Record->dropAttr();
+  } else if (Record->needsImplicitMoveConstructor() &&
+ Record->defaultedMoveConstructorIsDeleted()) {

This is dead code. `Record` never needs an implicit move constructor at this 
point, because either 1) it never did or 2) it was defined above by 
`LookupSpecialMember`.



Comment at: lib/Sema/SemaDeclCXX.cpp:12631
 ClassDecl->setImplicitMoveConstructorIsDeleted();
+ClassDecl->setIsNotNaturallyTriviallyRelocatable();
 SetDeclDeleted(MoveConstructor, ClassLoc);

Same, already handled by `CheckCompleteCXXClass`.



Comment at: lib/Sema/SemaDeclCXX.cpp:6157
+
+  if (getLangOpts().CPlusPlus11 &&
+  !Record->hasAttr() &&

Quuxplusone wrote:
> Rakete wrote:
> > This really just checks whether the type has defaulted copy constructor. If 
> > there was a move constructor, it would have been handled above. If the 
> > copy/move constructor is implicitly deleted, it would have been handled 
> > also above. Please simplify this accordingly.
> Can you elaborate on this one? I assume you mean that some of lines 6157 
> through 6171 are superfluous, but I can't figure out which ones or how to 
> simplify it.
Actually, nvm. I was thinking of calling a few functions instead of call 
`LookupSpecialMember`, but I forgot that those functions can only work if there 
was previously a call to `LookupSpecialMember` :/.



Comment at: test/SemaCXX/trivially-relocatable.cpp:42
+struct A6;
+struct [[trivially_relocatable]] A6 {};
+// expected-error@-1{{type A6 declared 'trivially_relocatable' after its first 
declaration}}

Quuxplusone wrote:
> Rakete wrote:
> > Why does this restriction exi

[PATCH] D50119: Compiler support for P1144R0 "__is_trivially_relocatable(T)"

2018-08-01 Thread Nicolas Lesser via Phabricator via cfe-commits
Rakete added a comment.

- There's a bug in your implementation:

  struct X {
X &operator=(X &&);
  };
  static_assert(__is_trivially_relocatable(X)); // oops, fires!

`X` has a move constructor and a destructor, so it is trivially relocatable.

- Please run your code through clang-format.

- Might be useful to add a note explaining why the type isn't trivially 
relocatable isn't of the general "because it is not destructible".




Comment at: include/clang/Sema/Sema.h:4304
 
+  bool IsTriviallyRelocatableType(QualType QT) const;
+

Any reason why this is a free function? Should be a member function of 
`QualType`.



Comment at: lib/AST/DeclCXX.cpp:283
+if (Base->isVirtual() || !BaseClassDecl->isTriviallyRelocatable()) {
+  //puts("because 283");
+  setIsNotNaturallyTriviallyRelocatable();

Lingering debug message? :) There are many of them.

For a single expression, drop the braces of the if statement.



Comment at: lib/Sema/SemaDeclCXX.cpp:6066
+if (M->hasAttr() || Record->hasAttr()) {
+  // Consider removing this case to simplify the Standard wording.
+} else {

This should be a `// TODO: ...`. Is this comment really appropriate? The 
intended audience isn't compiler writers I think.



Comment at: lib/Sema/SemaDeclCXX.cpp:6157
+
+  if (getLangOpts().CPlusPlus11 &&
+  !Record->hasAttr() &&

This really just checks whether the type has defaulted copy constructor. If 
there was a move constructor, it would have been handled above. If the 
copy/move constructor is implicitly deleted, it would have been handled also 
above. Please simplify this accordingly.



Comment at: lib/Sema/SemaDeclCXX.cpp:6158
+  if (getLangOpts().CPlusPlus11 &&
+  !Record->hasAttr() &&
+  Record->isTriviallyRelocatable()) {

Why do you need to check whether the attribute is present or not? This is 
supposed to be whether the type is naturally trivially relocatable, so the 
presence of the attribute is not important.



Comment at: lib/Sema/SemaDeclCXX.cpp:6656
   SetDeclDeleted(MD, MD->getLocation());
+  if (CSM == CXXMoveConstructor || CSM == CXXDestructor) {
+//puts("because 6646");

You don't actually need those three lines. This is already handled in 
`CheckCompletedCXXClass`.



Comment at: test/SemaCXX/trivially-relocatable.cpp:42
+struct A6;
+struct [[trivially_relocatable]] A6 {};
+// expected-error@-1{{type A6 declared 'trivially_relocatable' after its first 
declaration}}

Why does this restriction exist? None of the existing attributes have it and I 
don't see why it would make sense to disallow this.



Comment at: test/SemaCXX/trivially-relocatable.cpp:471
+struct Incomplete; // expected-note {{forward declaration of 'Incomplete'}}
+struct Regression1 {
+  Incomplete i; // expected-error {{field has incomplete type 'Incomplete'}}

This is the right place for regression tests. Add them to 
test/Parser/cxx-class.cpp.


Repository:
  rC Clang

https://reviews.llvm.org/D50119



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


[PATCH] D49848: Parse a possible trailing postfix expression suffix after a fold expression

2018-07-27 Thread Nicolas Lesser via Phabricator via cfe-commits
This revision was automatically updated to reflect the committed changes.
Closed by commit rL338170: Parse a possible trailing postfix expression suffix 
after a fold expression (authored by Rakete, committed by ).
Herald added a subscriber: llvm-commits.

Repository:
  rL LLVM

https://reviews.llvm.org/D49848

Files:
  cfe/trunk/include/clang/Parse/Parser.h
  cfe/trunk/lib/Parse/ParseExpr.cpp
  cfe/trunk/test/Parser/cxx1z-fold-expressions.cpp

Index: cfe/trunk/include/clang/Parse/Parser.h
===
--- cfe/trunk/include/clang/Parse/Parser.h
+++ cfe/trunk/include/clang/Parse/Parser.h
@@ -1653,6 +1653,7 @@
   /// ParenParseOption - Control what ParseParenExpression will parse.
   enum ParenParseOption {
 SimpleExpr,  // Only parse '(' expression ')'
+FoldExpr,// Also allow fold-expression 
 CompoundStmt,// Also allow '(' compound-statement ')'
 CompoundLiteral, // Also allow '(' type-name ')' '{' ... '}'
 CastExpr // Also allow '(' type-name ')' 
Index: cfe/trunk/test/Parser/cxx1z-fold-expressions.cpp
===
--- cfe/trunk/test/Parser/cxx1z-fold-expressions.cpp
+++ cfe/trunk/test/Parser/cxx1z-fold-expressions.cpp
@@ -60,3 +60,29 @@
 }
 
 static_assert(nestedFoldOperator<3, 1>() == 1);
+
+// A fold-expression is a primary-expression.
+template 
+constexpr auto castSum(Ts... Args) {
+  return (T)(Args + ...).Value; // expected-error{{member reference base type 'int' is not a structure or union}}
+}
+
+template 
+constexpr auto simpleSum(Ts... Args) {
+  return (... + Args).Value; // expected-error{{member reference base type 'int' is not a structure or union}}
+}
+
+void prim() {
+  castSum(1, 2);
+  // expected-note@-1{{in instantiation of function template specialization}}
+  simpleSum(1, 2);
+  // expected-note@-1{{in instantiation of function template specialization}}
+
+  struct Number {
+int Value;
+constexpr Number operator+(Number Rhs) const { return {Rhs.Value + Value}; }
+  };
+
+  static_assert(castSum(Number{1}, Number{2}) == 3);
+  static_assert(simpleSum(Number{1}, Number{2}) == 3);
+}
Index: cfe/trunk/lib/Parse/ParseExpr.cpp
===
--- cfe/trunk/lib/Parse/ParseExpr.cpp
+++ cfe/trunk/lib/Parse/ParseExpr.cpp
@@ -789,6 +789,10 @@
   // We have parsed the cast-expression and no postfix-expr pieces are
   // following.
   return Res;
+case FoldExpr:
+  // We only parsed a fold-expression. There might be postfix-expr pieces
+  // afterwards; parse them now.
+  break;
 }
 
 break;
@@ -2523,8 +2527,9 @@
   Diag(Tok, diag::err_expected_lbrace_in_compound_literal);
   return ExprError();
 }
-  } else if (Tok.is(tok::ellipsis) &&
+  } else if (ExprType >= FoldExpr && Tok.is(tok::ellipsis) &&
  isFoldOperator(NextToken().getKind())) {
+ExprType = FoldExpr;
 return ParseFoldExpression(ExprResult(), T);
   } else if (isTypeCast) {
 // Parse the expression-list.
@@ -2536,9 +2541,11 @@
 if (!ParseSimpleExpressionList(ArgExprs, CommaLocs)) {
   // FIXME: If we ever support comma expressions as operands to
   // fold-expressions, we'll need to allow multiple ArgExprs here.
-  if (ArgExprs.size() == 1 && isFoldOperator(Tok.getKind()) &&
-  NextToken().is(tok::ellipsis))
+  if (ExprType >= FoldExpr && ArgExprs.size() == 1 &&
+  isFoldOperator(Tok.getKind()) && NextToken().is(tok::ellipsis)) {
+ExprType = FoldExpr;
 return ParseFoldExpression(ArgExprs[0], T);
+  }
 
   ExprType = SimpleExpr;
   Result = Actions.ActOnParenListExpr(OpenLoc, Tok.getLocation(),
@@ -2553,10 +2560,13 @@
   // expressions are parsed correctly.
   Result = Actions.CorrectDelayedTyposInExpr(Result);
 }
-ExprType = SimpleExpr;
 
-if (isFoldOperator(Tok.getKind()) && NextToken().is(tok::ellipsis))
+if (ExprType >= FoldExpr && isFoldOperator(Tok.getKind()) &&
+NextToken().is(tok::ellipsis)) {
+  ExprType = FoldExpr;
   return ParseFoldExpression(Result, T);
+}
+ExprType = SimpleExpr;
 
 // Don't build a paren expression unless we actually match a ')'.
 if (!Result.isInvalid() && Tok.is(tok::r_paren))
___
cfe-commits mailing list
cfe-commits@lists.llvm.org
http://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits


[PATCH] D49848: Parse a possible trailing postfix expression suffix after a fold expression

2018-07-27 Thread Nicolas Lesser via Phabricator via cfe-commits
Rakete updated this revision to Diff 157759.
Rakete added a comment.

Addressed review comments :)


Repository:
  rC Clang

https://reviews.llvm.org/D49848

Files:
  include/clang/Parse/Parser.h
  lib/Parse/ParseExpr.cpp
  test/Parser/cxx1z-fold-expressions.cpp

Index: test/Parser/cxx1z-fold-expressions.cpp
===
--- test/Parser/cxx1z-fold-expressions.cpp
+++ test/Parser/cxx1z-fold-expressions.cpp
@@ -60,3 +60,29 @@
 }
 
 static_assert(nestedFoldOperator<3, 1>() == 1);
+
+// A fold-expression is a primary-expression.
+template 
+constexpr auto castSum(Ts... Args) {
+  return (T)(Args + ...).Value; // expected-error{{member reference base type 'int' is not a structure or union}}
+}
+
+template 
+constexpr auto simpleSum(Ts... Args) {
+  return (... + Args).Value; // expected-error{{member reference base type 'int' is not a structure or union}}
+}
+
+void prim() {
+  castSum(1, 2);
+  // expected-note@-1{{in instantiation of function template specialization}}
+  simpleSum(1, 2);
+  // expected-note@-1{{in instantiation of function template specialization}}
+
+  struct Number {
+int Value;
+constexpr Number operator+(Number Rhs) const { return {Rhs.Value + Value}; }
+  };
+
+  static_assert(castSum(Number{1}, Number{2}) == 3);
+  static_assert(simpleSum(Number{1}, Number{2}) == 3);
+}
Index: lib/Parse/ParseExpr.cpp
===
--- lib/Parse/ParseExpr.cpp
+++ lib/Parse/ParseExpr.cpp
@@ -787,6 +787,10 @@
   // We have parsed the cast-expression and no postfix-expr pieces are
   // following.
   return Res;
+case FoldExpr:
+  // We only parsed a fold-expression. There might be postfix-expr pieces
+  // afterwards; parse them now.
+  break;
 }
 
 break;
@@ -2520,8 +2524,9 @@
   Diag(Tok, diag::err_expected_lbrace_in_compound_literal);
   return ExprError();
 }
-  } else if (Tok.is(tok::ellipsis) &&
+  } else if (ExprType >= FoldExpr && Tok.is(tok::ellipsis) &&
  isFoldOperator(NextToken().getKind())) {
+ExprType = FoldExpr;
 return ParseFoldExpression(ExprResult(), T);
   } else if (isTypeCast) {
 // Parse the expression-list.
@@ -2533,9 +2538,11 @@
 if (!ParseSimpleExpressionList(ArgExprs, CommaLocs)) {
   // FIXME: If we ever support comma expressions as operands to
   // fold-expressions, we'll need to allow multiple ArgExprs here.
-  if (ArgExprs.size() == 1 && isFoldOperator(Tok.getKind()) &&
-  NextToken().is(tok::ellipsis))
+  if (ExprType >= FoldExpr && ArgExprs.size() == 1 &&
+  isFoldOperator(Tok.getKind()) && NextToken().is(tok::ellipsis)) {
+ExprType = FoldExpr;
 return ParseFoldExpression(ArgExprs[0], T);
+  }
 
   ExprType = SimpleExpr;
   Result = Actions.ActOnParenListExpr(OpenLoc, Tok.getLocation(),
@@ -2550,10 +2557,13 @@
   // expressions are parsed correctly.
   Result = Actions.CorrectDelayedTyposInExpr(Result);
 }
-ExprType = SimpleExpr;
 
-if (isFoldOperator(Tok.getKind()) && NextToken().is(tok::ellipsis))
+if (ExprType >= FoldExpr && isFoldOperator(Tok.getKind()) &&
+NextToken().is(tok::ellipsis)) {
+  ExprType = FoldExpr;
   return ParseFoldExpression(Result, T);
+}
+ExprType = SimpleExpr;
 
 // Don't build a paren expression unless we actually match a ')'.
 if (!Result.isInvalid() && Tok.is(tok::r_paren))
Index: include/clang/Parse/Parser.h
===
--- include/clang/Parse/Parser.h
+++ include/clang/Parse/Parser.h
@@ -1653,6 +1653,7 @@
   /// ParenParseOption - Control what ParseParenExpression will parse.
   enum ParenParseOption {
 SimpleExpr,  // Only parse '(' expression ')'
+FoldExpr,// Also allow fold-expression 
 CompoundStmt,// Also allow '(' compound-statement ')'
 CompoundLiteral, // Also allow '(' type-name ')' '{' ... '}'
 CastExpr // Also allow '(' type-name ')' 
___
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

2018-07-26 Thread Nicolas Lesser via Phabricator via cfe-commits
Rakete updated this revision to Diff 157642.
Rakete added a comment.

Addressed review comments.

Note that clang doesn't support the fourth kind of lambda yet ([]<>), because 
https://reviews.llvm.org/D36527 hasn't been merged yet, so I didn't add a test 
case for that one.


Repository:
  rC Clang

https://reviews.llvm.org/D36357

Files:
  include/clang/Basic/DiagnosticParseKinds.td
  lib/Parse/ParseExprCXX.cpp
  test/FixIt/fixit-cxx0x.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,6 @@
 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 {{'[]' after delete interpreted as 'delete[]'}}
 }
+
Index: test/Parser/cxx0x-lambda-expressions.cpp
===
--- test/Parser/cxx0x-lambda-expressions.cpp
+++ test/Parser/cxx0x-lambda-expressions.cpp
@@ -53,8 +53,11 @@
   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 {{'[]' after delete interpreted as 'delete[]'}}
 delete [&] { return new int; } (); // ok, lambda
+
+delete []() { return new int; }(); // expected-error{{'[]' after delete interpreted as 'delete[]'}}
+delete [](E Enum) { return new int((int)Enum); }(e); // expected-error{{'[]' after delete interpreted as 'delete[]'}}
   }
 
   // We support init-captures in C++11 as an extension.
Index: test/FixIt/fixit-cxx0x.cpp
===
--- test/FixIt/fixit-cxx0x.cpp
+++ test/FixIt/fixit-cxx0x.cpp
@@ -58,6 +58,9 @@
   (void)[&, i, i]{ }; // expected-error{{'i' can appear only once in a capture list}}
   (void)[] mutable { }; // expected-error{{lambda requires '()' before 'mutable'}}
   (void)[] -> int { }; // expected-error{{lambda requires '()' before return type}}
+
+  delete []() { return new int; }(); // expected-error{{'[]' after delete interpreted as 'delete[]'}}
+  delete [] { return new int; }(); // expected-error{{'[]' after delete interpreted as 'delete[]'}}
 }
 
 #define bar "bar"
Index: lib/Parse/ParseExprCXX.cpp
===
--- lib/Parse/ParseExprCXX.cpp
+++ lib/Parse/ParseExprCXX.cpp
@@ -2946,8 +2946,38 @@
 //   [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.
+
+const Token Next = GetLookAheadToken(2);
+
+// Basic lookahead to check if we have a lambda expression.
+if (Next.isOneOf(tok::l_brace, tok::less) ||
+(Next.is(tok::l_paren) &&
+ (GetLookAheadToken(3).is(tok::r_paren) ||
+  (GetLookAheadToken(3).is(tok::identifier) &&
+   GetLookAheadToken(4).is(tok::identifier) {
+  SourceLocation RightBracketLock = NextToken().getLocation();
+  // Warn if the non-capturing lambda isn't surrounded by parenthesis
+  // to disambiguate it from 'delete[]'.
+  ExprResult Lambda = ParseLambdaExpression();
+  if (Lambda.isInvalid())
+return ExprError();
+
+  SourceLocation StartLoc = Lambda.get()->getLocStart();
+  Diag(Start, diag::err_lambda_after_delete)
+  << SourceRange(Start, RightBracketLock)
+  << FixItHint::CreateInsertion(StartLoc, "(")
+  << FixItHint::CreateInsertion(
+ Lexer::getLocForEndOfToken(Lambda.get()->getLocEnd(), 0,
+Actions.getSourceManager(),
+getLangOpts()),
+ ")");
+
+  // Evaluate any postfix expressions used on the lambda.
+  Lambda = ParsePostfixExpressionSuffix(Lambda);
+  return Actions.ActOnCXXDelete(Start, UseGlobal, /*ArrayForm=*/false,
+Lambda.get());
+}
+
 ArrayDelete = true;
 BalancedDelimiterTracker T(*this, tok::l_square);
 
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_delete : Erro

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

2018-07-26 Thread Nicolas Lesser via Phabricator via cfe-commits
Rakete updated this revision to Diff 157611.
Rakete added a comment.

Rebased + friendly ping


Repository:
  rC Clang

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,6 @@
 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 {{'[]' after delete 
interpreted as 'delete[]'}}
 }
+
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 {{'[]' after delete 
interpreted as 'delete[]'}}
 delete [&] { return new int; } (); // ok, lambda
   }
 
Index: lib/Parse/ParseExprCXX.cpp
===
--- lib/Parse/ParseExprCXX.cpp
+++ lib/Parse/ParseExprCXX.cpp
@@ -2946,15 +2946,44 @@
 //   [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);
 
-T.consumeOpen();
-T.consumeClose();
-if (T.getCloseLocation().isInvalid())
-  return ExprError();
+const Token Next = GetLookAheadToken(2);
+
+// Basic lookahead to check if we have a lambda expression.
+if (Next.isOneOf(tok::l_brace, tok::less) ||
+(Next.is(tok::l_paren) &&
+ GetLookAheadToken(3).isOneOf(tok::r_paren, tok::identifier) &&
+ GetLookAheadToken(4).is(tok::identifier))) {
+  SourceLocation RightBracketLock = NextToken().getLocation();
+  // Warn if the non-capturing lambda isn't surrounded by parenthesis
+  // to disambiguate it from 'delete[]'.
+  ExprResult Lambda = ParseLambdaExpression();
+  if (Lambda.isInvalid())
+return ExprError();
+
+  SourceLocation StartLoc = Lambda.get()->getLocStart();
+  Diag(Start, diag::err_lambda_after_delete)
+  << SourceRange(Start, RightBracketLock)
+  << FixItHint::CreateInsertion(StartLoc, "(")
+  << FixItHint::CreateInsertion(
+ Lexer::getLocForEndOfToken(Lambda.get()->getLocEnd(), 1,
+Actions.getSourceManager(),
+getLangOpts()),
+ ")");
+
+  // Evaluate any postfix expressions used on the lambda.
+  Lambda = ParsePostfixExpressionSuffix(Lambda);
+  return Actions.ActOnCXXDelete(Start, UseGlobal, /*ArrayForm=*/false,
+Lambda.get());
+} else {
+  ArrayDelete = true;
+  BalancedDelimiterTracker T(*this, tok::l_square);
+
+  T.consumeOpen();
+  T.consumeClose();
+  if (T.getCloseLocation().isInvalid())
+return ExprError();
+}
   }
 
   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_delete : Error<
+  "'[]' after delete interpreted as 'delete[]'">;
 
 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,6 @@
 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 {{'[]' after delete interpreted as 'delete[]'}}
 }
+
Index: test/Parser/cxx0x-lambda-expressions.cpp
===
--- 

[PATCH] D49848: Parse a possible trailing postfix expression suffix after a fold expression

2018-07-26 Thread Nicolas Lesser via Phabricator via cfe-commits
Rakete updated this revision to Diff 157580.
Rakete added a comment.

Add a test without any casts.


Repository:
  rC Clang

https://reviews.llvm.org/D49848

Files:
  include/clang/Parse/Parser.h
  lib/Parse/ParseExpr.cpp
  test/Parser/cxx1z-fold-expressions.cpp


Index: test/Parser/cxx1z-fold-expressions.cpp
===
--- test/Parser/cxx1z-fold-expressions.cpp
+++ test/Parser/cxx1z-fold-expressions.cpp
@@ -60,3 +60,29 @@
 }
 
 static_assert(nestedFoldOperator<3, 1>() == 1);
+
+// A fold-expression is a primary-expression.
+template 
+constexpr auto castSum(Ts... Args) {
+  return (T)(Args + ...).Value; // expected-error{{member reference base type 
'int' is not a structure or union}}
+}
+
+template 
+constexpr auto simpleSum(Ts... Args) {
+  return (... + Args).Value; // expected-error{{member reference base type 
'int' is not a structure or union}}
+}
+
+void prim() {
+  castSum(1, 2);
+  // expected-note@-1{{in instantiation of function template specialization}}
+  simpleSum(1, 2);
+  // expected-note@-1{{in instantiation of function template specialization}}
+
+  struct Number {
+int Value;
+constexpr Number operator+(Number Rhs) const { return {Rhs.Value + Value}; 
}
+  };
+
+  static_assert(castSum(Number{1}, Number{2}) == 3);
+  static_assert(simpleSum(Number{1}, Number{2}) == 3);
+}
Index: lib/Parse/ParseExpr.cpp
===
--- lib/Parse/ParseExpr.cpp
+++ lib/Parse/ParseExpr.cpp
@@ -779,6 +779,10 @@
   // We have parsed the cast-expression and no postfix-expr pieces are
   // following.
   return Res;
+case FoldExpr:
+  // We parsed fold-expression only. There might be postfix-expr pieces
+  // afterwards; parse them now.
+  break;
 }
 
 break;
@@ -2514,6 +2518,7 @@
 }
   } else if (Tok.is(tok::ellipsis) &&
  isFoldOperator(NextToken().getKind())) {
+ExprType = FoldExpr;
 return ParseFoldExpression(ExprResult(), T);
   } else if (isTypeCast) {
 // Parse the expression-list.
@@ -2526,8 +2531,10 @@
   // FIXME: If we ever support comma expressions as operands to
   // fold-expressions, we'll need to allow multiple ArgExprs here.
   if (ArgExprs.size() == 1 && isFoldOperator(Tok.getKind()) &&
-  NextToken().is(tok::ellipsis))
+  NextToken().is(tok::ellipsis)) {
+ExprType = FoldExpr;
 return ParseFoldExpression(ArgExprs[0], T);
+  }
 
   ExprType = SimpleExpr;
   Result = Actions.ActOnParenListExpr(OpenLoc, Tok.getLocation(),
@@ -2544,8 +2551,10 @@
 }
 ExprType = SimpleExpr;
 
-if (isFoldOperator(Tok.getKind()) && NextToken().is(tok::ellipsis))
+if (isFoldOperator(Tok.getKind()) && NextToken().is(tok::ellipsis)) {
+  ExprType = FoldExpr;
   return ParseFoldExpression(Result, T);
+}
 
 // Don't build a paren expression unless we actually match a ')'.
 if (!Result.isInvalid() && Tok.is(tok::r_paren))
Index: include/clang/Parse/Parser.h
===
--- include/clang/Parse/Parser.h
+++ include/clang/Parse/Parser.h
@@ -1654,7 +1654,8 @@
 SimpleExpr,  // Only parse '(' expression ')'
 CompoundStmt,// Also allow '(' compound-statement ')'
 CompoundLiteral, // Also allow '(' type-name ')' '{' ... '}'
-CastExpr // Also allow '(' type-name ')' 
+CastExpr,// Also allow '(' type-name ')' 
+FoldExpr // Also allow fold-expression 
   };
   ExprResult ParseParenExpression(ParenParseOption &ExprType,
 bool stopIfCastExpr,


Index: test/Parser/cxx1z-fold-expressions.cpp
===
--- test/Parser/cxx1z-fold-expressions.cpp
+++ test/Parser/cxx1z-fold-expressions.cpp
@@ -60,3 +60,29 @@
 }
 
 static_assert(nestedFoldOperator<3, 1>() == 1);
+
+// A fold-expression is a primary-expression.
+template 
+constexpr auto castSum(Ts... Args) {
+  return (T)(Args + ...).Value; // expected-error{{member reference base type 'int' is not a structure or union}}
+}
+
+template 
+constexpr auto simpleSum(Ts... Args) {
+  return (... + Args).Value; // expected-error{{member reference base type 'int' is not a structure or union}}
+}
+
+void prim() {
+  castSum(1, 2);
+  // expected-note@-1{{in instantiation of function template specialization}}
+  simpleSum(1, 2);
+  // expected-note@-1{{in instantiation of function template specialization}}
+
+  struct Number {
+int Value;
+constexpr Number operator+(Number Rhs) const { return {Rhs.Value + Value}; }
+  };
+
+  static_assert(castSum(Number{1}, Number{2}) == 3);
+  static_assert(simpleSum(Number{1}, Number{2}) == 3);
+}
Index: lib/Parse/ParseExpr.cpp
===
--- lib/Parse/ParseExpr.cpp
+++ lib/Parse/ParseExpr.cpp
@@ -779,6 +779,10 @@
 

[PATCH] D49848: Parse a possible trailing postfix expression suffix after a fold expression

2018-07-26 Thread Nicolas Lesser via Phabricator via cfe-commits
Rakete updated this revision to Diff 157578.
Rakete added a comment.

@rsmith you're right, it should. But it doesn't, because the the fold 
expression is considered to be a cast expression by ParseParenExpression and 
which parses any postfix pieces immediately after a cast, but it doesn't do so 
for fold expression, because they don't (not surprisingly) involve a cast.

I've added a new type of ParenParseOption for fold-expressions for this, which 
makes the patch way more cleaner :) (I didn't want to reuse SimpleExpr for fold 
expressions - conflicts with the docs for it)


Repository:
  rC Clang

https://reviews.llvm.org/D49848

Files:
  include/clang/Parse/Parser.h
  lib/Parse/ParseExpr.cpp
  test/Parser/cxx1z-fold-expressions.cpp


Index: test/Parser/cxx1z-fold-expressions.cpp
===
--- test/Parser/cxx1z-fold-expressions.cpp
+++ test/Parser/cxx1z-fold-expressions.cpp
@@ -60,3 +60,21 @@
 }
 
 static_assert(nestedFoldOperator<3, 1>() == 1);
+
+// A fold-expression is a primary-expression.
+template 
+constexpr auto castSum(Ts... Args) {
+  return (T)(Args + ...).Value; // expected-error{{member reference base type 
'int' is not a structure or union}}
+}
+
+void prim() {
+  castSum(1, 2);
+  // expected-note@-1{{in instantiation of function template specialization}}
+
+  struct Number {
+int Value;
+constexpr Number operator+(Number Rhs) const { return {Rhs.Value + Value}; 
}
+  };
+
+  static_assert(castSum(Number{1}, Number{2}) == 3);
+}
Index: lib/Parse/ParseExpr.cpp
===
--- lib/Parse/ParseExpr.cpp
+++ lib/Parse/ParseExpr.cpp
@@ -779,6 +779,10 @@
   // We have parsed the cast-expression and no postfix-expr pieces are
   // following.
   return Res;
+case FoldExpr:
+  // We parsed fold-expression only. There might be postfix-expr pieces
+  // afterwards; parse them now.
+  break;
 }
 
 break;
@@ -2514,6 +2518,7 @@
 }
   } else if (Tok.is(tok::ellipsis) &&
  isFoldOperator(NextToken().getKind())) {
+ExprType = FoldExpr;
 return ParseFoldExpression(ExprResult(), T);
   } else if (isTypeCast) {
 // Parse the expression-list.
@@ -2526,8 +2531,10 @@
   // FIXME: If we ever support comma expressions as operands to
   // fold-expressions, we'll need to allow multiple ArgExprs here.
   if (ArgExprs.size() == 1 && isFoldOperator(Tok.getKind()) &&
-  NextToken().is(tok::ellipsis))
+  NextToken().is(tok::ellipsis)) {
+ExprType = FoldExpr;
 return ParseFoldExpression(ArgExprs[0], T);
+  }
 
   ExprType = SimpleExpr;
   Result = Actions.ActOnParenListExpr(OpenLoc, Tok.getLocation(),
@@ -2544,8 +2551,10 @@
 }
 ExprType = SimpleExpr;
 
-if (isFoldOperator(Tok.getKind()) && NextToken().is(tok::ellipsis))
+if (isFoldOperator(Tok.getKind()) && NextToken().is(tok::ellipsis)) {
+  ExprType = FoldExpr;
   return ParseFoldExpression(Result, T);
+}
 
 // Don't build a paren expression unless we actually match a ')'.
 if (!Result.isInvalid() && Tok.is(tok::r_paren))
Index: include/clang/Parse/Parser.h
===
--- include/clang/Parse/Parser.h
+++ include/clang/Parse/Parser.h
@@ -1654,7 +1654,8 @@
 SimpleExpr,  // Only parse '(' expression ')'
 CompoundStmt,// Also allow '(' compound-statement ')'
 CompoundLiteral, // Also allow '(' type-name ')' '{' ... '}'
-CastExpr // Also allow '(' type-name ')' 
+CastExpr,// Also allow '(' type-name ')' 
+FoldExpr // Also allow fold-expression 
   };
   ExprResult ParseParenExpression(ParenParseOption &ExprType,
 bool stopIfCastExpr,


Index: test/Parser/cxx1z-fold-expressions.cpp
===
--- test/Parser/cxx1z-fold-expressions.cpp
+++ test/Parser/cxx1z-fold-expressions.cpp
@@ -60,3 +60,21 @@
 }
 
 static_assert(nestedFoldOperator<3, 1>() == 1);
+
+// A fold-expression is a primary-expression.
+template 
+constexpr auto castSum(Ts... Args) {
+  return (T)(Args + ...).Value; // expected-error{{member reference base type 'int' is not a structure or union}}
+}
+
+void prim() {
+  castSum(1, 2);
+  // expected-note@-1{{in instantiation of function template specialization}}
+
+  struct Number {
+int Value;
+constexpr Number operator+(Number Rhs) const { return {Rhs.Value + Value}; }
+  };
+
+  static_assert(castSum(Number{1}, Number{2}) == 3);
+}
Index: lib/Parse/ParseExpr.cpp
===
--- lib/Parse/ParseExpr.cpp
+++ lib/Parse/ParseExpr.cpp
@@ -779,6 +779,10 @@
   // We have parsed the cast-expression and no postfix-expr pieces are
   // following.
   return Res;
+case FoldExpr:
+  // We parsed fold-expre

[PATCH] D49848: Parse a possible trailing postsfix expression suffix after a fold expression

2018-07-26 Thread Nicolas Lesser via Phabricator via cfe-commits
Rakete created this revision.
Rakete added a reviewer: rsmith.

This patch allows the parsing of a postfix expression involving a fold 
expression, which is legal as a fold-expression is a primary-expression.

See also https://llvm.org/pr38282


Repository:
  rC Clang

https://reviews.llvm.org/D49848

Files:
  lib/Parse/ParseExpr.cpp
  test/Parser/cxx1z-fold-expressions.cpp


Index: test/Parser/cxx1z-fold-expressions.cpp
===
--- test/Parser/cxx1z-fold-expressions.cpp
+++ test/Parser/cxx1z-fold-expressions.cpp
@@ -60,3 +60,21 @@
 }
 
 static_assert(nestedFoldOperator<3, 1>() == 1);
+
+// A fold-expression is a primary-expression.
+template 
+constexpr auto castSum(Ts... Args) {
+  return (T)(Args + ...).Value; // expected-error{{member reference base type 
'int' is not a structure or union}}
+}
+
+void prim() {
+  castSum(1, 2);
+  // expected-note@-1{{in instantiation of function template specialization}}
+
+  struct Number {
+int Value;
+constexpr Number operator+(Number Rhs) const { return {Rhs.Value + Value}; 
}
+  };
+
+  static_assert(castSum(Number{1}, Number{2}) == 3);
+}
Index: lib/Parse/ParseExpr.cpp
===
--- lib/Parse/ParseExpr.cpp
+++ lib/Parse/ParseExpr.cpp
@@ -2514,7 +2514,10 @@
 }
   } else if (Tok.is(tok::ellipsis) &&
  isFoldOperator(NextToken().getKind())) {
-return ParseFoldExpression(ExprResult(), T);
+Result = ParseFoldExpression(ExprResult(), T);
+if (!Result.isInvalid())
+  Result = ParsePostfixExpressionSuffix(Result.get());
+return Result;
   } else if (isTypeCast) {
 // Parse the expression-list.
 InMessageExpressionRAIIObject InMessage(*this, false);
@@ -2526,8 +2529,12 @@
   // FIXME: If we ever support comma expressions as operands to
   // fold-expressions, we'll need to allow multiple ArgExprs here.
   if (ArgExprs.size() == 1 && isFoldOperator(Tok.getKind()) &&
-  NextToken().is(tok::ellipsis))
-return ParseFoldExpression(ArgExprs[0], T);
+  NextToken().is(tok::ellipsis)) {
+Result = ParseFoldExpression(ArgExprs[0], T);
+if (!Result.isInvalid())
+  Result = ParsePostfixExpressionSuffix(Result.get());
+return Result;
+  }
 
   ExprType = SimpleExpr;
   Result = Actions.ActOnParenListExpr(OpenLoc, Tok.getLocation(),
@@ -2544,8 +2551,12 @@
 }
 ExprType = SimpleExpr;
 
-if (isFoldOperator(Tok.getKind()) && NextToken().is(tok::ellipsis))
-  return ParseFoldExpression(Result, T);
+if (isFoldOperator(Tok.getKind()) && NextToken().is(tok::ellipsis)) {
+  Result = ParseFoldExpression(Result, T);
+  if (!Result.isInvalid())
+Result = ParsePostfixExpressionSuffix(Result.get());
+  return Result;
+}
 
 // Don't build a paren expression unless we actually match a ')'.
 if (!Result.isInvalid() && Tok.is(tok::r_paren))


Index: test/Parser/cxx1z-fold-expressions.cpp
===
--- test/Parser/cxx1z-fold-expressions.cpp
+++ test/Parser/cxx1z-fold-expressions.cpp
@@ -60,3 +60,21 @@
 }
 
 static_assert(nestedFoldOperator<3, 1>() == 1);
+
+// A fold-expression is a primary-expression.
+template 
+constexpr auto castSum(Ts... Args) {
+  return (T)(Args + ...).Value; // expected-error{{member reference base type 'int' is not a structure or union}}
+}
+
+void prim() {
+  castSum(1, 2);
+  // expected-note@-1{{in instantiation of function template specialization}}
+
+  struct Number {
+int Value;
+constexpr Number operator+(Number Rhs) const { return {Rhs.Value + Value}; }
+  };
+
+  static_assert(castSum(Number{1}, Number{2}) == 3);
+}
Index: lib/Parse/ParseExpr.cpp
===
--- lib/Parse/ParseExpr.cpp
+++ lib/Parse/ParseExpr.cpp
@@ -2514,7 +2514,10 @@
 }
   } else if (Tok.is(tok::ellipsis) &&
  isFoldOperator(NextToken().getKind())) {
-return ParseFoldExpression(ExprResult(), T);
+Result = ParseFoldExpression(ExprResult(), T);
+if (!Result.isInvalid())
+  Result = ParsePostfixExpressionSuffix(Result.get());
+return Result;
   } else if (isTypeCast) {
 // Parse the expression-list.
 InMessageExpressionRAIIObject InMessage(*this, false);
@@ -2526,8 +2529,12 @@
   // FIXME: If we ever support comma expressions as operands to
   // fold-expressions, we'll need to allow multiple ArgExprs here.
   if (ArgExprs.size() == 1 && isFoldOperator(Tok.getKind()) &&
-  NextToken().is(tok::ellipsis))
-return ParseFoldExpression(ArgExprs[0], T);
+  NextToken().is(tok::ellipsis)) {
+Result = ParseFoldExpression(ArgExprs[0], T);
+if (!Result.isInvalid())
+  Result = ParsePostfixExpressionSuffix(Result.get());
+return Result;
+  }
 
   ExprType = SimpleExpr;
 

[PATCH] D38075: Fix PR34668 - P0704R1 implementation is too permissive

2018-07-13 Thread Nicolas Lesser via Phabricator via cfe-commits
This revision was automatically updated to reflect the committed changes.
Closed by commit rC337017: Fix PR34668 - P0704R1 implementation is too 
permissive (authored by Rakete, committed by ).

Changed prior to commit:
  https://reviews.llvm.org/D38075?vs=155410&id=155412#toc

Repository:
  rC Clang

https://reviews.llvm.org/D38075

Files:
  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
@@ -3,12 +3,15 @@
 struct X {
   void ref() & {} // expected-note{{'ref' declared here}}
   void cref() const& {}
+  void cvref() const volatile & {} // expected-note{{'cvref' declared here}}
 };
 
 void test() {
   X{}.ref(); // expected-error{{'this' argument to member function 'ref' is an 
rvalue, but function has non-const lvalue ref-qualifier}}
   X{}.cref(); // expected-no-error
+  X{}.cvref(); // expected-error{{'this' argument to member function 'cvref' 
is an rvalue, but function has non-const lvalue ref-qualifier}}
 
   (X{}.*&X::ref)(); // expected-error-re{{pointer-to-member function type 
'void (X::*)() {{.*}}&' can only be called on an lvalue}}
   (X{}.*&X::cref)(); // expected-no-error
+  (X{}.*&X::cvref)(); // expected-error-re{{pointer-to-member function type 
'void (X::*)() {{.*}}&' can only be called on an lvalue}}
 }
Index: lib/Sema/SemaExprCXX.cpp
===
--- lib/Sema/SemaExprCXX.cpp
+++ lib/Sema/SemaExprCXX.cpp
@@ -5472,8 +5472,9 @@
 
 case RQ_LValue:
   if (!isIndirect && !LHS.get()->Classify(Context).isLValue()) {
-// C++2a allows functions with ref-qualifier & if they are also 
'const'.
-if (Proto->isConst())
+// C++2a allows functions with ref-qualifier & if their 
cv-qualifier-seq
+// is (exactly) 'const'.
+if (Proto->isConst() && !Proto->isVolatile())
   Diag(Loc, getLangOpts().CPlusPlus2a
 ? 
diag::warn_cxx17_compat_pointer_to_const_ref_member_on_rvalue
 : diag::ext_pointer_to_const_ref_member_on_rvalue);


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
@@ -3,12 +3,15 @@
 struct X {
   void ref() & {} // expected-note{{'ref' declared here}}
   void cref() const& {}
+  void cvref() const volatile & {} // expected-note{{'cvref' declared here}}
 };
 
 void test() {
   X{}.ref(); // expected-error{{'this' argument to member function 'ref' is an rvalue, but function has non-const lvalue ref-qualifier}}
   X{}.cref(); // expected-no-error
+  X{}.cvref(); // expected-error{{'this' argument to member function 'cvref' is an rvalue, but function has non-const lvalue ref-qualifier}}
 
   (X{}.*&X::ref)(); // expected-error-re{{pointer-to-member function type 'void (X::*)() {{.*}}&' can only be called on an lvalue}}
   (X{}.*&X::cref)(); // expected-no-error
+  (X{}.*&X::cvref)(); // expected-error-re{{pointer-to-member function type 'void (X::*)() {{.*}}&' can only be called on an lvalue}}
 }
Index: lib/Sema/SemaExprCXX.cpp
===
--- lib/Sema/SemaExprCXX.cpp
+++ lib/Sema/SemaExprCXX.cpp
@@ -5472,8 +5472,9 @@
 
 case RQ_LValue:
   if (!isIndirect && !LHS.get()->Classify(Context).isLValue()) {
-// C++2a allows functions with ref-qualifier & if they are also 'const'.
-if (Proto->isConst())
+// C++2a allows functions with ref-qualifier & if their cv-qualifier-seq
+// is (exactly) 'const'.
+if (Proto->isConst() && !Proto->isVolatile())
   Diag(Loc, getLangOpts().CPlusPlus2a
 ? diag::warn_cxx17_compat_pointer_to_const_ref_member_on_rvalue
 : diag::ext_pointer_to_const_ref_member_on_rvalue);
___
cfe-commits mailing list
cfe-commits@lists.llvm.org
http://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits


  1   2   >