r292545 - Finish implementation of C++ DR1310 (http://wg21.link/cwg1310).

Richard Smith via cfe-commits cfe-commits at lists.llvm.org
Thu Jan 19 16:20:39 PST 2017


Author: rsmith
Date: Thu Jan 19 18:20:39 2017
New Revision: 292545

URL: http://llvm.org/viewvc/llvm-project?rev=292545&view=rev
Log:
Finish implementation of C++ DR1310 (http://wg21.link/cwg1310).

Diagnose the case when a dependent template name instantiates to an
injected-class-name outside a nested-name-specifier.

Modified:
    cfe/trunk/include/clang/Sema/Sema.h
    cfe/trunk/lib/Parse/ParseExprCXX.cpp
    cfe/trunk/lib/Sema/SemaTemplate.cpp
    cfe/trunk/lib/Sema/SemaTemplateInstantiate.cpp
    cfe/trunk/lib/Sema/TreeTransform.h
    cfe/trunk/test/CXX/basic/basic.lookup/basic.lookup.qual/class.qual/p2.cpp
    cfe/trunk/test/CXX/drs/dr10xx.cpp
    cfe/trunk/test/CXX/drs/dr13xx.cpp
    cfe/trunk/www/cxx_dr_status.html

Modified: cfe/trunk/include/clang/Sema/Sema.h
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/Sema/Sema.h?rev=292545&r1=292544&r2=292545&view=diff
==============================================================================
--- cfe/trunk/include/clang/Sema/Sema.h (original)
+++ cfe/trunk/include/clang/Sema/Sema.h Thu Jan 19 18:20:39 2017
@@ -5984,13 +5984,10 @@ public:
                                const DeclarationNameInfo &NameInfo,
                                const TemplateArgumentListInfo *TemplateArgs);
 
-  TemplateNameKind ActOnDependentTemplateName(Scope *S,
-                                              CXXScopeSpec &SS,
-                                              SourceLocation TemplateKWLoc,
-                                              UnqualifiedId &Name,
-                                              ParsedType ObjectType,
-                                              bool EnteringContext,
-                                              TemplateTy &Template);
+  TemplateNameKind ActOnDependentTemplateName(
+      Scope *S, CXXScopeSpec &SS, SourceLocation TemplateKWLoc,
+      UnqualifiedId &Name, ParsedType ObjectType, bool EnteringContext,
+      TemplateTy &Template, bool AllowInjectedClassName = false);
 
   DeclResult
   ActOnClassTemplateSpecialization(Scope *S, unsigned TagSpec, TagUseKind TUK,

Modified: cfe/trunk/lib/Parse/ParseExprCXX.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Parse/ParseExprCXX.cpp?rev=292545&r1=292544&r2=292545&view=diff
==============================================================================
--- cfe/trunk/lib/Parse/ParseExprCXX.cpp (original)
+++ cfe/trunk/lib/Parse/ParseExprCXX.cpp Thu Jan 19 18:20:39 2017
@@ -310,11 +310,9 @@ bool Parser::ParseOptionalCXXScopeSpecif
       // Commit to parsing the template-id.
       TPA.Commit();
       TemplateTy Template;
-      if (TemplateNameKind TNK
-          = Actions.ActOnDependentTemplateName(getCurScope(),
-                                               SS, TemplateKWLoc, TemplateName,
-                                               ObjectType, EnteringContext,
-                                               Template)) {
+      if (TemplateNameKind TNK = Actions.ActOnDependentTemplateName(
+              getCurScope(), SS, TemplateKWLoc, TemplateName, ObjectType,
+              EnteringContext, Template, /*AllowInjectedClassName*/ true)) {
         if (AnnotateTemplateIdToken(Template, TNK, SS, TemplateKWLoc,
                                     TemplateName, false))
           return true;
@@ -509,12 +507,10 @@ bool Parser::ParseOptionalCXXScopeSpecif
         Diag(Tok.getLocation(), DiagID)
           << II.getName()
           << FixItHint::CreateInsertion(Tok.getLocation(), "template ");
-        
-        if (TemplateNameKind TNK 
-              = Actions.ActOnDependentTemplateName(getCurScope(), 
-                                                   SS, SourceLocation(),
-                                                   TemplateName, ObjectType,
-                                                   EnteringContext, Template)) {
+
+        if (TemplateNameKind TNK = Actions.ActOnDependentTemplateName(
+                getCurScope(), SS, SourceLocation(), TemplateName, ObjectType,
+                EnteringContext, Template, /*AllowInjectedClassName*/ true)) {
           // Consume the identifier.
           ConsumeToken();
           if (AnnotateTemplateIdToken(Template, TNK, SS, SourceLocation(),
@@ -2020,9 +2016,11 @@ bool Parser::ParseUnqualifiedIdTemplateI
   case UnqualifiedId::IK_OperatorFunctionId:
   case UnqualifiedId::IK_LiteralOperatorId:
     if (AssumeTemplateId) {
-      TNK = Actions.ActOnDependentTemplateName(getCurScope(), SS, TemplateKWLoc,
-                                               Id, ObjectType, EnteringContext,
-                                               Template);
+      // We defer the injected-class-name checks until we've found whether
+      // this template-id is used to form a nested-name-specifier or not.
+      TNK = Actions.ActOnDependentTemplateName(
+          getCurScope(), SS, TemplateKWLoc, Id, ObjectType, EnteringContext,
+          Template, /*AllowInjectedClassName*/ true);
       if (TNK == TNK_Non_template)
         return true;
     } else {
@@ -2051,10 +2049,9 @@ bool Parser::ParseUnqualifiedIdTemplateI
         Diag(Id.StartLocation, diag::err_missing_dependent_template_keyword)
           << Name
           << FixItHint::CreateInsertion(Id.StartLocation, "template ");
-        TNK = Actions.ActOnDependentTemplateName(getCurScope(),
-                                                 SS, TemplateKWLoc, Id,
-                                                 ObjectType, EnteringContext,
-                                                 Template);
+        TNK = Actions.ActOnDependentTemplateName(
+            getCurScope(), SS, TemplateKWLoc, Id, ObjectType, EnteringContext,
+            Template, /*AllowInjectedClassName*/ true);
         if (TNK == TNK_Non_template)
           return true;              
       }
@@ -2077,10 +2074,9 @@ bool Parser::ParseUnqualifiedIdTemplateI
     bool MemberOfUnknownSpecialization;
     TemplateName.setIdentifier(Name, NameLoc);
     if (ObjectType) {
-      TNK = Actions.ActOnDependentTemplateName(getCurScope(),
-                                               SS, TemplateKWLoc, TemplateName,
-                                               ObjectType, EnteringContext,
-                                               Template);
+      TNK = Actions.ActOnDependentTemplateName(
+          getCurScope(), SS, TemplateKWLoc, TemplateName, ObjectType,
+          EnteringContext, Template, /*AllowInjectedClassName*/ true);
       if (TNK == TNK_Non_template)
         return true;
     } else {

Modified: cfe/trunk/lib/Sema/SemaTemplate.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Sema/SemaTemplate.cpp?rev=292545&r1=292544&r2=292545&view=diff
==============================================================================
--- cfe/trunk/lib/Sema/SemaTemplate.cpp (original)
+++ cfe/trunk/lib/Sema/SemaTemplate.cpp Thu Jan 19 18:20:39 2017
@@ -3241,7 +3241,8 @@ TemplateNameKind Sema::ActOnDependentTem
                                                   UnqualifiedId &Name,
                                                   ParsedType ObjectType,
                                                   bool EnteringContext,
-                                                  TemplateTy &Result) {
+                                                  TemplateTy &Result,
+                                                  bool AllowInjectedClassName) {
   if (TemplateKWLoc.isValid() && S && !S->getTemplateParamParent())
     Diag(TemplateKWLoc,
          getLangOpts().CPlusPlus11 ?
@@ -3289,6 +3290,24 @@ TemplateNameKind Sema::ActOnDependentTem
       return TNK_Non_template;
     } else {
       // We found something; return it.
+      auto *LookupRD = dyn_cast<CXXRecordDecl>(LookupCtx);
+      if (!AllowInjectedClassName && SS.isSet() && LookupRD &&
+          Name.getKind() == UnqualifiedId::IK_Identifier && Name.Identifier &&
+          LookupRD->getIdentifier() == Name.Identifier) {
+        // C++14 [class.qual]p2:
+        //   In a lookup in which function names are not ignored and the
+        //   nested-name-specifier nominates a class C, if the name specified
+        //   [...] is the injected-class-name of C, [...] the name is instead
+        //   considered to name the constructor
+        //
+        // We don't get here if naming the constructor would be valid, so we
+        // just reject immediately and recover by treating the
+        // injected-class-name as naming the template.
+        Diag(Name.getLocStart(),
+             diag::ext_out_of_line_qualified_id_type_names_constructor)
+          << Name.Identifier << 0 /*injected-class-name used as template name*/
+          << 1 /*'template' keyword was used*/;
+      }
       return TNK;
     }
   }

Modified: cfe/trunk/lib/Sema/SemaTemplateInstantiate.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Sema/SemaTemplateInstantiate.cpp?rev=292545&r1=292544&r2=292545&view=diff
==============================================================================
--- cfe/trunk/lib/Sema/SemaTemplateInstantiate.cpp (original)
+++ cfe/trunk/lib/Sema/SemaTemplateInstantiate.cpp Thu Jan 19 18:20:39 2017
@@ -806,7 +806,8 @@ namespace {
     TransformTemplateName(CXXScopeSpec &SS, TemplateName Name,
                           SourceLocation NameLoc,
                           QualType ObjectType = QualType(),
-                          NamedDecl *FirstQualifierInScope = nullptr);
+                          NamedDecl *FirstQualifierInScope = nullptr,
+                          bool AllowInjectedClassName = false);
 
     const LoopHintAttr *TransformLoopHintAttr(const LoopHintAttr *LH);
 
@@ -1040,11 +1041,10 @@ TemplateInstantiator::RebuildElaboratedT
                                                                     T);
 }
 
-TemplateName TemplateInstantiator::TransformTemplateName(CXXScopeSpec &SS,
-                                                         TemplateName Name,
-                                                         SourceLocation NameLoc,
-                                                         QualType ObjectType,
-                                             NamedDecl *FirstQualifierInScope) {
+TemplateName TemplateInstantiator::TransformTemplateName(
+    CXXScopeSpec &SS, TemplateName Name, SourceLocation NameLoc,
+    QualType ObjectType, NamedDecl *FirstQualifierInScope,
+    bool AllowInjectedClassName) {
   if (TemplateTemplateParmDecl *TTP
        = dyn_cast_or_null<TemplateTemplateParmDecl>(Name.getAsTemplateDecl())) {
     if (TTP->getDepth() < TemplateArgs.getNumLevels()) {
@@ -1095,9 +1095,10 @@ TemplateName TemplateInstantiator::Trans
     Arg = getPackSubstitutedTemplateArgument(getSema(), Arg);
     return Arg.getAsTemplate();
   }
-  
-  return inherited::TransformTemplateName(SS, Name, NameLoc, ObjectType, 
-                                          FirstQualifierInScope);  
+
+  return inherited::TransformTemplateName(SS, Name, NameLoc, ObjectType,
+                                          FirstQualifierInScope,
+                                          AllowInjectedClassName);
 }
 
 ExprResult 

Modified: cfe/trunk/lib/Sema/TreeTransform.h
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Sema/TreeTransform.h?rev=292545&r1=292544&r2=292545&view=diff
==============================================================================
--- cfe/trunk/lib/Sema/TreeTransform.h (original)
+++ cfe/trunk/lib/Sema/TreeTransform.h Thu Jan 19 18:20:39 2017
@@ -505,7 +505,8 @@ public:
   TransformTemplateName(CXXScopeSpec &SS, TemplateName Name,
                         SourceLocation NameLoc,
                         QualType ObjectType = QualType(),
-                        NamedDecl *FirstQualifierInScope = nullptr);
+                        NamedDecl *FirstQualifierInScope = nullptr,
+                        bool AllowInjectedClassName = false);
 
   /// \brief Transform the given template argument.
   ///
@@ -916,14 +917,15 @@ public:
                                           NestedNameSpecifierLoc QualifierLoc,
                                           const IdentifierInfo *Name,
                                           SourceLocation NameLoc,
-                                          TemplateArgumentListInfo &Args) {
+                                          TemplateArgumentListInfo &Args,
+                                          bool AllowInjectedClassName) {
     // Rebuild the template name.
     // TODO: avoid TemplateName abstraction
     CXXScopeSpec SS;
     SS.Adopt(QualifierLoc);
     TemplateName InstName
       = getDerived().RebuildTemplateName(SS, *Name, NameLoc, QualType(),
-                                         nullptr);
+                                         nullptr, AllowInjectedClassName);
 
     if (InstName.isNull())
       return QualType();
@@ -1088,7 +1090,8 @@ public:
                                    const IdentifierInfo &Name,
                                    SourceLocation NameLoc,
                                    QualType ObjectType,
-                                   NamedDecl *FirstQualifierInScope);
+                                   NamedDecl *FirstQualifierInScope,
+                                   bool AllowInjectedClassName);
 
   /// \brief Build a new template name given a nested name specifier and the
   /// overloaded operator name that is referred to as a template.
@@ -1100,7 +1103,8 @@ public:
   TemplateName RebuildTemplateName(CXXScopeSpec &SS,
                                    OverloadedOperatorKind Operator,
                                    SourceLocation NameLoc,
-                                   QualType ObjectType);
+                                   QualType ObjectType,
+                                   bool AllowInjectedClassName);
 
   /// \brief Build a new template name given a template template parameter pack
   /// and the
@@ -3601,7 +3605,8 @@ TreeTransform<Derived>::TransformTemplat
                                               TemplateName Name,
                                               SourceLocation NameLoc,
                                               QualType ObjectType,
-                                              NamedDecl *FirstQualifierInScope) {
+                                              NamedDecl *FirstQualifierInScope,
+                                              bool AllowInjectedClassName) {
   if (QualifiedTemplateName *QTN = Name.getAsQualifiedTemplateName()) {
     TemplateDecl *Template = QTN->getTemplateDecl();
     assert(Template && "qualified template name must refer to a template");
@@ -3638,11 +3643,12 @@ TreeTransform<Derived>::TransformTemplat
                                               *DTN->getIdentifier(),
                                               NameLoc,
                                               ObjectType,
-                                              FirstQualifierInScope);
+                                              FirstQualifierInScope,
+                                              AllowInjectedClassName);
     }
 
     return getDerived().RebuildTemplateName(SS, DTN->getOperator(), NameLoc,
-                                            ObjectType);
+                                            ObjectType, AllowInjectedClassName);
   }
 
   if (TemplateDecl *Template = Name.getAsTemplateDecl()) {
@@ -4152,11 +4158,9 @@ TypeSourceInfo *TreeTransform<Derived>::
     TemplateSpecializationTypeLoc SpecTL =
         TL.castAs<TemplateSpecializationTypeLoc>();
 
-    TemplateName Template
-    = getDerived().TransformTemplateName(SS,
-                                         SpecTL.getTypePtr()->getTemplateName(),
-                                         SpecTL.getTemplateNameLoc(),
-                                         ObjectType, UnqualLookup);
+    TemplateName Template = getDerived().TransformTemplateName(
+        SS, SpecTL.getTypePtr()->getTemplateName(), SpecTL.getTemplateNameLoc(),
+        ObjectType, UnqualLookup, /*AllowInjectedClassName*/true);
     if (Template.isNull())
       return nullptr;
 
@@ -4170,7 +4174,8 @@ TypeSourceInfo *TreeTransform<Derived>::
       = getDerived().RebuildTemplateName(SS,
                                          *SpecTL.getTypePtr()->getIdentifier(),
                                          SpecTL.getTemplateNameLoc(),
-                                         ObjectType, UnqualLookup);
+                                         ObjectType, UnqualLookup,
+                                         /*AllowInjectedClassName*/true);
     if (Template.isNull())
       return nullptr;
 
@@ -5878,12 +5883,10 @@ TransformDependentTemplateSpecialization
                                               NewTemplateArgs))
     return QualType();
 
-  QualType Result
-    = getDerived().RebuildDependentTemplateSpecializationType(T->getKeyword(),
-                                                              QualifierLoc,
-                                                            T->getIdentifier(),
-                                                       TL.getTemplateNameLoc(),
-                                                            NewTemplateArgs);
+  QualType Result = getDerived().RebuildDependentTemplateSpecializationType(
+      T->getKeyword(), QualifierLoc, T->getIdentifier(),
+      TL.getTemplateNameLoc(), NewTemplateArgs,
+      /*AllowInjectedClassName*/ false);
   if (Result.isNull())
     return QualType();
 
@@ -12015,7 +12018,8 @@ TreeTransform<Derived>::RebuildTemplateN
                                             const IdentifierInfo &Name,
                                             SourceLocation NameLoc,
                                             QualType ObjectType,
-                                            NamedDecl *FirstQualifierInScope) {
+                                            NamedDecl *FirstQualifierInScope,
+                                            bool AllowInjectedClassName) {
   UnqualifiedId TemplateName;
   TemplateName.setIdentifier(&Name, NameLoc);
   Sema::TemplateTy Template;
@@ -12024,7 +12028,7 @@ TreeTransform<Derived>::RebuildTemplateN
                                        SS, TemplateKWLoc, TemplateName,
                                        ParsedType::make(ObjectType),
                                        /*EnteringContext=*/false,
-                                       Template);
+                                       Template, AllowInjectedClassName);
   return Template.get();
 }
 
@@ -12033,7 +12037,8 @@ TemplateName
 TreeTransform<Derived>::RebuildTemplateName(CXXScopeSpec &SS,
                                             OverloadedOperatorKind Operator,
                                             SourceLocation NameLoc,
-                                            QualType ObjectType) {
+                                            QualType ObjectType,
+                                            bool AllowInjectedClassName) {
   UnqualifiedId Name;
   // FIXME: Bogus location information.
   SourceLocation SymbolLocations[3] = { NameLoc, NameLoc, NameLoc };
@@ -12044,7 +12049,7 @@ TreeTransform<Derived>::RebuildTemplateN
                                        SS, TemplateKWLoc, Name,
                                        ParsedType::make(ObjectType),
                                        /*EnteringContext=*/false,
-                                       Template);
+                                       Template, AllowInjectedClassName);
   return Template.get();
 }
 

Modified: cfe/trunk/test/CXX/basic/basic.lookup/basic.lookup.qual/class.qual/p2.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/CXX/basic/basic.lookup/basic.lookup.qual/class.qual/p2.cpp?rev=292545&r1=292544&r2=292545&view=diff
==============================================================================
--- cfe/trunk/test/CXX/basic/basic.lookup/basic.lookup.qual/class.qual/p2.cpp (original)
+++ cfe/trunk/test/CXX/basic/basic.lookup/basic.lookup.qual/class.qual/p2.cpp Thu Jan 19 18:20:39 2017
@@ -81,9 +81,7 @@ template void in_instantiation_x0<X0>();
 
 template<typename T> void in_instantiation_x1() {
   typename T::X1 x1; // expected-warning{{qualified reference to 'X1' is a constructor name rather than a type in this context}}
-  // FIXME: Matching the behavior of other compilers, we do not treat this case
-  // as naming the constructor.
-  typename T::template X1<int> x1i;
+  typename T::template X1<int> x1i; // expected-warning{{qualified reference to 'X1' is a constructor name rather than a template name in this context}}
   typename T::X0 x0;
 }
 template void in_instantiation_x1<X1<int> >(); // expected-note {{instantiation of}}

Modified: cfe/trunk/test/CXX/drs/dr10xx.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/CXX/drs/dr10xx.cpp?rev=292545&r1=292544&r2=292545&view=diff
==============================================================================
--- cfe/trunk/test/CXX/drs/dr10xx.cpp (original)
+++ cfe/trunk/test/CXX/drs/dr10xx.cpp Thu Jan 19 18:20:39 2017
@@ -29,10 +29,11 @@ namespace dr1004 { // dr1004: 5
     }
   };
 
-  // FIXME: Is this example (from the standard) really OK, or does name lookup
-  // of "T::template A" name the constructor?
-  template<class T, template<class> class U = T::template A> struct Third { };
-  Third<A<int> > t;
+  // This example (from the standard) is actually ill-formed, because
+  // name lookup of "T::template A" names the constructor.
+  // FIXME: Only issue one diagnostic for this case.
+  template<class T, template<class> class U = T::template A> struct Third { }; // expected-error 2{{is a constructor name}}
+  Third<A<int> > t; // expected-note {{in instantiation of}} expected-note {{while substituting}} expected-note {{while checking}}
 }
 
 namespace dr1048 { // dr1048: 3.6

Modified: cfe/trunk/test/CXX/drs/dr13xx.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/CXX/drs/dr13xx.cpp?rev=292545&r1=292544&r2=292545&view=diff
==============================================================================
--- cfe/trunk/test/CXX/drs/dr13xx.cpp (original)
+++ cfe/trunk/test/CXX/drs/dr13xx.cpp Thu Jan 19 18:20:39 2017
@@ -13,7 +13,7 @@ namespace std {
   };
 }
 
-namespace dr1310 { // dr1310: partial
+namespace dr1310 { // dr1310: 5
   struct S {} * sp = new S::S; // expected-error {{qualified reference to 'S' is a constructor name}}
   void f() {
     S::S(a); // expected-error {{qualified reference to 'S' is a constructor name}}
@@ -36,34 +36,61 @@ namespace dr1310 { // dr1310: partial
   template struct VT<T>;
 
   template<template<typename> class> class TT {};
+  template<typename> class TTy {};
 
-  template<typename T> struct W {};
+  template<typename T> struct WBase {};
+  template<typename T> struct W : WBase<T> { typedef int X; int n; };
 
   void w_test() {
     W<int>::W w1a; // expected-error {{qualified reference to 'W' is a constructor name}}
+    W<int>::W::X w1ax;
     W<int>::W<int> w1b; // expected-error {{qualified reference to 'W' is a constructor name}}
-    typename W<int>::W w2a; // expected-error {{qualified reference to 'W' is a constructor name}} expected-error 0-1{{typename}}
-    typename W<int>::W<int> w2b; // expected-error {{qualified reference to 'W' is a constructor name}} expected-error 0-1{{typename}}
-    W<int>::template W<int> w3; // expected-error {{qualified reference to 'W' is a constructor name}} expected-error 0-1{{template}}
-    typename W<int>::template W<int> w4; // expected-error {{qualified reference to 'W' is a constructor name}} expected-error 0-1{{typename}} expected-error 0-1{{template}}
-    TT<W<int>::W> tt1; // expected-error {{qualified reference to 'W' is a constructor name}} expected-error 0-1{{template}}
-    // FIXME: It's inconsistent for us to reject the above 'template' cases but
-    // not this one; per the standard, they are all ill-formed.
-    TT<W<int>::template W> tt2; // expected-error 0-1{{template}}
+    W<int>::W<int>::X w1bx;
+    typename W<int>::W w2a; // expected-error {{qualified reference to 'W' is a constructor name}} expected-error 0-1{{outside of a template}}
+    typename W<int>::W::X w2ax; // expected-error 0-1{{outside of a template}}
+    typename W<int>::W<int> w2b; // expected-error {{qualified reference to 'W' is a constructor name}} expected-error 0-1{{outside of a template}}
+    typename W<int>::W<int>::X w2bx; // expected-error 0-1{{outside of a template}}
+    W<int>::template W<int> w3; // expected-error {{qualified reference to 'W' is a constructor name}} expected-error 0-1{{outside of a template}}
+    W<int>::template W<int>::X w3x; // expected-error 0-1{{outside of a template}}
+    typename W<int>::template W<int> w4; // expected-error {{qualified reference to 'W' is a constructor name}} expected-error 0-2{{outside of a template}}
+    typename W<int>::template W<int>::X w4x; // expected-error 0-2{{outside of a template}}
+
+    TT<W<int>::W> tt1; // expected-error {{qualified reference to 'W' is a constructor name}}
+    TTy<W<int>::W> tt1a; // expected-error {{qualified reference to 'W' is a constructor name}}
+    TT<W<int>::template W> tt2; // expected-error {{qualified reference to 'W' is a constructor name}} expected-error 0-1{{outside of a template}}
+    TT<W<int>::WBase> tt3;
+    TTy<W<int>::WBase> tt3a;
+    TT<W<int>::template WBase> tt4; // expected-error 0-1{{outside of a template}}
+
+    W<int> w;
+    (void)w.W::W::n;
+    (void)w.W<int>::W::n;
+    (void)w.W<int>::W<int>::n;
+    (void)w.W<int>::template W<int>::n; // expected-error 0-1{{outside of a template}}
   }
 
   template<typename W>
   void wt_test() {
-    typename W::W w2a; // expected-error {{qualified reference to 'W' is a constructor name}} expected-error 0-1{{typename}}
-    // FIXME: We reject the non-dependent form of this, and this case appears
-    // to be ill-formed too. However, our behavior here matches that of other
-    // implementations.
-    typename W::template W<int> w4; // expected-error 0-1{{typename}} expected-error 0-1{{template}}
-    // FIXME: We reject the non-dependent form of this one, too.
-    TT<W::W> tt1; // expected-error 0-1{{template}}
-    TT<W::template W> tt2; // expected-error 0-1{{template}}
+    typename W::W w2a; // expected-error {{qualified reference to 'W' is a constructor name}}
+    typename W::template W<int> w4; // expected-error {{qualified reference to 'W' is a constructor name}}
+    TTy<typename W::W> tt2; // expected-error {{qualified reference to 'W' is a constructor name}}
+    TT<W::template W> tt3; // expected-error {{qualified reference to 'W' is a constructor name}}
+  }
+  template<typename W>
+  void wt_test_good() {
+    typename W::W::X w2ax;
+    typename W::template W<int>::X w4x;
+    TTy<typename W::WBase> tt4;
+    TT<W::template WBase> tt5;
+
+    W w;
+    (void)w.W::W::n;
+    (void)w.W::template W<int>::n;
+    (void)w.template W<int>::W::n;
+    (void)w.template W<int>::template W<int>::n;
   }
   template void wt_test<W<int> >(); // expected-note {{instantiation of}}
+  template void wt_test_good<W<int> >();
 }
 
 namespace dr1315 { // dr1315: partial

Modified: cfe/trunk/www/cxx_dr_status.html
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/www/cxx_dr_status.html?rev=292545&r1=292544&r2=292545&view=diff
==============================================================================
--- cfe/trunk/www/cxx_dr_status.html (original)
+++ cfe/trunk/www/cxx_dr_status.html Thu Jan 19 18:20:39 2017
@@ -1949,7 +1949,7 @@ of class templates</td>
     <td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_defects.html#318">318</a></td>
     <td>CD1</td>
     <td><TT>struct A::A</TT> should not name the constructor of <TT>A</TT></td>
-    <td class="partial" align="center">Superseded by <a href="#1310">1310</a></td>
+    <td class="svn" align="center">Superseded by <a href="#1310">1310</a></td>
   </tr>
   <tr id="319">
     <td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_defects.html#319">319</a></td>
@@ -7675,7 +7675,7 @@ and <I>POD class</I></td>
     <td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_defects.html#1310">1310</a></td>
     <td>CD3</td>
     <td>What is an “acceptable lookup result?”</td>
-    <td class="partial" align="center">Partial</td>
+    <td class="svn" align="center">SVN</td>
   </tr>
   <tr id="1311">
     <td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_defects.html#1311">1311</a></td>




More information about the cfe-commits mailing list