Rakete1111 updated this revision to Diff 200423.
Rakete1111 marked 10 inline comments as done.
Rakete1111 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<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'}}
@@ -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<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'}}
@@ -118,4 +116,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: 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
===================================================================
--- clang/test/SemaCXX/MicrosoftExtensions.cpp
+++ clang/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: clang/test/SemaCXX/MicrosoftCompatibility.cpp
===================================================================
--- clang/test/SemaCXX/MicrosoftCompatibility.cpp
+++ clang/test/SemaCXX/MicrosoftCompatibility.cpp
@@ -199,14 +199,14 @@
    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 {
@@ -215,9 +215,9 @@
 };
 
 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 {{missing 'typename'}}
 {
-    const T::Type var = 2; // expected-warning {{missing 'typename' prior to dependent type name}}
+    const T::Type var = 2; // expected-warning {{missing 'typename'}}
 }
 
 template void function_missing_typename<D>(const D::Type param);
Index: clang/test/Parser/editor-placeholder-recovery.cpp
===================================================================
--- clang/test/Parser/editor-placeholder-recovery.cpp
+++ clang/test/Parser/editor-placeholder-recovery.cpp
@@ -64,7 +64,7 @@
     }
 }
 
-void Struct::method(<#Struct &x#>, noSupressionHere) { // expected-error {{unknown type name 'noSupressionHere'}} expected-error {{C++ requires a type specifier for all declarations}}
+void Struct::method(<#Struct &x#>, noSupressionHere) { // expected-error {{unknown type name 'noSupressionHere'}}
 #ifndef SUPPRESS
   // expected-error@-2 {{editor placeholder in source file}}
 #endif
Index: clang/test/Parser/cxx-member-initializers.cpp
===================================================================
--- clang/test/Parser/cxx-member-initializers.cpp
+++ clang/test/Parser/cxx-member-initializers.cpp
@@ -103,5 +103,5 @@
   void l(int x = C<int, C<int, int>::C1>().f()) {}
 
   // This isn't, but it shouldn't crash. The diagnostics don't matter much.
-  void m(int x = C<int, union int>().f()) {} // expected-error {{declaration of anonymous union must be a definition}} expected-error {{expected a type}}
+  void m(int x = C<int, union int>().f()) {} // expected-error {{declaration of anonymous union must be a definition}} expected-error {{type name requires a specifier or qualifier}}
 };
Index: clang/test/FixIt/fixit.cpp
===================================================================
--- clang/test/FixIt/fixit.cpp
+++ clang/test/FixIt/fixit.cpp
@@ -211,7 +211,7 @@
 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}}
+  expected-warning {{implicit 'typename' is a C++2a extension}}
   return Mystery<T>::get();
 }
 
Index: clang/test/CXX/temp/temp.res/temp.dep/temp.dep.type/p1.cpp
===================================================================
--- clang/test/CXX/temp/temp.res/temp.dep/temp.dep.type/p1.cpp
+++ clang/test/CXX/temp/temp.res/temp.dep/temp.dep.type/p1.cpp
@@ -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: clang/test/CXX/temp/temp.res/p5.cpp
===================================================================
--- /dev/null
+++ clang/test/CXX/temp/temp.res/p5.cpp
@@ -0,0 +1,159 @@
+// 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
+  // [its 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; // expected-error{{missing 'typename'}}
+  // - 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,
+  auto 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>(4);
+  // dynamic_cast
+  struct B {
+    virtual ~B() = default;
+  };
+  struct D : T::tclass {};
+  auto *Base = dynamic_cast<T::tclass *>(new B);
+
+  T::type Invalid; // expected-error{{missing 'typename'}}
+}
+
+template void f<X>();
+
+// As default argument.
+template <typename T, typename = T::type>
+struct DefaultArg {};
+
+template struct DefaultArg<X>;
+
+// 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 int VarTemp<X>;
+
+template <typename T>
+T::type FuncDef() { return 1; }
+
+template int FuncDef<X>();
+
+template <typename T>
+T::type funcDecl();
+
+template <typename T>
+void FuncParam(T::type); // ok, but variable template
+// expected-error@-1{{variable has incomplete type 'void'}}
+
+template <typename T>
+void FuncParam2(const T::type, int); // expected-error{{missing 'typename'}}
+
+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);
+};
+
+template struct MemberDecl<X>;
+
+// 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);
+  template <typename T>
+  void bar(T::type);
+};
+
+template <typename T>
+void QualifiedFunc::foo(T::type) {}
+template <typename T>
+void QualifiedFunc::bar(typename T::type) {}
+
+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) {};
+}
+
+template void g<X>();
+
+// parameter-declaration of a (non-type) template-parameter.
+template <typename T, T::type>
+void NonTypeArg() {}
+
+template void NonTypeArg<X, 0>();
+
+template <typename T>
+void f(T::type) {} // expected-error {{missing 'typename'}}
+
+namespace N {
+  template <typename T>
+  int f(typename T::type);
+  template <typename T>
+  extern int Var;
+}
+
+template <typename T>
+int N::f(T::type); // ok, function
+template <typename T>
+int N::Var(T::value); // ok, variable
+
+int h() {
+  return N::f<X>(10) + N::Var<X>;
+}
+
+namespace NN {
+  inline namespace A { template <typename T> int f(typename T::type); } // expected-note{{previous definition is here}}
+  inline namespace B { template <typename T> int f(T::type); }
+}
+
+template <typename T>
+int NN::f(T::type); // expected-error{{redefinition of 'f' as different kind of symbol}}
+
+template <auto V>
+struct videntity {
+  static constexpr auto value = V;
+};
+
+template <typename T,
+    bool = T::value,
+    bool = bool(T::value),
+    bool = videntity<bool(T::value)>::value>
+void f(int = T::value) {}
+
+template <typename> int test() = delete;
+template <auto> int test();
+
+template <typename T>
+int Test = test<int(T::value)>();
+template int Test<X>;
Index: clang/test/CXX/drs/dr5xx.cpp
===================================================================
--- clang/test/CXX/drs/dr5xx.cpp
+++ clang/test/CXX/drs/dr5xx.cpp
@@ -2,6 +2,7 @@
 // RUN: %clang_cc1 -std=c++11 %s -verify -fexceptions -fcxx-exceptions -pedantic-errors
 // RUN: %clang_cc1 -std=c++14 %s -verify -fexceptions -fcxx-exceptions -pedantic-errors
 // RUN: %clang_cc1 -std=c++17 %s -verify -fexceptions -fcxx-exceptions -pedantic-errors
+// RUN: %clang_cc1 -std=c++2a %s -verify -fexceptions -fcxx-exceptions -pedantic-errors
 
 // FIXME: This is included to avoid a diagnostic with no source location
 // pointing at the implicit operator new. We can't match such a diagnostic
@@ -228,8 +229,12 @@
   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;
+    X<+N>::type v3;
+#if __cplusplus <= 201703L
+    // expected-error@-3 {{implicit 'typename' is a C++2a extension}}
+    // expected-error@-3 {{implicit 'typename' is a C++2a extension}}
+#endif
   };
 }
 
@@ -477,7 +482,7 @@
 }
 
 namespace dr542 { // dr542: yes
-#if __cplusplus >= 201103L
+#if __cplusplus >= 201103L && __cplusplus <= 201703L
   struct A { A() = delete; int n; };
   A a[32] = {}; // ok, constructor not called
 
Index: clang/test/CXX/drs/dr4xx.cpp
===================================================================
--- clang/test/CXX/drs/dr4xx.cpp
+++ clang/test/CXX/drs/dr4xx.cpp
@@ -2,6 +2,7 @@
 // RUN: env ASAN_OPTIONS=detect_stack_use_after_return=0 %clang_cc1 -std=c++11 %s -verify -fexceptions -fcxx-exceptions -pedantic-errors
 // RUN: env ASAN_OPTIONS=detect_stack_use_after_return=0 %clang_cc1 -std=c++14 %s -verify -fexceptions -fcxx-exceptions -pedantic-errors
 // RUN: env ASAN_OPTIONS=detect_stack_use_after_return=0 %clang_cc1 -std=c++17 %s -verify -fexceptions -fcxx-exceptions -pedantic-errors
+// RUN: env ASAN_OPTIONS=detect_stack_use_after_return=0 %clang_cc1 -std=c++2a %s -verify -fexceptions -fcxx-exceptions -pedantic-errors
 
 // FIXME: __SIZE_TYPE__ expands to 'long long' on some targets.
 __extension__ typedef __SIZE_TYPE__ size_t;
@@ -173,7 +174,10 @@
     B b1;
     A::B b2;
     A<T>::B b3;
-    A<T*>::B b4; // expected-error {{missing 'typename'}}
+    A<T*>::B b4;
+#if __cplusplus <= 201703L
+    // expected-error@-2 {{implicit 'typename' is a C++2a extension}}
+#endif
   };
 }
 
Index: clang/test/CXX/drs/dr2xx.cpp
===================================================================
--- clang/test/CXX/drs/dr2xx.cpp
+++ clang/test/CXX/drs/dr2xx.cpp
@@ -2,6 +2,7 @@
 // RUN: %clang_cc1 -std=c++11 %s -verify -fexceptions -fcxx-exceptions -pedantic-errors
 // RUN: %clang_cc1 -std=c++14 %s -verify -fexceptions -fcxx-exceptions -pedantic-errors
 // RUN: %clang_cc1 -std=c++17 %s -verify -fexceptions -fcxx-exceptions -pedantic-errors
+// RUN: %clang_cc1 -std=c++2a %s -verify -fexceptions -fcxx-exceptions -pedantic-errors
 
 // PR13819 -- __SIZE_TYPE__ is incompatible.
 typedef __SIZE_TYPE__ size_t; // expected-error 0-1 {{extension}}
@@ -242,7 +243,10 @@
       typedef int type;
       A::type a;
       A<T>::type b;
-      A<T*>::type c; // expected-error {{missing 'typename'}}
+      A<T*>::type c; 
+#if __cplusplus <= 201703L
+      // expected-error@-2 {{implicit 'typename' is a C++2a extension}}
+#endif
       ::dr224::example1::A<T>::type d;
 
       class B {
@@ -250,12 +254,18 @@
 
         A::type a;
         A<T>::type b;
-        A<T*>::type c; // expected-error {{missing 'typename'}}
+        A<T*>::type c;
+#if __cplusplus <= 201703L
+        // expected-error@-2 {{implicit 'typename' is a C++2a extension}}
+#endif
         ::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;
+#if __cplusplus <= 201703L
+        // expected-error@-2 {{implicit 'typename' is a C++2a extension}}
+#endif
         typename A<T*>::B::type h;
       };
     };
@@ -263,21 +273,32 @@
     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;
+#if __cplusplus <= 201703L
+        // expected-error@-2 {{implicit 'typename' is a C++2a extension}}
+#endif
     };
 
     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;
+#if __cplusplus <= 201703L
+      // expected-error@-2 {{implicit 'typename' is a C++2a extension}}
+#endif
 
       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;
+      B<my_T1, T2, my_I2>::type b4;
+      B<my_T1, T2, my_I3>::type b5;
+#if __cplusplus <= 201703L
+      // FIXME: expected-error@-4 {{implicit 'typename' is a C++2a extension}}
+      // expected-error@-4 {{implicit 'typename' is a C++2a extension}}
+      // FIXME: expected-error@-4 {{implicit 'typename' is a C++2a extension}}
+#endif
     };
   }
 
@@ -285,10 +306,16 @@
     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;
+      X<A::i, char>::type x;
+      X<A<T>::i, double>::type y;
+      X<A<T*>::i, long>::type z;
+#if __cplusplus <= 201703L
+      // FIXME: expected-error@-5 {{implicit 'typename' is a C++2a extension}}
+      // FIXME: expected-error@-5 {{implicit 'typename' is a C++2a extension}}
+      // FIXME: expected-error@-5 {{implicit 'typename' is a C++2a extension}}
+      // expected-error@-5 {{implicit 'typename' is a C++2a extension}}
+#endif
       int f();
     };
     template <class T> int A<T>::f() {
Index: clang/test/CXX/drs/dr1xx.cpp
===================================================================
--- clang/test/CXX/drs/dr1xx.cpp
+++ clang/test/CXX/drs/dr1xx.cpp
@@ -2,6 +2,7 @@
 // RUN: %clang_cc1 -std=c++11 -triple x86_64-unknown-unknown %s -verify -fexceptions -fcxx-exceptions -pedantic-errors
 // RUN: %clang_cc1 -std=c++14 -triple x86_64-unknown-unknown %s -verify -fexceptions -fcxx-exceptions -pedantic-errors
 // RUN: %clang_cc1 -std=c++17 -triple x86_64-unknown-unknown %s -verify -fexceptions -fcxx-exceptions -pedantic-errors
+// RUN: %clang_cc1 -std=c++2a -triple x86_64-unknown-unknown %s -verify -fexceptions -fcxx-exceptions -pedantic-errors
 
 namespace dr100 { // dr100: yes
   template<const char *> struct A {}; // expected-note 0-1{{declared here}}
@@ -58,7 +59,10 @@
 namespace dr108 { // dr108: yes
   template<typename T> struct A {
     struct B { typedef int X; };
-    B::X x; // expected-error {{missing 'typename'}}
+    B::X x;
+#if __cplusplus <= 201703L
+    // expected-error@-2 {{implicit 'typename' is a C++2a extension}}
+#endif
     struct C : B { X x; }; // expected-error {{unknown type name}}
   };
   template<> struct A<int>::B { int X; };
Index: clang/lib/Sema/SemaTemplate.cpp
===================================================================
--- clang/lib/Sema/SemaTemplate.cpp
+++ clang/lib/Sema/SemaTemplate.cpp
@@ -9483,10 +9483,11 @@
   return CreateParsedType(Result, TLB.getTypeSourceInfo(Context, Result));
 }
 
-TypeResult
-Sema::ActOnTypenameType(Scope *S, SourceLocation TypenameLoc,
-                        const CXXScopeSpec &SS, const IdentifierInfo &II,
-                        SourceLocation IdLoc) {
+TypeResult Sema::ActOnTypenameType(Scope *S, SourceLocation TypenameLoc,
+                                   const CXXScopeSpec &SS,
+                                   const IdentifierInfo &II,
+                                   SourceLocation IdLoc,
+                                   ImplicitTypenameContext IsImplicitTypename) {
   if (SS.isInvalid())
     return true;
 
@@ -9498,8 +9499,9 @@
       << FixItHint::CreateRemoval(TypenameLoc);
 
   NestedNameSpecifierLoc QualifierLoc = SS.getWithLocInContext(Context);
-  QualType T = CheckTypenameType(TypenameLoc.isValid()? ETK_Typename : ETK_None,
-                                 TypenameLoc, QualifierLoc, II, IdLoc);
+  QualType T = CheckTypenameType(
+      (TypenameLoc.isValid() || IsImplicitTypename) ? ETK_Typename : ETK_None,
+      TypenameLoc, QualifierLoc, II, IdLoc);
   if (T.isNull())
     return true;
 
Index: clang/lib/Sema/SemaDecl.cpp
===================================================================
--- clang/lib/Sema/SemaDecl.cpp
+++ clang/lib/Sema/SemaDecl.cpp
@@ -280,6 +280,7 @@
                              bool IsCtorOrDtorName,
                              bool WantNontrivialTypeSourceInfo,
                              bool IsClassTemplateDeductionContext,
+                             ImplicitTypenameContext AllowImplicitTypename,
                              IdentifierInfo **CorrectedII) {
   // FIXME: Consider allowing this outside C++1z mode as an extension.
   bool AllowDeducedTemplate = IsClassTemplateDeductionContext &&
@@ -306,17 +307,32 @@
         //
         // 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;
+        bool IsImplicitTypename = !isClassName && !IsCtorOrDtorName;
+        if (IsImplicitTypename) {
+          SourceLocation QualifiedLoc = SS->getRange().getBegin();
+          if (getLangOpts().CPlusPlus2a)
+            Diag(QualifiedLoc, diag::warn_cxx17_compat_implicit_typename);
+          else
+            Diag(QualifiedLoc, diag::ext_implicit_typename)
+                << SS->getScopeRep() << II.getName()
+                << FixItHint::CreateInsertion(QualifiedLoc, "typename ");
+        }
 
         // We know from the grammar that this name refers to a type,
         // so build a dependent node to describe the type.
         if (WantNontrivialTypeSourceInfo)
-          return ActOnTypenameType(S, SourceLocation(), *SS, II, NameLoc).get();
+          return ActOnTypenameType(S, SourceLocation(), *SS, II, NameLoc,
+                                   (ImplicitTypenameContext)IsImplicitTypename)
+              .get();
 
         NestedNameSpecifierLoc QualifierLoc = SS->getWithLocInContext(Context);
-        QualType T = CheckTypenameType(ETK_None, SourceLocation(), QualifierLoc,
-                                       II, NameLoc);
+        QualType T =
+            CheckTypenameType(IsImplicitTypename ? ETK_Typename : ETK_None,
+                              SourceLocation(), QualifierLoc, II, NameLoc);
         return ParsedType::make(T);
       }
 
@@ -5438,7 +5454,10 @@
 
     LookupName(Previous, S, CreateBuiltins);
   } else { // Something like "int foo::x;"
-    LookupQualifiedName(Previous, DC);
+    if (D.hasPrevLookupResult())
+      Previous = D.consumePrevLookupResult();
+    else
+      LookupQualifiedName(Previous, DC);
 
     // C++ [dcl.meaning]p1:
     //   When the declarator-id is qualified, the declaration shall refer to a
Index: clang/lib/Sema/Sema.cpp
===================================================================
--- clang/lib/Sema/Sema.cpp
+++ clang/lib/Sema/Sema.cpp
@@ -39,6 +39,7 @@
 #include "clang/Sema/TemplateInstCallback.h"
 #include "llvm/ADT/DenseMap.h"
 #include "llvm/ADT/SmallSet.h"
+#include "llvm/ADT/STLExtras.h"
 using namespace clang;
 using namespace sema;
 
@@ -2191,3 +2192,30 @@
   return checkOpenCLDisabledTypeOrDecl(&D, E.getBeginLoc(), FnName,
                                        OpenCLDeclExtMap, 1, D.getSourceRange());
 }
+
+bool Sema::isDeclaratorFunctionLike(Declarator &D) {
+  assert(D.getCXXScopeSpec().isSet() &&
+         "can only be called for qualified names");
+  assert(!D.hasPrevLookupResult() && "we looked this up already");
+
+  LookupResult LR(*this, D.getIdentifier(), D.getBeginLoc(), LookupOrdinaryName,
+                  forRedeclarationInCurContext());
+  DeclContext *DC = computeDeclContext(D.getCXXScopeSpec(),
+                                       !D.getDeclSpec().isFriendSpecified());
+  if (!DC)
+    return false;
+
+  LookupQualifiedName(LR, DC);
+  bool Result = std::all_of(LR.begin(), LR.end(), [](Decl *Dcl) {
+    if (NamedDecl *ND = dyn_cast<NamedDecl>(Dcl)) {
+      ND = ND->getUnderlyingDecl();
+      return isa<FunctionDecl>(ND) || isa<FunctionTemplateDecl>(ND) ||
+             isa<UsingDecl>(ND);
+    }
+    return false;
+  });
+
+  
+  D.setPrevLookupResult(llvm::make_unique<LookupResult>(std::move(LR)));
+  return Result;
+}
Index: clang/lib/Sema/DeclSpec.cpp
===================================================================
--- clang/lib/Sema/DeclSpec.cpp
+++ clang/lib/Sema/DeclSpec.cpp
@@ -18,9 +18,11 @@
 #include "clang/AST/TypeLoc.h"
 #include "clang/Basic/LangOptions.h"
 #include "clang/Basic/TargetInfo.h"
+#include "clang/Sema/Lookup.h"
 #include "clang/Sema/ParsedTemplate.h"
 #include "clang/Sema/Sema.h"
 #include "clang/Sema/SemaDiagnostic.h"
+#include "clang/Sema/Lookup.h"
 #include "llvm/ADT/STLExtras.h"
 #include "llvm/ADT/SmallString.h"
 #include <cstring>
@@ -1343,6 +1345,31 @@
   }
 }
 
+
+Declarator::Declarator(const DeclSpec &ds, DeclaratorContext C)
+      : DS(ds), Range(ds.getSourceRange()), Context(C),
+        InvalidType(DS.getTypeSpecType() == DeclSpec::TST_error),
+        GroupingParens(false), FunctionDefinition(FDK_Declaration),
+        Redeclaration(false), Extension(false), ObjCIvar(false),
+        ObjCWeakProperty(false), InlineStorageUsed(false),
+        Attrs(ds.getAttributePool().getFactory()), AsmLabel(nullptr),
+        PrevLookupResult(nullptr) {}
+
+Declarator::~Declarator() {
+  clear();
+}
+
+void Declarator::setPrevLookupResult(std::unique_ptr<LookupResult> LR) {
+  PrevLookupResult = std::move(LR);
+}
+
+LookupResult Declarator::consumePrevLookupResult() {
+  assert(PrevLookupResult);
+  LookupResult LR = std::move(*PrevLookupResult);
+  PrevLookupResult.reset();
+  return std::move(LR);
+}
+
 bool VirtSpecifiers::SetSpecifier(Specifier VS, SourceLocation Loc,
                                   const char *&PrevSpec) {
   if (!FirstLocation.isValid())
Index: clang/lib/Parse/Parser.cpp
===================================================================
--- clang/lib/Parse/Parser.cpp
+++ clang/lib/Parse/Parser.cpp
@@ -889,7 +889,7 @@
   // Handle K&R C argument lists: int X(f) int f; {}
   if (!getLangOpts().CPlusPlus &&
       Declarator.getFunctionTypeInfo().isKNRPrototype())
-    return isDeclarationSpecifier();
+    return isDeclarationSpecifier(ITC_Never);
 
   if (getLangOpts().CPlusPlus && Tok.is(tok::equal)) {
     const Token &KW = NextToken();
@@ -1280,7 +1280,7 @@
                             Scope::FunctionDeclarationScope | Scope::DeclScope);
 
   // Read all the argument declarations.
-  while (isDeclarationSpecifier()) {
+  while (isDeclarationSpecifier(ITC_Never)) {
     SourceLocation DSStart = Tok.getLocation();
 
     // Parse the common declaration-specifiers piece.
@@ -1486,9 +1486,13 @@
 ///        and might possibly have a dependent nested name specifier.
 /// \param CCC Indicates how to perform typo-correction for this name. If NULL,
 ///        no typo correction will be performed.
+/// \param AllowImplicitTypename Whether we are in a context where a dependent
+///        nested-name-specifier without typename is treated as a type (e.g.
+///        T::type).
 Parser::AnnotatedNameKind
 Parser::TryAnnotateName(bool IsAddressOfOperand,
-                        std::unique_ptr<CorrectionCandidateCallback> CCC) {
+                        std::unique_ptr<CorrectionCandidateCallback> CCC,
+                        ImplicitTypenameContext AllowImplicitTypename) {
   assert(Tok.is(tok::identifier) || Tok.is(tok::annot_cxxscope));
 
   const bool EnteringContext = false;
@@ -1500,7 +1504,8 @@
     return ANK_Error;
 
   if (Tok.isNot(tok::identifier) || SS.isInvalid()) {
-    if (TryAnnotateTypeOrScopeTokenAfterScopeSpec(SS, !WasScopeAnnotation))
+    if (TryAnnotateTypeOrScopeTokenAfterScopeSpec(SS, !WasScopeAnnotation,
+                                                  AllowImplicitTypename))
       return ANK_Error;
     return ANK_Unresolved;
   }
@@ -1510,10 +1515,11 @@
 
   // FIXME: Move the tentative declaration logic into ClassifyName so we can
   // typo-correct to tentatively-declared identifiers.
-  if (isTentativelyDeclared(Name)) {
+  if (isTentativelyDeclared(Name) && SS.isEmpty()) {
     // Identifier has been tentatively declared, and thus cannot be resolved as
     // an expression. Fall back to annotating it as a type.
-    if (TryAnnotateTypeOrScopeTokenAfterScopeSpec(SS, !WasScopeAnnotation))
+    if (TryAnnotateTypeOrScopeTokenAfterScopeSpec(SS, !WasScopeAnnotation,
+                                                  AllowImplicitTypename))
       return ANK_Error;
     return Tok.is(tok::annot_typename) ? ANK_Success : ANK_TentativeDecl;
   }
@@ -1651,7 +1657,8 @@
 ///
 /// Note that this routine emits an error if you call it with ::new or ::delete
 /// as the current tokens, so only call it in contexts where these are invalid.
-bool Parser::TryAnnotateTypeOrScopeToken() {
+bool Parser::TryAnnotateTypeOrScopeToken(
+    ImplicitTypenameContext AllowImplicitTypename) {
   assert((Tok.is(tok::identifier) || Tok.is(tok::coloncolon) ||
           Tok.is(tok::kw_typename) || Tok.is(tok::annot_cxxscope) ||
           Tok.is(tok::kw_decltype) || Tok.is(tok::annot_template_id) ||
@@ -1668,7 +1675,7 @@
     if (getLangOpts().MSVCCompat && NextToken().is(tok::kw_typedef)) {
       Token TypedefToken;
       PP.Lex(TypedefToken);
-      bool Result = TryAnnotateTypeOrScopeToken();
+      bool Result = TryAnnotateTypeOrScopeToken(AllowImplicitTypename);
       PP.EnterToken(Tok);
       Tok = TypedefToken;
       if (!Result)
@@ -1693,7 +1700,8 @@
           Tok.is(tok::annot_decltype)) {
         // Attempt to recover by skipping the invalid 'typename'
         if (Tok.is(tok::annot_decltype) ||
-            (!TryAnnotateTypeOrScopeToken() && Tok.isAnnotation())) {
+            (!TryAnnotateTypeOrScopeToken(AllowImplicitTypename) &&
+             Tok.isAnnotation())) {
           unsigned DiagID = diag::err_expected_qualified_after_typename;
           // MS compatibility: MSVC permits using known types with typename.
           // e.g. "typedef typename T* pointer_type"
@@ -1759,22 +1767,24 @@
     if (ParseOptionalCXXScopeSpecifier(SS, nullptr, /*EnteringContext*/false))
       return true;
 
-  return TryAnnotateTypeOrScopeTokenAfterScopeSpec(SS, !WasScopeAnnotation);
+  return TryAnnotateTypeOrScopeTokenAfterScopeSpec(SS, !WasScopeAnnotation,
+                                                   AllowImplicitTypename);
 }
 
 /// Try to annotate a type or scope token, having already parsed an
 /// optional scope specifier. \p IsNewScope should be \c true unless the scope
 /// specifier was extracted from an existing tok::annot_cxxscope annotation.
-bool Parser::TryAnnotateTypeOrScopeTokenAfterScopeSpec(CXXScopeSpec &SS,
-                                                       bool IsNewScope) {
+bool Parser::TryAnnotateTypeOrScopeTokenAfterScopeSpec(
+    CXXScopeSpec &SS, bool IsNewScope,
+    ImplicitTypenameContext AllowImplicitTypename) {
   if (Tok.is(tok::identifier)) {
     // Determine whether the identifier is a type name.
     if (ParsedType Ty = Actions.getTypeName(
             *Tok.getIdentifierInfo(), Tok.getLocation(), getCurScope(), &SS,
             false, NextToken().is(tok::period), nullptr,
             /*IsCtorOrDtorName=*/false,
-            /*NonTrivialTypeSourceInfo*/true,
-            /*IsClassTemplateDeductionContext*/true)) {
+            /*NonTrivialTypeSourceInfo*/ true,
+            /*IsClassTemplateDeductionContext*/ true, AllowImplicitTypename)) {
       SourceLocation BeginLoc = Tok.getLocation();
       if (SS.isNotEmpty()) // it was a C++ qualified type name.
         BeginLoc = SS.getBeginLoc();
Index: clang/lib/Parse/ParseTentative.cpp
===================================================================
--- clang/lib/Parse/ParseTentative.cpp
+++ clang/lib/Parse/ParseTentative.cpp
@@ -111,7 +111,7 @@
   // a case.
 
   bool InvalidAsDeclaration = false;
-  TPResult TPR = isCXXDeclarationSpecifier(TPResult::False,
+  TPResult TPR = isCXXDeclarationSpecifier(ITC_Never, TPResult::False,
                                            &InvalidAsDeclaration);
   if (TPR != TPResult::Ambiguous)
     return TPR != TPResult::False; // Returns true for TPResult::True or
@@ -246,7 +246,7 @@
   // simple-declaration. Don't bother calling isCXXDeclarationSpecifier in the
   // overwhelmingly common case that the next token is a '('.
   if (Tok.isNot(tok::l_paren)) {
-    TPResult TPR = isCXXDeclarationSpecifier();
+    TPResult TPR = isCXXDeclarationSpecifier(ITC_Never);
     if (TPR == TPResult::Ambiguous)
       return TPResult::True;
     if (TPR == TPResult::True || TPR == TPResult::Error)
@@ -466,7 +466,7 @@
   ConditionDeclarationOrInitStatementState State(*this, CanBeInitStatement,
                                                  CanBeForRangeDecl);
 
-  if (State.update(isCXXDeclarationSpecifier()))
+  if (State.update(isCXXDeclarationSpecifier(ITC_Never)))
     return State.result();
 
   // It might be a declaration; we need tentative parsing.
@@ -552,7 +552,7 @@
   // type. The resolution is that any construct that could possibly be a type-id
   // in its syntactic context shall be considered a type-id.
 
-  TPResult TPR = isCXXDeclarationSpecifier();
+  TPResult TPR = isCXXDeclarationSpecifier(ITC_Never);
   if (TPR != TPResult::Ambiguous)
     return TPR != TPResult::False; // Returns true for TPResult::True or
                                      // TPResult::Error.
@@ -856,7 +856,7 @@
   // Maybe this is a conversion-function-id.
   bool AnyDeclSpecifiers = false;
   while (true) {
-    TPResult TPR = isCXXDeclarationSpecifier();
+    TPResult TPR = isCXXDeclarationSpecifier(ITC_Never);
     if (TPR == TPResult::Error)
       return TPR;
     if (TPR == TPResult::False) {
@@ -958,7 +958,7 @@
         (Tok.is(tok::r_paren) ||       // 'int()' is a function.
          // 'int(...)' is a function.
          (Tok.is(tok::ellipsis) && NextToken().is(tok::r_paren)) ||
-         isDeclarationSpecifier())) {   // 'int(int)' is a function.
+         isDeclarationSpecifier(ITC_Never))) {   // 'int(int)' is a function.
       // '(' parameter-declaration-clause ')' cv-qualifier-seq[opt]
       //        exception-specification[opt]
       TPResult TPR = TryParseFunctionDeclarator();
@@ -1274,8 +1274,10 @@
 /// [GNU]     restrict
 ///
 Parser::TPResult
-Parser::isCXXDeclarationSpecifier(Parser::TPResult BracedCastResult,
+Parser::isCXXDeclarationSpecifier(ImplicitTypenameContext AllowImplicitTypename,
+                                  Parser::TPResult BracedCastResult,
                                   bool *HasMissingTypename) {
+
   switch (Tok.getKind()) {
   case tok::identifier: {
     // Check for need to substitute AltiVec __vector keyword
@@ -1305,7 +1307,7 @@
         // template template argument, we'll undo this when checking the
         // validity of the argument.
         if (getLangOpts().CPlusPlus17) {
-          if (TryAnnotateTypeOrScopeToken())
+          if (TryAnnotateTypeOrScopeToken(AllowImplicitTypename))
             return TPResult::Error;
           if (Tok.isNot(tok::identifier))
             break;
@@ -1326,7 +1328,7 @@
       // a missing 'typename' keyword. Don't use TryAnnotateName in this case,
       // since it will annotate as a primary expression, and we want to use the
       // "missing 'typename'" logic.
-      if (TryAnnotateTypeOrScopeToken())
+      if (TryAnnotateTypeOrScopeToken(AllowImplicitTypename))
         return TPResult::Error;
       // If annotation failed, assume it's a non-type.
       // FIXME: If this happens due to an undeclared identifier, treat it as
@@ -1336,15 +1338,17 @@
     }
 
     // We annotated this token as something. Recurse to handle whatever we got.
-    return isCXXDeclarationSpecifier(BracedCastResult, HasMissingTypename);
+    return isCXXDeclarationSpecifier(AllowImplicitTypename, BracedCastResult,
+                                     HasMissingTypename);
   }
 
   case tok::kw_typename:  // typename T::type
     // Annotate typenames and C++ scope specifiers.  If we get one, just
     // recurse to handle whatever we get.
-    if (TryAnnotateTypeOrScopeToken())
+    if (TryAnnotateTypeOrScopeToken(ITC_Yes))
       return TPResult::Error;
-    return isCXXDeclarationSpecifier(BracedCastResult, HasMissingTypename);
+    return isCXXDeclarationSpecifier(ITC_Yes, BracedCastResult,
+                                     HasMissingTypename);
 
   case tok::coloncolon: {    // ::foo::bar
     const Token &Next = NextToken();
@@ -1357,9 +1361,10 @@
   case tok::kw_decltype:
     // Annotate typenames and C++ scope specifiers.  If we get one, just
     // recurse to handle whatever we get.
-    if (TryAnnotateTypeOrScopeToken())
+    if (TryAnnotateTypeOrScopeToken(AllowImplicitTypename))
       return TPResult::Error;
-    return isCXXDeclarationSpecifier(BracedCastResult, HasMissingTypename);
+    return isCXXDeclarationSpecifier(AllowImplicitTypename, BracedCastResult,
+                                     HasMissingTypename);
 
     // decl-specifier:
     //   storage-class-specifier
@@ -1469,7 +1474,7 @@
 
   case tok::annot_cxxscope: // foo::bar or ::foo::bar, but already parsed
     // We've already annotated a scope; try to annotate a type.
-    if (TryAnnotateTypeOrScopeToken())
+    if (TryAnnotateTypeOrScopeToken(AllowImplicitTypename))
       return TPResult::Error;
     if (!Tok.is(tok::annot_typename)) {
       // If the next token is an identifier or a type qualifier, then this
@@ -1486,8 +1491,8 @@
           bool isIdentifier = Tok.is(tok::identifier);
           TPResult TPR = TPResult::False;
           if (!isIdentifier)
-            TPR = isCXXDeclarationSpecifier(BracedCastResult,
-                                            HasMissingTypename);
+            TPR = isCXXDeclarationSpecifier(
+                AllowImplicitTypename, BracedCastResult, HasMissingTypename);
 
           if (isIdentifier ||
               TPR == TPResult::True || TPR == TPResult::Error)
@@ -1513,7 +1518,8 @@
         } else {
           // Try to resolve the name. If it doesn't exist, assume it was
           // intended to name a type and keep disambiguating.
-          switch (TryAnnotateName(false /* SS is not dependent */)) {
+          switch (TryAnnotateName(false /* SS is not dependent */,
+                                  /*CCC=*/nullptr, AllowImplicitTypename)) {
           case ANK_Error:
             return TPResult::Error;
           case ANK_TentativeDecl:
@@ -1544,8 +1550,8 @@
           // Annotated it, check again.
           assert(Tok.isNot(tok::annot_cxxscope) ||
                  NextToken().isNot(tok::identifier));
-          return isCXXDeclarationSpecifier(BracedCastResult,
-                                           HasMissingTypename);
+          return isCXXDeclarationSpecifier(
+              AllowImplicitTypename, BracedCastResult, HasMissingTypename);
         }
       }
       return TPResult::False;
@@ -1778,7 +1784,8 @@
 /// '(' parameter-declaration-clause ')' cv-qualifier-seq[opt]
 ///         exception-specification[opt]
 ///
-bool Parser::isCXXFunctionDeclarator(bool *IsAmbiguous) {
+bool Parser::isCXXFunctionDeclarator(
+    bool *IsAmbiguous, ImplicitTypenameContext AllowImplicitTypename) {
 
   // C++ 8.2p1:
   // The ambiguity arising from the similarity between a function-style cast and
@@ -1793,7 +1800,9 @@
 
   ConsumeParen();
   bool InvalidAsDeclaration = false;
-  TPResult TPR = TryParseParameterDeclarationClause(&InvalidAsDeclaration);
+  TPResult TPR = TryParseParameterDeclarationClause(
+      &InvalidAsDeclaration, /*VersusTemplateArgument=*/false,
+      AllowImplicitTypename);
   if (TPR == TPResult::Ambiguous) {
     if (Tok.isNot(tok::r_paren))
       TPR = TPResult::False;
@@ -1837,9 +1846,9 @@
 ///   attribute-specifier-seq[opt] decl-specifier-seq abstract-declarator[opt]
 ///     attributes[opt] '=' assignment-expression
 ///
-Parser::TPResult
-Parser::TryParseParameterDeclarationClause(bool *InvalidAsDeclaration,
-                                           bool VersusTemplateArgument) {
+Parser::TPResult Parser::TryParseParameterDeclarationClause(
+    bool *InvalidAsDeclaration, bool VersusTemplateArgument,
+    ImplicitTypenameContext AllowImplicitTypename) {
 
   if (Tok.is(tok::r_paren))
     return TPResult::Ambiguous;
@@ -1872,8 +1881,8 @@
     // decl-specifier-seq
     // A parameter-declaration's initializer must be preceded by an '=', so
     // decl-specifier-seq '{' is not a parameter in C++11.
-    TPResult TPR = isCXXDeclarationSpecifier(TPResult::False,
-                                             InvalidAsDeclaration);
+    TPResult TPR = isCXXDeclarationSpecifier(
+        AllowImplicitTypename, TPResult::False, InvalidAsDeclaration);
 
     if (VersusTemplateArgument && TPR == TPResult::True) {
       // Consume the decl-specifier-seq. We have to look past it, since a
@@ -1888,7 +1897,7 @@
         if (SeenType && Tok.is(tok::identifier))
           return TPResult::True;
 
-        TPR = isCXXDeclarationSpecifier(TPResult::False,
+        TPR = isCXXDeclarationSpecifier(AllowImplicitTypename, TPResult::False,
                                         InvalidAsDeclaration);
         if (TPR == TPResult::Error)
           return TPR;
Index: clang/lib/Parse/ParseTemplate.cpp
===================================================================
--- clang/lib/Parse/ParseTemplate.cpp
+++ clang/lib/Parse/ParseTemplate.cpp
@@ -16,6 +16,7 @@
 #include "clang/Parse/Parser.h"
 #include "clang/Parse/RAIIObjectsForParser.h"
 #include "clang/Sema/DeclSpec.h"
+#include "clang/Sema/Lookup.h"
 #include "clang/Sema/ParsedTemplate.h"
 #include "clang/Sema/Scope.h"
 using namespace clang;
@@ -1288,7 +1289,7 @@
     return true;
 
   // See whether we have declaration specifiers, which indicate a type.
-  while (isCXXDeclarationSpecifier() == TPResult::True)
+  while (isCXXDeclarationSpecifier(ITC_Never) == TPResult::True)
     ConsumeAnyToken();
 
   // If we have a '>' or a ',' then this is a template argument list.
Index: clang/lib/Parse/ParseExprCXX.cpp
===================================================================
--- clang/lib/Parse/ParseExprCXX.cpp
+++ clang/lib/Parse/ParseExprCXX.cpp
@@ -1343,7 +1343,8 @@
 
   // Parse the common declaration-specifiers piece.
   DeclSpec DS(AttrFactory);
-  ParseSpecifierQualifierList(DS);
+  ParseSpecifierQualifierList(DS, /*AccessSpecifier=*/AS_none,
+                              DeclSpecContext::DSC_type_specifier);
 
   // Parse the abstract-declarator, if present.
   Declarator DeclaratorInfo(DS, DeclaratorContext::TypeNameContext);
Index: clang/lib/Parse/ParseDeclCXX.cpp
===================================================================
--- clang/lib/Parse/ParseDeclCXX.cpp
+++ clang/lib/Parse/ParseDeclCXX.cpp
@@ -1199,7 +1199,7 @@
       *Id, IdLoc, getCurScope(), &SS, /*IsClassName=*/true, false, nullptr,
       /*IsCtorOrDtorName=*/false,
       /*NonTrivialTypeSourceInfo=*/true,
-      /*IsClassTemplateDeductionContext*/ false, &CorrectedII);
+      /*IsClassTemplateDeductionContext*/ false, ITC_Never, &CorrectedII);
   if (!Type) {
     Diag(IdLoc, diag::err_expected_class_name);
     return true;
Index: clang/lib/Parse/ParseDecl.cpp
===================================================================
--- clang/lib/Parse/ParseDecl.cpp
+++ clang/lib/Parse/ParseDecl.cpp
@@ -2002,7 +2002,7 @@
         return Actions.ConvertDeclToDeclGroup(TheDecl);
       }
 
-      if (isDeclarationSpecifier()) {
+      if (isDeclarationSpecifier(ITC_Never)) {
         // If there is an invalid declaration specifier right after the
         // function prototype, then we must be in a missing semicolon case
         // where this isn't actually a body.  Just fall through into the code
@@ -2116,7 +2116,7 @@
     // Okay, there was no semicolon and one was expected.  If we see a
     // declaration specifier, just assume it was missing and continue parsing.
     // Otherwise things are very confused and we skip to recover.
-    if (!isDeclarationSpecifier()) {
+    if (!isDeclarationSpecifier(ITC_Never)) {
       SkipUntil(tok::r_brace, StopAtSemi | StopBeforeMatch);
       TryConsumeToken(tok::semi);
     }
@@ -2649,6 +2649,9 @@
     case tok::semi:
       // This looks like a variable or function declaration. The type is
       // probably missing. We're done parsing decl-specifiers.
+      // But only if we are not in a function prototype scope.
+      if (getCurScope()->isFunctionPrototypeScope())
+        break;
       if (SS)
         AnnotateScopeToken(*SS, /*IsNewAnnotation*/false);
       return false;
@@ -2712,22 +2715,46 @@
 /// DeclaratorContext enumerator values.
 Parser::DeclSpecContext
 Parser::getDeclSpecContextFromDeclaratorContext(DeclaratorContext Context) {
-  if (Context == DeclaratorContext::MemberContext)
+  switch (Context) {
+  case DeclaratorContext::MemberContext:
     return DeclSpecContext::DSC_class;
-  if (Context == DeclaratorContext::FileContext)
+  case DeclaratorContext::FileContext:
     return DeclSpecContext::DSC_top_level;
-  if (Context == DeclaratorContext::TemplateParamContext)
+  case DeclaratorContext::TemplateParamContext:
     return DeclSpecContext::DSC_template_param;
-  if (Context == DeclaratorContext::TemplateArgContext ||
-      Context == DeclaratorContext::TemplateTypeArgContext)
+  case DeclaratorContext::TemplateArgContext:
+    return DeclSpecContext::DSC_template_arg;
+  case DeclaratorContext::TemplateTypeArgContext:
     return DeclSpecContext::DSC_template_type_arg;
-  if (Context == DeclaratorContext::TrailingReturnContext ||
-      Context == DeclaratorContext::TrailingReturnVarContext)
+  case DeclaratorContext::TrailingReturnContext:
+  case DeclaratorContext::TrailingReturnVarContext:
     return DeclSpecContext::DSC_trailing;
-  if (Context == DeclaratorContext::AliasDeclContext ||
-      Context == DeclaratorContext::AliasTemplateContext)
+  case DeclaratorContext::AliasDeclContext:
+  case DeclaratorContext::AliasTemplateContext:
     return DeclSpecContext::DSC_alias_declaration;
-  return DeclSpecContext::DSC_normal;
+  case DeclaratorContext::TypeNameContext:
+    return DeclSpecContext::DSC_type_specifier;
+  case DeclaratorContext::ConditionContext:
+    return DeclSpecContext::DSC_condition;
+  case DeclaratorContext::PrototypeContext:
+  case DeclaratorContext::ObjCResultContext:
+  case DeclaratorContext::ObjCParameterContext:
+  case DeclaratorContext::KNRTypeListContext:
+  case DeclaratorContext::FunctionalCastContext:
+  case DeclaratorContext::BlockContext:
+  case DeclaratorContext::ForContext:
+  case DeclaratorContext::InitStmtContext:
+  case DeclaratorContext::CXXNewContext:
+  case DeclaratorContext::CXXCatchContext:
+  case DeclaratorContext::ObjCCatchContext:
+  case DeclaratorContext::BlockLiteralContext:
+  case DeclaratorContext::LambdaExprContext:
+  case DeclaratorContext::LambdaExprParameterContext:
+  case DeclaratorContext::ConversionIdContext:
+    return DeclSpecContext::DSC_normal;
+  }
+
+  llvm_unreachable("Missing DeclaratorContext case");
 }
 
 /// ParseAlignArgument - Parse the argument to an alignment-specifier.
@@ -2940,11 +2967,10 @@
 /// [OpenCL] '__kernel'
 ///       'friend': [C++ dcl.friend]
 ///       'constexpr': [C++0x dcl.constexpr]
-void Parser::ParseDeclarationSpecifiers(DeclSpec &DS,
-                                        const ParsedTemplateInfo &TemplateInfo,
-                                        AccessSpecifier AS,
-                                        DeclSpecContext DSContext,
-                                        LateParsedAttrList *LateAttrs) {
+void Parser::ParseDeclarationSpecifiers(
+    DeclSpec &DS, const ParsedTemplateInfo &TemplateInfo, AccessSpecifier AS,
+    DeclSpecContext DSContext, LateParsedAttrList *LateAttrs,
+    ImplicitTypenameContext AllowImplicitTypename) {
   if (DS.getSourceRange().isInvalid()) {
     // Start the range at the current token but make the end of the range
     // invalid.  This will make the entire range invalid unless we successfully
@@ -3132,12 +3158,13 @@
           isConstructorDeclarator(/*Unqualified*/ false))
         goto DoneWithDeclSpec;
 
-      ParsedType TypeRep =
-          Actions.getTypeName(*Next.getIdentifierInfo(), Next.getLocation(),
-                              getCurScope(), &SS, false, false, nullptr,
-                              /*IsCtorOrDtorName=*/false,
-                              /*WantNonTrivialSourceInfo=*/true,
-                              isClassTemplateDeductionContext(DSContext));
+      ParsedType TypeRep = Actions.getTypeName(
+          *Next.getIdentifierInfo(), Next.getLocation(), getCurScope(), &SS,
+          false, false, nullptr,
+          /*IsCtorOrDtorName=*/false,
+          /*WantNonTrivialSourceInfo=*/true,
+          isClassTemplateDeductionContext(DSContext),
+          AllowImplicitTypename);
 
       // If the referenced identifier is not a type, then this declspec is
       // erroneous: We already checked about that it has no type specifier, and
@@ -4281,8 +4308,9 @@
         // FIXME: The standard is not entirely clear on how to disambiguate in
         // this case.
         if ((getLangOpts().CPlusPlus &&
-             isCXXDeclarationSpecifier(TPResult::True) != TPResult::True) ||
-            (!getLangOpts().CPlusPlus && !isDeclarationSpecifier(true))) {
+             isCXXDeclarationSpecifier(ITC_Never, TPResult::True) !=
+                 TPResult::True) ||
+            (!getLangOpts().CPlusPlus && !isDeclarationSpecifier(ITC_Yes))) {
           // We'll parse this as a bitfield later.
           PossibleBitfield = true;
           TPA.Revert();
@@ -4807,9 +4835,13 @@
 /// isDeclarationSpecifier() - Return true if the current token is part of a
 /// declaration specifier.
 ///
+/// \param AllowImplicitTypename whether this is a context where T::type [T
+/// dependent] can appear.
 /// \param DisambiguatingWithExpression True to indicate that the purpose of
 /// this check is to disambiguate between an expression and a declaration.
-bool Parser::isDeclarationSpecifier(bool DisambiguatingWithExpression) {
+bool Parser::isDeclarationSpecifier(
+    ImplicitTypenameContext AllowImplicitTypename,
+    bool DisambiguatingWithExpression) {
   switch (Tok.getKind()) {
   default: return false;
 
@@ -4827,7 +4859,7 @@
   case tok::kw_typename: // typename T::type
     // Annotate typenames and C++ scope specifiers.  If we get one, just
     // recurse to handle whatever we get.
-    if (TryAnnotateTypeOrScopeToken())
+    if (TryAnnotateTypeOrScopeToken(AllowImplicitTypename))
       return true;
     if (Tok.is(tok::identifier))
       return false;
@@ -4841,7 +4873,7 @@
         isStartOfObjCClassMessageMissingOpenBracket())
       return false;
 
-    return isDeclarationSpecifier();
+    return isDeclarationSpecifier(AllowImplicitTypename);
 
   case tok::coloncolon:   // ::foo::bar
     if (NextToken().is(tok::kw_new) ||    // ::new
@@ -4852,7 +4884,7 @@
     // recurse to handle whatever we get.
     if (TryAnnotateTypeOrScopeToken())
       return true;
-    return isDeclarationSpecifier();
+    return isDeclarationSpecifier(ITC_Never);
 
     // storage-class-specifier
   case tok::kw_typedef:
@@ -5056,7 +5088,7 @@
   // specifier, in which case we have the start of a parameter and,
   // therefore, we know that this is a constructor.
   bool IsConstructor = false;
-  if (isDeclarationSpecifier())
+  if (isDeclarationSpecifier(ITC_Never))
     IsConstructor = true;
   else if (Tok.is(tok::identifier) ||
            (Tok.is(tok::annot_cxxscope) && NextToken().is(tok::identifier))) {
@@ -5850,10 +5882,26 @@
       // is not, the declarator has been fully parsed.
       bool IsAmbiguous = false;
       if (getLangOpts().CPlusPlus && D.mayBeFollowedByCXXDirectInit()) {
+        // C++2a [temp.res]p5
+        // A qualified-id is assumed to name a type if
+        //   - [...]
+        //   - it is a decl-specifier of the decl-specifier-seq of a
+        //     - [...]
+        //     - parameter-declaration in a member-declaration [...]
+        //     - parameter-declaration in a declarator of a function or function
+        //       template declaration whose declarator-id is qualified [...]
+        ImplicitTypenameContext AllowImplicitTypename = ITC_Never;
+        if (D.getCXXScopeSpec().isSet())
+          AllowImplicitTypename =
+              (ImplicitTypenameContext)Actions.isDeclaratorFunctionLike(D);
+        else if (D.getContext() == DeclaratorContext::MemberContext)
+          AllowImplicitTypename = ITC_Yes;
+
         // The name of the declarator, if any, is tentatively declared within
         // a possible direct initializer.
         TentativelyDeclaredIdentifiers.push_back(D.getIdentifier());
-        bool IsFunctionDecl = isCXXFunctionDeclarator(&IsAmbiguous);
+        bool IsFunctionDecl =
+            isCXXFunctionDeclarator(&IsAmbiguous, AllowImplicitTypename);
         TentativelyDeclaredIdentifiers.pop_back();
         if (!IsFunctionDecl)
           break;
@@ -5991,11 +6039,11 @@
     // If this can't be an abstract-declarator, this *must* be a grouping
     // paren, because we haven't seen the identifier yet.
     isGrouping = true;
-  } else if (Tok.is(tok::r_paren) ||           // 'int()' is a function.
+  } else if (Tok.is(tok::r_paren) ||              // 'int()' is a function.
              (getLangOpts().CPlusPlus && Tok.is(tok::ellipsis) &&
-              NextToken().is(tok::r_paren)) || // C++ int(...)
-             isDeclarationSpecifier() ||       // 'int(int)' is a function.
-             isCXX11AttributeSpecifier()) {    // 'int([[]]int)' is a function.
+              NextToken().is(tok::r_paren)) ||    // C++ int(...)
+             isDeclarationSpecifier(ITC_Never) || // 'int(int)' is a function.
+             isCXX11AttributeSpecifier()) {       // 'int([[]]int)' is a function.
     // This handles C99 6.7.5.3p11: in "typedef int X; void foo(X)", X is
     // considered to be a type, not a K&R identifier-list.
     isGrouping = false;
@@ -6404,6 +6452,23 @@
        ParsedAttributes &FirstArgAttrs,
        SmallVectorImpl<DeclaratorChunk::ParamInfo> &ParamInfo,
        SourceLocation &EllipsisLoc) {
+
+  // C++2a [temp.res]p5
+  // A qualified-id is assumed to name a type if
+  //   - [...]
+  //   - it is a decl-specifier of the decl-specifier-seq of a
+  //     - [...]
+  //     - parameter-declaration in a member-declaration [...]
+  //     - parameter-declaration in a declarator of a function or function
+  //       template declaration whose declarator-id is qualified [...]
+  //     - parameter-declaration in a lambda-declarator [...]
+  ImplicitTypenameContext AllowImplicitTypename = ITC_Never;
+  if (D.getContext() == DeclaratorContext::MemberContext ||
+      D.getContext() == DeclaratorContext::LambdaExprContext ||
+      (D.getCXXScopeSpec().isSet() &&
+       D.isFunctionDeclaratorAFunctionDeclaration()))
+    AllowImplicitTypename = ITC_Yes;
+
   do {
     // FIXME: Issue a diagnostic if we parsed an attribute-specifier-seq
     // before deciding this was a parameter-declaration-clause.
@@ -6429,8 +6494,9 @@
     // too much hassle.
     DS.takeAttributesFrom(FirstArgAttrs);
 
-    ParseDeclarationSpecifiers(DS);
-
+    ParseDeclarationSpecifiers(DS, /*TemplateInfo=*/ParsedTemplateInfo(),
+                               AS_none, DeclSpecContext::DSC_normal,
+                               /*LateAttrs=*/nullptr, AllowImplicitTypename);
 
     // Parse the declarator.  This is "PrototypeContext" or
     // "LambdaExprParameterContext", because we must accept either
Index: clang/include/clang/Sema/Sema.h
===================================================================
--- clang/include/clang/Sema/Sema.h
+++ clang/include/clang/Sema/Sema.h
@@ -1774,14 +1774,15 @@
 
   bool isSimpleTypeSpecifier(tok::TokenKind Kind) const;
 
-  ParsedType getTypeName(const IdentifierInfo &II, SourceLocation NameLoc,
-                         Scope *S, CXXScopeSpec *SS = nullptr,
-                         bool isClassName = false, bool HasTrailingDot = false,
-                         ParsedType ObjectType = nullptr,
-                         bool IsCtorOrDtorName = false,
-                         bool WantNontrivialTypeSourceInfo = false,
-                         bool IsClassTemplateDeductionContext = true,
-                         IdentifierInfo **CorrectedII = nullptr);
+  ParsedType
+  getTypeName(const IdentifierInfo &II, SourceLocation NameLoc, Scope *S,
+              CXXScopeSpec *SS = nullptr, bool isClassName = false,
+              bool HasTrailingDot = false, ParsedType ObjectType = nullptr,
+              bool IsCtorOrDtorName = false,
+              bool WantNontrivialTypeSourceInfo = false,
+              bool IsClassTemplateDeductionContext = true,
+              ImplicitTypenameContext AllowImplicitTypename = ITC_Never,
+              IdentifierInfo **CorrectedII = nullptr);
   TypeSpecifierType isTagName(IdentifierInfo &II, Scope *S);
   bool isMicrosoftMissingTypename(const CXXScopeSpec *SS, Scope *S);
   void DiagnoseUnknownTypeName(IdentifierInfo *&II,
@@ -2122,6 +2123,10 @@
   /// \c constexpr in C++11 or has an 'auto' return type in C++14).
   bool canSkipFunctionBody(Decl *D);
 
+  /// Determine whether \param D is function like (function or function
+  /// template) for parsing.
+  bool isDeclaratorFunctionLike(Declarator &D);
+
   void computeNRVO(Stmt *Body, sema::FunctionScopeInfo *Scope);
   Decl *ActOnFinishFunctionBody(Decl *Decl, Stmt *Body);
   Decl *ActOnFinishFunctionBody(Decl *Decl, Stmt *Body, bool IsInstantiation);
@@ -6618,10 +6623,12 @@
   /// \param SS the nested-name-specifier following the typename (e.g., 'T::').
   /// \param II the identifier we're retrieving (e.g., 'type' in the example).
   /// \param IdLoc the location of the identifier.
+  /// \param IsImplicitTypename context where T::type refers to a type
   TypeResult
   ActOnTypenameType(Scope *S, SourceLocation TypenameLoc,
                     const CXXScopeSpec &SS, const IdentifierInfo &II,
-                    SourceLocation IdLoc);
+                    SourceLocation IdLoc,
+                    ImplicitTypenameContext IsImplicitTypename = ITC_Never);
 
   /// Called when the parser has parsed a C++ typename
   /// specifier that ends in a template-id, e.g.,
Index: clang/include/clang/Sema/DeclSpec.h
===================================================================
--- clang/include/clang/Sema/DeclSpec.h
+++ clang/include/clang/Sema/DeclSpec.h
@@ -33,12 +33,14 @@
 #include "llvm/ADT/SmallVector.h"
 #include "llvm/Support/Compiler.h"
 #include "llvm/Support/ErrorHandling.h"
+#include <memory>
 
 namespace clang {
   class ASTContext;
   class CXXRecordDecl;
   class TypeLoc;
   class LangOptions;
+  class LookupResult;
   class IdentifierInfo;
   class NamespaceAliasDecl;
   class NamespaceDecl;
@@ -1748,6 +1750,12 @@
     AliasTemplateContext // C++11 alias-declaration template.
 };
 
+// Describes whether the current context is a context where an implicit
+// typename is allowed (C++2a [temp.res]p5]).
+enum ImplicitTypenameContext {
+  ITC_Never,
+  ITC_Yes,
+};
 
 /// Information about one declarator, including the parsed type
 /// information and the identifier.
@@ -1834,20 +1842,16 @@
   /// this declarator as a parameter pack.
   SourceLocation EllipsisLoc;
 
+  /// Lookup result of declarator, if any.
+  std::unique_ptr<LookupResult> PrevLookupResult;
+
   friend struct DeclaratorChunk;
 
 public:
-  Declarator(const DeclSpec &ds, DeclaratorContext C)
-      : DS(ds), Range(ds.getSourceRange()), Context(C),
-        InvalidType(DS.getTypeSpecType() == DeclSpec::TST_error),
-        GroupingParens(false), FunctionDefinition(FDK_Declaration),
-        Redeclaration(false), Extension(false), ObjCIvar(false),
-        ObjCWeakProperty(false), InlineStorageUsed(false),
-        Attrs(ds.getAttributePool().getFactory()), AsmLabel(nullptr) {}
+  Declarator(const DeclSpec &ds, DeclaratorContext C);
+
+  ~Declarator();
 
-  ~Declarator() {
-    clear();
-  }
   /// getDeclSpec - Return the declaration-specifier that this declarator was
   /// declared with.
   const DeclSpec &getDeclSpec() const { return DS; }
@@ -2482,6 +2486,10 @@
 
   void setRedeclaration(bool Val) { Redeclaration = Val; }
   bool isRedeclaration() const { return Redeclaration; }
+
+  void setPrevLookupResult(std::unique_ptr<LookupResult> LR);
+  LookupResult consumePrevLookupResult();
+  bool hasPrevLookupResult() const { return (bool)PrevLookupResult; }
 };
 
 /// This little struct is used to capture information about
Index: clang/include/clang/Parse/Parser.h
===================================================================
--- clang/include/clang/Parse/Parser.h
+++ clang/include/clang/Parse/Parser.h
@@ -771,9 +771,11 @@
 public:
   // If NeedType is true, then TryAnnotateTypeOrScopeToken will try harder to
   // find a type name by attempting typo correction.
-  bool TryAnnotateTypeOrScopeToken();
-  bool TryAnnotateTypeOrScopeTokenAfterScopeSpec(CXXScopeSpec &SS,
-                                                 bool IsNewScope);
+  bool TryAnnotateTypeOrScopeToken(
+      ImplicitTypenameContext AllowImplicitTypename = ITC_Never);
+  bool TryAnnotateTypeOrScopeTokenAfterScopeSpec(
+      CXXScopeSpec &SS, bool IsNewScope,
+      ImplicitTypenameContext AllowImplicitTypename);
   bool TryAnnotateCXXScopeToken(bool EnteringContext = false);
 
 private:
@@ -791,7 +793,8 @@
   };
   AnnotatedNameKind
   TryAnnotateName(bool IsAddressOfOperand,
-                  std::unique_ptr<CorrectionCandidateCallback> CCC = nullptr);
+                  std::unique_ptr<CorrectionCandidateCallback> CCC = nullptr,
+                  ImplicitTypenameContext AllowImplicitTypename = ITC_Never);
 
   /// Push a tok::annot_cxxscope token onto the token stream.
   void AnnotateScopeToken(CXXScopeSpec &SS, bool IsNewAnnotation);
@@ -2019,6 +2022,7 @@
     DSC_alias_declaration, // C++11 type-specifier-seq in an alias-declaration
     DSC_top_level, // top-level/namespace declaration context
     DSC_template_param, // template parameter context
+    DSC_template_arg, // template argument context
     DSC_template_type_arg, // template type argument context
     DSC_objc_method_result, // ObjC method result context, enables 'instancetype'
     DSC_condition // condition declaration context
@@ -2030,6 +2034,7 @@
     switch (DSC) {
     case DeclSpecContext::DSC_normal:
     case DeclSpecContext::DSC_template_param:
+    case DeclSpecContext::DSC_template_arg:
     case DeclSpecContext::DSC_class:
     case DeclSpecContext::DSC_top_level:
     case DeclSpecContext::DSC_objc_method_result:
@@ -2051,6 +2056,7 @@
     switch (DSC) {
     case DeclSpecContext::DSC_normal:
     case DeclSpecContext::DSC_template_param:
+    case DeclSpecContext::DSC_template_arg:
     case DeclSpecContext::DSC_class:
     case DeclSpecContext::DSC_top_level:
     case DeclSpecContext::DSC_condition:
@@ -2066,6 +2072,27 @@
     llvm_unreachable("Missing DeclSpecContext case");
   }
 
+  // Is this a context in which an implicit 'typename' is allowed?
+  static bool isImplicitTypenameContext(DeclSpecContext DSC) {
+    switch (DSC) {
+    case DeclSpecContext::DSC_class:
+    case DeclSpecContext::DSC_top_level:
+    case DeclSpecContext::DSC_type_specifier:
+    case DeclSpecContext::DSC_template_type_arg:
+    case DeclSpecContext::DSC_trailing:
+    case DeclSpecContext::DSC_alias_declaration:
+    case DeclSpecContext::DSC_template_param:
+      return true;
+
+    case DeclSpecContext::DSC_normal:
+    case DeclSpecContext::DSC_objc_method_result:
+    case DeclSpecContext::DSC_condition:
+    case DeclSpecContext::DSC_template_arg:
+      return false;
+    }
+    llvm_unreachable("Missing DeclSpecContext case");
+  }
+
   /// Information on a C++0x for-range-initializer found while parsing a
   /// declaration which turns out to be a for-range-declaration.
   struct ForRangeInit {
@@ -2117,7 +2144,19 @@
       const ParsedTemplateInfo &TemplateInfo = ParsedTemplateInfo(),
       AccessSpecifier AS = AS_none,
       DeclSpecContext DSC = DeclSpecContext::DSC_normal,
-      LateParsedAttrList *LateAttrs = nullptr);
+      LateParsedAttrList *LateAttrs = nullptr) {
+    return ParseDeclarationSpecifiers(
+        DS, TemplateInfo, AS, DSC, LateAttrs,
+        (ImplicitTypenameContext)isImplicitTypenameContext(DSC));
+  }
+  void ParseDeclarationSpecifiers(
+      DeclSpec &DS,
+      const ParsedTemplateInfo &TemplateInfo,
+      AccessSpecifier AS,
+      DeclSpecContext DSC,
+      LateParsedAttrList *LateAttrs,
+      ImplicitTypenameContext AllowImplicitTypename);
+
   bool DiagnoseMissingSemiAfterTagDefinition(
       DeclSpec &DS, AccessSpecifier AS, DeclSpecContext DSContext,
       LateParsedAttrList *LateAttrs = nullptr);
@@ -2140,7 +2179,8 @@
       ParsingDeclSpec &DS,
       llvm::function_ref<void(ParsingFieldDeclarator &)> FieldsCallback);
 
-  bool isDeclarationSpecifier(bool DisambiguatingWithExpression = false);
+  bool isDeclarationSpecifier(ImplicitTypenameContext AllowImplicitTypename,
+                              bool DisambiguatingWithExpression = false);
   bool isTypeSpecifierQualifier();
 
   /// isKnownToBeTypeSpecifier - Return true if we know that the specified token
@@ -2153,8 +2193,8 @@
   /// cast. Return false if it's no a decl-specifier, or we're not sure.
   bool isKnownToBeDeclarationSpecifier() {
     if (getLangOpts().CPlusPlus)
-      return isCXXDeclarationSpecifier() == TPResult::True;
-    return isDeclarationSpecifier(true);
+      return isCXXDeclarationSpecifier(ITC_Never) == TPResult::True;
+    return isDeclarationSpecifier(ITC_Never, true);
   }
 
   /// isDeclarationStatement - Disambiguates between a declaration or an
@@ -2163,7 +2203,7 @@
   bool isDeclarationStatement() {
     if (getLangOpts().CPlusPlus)
       return isCXXDeclarationStatement();
-    return isDeclarationSpecifier(true);
+    return isDeclarationSpecifier(ITC_Never, true);
   }
 
   /// isForInitDeclaration - Disambiguates between a declaration or an
@@ -2175,7 +2215,7 @@
       Actions.startOpenMPLoop();
     if (getLangOpts().CPlusPlus)
       return isCXXSimpleDeclaration(/*AllowForRangeDecl=*/true);
-    return isDeclarationSpecifier(true);
+    return isDeclarationSpecifier(ITC_Never, true);
   }
 
   /// Determine whether this is a C++1z for-range-identifier.
@@ -2242,7 +2282,9 @@
   /// might be a constructor-style initializer.
   /// If during the disambiguation process a parsing error is encountered,
   /// the function returns true to let the declaration parsing code handle it.
-  bool isCXXFunctionDeclarator(bool *IsAmbiguous = nullptr);
+  bool isCXXFunctionDeclarator(
+      bool *IsAmbiguous = nullptr,
+      ImplicitTypenameContext AllowImplicitTypename = ITC_Never);
 
   struct ConditionDeclarationOrInitStatementState;
   enum class ConditionOrInitStatement {
@@ -2291,7 +2333,8 @@
   /// BracedCastResult.
   /// Doesn't consume tokens.
   TPResult
-  isCXXDeclarationSpecifier(TPResult BracedCastResult = TPResult::False,
+  isCXXDeclarationSpecifier(ImplicitTypenameContext AllowImplicitTypename,
+                            TPResult BracedCastResult = TPResult::False,
                             bool *HasMissingTypename = nullptr);
 
   /// Given that isCXXDeclarationSpecifier returns \c TPResult::True or
@@ -2319,9 +2362,9 @@
   TPResult TryParseInitDeclaratorList();
   TPResult TryParseDeclarator(bool mayBeAbstract, bool mayHaveIdentifier = true,
                               bool mayHaveDirectInit = false);
-  TPResult
-  TryParseParameterDeclarationClause(bool *InvalidAsDeclaration = nullptr,
-                                     bool VersusTemplateArg = false);
+  TPResult TryParseParameterDeclarationClause(
+      bool *InvalidAsDeclaration = nullptr, bool VersusTemplateArg = false,
+      ImplicitTypenameContext AllowImplicitTypename = ITC_Never);
   TPResult TryParseFunctionDeclarator();
   TPResult TryParseBracketDeclarator();
   TPResult TryConsumeDeclarationSpecifier();
Index: clang/include/clang/Basic/DiagnosticSemaKinds.td
===================================================================
--- clang/include/clang/Basic/DiagnosticSemaKinds.td
+++ clang/include/clang/Basic/DiagnosticSemaKinds.td
@@ -4459,6 +4459,12 @@
   "%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<"missing 'typename' prior to dependent "
+  "type name %0%1; 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
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits

Reply via email to