Rakete1111 created this revision.
Rakete1111 added a reviewer: rsmith.

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

For example,

  template <typename T>
  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<typename T>
-A<T>::type g(T t) { return t; } // expected-error{{missing 'typename'}}
+A<T>::type g(T t) { return t; } // expected-warning {{implicit 'typename' is a C++2a extension}}
 
 template<typename T>
-A<T>::type A<T>::f() { return type(); } // expected-error{{missing 'typename'}}
+A<T>::type A<T>::f() { return type(); } // expected-warning {{implicit 'typename' is a C++2a extension}}
 
 template<typename T>
-void f(T::type) { } // expected-error{{missing 'typename'}}
+void f(T::type) { } // expected-warning {{implicit 'typename' is a C++2a extension}}
 
 template<typename T>
-void g(T::type x) { } // expected-error{{missing 'typename'}}
+void g(T::type x) { } // expected-warning {{implicit 'typename' is a C++2a extension}}
 
 template<typename T>
-void f(T::type, int) { } // expected-error{{missing 'typename'}}
+void f(T::type, int) { } // expected-warning {{implicit 'typename' is a C++2a extension}}
 
 template<typename T>
-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<typename T>
-void f(int, T::type) { } // expected-error{{missing 'typename'}}
+void f(int, T::type) { } // expected-warning {{implicit 'typename' is a C++2a extension}}
 
 template<typename T>
-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<typename T>
-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<typename T>
-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<typename T> int A<T>::n(T::value); // ok
 template<typename T>
-A<T>::type // expected-error{{missing 'typename'}}
+A<T>::type // expected-warning {{implicit 'typename' is a C++2a extension}}
 A<T>::m(T::value, 0); // ok
 
-template<typename T> int A<T>::h(T::type, int) {} // expected-error{{missing 'typename'}}
-template<typename T> int A<T>::h(T::type x, char) {} // expected-error{{missing 'typename'}}
+template<typename T> int A<T>::h(T::type, int) {} // expected-warning {{implicit 'typename' is a C++2a extension}}
+template<typename T> int A<T>::h(T::type x, char) {} // expected-warning {{implicit 'typename' is a C++2a extension}}
 
-template<typename T> int h(T::type, int); // expected-error{{missing 'typename'}}
-template<typename T> int h(T::type x, char); // expected-error{{missing 'typename'}}
+template<typename T> int h(T::type, int); // expected-warning {{implicit 'typename' is a C++2a extension}}
+template<typename T> int h(T::type x, char); // expected-warning {{implicit 'typename' is a C++2a extension}}
 
 template<typename T> int junk1(T::junk);
 #if __cplusplus <= 201103L
 // expected-warning@-2 {{variable templates are a C++14 extension}}
 #endif
-template<typename T> int junk2(T::junk) throw(); // expected-error{{missing 'typename'}}
-template<typename T> int junk3(T::junk) = delete; // expected-error{{missing 'typename'}}
+template<typename T> int junk2(T::junk) throw(); // expected-warning {{implicit 'typename' is a C++2a extension}}
+template<typename T> 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<typename T> int junk4(T::junk j); // expected-error{{missing 'typename'}}
+template<typename T> 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 have been specified here. Provide
 //        a fix-it to add 'typename A<T>::type'
 template<typename T>
-A<T>::g() { } // expected-error{{requires a type specifier}}
+A<T>::g() { } // expected-error{{expected unqualified-id}}
+// expected-warning@-1{{implicit 'typename' is a C++2a extension}}
Index: test/SemaCXX/PR11358.cpp
===================================================================
--- test/SemaCXX/PR11358.cpp
+++ test/SemaCXX/PR11358.cpp
@@ -12,7 +12,7 @@
   struct Test {
     typedef container<T> Container;
     void test() {
-      Container::iterator i = c.begin(); // expected-error{{missing 'typename'}}
+      Container::iterator i = c.begin(); // expected-warning{{implicit 'typename' is a C++2a extension}}
     }
     Container c;
   };
@@ -28,7 +28,7 @@
 
   template <typename KeyType, typename ValueType>
   void MapTest(hash_map<KeyType, ValueType> map) {
-    for (hash_map<KeyType, ValueType>::const_iterator it = map.begin(); // expected-error{{missing 'typename'}}
+    for (hash_map<KeyType, ValueType>::const_iterator it = map.begin(); // expected-warning {{implicit 'typename' is a C++2a extension}}
          it != map.end(); it++) {
     }
   }
@@ -44,7 +44,7 @@
   struct Test {
     typedef container<T> Container;
     void test() {
-      Container::iterator const i; // expected-error{{missing 'typename'}}
+      Container::iterator const i; // expected-warning {{implicit 'typename' is a C++2a extension}}
     }
     Container c;
   };
Index: test/SemaCXX/MicrosoftSuper.cpp
===================================================================
--- test/SemaCXX/MicrosoftSuper.cpp
+++ test/SemaCXX/MicrosoftSuper.cpp
@@ -108,15 +108,15 @@
   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;
     typedef typename __super::XXX f;
 
-    __super::XXX g;         // expected-error {{missing 'typename'}}
-    typedef __super::XXX h; // expected-error {{missing 'typename'}}
+    __super::XXX g;         // expected-warning {{implicit 'typename' is a C++2a extension}}
+    typedef __super::XXX h; // expected-warning {{implicit 'typename' is a C++2a extension}}
 
     int x = __super::foo();
   }
@@ -127,15 +127,15 @@
   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;
     typedef typename __super::XXX f;
 
-    __super::XXX g;         // expected-error {{missing 'typename'}}
-    typedef __super::XXX h; // expected-error {{missing 'typename'}}
+    __super::XXX g;         // expected-warning {{implicit 'typename' is a C++2a extension}}
+    typedef __super::XXX h; // expected-warning {{implicit 'typename' is a C++2a extension}}
 
     __super::foo(1);
   }
Index: test/SemaCXX/MicrosoftExtensions.cpp
===================================================================
--- test/SemaCXX/MicrosoftExtensions.cpp
+++ test/SemaCXX/MicrosoftExtensions.cpp
@@ -526,7 +526,7 @@
 
 namespace PR32750 {
 template<typename T> struct A {};
-template<typename T> struct B : A<A<T>> { A<T>::C::D d; }; // expected-error {{missing 'typename' prior to dependent type name 'A<T>::C::D'}}
+template<typename T> struct B : A<A<T>> { A<T>::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<U> Base2;
    typedef A<U> Base3;
 
-   A<T>::TYPE a1; // expected-warning {{missing 'typename' prior to dependent type name}}
-   Base1::TYPE a2; // expected-warning {{missing 'typename' prior to dependent type name}}
+   A<T>::TYPE a1; // expected-warning {{implicit 'typename' is a C++2a extension}}
+   Base1::TYPE a2; // expected-warning {{implicit 'typename' is a C++2a extension}}
 
-   B<U>::TYPE a3; // expected-warning {{missing 'typename' prior to dependent type name}}
-   Base2::TYPE a4; // expected-warning {{missing 'typename' prior to dependent type name}}
+   B<U>::TYPE a3; // expected-warning {{implicit 'typename' is a C++2a extension}}
+   Base2::TYPE a4; // expected-warning {{implicit 'typename' is a C++2a extension}}
 
-   A<U>::TYPE a5; // expected-error {{missing 'typename' prior to dependent type name}}
-   Base3::TYPE a6; // expected-error {{missing 'typename' prior to dependent type name}}
+   A<U>::TYPE a5; // expected-warning {{implicit 'typename' is a C++2a extension}}
+   Base3::TYPE a6; // expected-warning {{implicit 'typename' is a C++2a extension}}
  };
 
 class D {
 public:
     typedef int Type;
 };
 
 template <class T>
-void function_missing_typename(const T::Type param)// expected-warning {{missing 'typename' prior to dependent type name}}
+void function_missing_typename(const T::Type param)// expected-warning {{implicit 'typename' is a C++2a extension}}
 {
-    const T::Type var = 2; // expected-warning {{missing 'typename' prior to dependent type name}}
+    const T::Type var = 2; // expected-warning {{implicit 'typename' is a C++2a extension}}
 }
 
 template void function_missing_typename<D>(const D::Type param);
Index: test/FixIt/fixit.cpp
===================================================================
--- test/FixIt/fixit.cpp
+++ test/FixIt/fixit.cpp
@@ -208,13 +208,6 @@
   virtual void g(), // expected-error {{expected ';' at end of declaration}}
 };
 
-template<class T> struct Mystery;
-template<class T> typedef Mystery<T>::type getMysteriousThing() { // \
-  expected-error {{function definition declared 'typedef'}} \
-  expected-error {{missing 'typename' prior to dependent}}
-  return Mystery<T>::get();
-}
-
 template<template<typename> Foo, // expected-error {{template template parameter requires 'class' after the parameter list}}
          template<typename> typename Bar, // expected-warning {{template template parameter using 'typename' is a C++17 extension}}
          template<typename> struct Baz> // expected-error {{template template parameter requires 'class' after the parameter list}}
Index: test/CXX/temp/temp.res/temp.dep/temp.dep.type/p1.cpp
===================================================================
--- test/CXX/temp/temp.res/temp.dep/temp.dep.type/p1.cpp
+++ test/CXX/temp/temp.res/temp.dep/temp.dep.type/p1.cpp
@@ -1,4 +1,4 @@
-// RUN: %clang_cc1 -fsyntax-only -verify -std=c++11 %s 
+// RUN: %clang_cc1 -Wc++2a-compat -fsyntax-only -verify -std=c++11 %s 
 
 // Examples from CWG1056.
 namespace Example1 {
@@ -17,7 +17,7 @@
 
   template<class T> struct A<A<A<T>>> {
     struct C {};
-    B<B<T>>::C bc; // expected-error {{missing 'typename'}}
+    B<B<T>>::C bc; // expected-warning {{implicit 'typename' is a C++2a extension}}
   };
 }
 
Index: test/CXX/temp/temp.res/p5.cpp
===================================================================
--- /dev/null
+++ test/CXX/temp/temp.res/p5.cpp
@@ -0,0 +1,88 @@
+// RUN: %clang_cc1 -std=c++2a -pedantic -verify %s
+
+struct X {
+  using type = int;
+  static constexpr int value = 1;
+  class tclass {};
+};
+
+// [temp.res]p5
+//   A qualified-id is assumed to name a type if
+
+template <typename T>
+void f() {
+  // it is a qualified name in a type-id-only context (see below), or
+  // [it's smallest enclosing [/new/defining/]-type-id is]:
+  // - a new-type-id
+  auto *Ptr = new T::type();
+  // - a defining-type-id
+  class T::tclass Empty1;
+  T::tclass Empty2;
+  // - a trailing-return-type
+  auto f()->T::type;
+  // - default argument of a type-parameter of a template [see below]
+
+  // - type-id of a
+  // static_cast,
+  T::type StaticCast = static_cast<T::type>(1.2);
+  // const_cast,
+  const auto *ConstCast = const_cast<const T::type *>(Ptr);
+  // reinterpret_cast,
+  int ReinterpretCast = reinterpret_cast<T::type>(short(4.));
+  // dynamic_cast
+  struct B {
+    ~B() = default;
+  };
+  struct D : T::tclass {};
+  auto *Base = dynamic_cast<T::tclass>(new B);
+}
+
+// As default argument.
+template <typename T, typename = T::type>
+struct DefaultArg {};
+
+// it is a decl-specifier of the decl-specifier-seq of a
+// - simple-declaration or a function-definition in namespace scope
+template <typename T>
+T::type VarTemp = 1;
+
+template <typename T>
+T::type FuncDef() { return 1; }
+
+template <typename T>
+struct MemberDecl {
+  // member-declaration,
+  T::type Member;
+
+  // parameter-declaration in a member-declaration, unless that
+  // parameter-declaration appears in a default argument
+  void NoDefault(T::type);
+  void Default(int A = T::value);
+};
+
+// parameter-declaration in a declarator of a function or function template
+// declaration where the declarator-id is qualified, unless that
+// parameter-declaration appears in a default argument,
+struct QualifiedFunc {
+  template <typename T>
+  void foo(typename T::type); // No implicit typename here.
+};
+
+// FIXME: This is ok.
+template <typename T>
+void QualifiedFunc::foo(T::type) {} // expected-error{{out-of-line definition}}
+
+template <typename T>
+void g() {
+  // parameter-declaration in a lambda-declarator, unless that
+  // parameter-declaration appears in a default argument, or
+  auto Lambda1 = [](T::type) {};
+  auto Lambda2 = [](int A = T::value) {};
+}
+
+// parameter-declaration of a (non-type) template-parameter.
+template <typename T, T::type>
+void NonTypeArg();
+
+template <typename T>
+void var(T::type); // expected-error{{variable has incomplete type 'void'}}
Index: test/CXX/drs/dr5xx.cpp
===================================================================
--- test/CXX/drs/dr5xx.cpp
+++ test/CXX/drs/dr5xx.cpp
@@ -228,8 +228,8 @@
   template<int N> struct X {
     typedef int type;
     X<N>::type v1;
-    X<(N)>::type v2; // expected-error {{missing 'typename'}}
-    X<+N>::type v3; // expected-error {{missing 'typename'}}
+    X<(N)>::type v2; // expected-error {{implicit 'typename' is a C++2a extension}}
+    X<+N>::type v3; // expected-error {{implicit 'typename' is a C++2a extension}}
   };
 }
 
Index: test/CXX/drs/dr4xx.cpp
===================================================================
--- test/CXX/drs/dr4xx.cpp
+++ test/CXX/drs/dr4xx.cpp
@@ -173,7 +173,7 @@
     B b1;
     A::B b2;
     A<T>::B b3;
-    A<T*>::B b4; // expected-error {{missing 'typename'}}
+    A<T*>::B b4; // expected-error {{implicit 'typename' is a C++2a extension}}
   };
 }
 
Index: test/CXX/drs/dr2xx.cpp
===================================================================
--- test/CXX/drs/dr2xx.cpp
+++ test/CXX/drs/dr2xx.cpp
@@ -242,53 +242,53 @@
       typedef int type;
       A::type a;
       A<T>::type b;
-      A<T*>::type c; // expected-error {{missing 'typename'}}
+      A<T*>::type c; // expected-error {{implicit 'typename' is a C++2a extension}}
       ::dr224::example1::A<T>::type d;
 
       class B {
         typedef int type;
 
         A::type a;
         A<T>::type b;
-        A<T*>::type c; // expected-error {{missing 'typename'}}
+        A<T*>::type c; // expected-error {{implicit 'typename' is a C++2a extension}}
         ::dr224::example1::A<T>::type d;
 
         B::type e;
         A<T>::B::type f;
-        A<T*>::B::type g; // expected-error {{missing 'typename'}}
+        A<T*>::B::type g; // expected-error {{implicit 'typename' is a C++2a extension}}
         typename A<T*>::B::type h;
       };
     };
 
     template <class T> class A<T*> {
       typedef int type;
       A<T*>::type a;
-      A<T>::type b; // expected-error {{missing 'typename'}}
+      A<T>::type b; // expected-error {{implicit 'typename' is a C++2a extension}}
     };
 
     template <class T1, class T2, int I> struct B {
       typedef int type;
       B<T1, T2, I>::type b1;
-      B<T2, T1, I>::type b2; // expected-error {{missing 'typename'}}
+      B<T2, T1, I>::type b2; // expected-error {{implicit 'typename' is a C++2a extension}}
 
       typedef T1 my_T1;
       static const int my_I = I;
       static const int my_I2 = I+0;
       static const int my_I3 = my_I;
-      B<my_T1, T2, my_I>::type b3; // FIXME: expected-error {{missing 'typename'}}
-      B<my_T1, T2, my_I2>::type b4; // expected-error {{missing 'typename'}}
-      B<my_T1, T2, my_I3>::type b5; // FIXME: expected-error {{missing 'typename'}}
+      B<my_T1, T2, my_I>::type b3; // FIXME: expected-error {{implicit 'typename' is a C++2a extension}}
+      B<my_T1, T2, my_I2>::type b4; // expected-error {{implicit 'typename' is a C++2a extension}}
+      B<my_T1, T2, my_I3>::type b5; // FIXME: expected-error {{implicit 'typename' is a C++2a extension}}
     };
   }
 
   namespace example2 {
     template <int, typename T> struct X { typedef T type; };
     template <class T> class A {
       static const int i = 5;
-      X<i, int>::type w; // FIXME: expected-error {{missing 'typename'}}
-      X<A::i, char>::type x; // FIXME: expected-error {{missing 'typename'}}
-      X<A<T>::i, double>::type y; // FIXME: expected-error {{missing 'typename'}}
-      X<A<T*>::i, long>::type z; // expected-error {{missing 'typename'}}
+      X<i, int>::type w; // FIXME: expected-error {{implicit 'typename' is a C++2a extension}}
+      X<A::i, char>::type x; // FIXME: expected-error {{implicit 'typename' is a C++2a extension}}
+      X<A<T>::i, double>::type y; // FIXME: expected-error {{implicit 'typename' is a C++2a extension}}
+      X<A<T*>::i, long>::type z; // expected-error {{implicit 'typename' is a C++2a extension}}
       int f();
     };
     template <class T> int A<T>::f() {
Index: test/CXX/drs/dr1xx.cpp
===================================================================
--- test/CXX/drs/dr1xx.cpp
+++ test/CXX/drs/dr1xx.cpp
@@ -58,7 +58,7 @@
 namespace dr108 { // dr108: yes
   template<typename T> struct A {
     struct B { typedef int X; };
-    B::X x; // expected-error {{missing 'typename'}}
+    B::X x; // expected-error {{implicit 'typename' is a C++2a extension}}
     struct C : B { X x; }; // expected-error {{unknown type name}}
   };
   template<> struct A<int>::B { int X; };
Index: lib/Sema/SemaDecl.cpp
===================================================================
--- lib/Sema/SemaDecl.cpp
+++ lib/Sema/SemaDecl.cpp
@@ -281,6 +281,7 @@
                              bool IsCtorOrDtorName,
                              bool WantNontrivialTypeSourceInfo,
                              bool IsClassTemplateDeductionContext,
+                             bool AllowImplicitTypename,
                              IdentifierInfo **CorrectedII) {
   // FIXME: Consider allowing this outside C++1z mode as an extension.
   bool AllowDeducedTemplate = IsClassTemplateDeductionContext &&
@@ -307,9 +308,16 @@
         //
         // We therefore do not perform any name lookup if the result would
         // refer to a member of an unknown specialization.
-        if (!isClassName && !IsCtorOrDtorName)
+        // In C++2a, in several contexts a 'typename' is not required. Also
+        // allow this as an extension.
+        if (!AllowImplicitTypename && !isClassName && !IsCtorOrDtorName)
           return nullptr;
 
+        if (!isClassName && !IsCtorOrDtorName)
+          Diag(NameLoc, getLangOpts().CPlusPlus2a
+                            ? diag::warn_cxx17_compat_implicit_typename
+                            : diag::ext_implicit_typename);
+
         // We know from the grammar that this name refers to a type,
         // so build a dependent node to describe the type.
         if (WantNontrivialTypeSourceInfo)
@@ -395,7 +403,8 @@
                                     isClassName, HasTrailingDot, ObjectTypePtr,
                                     IsCtorOrDtorName,
                                     WantNontrivialTypeSourceInfo,
-                                    IsClassTemplateDeductionContext);
+                                    IsClassTemplateDeductionContext,
+                                    AllowImplicitTypename);
         if (Ty) {
           diagnoseTypo(Correction,
                        PDiag(diag::err_unknown_type_or_class_name_suggest)
Index: lib/Parse/Parser.cpp
===================================================================
--- lib/Parse/Parser.cpp
+++ lib/Parse/Parser.cpp
@@ -1774,7 +1774,8 @@
             false, NextToken().is(tok::period), nullptr,
             /*IsCtorOrDtorName=*/false,
             /*NonTrivialTypeSourceInfo*/true,
-            /*IsClassTemplateDeductionContext*/true)) {
+            /*IsClassTemplateDeductionContext*/true,
+            /*AllowImplicitTypename*/false)) {
       SourceLocation BeginLoc = Tok.getLocation();
       if (SS.isNotEmpty()) // it was a C++ qualified type name.
         BeginLoc = SS.getBeginLoc();
Index: lib/Parse/ParseDeclCXX.cpp
===================================================================
--- lib/Parse/ParseDeclCXX.cpp
+++ lib/Parse/ParseDeclCXX.cpp
@@ -1175,7 +1175,8 @@
       *Id, IdLoc, getCurScope(), &SS, /*IsClassName=*/true, false, nullptr,
       /*IsCtorOrDtorName=*/false,
       /*NonTrivialTypeSourceInfo=*/true,
-      /*IsClassTemplateDeductionContext*/ false, &CorrectedII);
+      /*IsClassTemplateDeductionContext*/ false,
+      /*AllowImplicitTypename*/true, &CorrectedII);
   if (!Type) {
     Diag(IdLoc, diag::err_expected_class_name);
     return true;
Index: lib/Parse/ParseDecl.cpp
===================================================================
--- lib/Parse/ParseDecl.cpp
+++ lib/Parse/ParseDecl.cpp
@@ -3101,7 +3101,8 @@
                               getCurScope(), &SS, false, false, nullptr,
                               /*IsCtorOrDtorName=*/false,
                               /*WantNonTrivialSourceInfo=*/true,
-                              isClassTemplateDeductionContext(DSContext));
+                              isClassTemplateDeductionContext(DSContext),
+                              /*AllowImplicitTypename=*/true);
 
       // If the referenced identifier is not a type, then this declspec is
       // erroneous: We already checked about that it has no type specifier, and
Index: include/clang/Sema/Sema.h
===================================================================
--- include/clang/Sema/Sema.h
+++ include/clang/Sema/Sema.h
@@ -1698,6 +1698,7 @@
                          bool IsCtorOrDtorName = false,
                          bool WantNontrivialTypeSourceInfo = false,
                          bool IsClassTemplateDeductionContext = true,
+                         bool AllowImplicitTypename = false,
                          IdentifierInfo **CorrectedII = nullptr);
   TypeSpecifierType isTagName(IdentifierInfo &II, Scope *S);
   bool isMicrosoftMissingTypename(const CXXScopeSpec *SS, Scope *S);
Index: include/clang/Basic/DiagnosticSemaKinds.td
===================================================================
--- include/clang/Basic/DiagnosticSemaKinds.td
+++ include/clang/Basic/DiagnosticSemaKinds.td
@@ -4456,6 +4456,11 @@
   "%0 in %1">;
 def note_using_value_decl_missing_typename : Note<
   "add 'typename' to treat this using declaration as a type">;
+def warn_cxx17_compat_implicit_typename : Warning<"use of implicit 'typename' is "
+  "incompatible with C++ standards before C++2a">, InGroup<CXX2aCompat>,
+  DefaultIgnore;
+def ext_implicit_typename : ExtWarn<"implicit 'typename' is a C++2a extension">,
+  InGroup<CXX2a>;
 
 def err_template_kw_refers_to_non_template : Error<
   "%0 following the 'template' keyword does not refer to a template">;
_______________________________________________
cfe-commits mailing list
cfe-commits@lists.llvm.org
http://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits

Reply via email to