Rakete1111 updated this revision to Diff 172218.
Rakete1111 added a comment.

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


Repository:
  rC Clang

https://reviews.llvm.org/D53847

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

Index: test/SemaCXX/unknown-type-name.cpp
===================================================================
--- test/SemaCXX/unknown-type-name.cpp
+++ test/SemaCXX/unknown-type-name.cpp
@@ -36,15 +36,15 @@
 
   static int n;
   static type m;
-  static int h(T::type, int); // expected-error{{missing 'typename'}}
-  static int h(T::type x, char); // expected-error{{missing 'typename'}}
+  static int h(T::type, int); // expected-warning{{implicit 'typename' is a C++2a extension}}
+  static int h(T::type x, char); // expected-warning{{implicit 'typename' is a C++2a extension}}
 };
 
 template<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'}}
@@ -86,11 +86,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 +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/MicrosoftSuper.cpp
===================================================================
--- test/SemaCXX/MicrosoftSuper.cpp
+++ test/SemaCXX/MicrosoftSuper.cpp
@@ -108,8 +108,8 @@
   typename __super::XXX a;
   typedef typename __super::XXX b;
 
-  __super::XXX c;         // expected-error {{missing 'typename'}}
-  typedef __super::XXX d; // expected-error {{missing 'typename'}}
+  __super::XXX c;         // expected-warning {{implicit 'typename' is a C++2a extension}}
+  typedef __super::XXX d; // expected-warning {{implicit 'typename' is a C++2a extension}}
 
   void foo() {
     typename __super::XXX e;
@@ -127,8 +127,8 @@
   typename __super::XXX a;
   typedef typename __super::XXX b;
 
-  __super::XXX c;         // expected-error {{missing 'typename'}}
-  typedef __super::XXX d; // expected-error {{missing 'typename'}}
+  __super::XXX c;         // expected-warning {{implicit 'typename' is a C++2a extension}}
+  typedef __super::XXX d; // expected-warning {{implicit 'typename' is a C++2a extension}}
 
   void foo() {
     typename __super::XXX e;
Index: test/SemaCXX/MicrosoftExtensions.cpp
===================================================================
--- test/SemaCXX/MicrosoftExtensions.cpp
+++ test/SemaCXX/MicrosoftExtensions.cpp
@@ -526,7 +526,7 @@
 
 namespace PR32750 {
 template<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-error {{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: test/FixIt/fixit.cpp
===================================================================
--- test/FixIt/fixit.cpp
+++ 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: 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
@@ -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,141 @@
+// 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}}
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/SemaTemplate.cpp
===================================================================
--- lib/Sema/SemaTemplate.cpp
+++ lib/Sema/SemaTemplate.cpp
@@ -9413,7 +9413,7 @@
 TypeResult
 Sema::ActOnTypenameType(Scope *S, SourceLocation TypenameLoc,
                         const CXXScopeSpec &SS, const IdentifierInfo &II,
-                        SourceLocation IdLoc) {
+                        SourceLocation IdLoc, bool IsImplicitTypename) {
   if (SS.isInvalid())
     return true;
 
@@ -9425,8 +9425,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: 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,17 +308,37 @@
         //
         // 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;
+
+        // We need to delay this diagnostic for function parameters, because
+        // at that point we don't know whether the declarator-id of the
+        // function is qualified, which affects the interpretation of
+        // a dependent qualified name.
+        if (IsImplicitTypename && !S->isFunctionPrototypeScope()) {
+            SourceLocation QualifiedLoc = SS->getRange().getBegin();
+            if (getLangOpts().CPlusPlus2a)
+              Diag(QualifiedLoc,
+                   diag::warn_cxx17_compat_implicit_typename);
+            else
+              Diag(QualifiedLoc, diag::ext_implicit_typename)
+                  << 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,
+                                   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);
       }
 
@@ -395,7 +416,8 @@
                                     isClassName, HasTrailingDot, ObjectTypePtr,
                                     IsCtorOrDtorName,
                                     WantNontrivialTypeSourceInfo,
-                                    IsClassTemplateDeductionContext);
+                                    IsClassTemplateDeductionContext,
+                                    AllowImplicitTypename);
         if (Ty) {
           diagnoseTypo(Correction,
                        PDiag(diag::err_unknown_type_or_class_name_suggest)
@@ -8294,6 +8316,48 @@
   return S;
 }
 
+static bool HasParamImplicitTypename(Sema &S, ParmVarDecl *Param,
+                                     bool AllowImplicitTypename) {
+  if (const auto *TSI = Param->getTypeSourceInfo()) {
+    if (const auto DLoc = TSI->getTypeLoc()
+                              .getUnqualifiedLoc()
+                              .getAs<DependentNameTypeLoc>()) {
+      auto *DependentName =
+          cast<DependentNameType>(Param->getType().getTypePtr());
+      if (DependentName->getKeyword() == ETK_Typename &&
+          DLoc.getElaboratedKeywordLoc().isInvalid()) {
+        if (!AllowImplicitTypename)
+          S.Diag(Param->getBeginLoc(), diag::err_typename_missing)
+              << DependentName->getQualifier()
+              << DependentName->getIdentifier()->getName();
+        return true;
+      }
+    }
+  }
+  return false;
+}
+
+static void
+DiagnoseImplicitTypename(Sema &S, const DeclaratorChunk::FunctionTypeInfo &FTI,
+                         bool AllowImplicitTypename) {
+  for (std::size_t I = 0, Size = FTI.NumParams; I < Size; ++I) {
+    if (!FTI.Params[I].Param)
+      continue;
+
+    if (HasParamImplicitTypename(S, cast<ParmVarDecl>(FTI.Params[I].Param),
+                                 AllowImplicitTypename)) {
+      SourceLocation NameLoc = FTI.Params[I].Param->getBeginLoc();
+      if (AllowImplicitTypename) {
+        if (S.getLangOpts().CPlusPlus2a)
+          S.Diag(NameLoc, diag::warn_cxx17_compat_implicit_typename);
+        else
+          S.Diag(NameLoc, diag::ext_implicit_typename)
+              << FixItHint::CreateInsertion(NameLoc, "typename ");
+      }
+    }
+  }
+}
+
 NamedDecl*
 Sema::ActOnFunctionDeclarator(Scope *S, Declarator &D, DeclContext *DC,
                               TypeSourceInfo *TInfo, LookupResult &Previous,
@@ -9108,11 +9172,18 @@
   // marking the function.
   AddCFAuditedAttribute(NewFD);
 
-  // If this is a function definition, check if we have to apply optnone due to
-  // a pragma.
+  // If this is a function definition, check if we have to apply optnone due
+  // to a pragma.
   if(D.isFunctionDefinition())
     AddRangeBasedOptnone(NewFD);
 
+  // We delayed the diagnostic for implicit typename. Do it now.
+  if (D.isFunctionDeclarator()) {
+    DeclaratorChunk::FunctionTypeInfo FuncInfo = D.getFunctionTypeInfo();
+    DiagnoseImplicitTypename(*this, FuncInfo,
+                             S->isClassScope() || D.getCXXScopeSpec().isSet());
+  }
+
   // If this is the first declaration of an extern C variable, update
   // the map of such variables.
   if (NewFD->isFirstDecl() && !NewFD->isInvalidDecl() &&
Index: lib/Parse/Parser.cpp
===================================================================
--- lib/Parse/Parser.cpp
+++ lib/Parse/Parser.cpp
@@ -1773,8 +1773,9 @@
             *Tok.getIdentifierInfo(), Tok.getLocation(), getCurScope(), &SS,
             false, NextToken().is(tok::period), nullptr,
             /*IsCtorOrDtorName=*/false,
-            /*NonTrivialTypeSourceInfo*/true,
-            /*IsClassTemplateDeductionContext*/true)) {
+            /*NonTrivialTypeSourceInfo*/ 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/ParseTentative.cpp
===================================================================
--- lib/Parse/ParseTentative.cpp
+++ lib/Parse/ParseTentative.cpp
@@ -1788,9 +1788,14 @@
         // and can appear next in a function definition. This must be a function
         // declarator.
         TPR = TPResult::True;
-      else if (InvalidAsDeclaration)
+      else if (InvalidAsDeclaration) {
         // Use the absence of 'typename' as a tie-breaker.
         TPR = TPResult::False;
+        // But still mark the declaration as ambiguous, as the tie-breakter is
+        // not perfect.
+        if (IsAmbiguous)
+          *IsAmbiguous = true;
+      }
     }
   }
 
Index: lib/Parse/ParseExprCXX.cpp
===================================================================
--- lib/Parse/ParseExprCXX.cpp
+++ lib/Parse/ParseExprCXX.cpp
@@ -1351,7 +1351,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: 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
@@ -2691,6 +2691,16 @@
   if (Context == DeclaratorContext::AliasDeclContext ||
       Context == DeclaratorContext::AliasTemplateContext)
     return DeclSpecContext::DSC_alias_declaration;
+  if (Context == DeclaratorContext::BlockContext ||
+      Context == DeclaratorContext::ForContext ||
+      Context == DeclaratorContext::InitStmtContext ||
+      Context == DeclaratorContext::LambdaExprContext ||
+      Context == DeclaratorContext::CXXCatchContext)
+    return DeclSpecContext::DSC_block;
+  if (Context == DeclaratorContext::TypeNameContext)
+    return DeclSpecContext::DSC_type_specifier;
+  if (Context == DeclaratorContext::ConditionContext)
+    return DeclSpecContext::DSC_condition;
   return DeclSpecContext::DSC_normal;
 }
 
@@ -3101,7 +3111,8 @@
                               getCurScope(), &SS, false, false, nullptr,
                               /*IsCtorOrDtorName=*/false,
                               /*WantNonTrivialSourceInfo=*/true,
-                              isClassTemplateDeductionContext(DSContext));
+                              isClassTemplateDeductionContext(DSContext),
+                              isImplicitTypenameContext(DSContext));
 
       // If the referenced identifier is not a type, then this declspec is
       // erroneous: We already checked about that it has no type specifier, and
@@ -3231,7 +3242,6 @@
       if (DSContext == DeclSpecContext::DSC_objc_method_result &&
           isObjCInstancetype()) {
         ParsedType TypeRep = Actions.ActOnObjCInstanceType(Loc);
-        assert(TypeRep);
         isInvalid = DS.SetTypeSpecType(DeclSpec::TST_typename, Loc, PrevSpec,
                                        DiagID, TypeRep, Policy);
         if (isInvalid)
@@ -5828,6 +5838,25 @@
         TentativelyDeclaredIdentifiers.push_back(D.getIdentifier());
         bool IsFunctionDecl = isCXXFunctionDeclarator(&IsAmbiguous);
         TentativelyDeclaredIdentifiers.pop_back();
+
+        if (!IsFunctionDecl && IsAmbiguous) {
+          // We have an ambiguity between a function and a variable:
+          //   template <typename T> void N::f(T::type) [...]
+          // but only for qualified names.
+          if (D.getCXXScopeSpec().isSet()) {
+            LookupResult LR(Actions, D.getIdentifier(), D.getBeginLoc(),
+                            Sema::LookupOrdinaryName,
+                            Sema::ForVisibleRedeclaration);
+            DeclContext *DC = Actions.computeDeclContext(D.getCXXScopeSpec());
+            assert(DC && "couldn't find decl context of qualified name");
+            Actions.LookupQualifiedName(LR, DC);
+
+            IsFunctionDecl = true;
+            for (Decl *D : LR)
+              IsFunctionDecl &=
+                  isa<FunctionDecl>(D) || isa<FunctionTemplateDecl>(D);
+          }
+        }
         if (!IsFunctionDecl)
           break;
       }
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);
@@ -6486,10 +6487,11 @@
   /// \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.
-  TypeResult
-  ActOnTypenameType(Scope *S, SourceLocation TypenameLoc,
-                    const CXXScopeSpec &SS, const IdentifierInfo &II,
-                    SourceLocation IdLoc);
+  /// \param IsImplicitTypename whether the 'typename' is implicit.
+  TypeResult ActOnTypenameType(Scope *S, SourceLocation TypenameLoc,
+                               const CXXScopeSpec &SS, const IdentifierInfo &II,
+                               SourceLocation IdLoc,
+                               bool IsImplicitTypename = false);
 
   /// Called when the parser has parsed a C++ typename
   /// specifier that ends in a template-id, e.g.,
Index: include/clang/Parse/Parser.h
===================================================================
--- include/clang/Parse/Parser.h
+++ include/clang/Parse/Parser.h
@@ -1994,7 +1994,8 @@
     DSC_template_param, // template parameter context
     DSC_template_type_arg, // template type argument context
     DSC_objc_method_result, // ObjC method result context, enables 'instancetype'
-    DSC_condition // condition declaration context
+    DSC_condition, // condition declaration context
+    DSC_block, // declaration within a block
   };
 
   /// Is this a context in which we are parsing just a type-specifier (or
@@ -2007,6 +2008,7 @@
     case DeclSpecContext::DSC_top_level:
     case DeclSpecContext::DSC_objc_method_result:
     case DeclSpecContext::DSC_condition:
+    case DeclSpecContext::DSC_block:
       return false;
 
     case DeclSpecContext::DSC_template_type_arg:
@@ -2028,6 +2030,7 @@
     case DeclSpecContext::DSC_top_level:
     case DeclSpecContext::DSC_condition:
     case DeclSpecContext::DSC_type_specifier:
+    case DeclSpecContext::DSC_block:
       return true;
 
     case DeclSpecContext::DSC_objc_method_result:
@@ -2039,6 +2042,27 @@
     llvm_unreachable("Missing DeclSpecContext case");
   }
 
+  /// Context where an implicit typename is allowed.
+  static bool isImplicitTypenameContext(DeclSpecContext DSC) {
+    switch (DSC) {
+    case DeclSpecContext::DSC_class:
+    case DeclSpecContext::DSC_type_specifier:
+    case DeclSpecContext::DSC_trailing:
+    case DeclSpecContext::DSC_alias_declaration:
+    case DeclSpecContext::DSC_top_level:
+    case DeclSpecContext::DSC_template_param:
+    case DeclSpecContext::DSC_template_type_arg:
+    case DeclSpecContext::DSC_normal:
+      return true;
+
+    case DeclSpecContext::DSC_objc_method_result:
+    case DeclSpecContext::DSC_condition:
+    case DeclSpecContext::DSC_block:
+      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 {
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