r292518 - PR13403 (+duplicates): implement C++ DR1310 (http://wg21.link/cwg1310).

Richard Smith via cfe-commits cfe-commits at lists.llvm.org
Thu Jan 19 13:00:13 PST 2017


Author: rsmith
Date: Thu Jan 19 15:00:13 2017
New Revision: 292518

URL: http://llvm.org/viewvc/llvm-project?rev=292518&view=rev
Log:
PR13403 (+duplicates): implement C++ DR1310 (http://wg21.link/cwg1310).

Under this defect resolution, the injected-class-name of a class or class
template cannot be used except in very limited circumstances (when declaring a
constructor, in a nested-name-specifier, in a base-specifier, or in an
elaborated-type-specifier). This is apparently done to make parsing easier, but
it's a pain for us since we don't know whether a template-id using the
injected-class-name is valid at the point when we annotate it (we don't yet
know whether the template-id will become part of an elaborated-type-specifier).

As a tentative resolution to a perceived language defect, mem-initializer-ids
are added to the list of exceptions here (they generally follow the same rules
as base-specifiers).

When the reference to the injected-class-name uses the 'typename' or 'template'
keywords, we permit it to be used to name a type or template as an extension;
other compilers also accept some cases in this area. There are also a couple of
corner cases with dependent template names that we do not yet diagnose, but
which will also get this treatment.

Modified:
    cfe/trunk/include/clang/Basic/DiagnosticParseKinds.td
    cfe/trunk/include/clang/Basic/DiagnosticSemaKinds.td
    cfe/trunk/include/clang/Sema/Sema.h
    cfe/trunk/lib/AST/ASTContext.cpp
    cfe/trunk/lib/Parse/ParseDecl.cpp
    cfe/trunk/lib/Parse/ParseExprCXX.cpp
    cfe/trunk/lib/Parse/ParseTemplate.cpp
    cfe/trunk/lib/Parse/Parser.cpp
    cfe/trunk/lib/Sema/SemaCXXScopeSpec.cpp
    cfe/trunk/lib/Sema/SemaDecl.cpp
    cfe/trunk/lib/Sema/SemaExprCXX.cpp
    cfe/trunk/lib/Sema/SemaTemplate.cpp
    cfe/trunk/test/CXX/basic/basic.lookup/basic.lookup.qual/class.qual/p2.cpp
    cfe/trunk/test/CXX/drs/dr13xx.cpp
    cfe/trunk/test/CXX/drs/dr1xx.cpp
    cfe/trunk/test/Driver/response-file.c
    cfe/trunk/test/Index/annotate-nested-name-specifier.cpp
    cfe/trunk/test/Parser/cxx0x-ambig.cpp
    cfe/trunk/test/SemaTemplate/injected-class-name.cpp
    cfe/trunk/test/SemaTemplate/instantiate-enum.cpp
    cfe/trunk/test/SemaTemplate/instantiate-member-class.cpp
    cfe/trunk/test/SemaTemplate/ms-sizeof-missing-typename.cpp
    cfe/trunk/www/cxx_dr_status.html

Modified: cfe/trunk/include/clang/Basic/DiagnosticParseKinds.td
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/Basic/DiagnosticParseKinds.td?rev=292518&r1=292517&r2=292518&view=diff
==============================================================================
--- cfe/trunk/include/clang/Basic/DiagnosticParseKinds.td (original)
+++ cfe/trunk/include/clang/Basic/DiagnosticParseKinds.td Thu Jan 19 15:00:13 2017
@@ -672,9 +672,6 @@ def warn_static_inline_explicit_inst_ign
 // Constructor template diagnostics.
 def err_out_of_line_constructor_template_id : Error<
   "out-of-line constructor for %0 cannot have template arguments">;
-def err_out_of_line_template_id_type_names_constructor : Error<
-  "qualified reference to %0 is a constructor name rather than a "
-  "%select{template name|type}1 wherever a constructor can be declared">;
 
 def err_expected_qualified_after_typename : Error<
   "expected a qualified name after 'typename'">;

Modified: cfe/trunk/include/clang/Basic/DiagnosticSemaKinds.td
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/Basic/DiagnosticSemaKinds.td?rev=292518&r1=292517&r2=292518&view=diff
==============================================================================
--- cfe/trunk/include/clang/Basic/DiagnosticSemaKinds.td (original)
+++ cfe/trunk/include/clang/Basic/DiagnosticSemaKinds.td Thu Jan 19 15:00:13 2017
@@ -1453,6 +1453,15 @@ def err_nested_name_spec_is_not_class :
 def ext_nested_name_spec_is_enum : ExtWarn<
   "use of enumeration in a nested name specifier is a C++11 extension">,
   InGroup<CXX11>;
+def err_out_of_line_qualified_id_type_names_constructor : Error<
+  "qualified reference to %0 is a constructor name rather than a "
+  "%select{template name|type}1 in this context">;
+def ext_out_of_line_qualified_id_type_names_constructor : ExtWarn<
+  "ISO C++ specifies that "
+  "qualified reference to %0 is a constructor name rather than a "
+  "%select{template name|type}1 in this context, despite preceding "
+  "%select{'typename'|'template'}2 keyword">, SFINAEFailure,
+  InGroup<DiagGroup<"injected-class-name">>;
 
 // C++ class members
 def err_storageclass_invalid_for_member : Error<
@@ -4316,7 +4325,7 @@ def err_template_kw_refers_to_non_templa
   "%0 following the 'template' keyword does not refer to a template">;
 def err_template_kw_refers_to_class_template : Error<
   "'%0%1' instantiated to a class template, not a function template">;
-def note_referenced_class_template : Error<
+def note_referenced_class_template : Note<
   "class template declared here">;
 def err_template_kw_missing : Error<
   "missing 'template' keyword prior to dependent template name '%0%1'">;

Modified: cfe/trunk/include/clang/Sema/Sema.h
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/Sema/Sema.h?rev=292518&r1=292517&r2=292518&view=diff
==============================================================================
--- cfe/trunk/include/clang/Sema/Sema.h (original)
+++ cfe/trunk/include/clang/Sema/Sema.h Thu Jan 19 15:00:13 2017
@@ -5937,7 +5937,8 @@ public:
 
   TypeResult
   ActOnTemplateIdType(CXXScopeSpec &SS, SourceLocation TemplateKWLoc,
-                      TemplateTy Template, SourceLocation TemplateLoc,
+                      TemplateTy Template, IdentifierInfo *TemplateII,
+                      SourceLocation TemplateIILoc,
                       SourceLocation LAngleLoc,
                       ASTTemplateArgsPtr TemplateArgs,
                       SourceLocation RAngleLoc,
@@ -6213,7 +6214,8 @@ public:
   /// \param SS the nested-name-specifier following the typename (e.g., 'T::').
   /// \param TemplateLoc the location of the 'template' keyword, if any.
   /// \param TemplateName The template name.
-  /// \param TemplateNameLoc The location of the template name.
+  /// \param TemplateII The identifier used to name the template.
+  /// \param TemplateIILoc The location of the template name.
   /// \param LAngleLoc The location of the opening angle bracket  ('<').
   /// \param TemplateArgs The template arguments.
   /// \param RAngleLoc The location of the closing angle bracket  ('>').
@@ -6222,7 +6224,8 @@ public:
                     const CXXScopeSpec &SS,
                     SourceLocation TemplateLoc,
                     TemplateTy TemplateName,
-                    SourceLocation TemplateNameLoc,
+                    IdentifierInfo *TemplateII,
+                    SourceLocation TemplateIILoc,
                     SourceLocation LAngleLoc,
                     ASTTemplateArgsPtr TemplateArgs,
                     SourceLocation RAngleLoc);

Modified: cfe/trunk/lib/AST/ASTContext.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/AST/ASTContext.cpp?rev=292518&r1=292517&r2=292518&view=diff
==============================================================================
--- cfe/trunk/lib/AST/ASTContext.cpp (original)
+++ cfe/trunk/lib/AST/ASTContext.cpp Thu Jan 19 15:00:13 2017
@@ -3785,12 +3785,8 @@ QualType ASTContext::getDependentNameTyp
                                           QualType Canon) const {
   if (Canon.isNull()) {
     NestedNameSpecifier *CanonNNS = getCanonicalNestedNameSpecifier(NNS);
-    ElaboratedTypeKeyword CanonKeyword = Keyword;
-    if (Keyword == ETK_None)
-      CanonKeyword = ETK_Typename;
-    
-    if (CanonNNS != NNS || CanonKeyword != Keyword)
-      Canon = getDependentNameType(CanonKeyword, CanonNNS, Name);
+    if (CanonNNS != NNS)
+      Canon = getDependentNameType(Keyword, CanonNNS, Name);
   }
 
   llvm::FoldingSetNodeID ID;

Modified: cfe/trunk/lib/Parse/ParseDecl.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Parse/ParseDecl.cpp?rev=292518&r1=292517&r2=292518&view=diff
==============================================================================
--- cfe/trunk/lib/Parse/ParseDecl.cpp (original)
+++ cfe/trunk/lib/Parse/ParseDecl.cpp Thu Jan 19 15:00:13 2017
@@ -2824,44 +2824,23 @@ void Parser::ParseDeclarationSpecifiers(
             ->Kind == TNK_Type_template) {
         // We have a qualified template-id, e.g., N::A<int>
 
-        // C++ [class.qual]p2:
-        //   In a lookup in which the constructor is an acceptable lookup
-        //   result and the nested-name-specifier nominates a class C:
+        // If this would be a valid constructor declaration with template
+        // arguments, we will reject the attempt to form an invalid type-id
+        // referring to the injected-class-name when we annotate the token,
+        // per C++ [class.qual]p2.
         //
-        //     - if the name specified after the
-        //       nested-name-specifier, when looked up in C, is the
-        //       injected-class-name of C (Clause 9), or
-        //
-        //     - if the name specified after the nested-name-specifier
-        //       is the same as the identifier or the
-        //       simple-template-id's template-name in the last
-        //       component of the nested-name-specifier,
-        //
-        //   the name is instead considered to name the constructor of
-        //   class C.
-        //
-        // Thus, if the template-name is actually the constructor
-        // name, then the code is ill-formed; this interpretation is
-        // reinforced by the NAD status of core issue 635.
+        // To improve diagnostics for this case, parse the declaration as a
+        // constructor (and reject the extra template arguments later).
         TemplateIdAnnotation *TemplateId = takeTemplateIdAnnotation(Next);
         if ((DSContext == DSC_top_level || DSContext == DSC_class) &&
             TemplateId->Name &&
-            Actions.isCurrentClassName(*TemplateId->Name, getCurScope(), &SS)) {
-          if (isConstructorDeclarator(/*Unqualified*/false)) {
-            // The user meant this to be an out-of-line constructor
-            // definition, but template arguments are not allowed
-            // there.  Just allow this as a constructor; we'll
-            // complain about it later.
-            goto DoneWithDeclSpec;
-          }
-
-          // The user meant this to name a type, but it actually names
-          // a constructor with some extraneous template
-          // arguments. Complain, then parse it as a type as the user
-          // intended.
-          Diag(TemplateId->TemplateNameLoc,
-               diag::err_out_of_line_template_id_type_names_constructor)
-            << TemplateId->Name << 0 /* template name */;
+            Actions.isCurrentClassName(*TemplateId->Name, getCurScope(), &SS) &&
+            isConstructorDeclarator(/*Unqualified*/false)) {
+          // The user meant this to be an out-of-line constructor
+          // definition, but template arguments are not allowed
+          // there.  Just allow this as a constructor; we'll
+          // complain about it later.
+          goto DoneWithDeclSpec;
         }
 
         DS.getTypeSpecScope() = SS;
@@ -2892,24 +2871,14 @@ void Parser::ParseDeclarationSpecifiers(
       if (Next.isNot(tok::identifier))
         goto DoneWithDeclSpec;
 
-      // If we're in a context where the identifier could be a class name,
-      // check whether this is a constructor declaration.
+      // Check whether this is a constructor declaration. If we're in a
+      // context where the identifier could be a class name, and it has the
+      // shape of a constructor declaration, process it as one.
       if ((DSContext == DSC_top_level || DSContext == DSC_class) &&
           Actions.isCurrentClassName(*Next.getIdentifierInfo(), getCurScope(),
-                                     &SS)) {
-        if (isConstructorDeclarator(/*Unqualified*/false))
-          goto DoneWithDeclSpec;
-
-        // As noted in C++ [class.qual]p2 (cited above), when the name
-        // of the class is qualified in a context where it could name
-        // a constructor, its a constructor name. However, we've
-        // looked at the declarator, and the user probably meant this
-        // to be a type. Complain that it isn't supposed to be treated
-        // as a type, then proceed to parse it as a type.
-        Diag(Next.getLocation(),
-             diag::err_out_of_line_template_id_type_names_constructor)
-          << Next.getIdentifierInfo() << 1 /* type */;
-      }
+                                     &SS) &&
+          isConstructorDeclarator(/*Unqualified*/ false))
+        goto DoneWithDeclSpec;
 
       ParsedType TypeRep =
           Actions.getTypeName(*Next.getIdentifierInfo(), Next.getLocation(),

Modified: cfe/trunk/lib/Parse/ParseExprCXX.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Parse/ParseExprCXX.cpp?rev=292518&r1=292517&r2=292518&view=diff
==============================================================================
--- cfe/trunk/lib/Parse/ParseExprCXX.cpp (original)
+++ cfe/trunk/lib/Parse/ParseExprCXX.cpp Thu Jan 19 15:00:13 2017
@@ -2155,7 +2155,7 @@ bool Parser::ParseUnqualifiedIdTemplateI
   // Constructor and destructor names.
   TypeResult Type
     = Actions.ActOnTemplateIdType(SS, TemplateKWLoc,
-                                  Template, NameLoc,
+                                  Template, Name, NameLoc,
                                   LAngleLoc, TemplateArgsPtr, RAngleLoc,
                                   /*IsCtorOrDtorName=*/true);
   if (Type.isInvalid())

Modified: cfe/trunk/lib/Parse/ParseTemplate.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Parse/ParseTemplate.cpp?rev=292518&r1=292517&r2=292518&view=diff
==============================================================================
--- cfe/trunk/lib/Parse/ParseTemplate.cpp (original)
+++ cfe/trunk/lib/Parse/ParseTemplate.cpp Thu Jan 19 15:00:13 2017
@@ -1000,13 +1000,13 @@ bool Parser::AnnotateTemplateIdToken(Tem
 
   // Build the annotation token.
   if (TNK == TNK_Type_template && AllowTypeAnnotation) {
-    TypeResult Type
-      = Actions.ActOnTemplateIdType(SS, TemplateKWLoc,
-                                    Template, TemplateNameLoc,
-                                    LAngleLoc, TemplateArgsPtr, RAngleLoc);
+    TypeResult Type = Actions.ActOnTemplateIdType(
+        SS, TemplateKWLoc, Template, TemplateName.Identifier,
+        TemplateNameLoc, LAngleLoc, TemplateArgsPtr, RAngleLoc);
     if (Type.isInvalid()) {
-      // If we failed to parse the template ID but skipped ahead to a >, we're not
-      // going to be able to form a token annotation.  Eat the '>' if present.
+      // If we failed to parse the template ID but skipped ahead to a >, we're
+      // not going to be able to form a token annotation.  Eat the '>' if
+      // present.
       TryConsumeToken(tok::greater);
       return true;
     }
@@ -1079,6 +1079,7 @@ void Parser::AnnotateTemplateIdTokenAsTy
     = Actions.ActOnTemplateIdType(TemplateId->SS,
                                   TemplateId->TemplateKWLoc,
                                   TemplateId->Template,
+                                  TemplateId->Name,
                                   TemplateId->TemplateNameLoc,
                                   TemplateId->LAngleLoc,
                                   TemplateArgsPtr,

Modified: cfe/trunk/lib/Parse/Parser.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Parse/Parser.cpp?rev=292518&r1=292517&r2=292518&view=diff
==============================================================================
--- cfe/trunk/lib/Parse/Parser.cpp (original)
+++ cfe/trunk/lib/Parse/Parser.cpp Thu Jan 19 15:00:13 2017
@@ -1701,6 +1701,7 @@ bool Parser::TryAnnotateTypeOrScopeToken
       Ty = Actions.ActOnTypenameType(getCurScope(), TypenameLoc, SS,
                                      TemplateId->TemplateKWLoc,
                                      TemplateId->Template,
+                                     TemplateId->Name,
                                      TemplateId->TemplateNameLoc,
                                      TemplateId->LAngleLoc,
                                      TemplateArgsPtr,

Modified: cfe/trunk/lib/Sema/SemaCXXScopeSpec.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Sema/SemaCXXScopeSpec.cpp?rev=292518&r1=292517&r2=292518&view=diff
==============================================================================
--- cfe/trunk/lib/Sema/SemaCXXScopeSpec.cpp (original)
+++ cfe/trunk/lib/Sema/SemaCXXScopeSpec.cpp Thu Jan 19 15:00:13 2017
@@ -933,8 +933,8 @@ bool Sema::ActOnCXXNestedNameSpecifier(S
 
   // We were able to resolve the template name to an actual template. 
   // Build an appropriate nested-name-specifier.
-  QualType T = CheckTemplateIdType(Template.get(), TemplateNameLoc, 
-                                   TemplateArgs);
+  QualType T =
+      CheckTemplateIdType(Template.get(), TemplateNameLoc, TemplateArgs);
   if (T.isNull())
     return true;
 

Modified: cfe/trunk/lib/Sema/SemaDecl.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Sema/SemaDecl.cpp?rev=292518&r1=292517&r2=292518&view=diff
==============================================================================
--- cfe/trunk/lib/Sema/SemaDecl.cpp (original)
+++ cfe/trunk/lib/Sema/SemaDecl.cpp Thu Jan 19 15:00:13 2017
@@ -425,6 +425,17 @@ ParsedType Sema::getTypeName(const Ident
 
   QualType T;
   if (TypeDecl *TD = dyn_cast<TypeDecl>(IIDecl)) {
+    // C++ [class.qual]p2: A lookup that would find the injected-class-name
+    // instead names the constructors of the class, except when naming a class.
+    // This is ill-formed when we're not actually forming a ctor or dtor name.
+    auto *LookupRD = dyn_cast_or_null<CXXRecordDecl>(LookupCtx);
+    auto *FoundRD = dyn_cast<CXXRecordDecl>(TD);
+    if (!isClassName && !IsCtorOrDtorName && LookupRD && FoundRD &&
+        FoundRD->isInjectedClassName() &&
+        declaresSameEntity(LookupRD, cast<Decl>(FoundRD->getParent())))
+      Diag(NameLoc, diag::err_out_of_line_qualified_id_type_names_constructor)
+          << &II << /*Type*/1;
+
     DiagnoseUseOfDecl(IIDecl, NameLoc);
 
     T = Context.getTypeDeclType(TD);
@@ -783,6 +794,13 @@ Sema::ClassifyName(Scope *S, CXXScopeSpe
   if (NextToken.is(tok::coloncolon)) {
     NestedNameSpecInfo IdInfo(Name, NameLoc, NextToken.getLocation());
     BuildCXXNestedNameSpecifier(S, IdInfo, false, SS, nullptr, false);
+  } else if (getLangOpts().CPlusPlus && SS.isSet() &&
+             isCurrentClassName(*Name, S, &SS)) {
+    // Per [class.qual]p2, this names the constructors of SS, not the
+    // injected-class-name. We don't have a classification for that.
+    // There's not much point caching this result, since the parser
+    // will reject it later.
+    return NameClassification::Unknown();
   }
 
   LookupResult Result(*this, Name, NameLoc, LookupOrdinaryName);

Modified: cfe/trunk/lib/Sema/SemaExprCXX.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Sema/SemaExprCXX.cpp?rev=292518&r1=292517&r2=292518&view=diff
==============================================================================
--- cfe/trunk/lib/Sema/SemaExprCXX.cpp (original)
+++ cfe/trunk/lib/Sema/SemaExprCXX.cpp Thu Jan 19 15:00:13 2017
@@ -6538,7 +6538,8 @@ ExprResult Sema::ActOnPseudoDestructorEx
   if (SecondTypeName.getKind() == UnqualifiedId::IK_Identifier) {
     ParsedType T = getTypeName(*SecondTypeName.Identifier,
                                SecondTypeName.StartLocation,
-                               S, &SS, true, false, ObjectTypePtrForLookup);
+                               S, &SS, true, false, ObjectTypePtrForLookup,
+                               /*IsCtorOrDtorName*/true);
     if (!T &&
         ((SS.isSet() && !computeDeclContext(SS, false)) ||
          (!SS.isSet() && ObjectType->isDependentType()))) {
@@ -6567,10 +6568,12 @@ ExprResult Sema::ActOnPseudoDestructorEx
     TypeResult T = ActOnTemplateIdType(TemplateId->SS,
                                        TemplateId->TemplateKWLoc,
                                        TemplateId->Template,
+                                       TemplateId->Name,
                                        TemplateId->TemplateNameLoc,
                                        TemplateId->LAngleLoc,
                                        TemplateArgsPtr,
-                                       TemplateId->RAngleLoc);
+                                       TemplateId->RAngleLoc,
+                                       /*IsCtorOrDtorName*/true);
     if (T.isInvalid() || !T.get()) {
       // Recover by assuming we had the right type all along.
       DestructedType = ObjectType;
@@ -6595,7 +6598,8 @@ ExprResult Sema::ActOnPseudoDestructorEx
     if (FirstTypeName.getKind() == UnqualifiedId::IK_Identifier) {
       ParsedType T = getTypeName(*FirstTypeName.Identifier,
                                  FirstTypeName.StartLocation,
-                                 S, &SS, true, false, ObjectTypePtrForLookup);
+                                 S, &SS, true, false, ObjectTypePtrForLookup,
+                                 /*IsCtorOrDtorName*/true);
       if (!T) {
         Diag(FirstTypeName.StartLocation,
              diag::err_pseudo_dtor_destructor_non_type)
@@ -6616,10 +6620,12 @@ ExprResult Sema::ActOnPseudoDestructorEx
       TypeResult T = ActOnTemplateIdType(TemplateId->SS,
                                          TemplateId->TemplateKWLoc,
                                          TemplateId->Template,
+                                         TemplateId->Name,
                                          TemplateId->TemplateNameLoc,
                                          TemplateId->LAngleLoc,
                                          TemplateArgsPtr,
-                                         TemplateId->RAngleLoc);
+                                         TemplateId->RAngleLoc,
+                                         /*IsCtorOrDtorName*/true);
       if (T.isInvalid() || !T.get()) {
         // Recover by dropping this type.
         ScopeType = QualType();

Modified: cfe/trunk/lib/Sema/SemaTemplate.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Sema/SemaTemplate.cpp?rev=292518&r1=292517&r2=292518&view=diff
==============================================================================
--- cfe/trunk/lib/Sema/SemaTemplate.cpp (original)
+++ cfe/trunk/lib/Sema/SemaTemplate.cpp Thu Jan 19 15:00:13 2017
@@ -2421,7 +2421,8 @@ QualType Sema::CheckTemplateIdType(Templ
 
 TypeResult
 Sema::ActOnTemplateIdType(CXXScopeSpec &SS, SourceLocation TemplateKWLoc,
-                          TemplateTy TemplateD, SourceLocation TemplateLoc,
+                          TemplateTy TemplateD, IdentifierInfo *TemplateII,
+                          SourceLocation TemplateIILoc,
                           SourceLocation LAngleLoc,
                           ASTTemplateArgsPtr TemplateArgsIn,
                           SourceLocation RAngleLoc,
@@ -2429,6 +2430,23 @@ Sema::ActOnTemplateIdType(CXXScopeSpec &
   if (SS.isInvalid())
     return true;
 
+  // Per C++ [class.qual]p2, if the template-id was an injected-class-name,
+  // it's not actually allowed to be used as a type in most cases. Because
+  // we annotate it before we know whether it's valid, we have to check for
+  // this case here.
+  if (!IsCtorOrDtorName) {
+    auto *LookupRD =
+        dyn_cast_or_null<CXXRecordDecl>(computeDeclContext(SS, true));
+    if (LookupRD && LookupRD->getIdentifier() == TemplateII) {
+      Diag(TemplateIILoc,
+           TemplateKWLoc.isInvalid()
+               ? diag::err_out_of_line_qualified_id_type_names_constructor
+               : diag::ext_out_of_line_qualified_id_type_names_constructor)
+        << TemplateII << 0 /*injected-class-name used as template name*/
+        << 1 /*if any keyword was present, it was 'template'*/;
+    }
+  }
+
   TemplateName Template = TemplateD.get();
 
   // Translate the parser's template argument list in our AST format.
@@ -2448,7 +2466,7 @@ Sema::ActOnTemplateIdType(CXXScopeSpec &
     SpecTL.setElaboratedKeywordLoc(SourceLocation());
     SpecTL.setQualifierLoc(SS.getWithLocInContext(Context));
     SpecTL.setTemplateKeywordLoc(TemplateKWLoc);
-    SpecTL.setTemplateNameLoc(TemplateLoc);
+    SpecTL.setTemplateNameLoc(TemplateIILoc);
     SpecTL.setLAngleLoc(LAngleLoc);
     SpecTL.setRAngleLoc(RAngleLoc);
     for (unsigned I = 0, N = SpecTL.getNumArgs(); I != N; ++I)
@@ -2456,8 +2474,7 @@ Sema::ActOnTemplateIdType(CXXScopeSpec &
     return CreateParsedType(T, TLB.getTypeSourceInfo(Context, T));
   }
 
-  QualType Result = CheckTemplateIdType(Template, TemplateLoc, TemplateArgs);
-
+  QualType Result = CheckTemplateIdType(Template, TemplateIILoc, TemplateArgs);
   if (Result.isNull())
     return true;
 
@@ -2466,7 +2483,7 @@ Sema::ActOnTemplateIdType(CXXScopeSpec &
   TemplateSpecializationTypeLoc SpecTL
     = TLB.push<TemplateSpecializationTypeLoc>(Result);
   SpecTL.setTemplateKeywordLoc(TemplateKWLoc);
-  SpecTL.setTemplateNameLoc(TemplateLoc);
+  SpecTL.setTemplateNameLoc(TemplateIILoc);
   SpecTL.setLAngleLoc(LAngleLoc);
   SpecTL.setRAngleLoc(RAngleLoc);
   for (unsigned i = 0, e = SpecTL.getNumArgs(); i != e; ++i)
@@ -8532,7 +8549,8 @@ Sema::ActOnTypenameType(Scope *S,
                         const CXXScopeSpec &SS,
                         SourceLocation TemplateKWLoc,
                         TemplateTy TemplateIn,
-                        SourceLocation TemplateNameLoc,
+                        IdentifierInfo *TemplateII,
+                        SourceLocation TemplateIILoc,
                         SourceLocation LAngleLoc,
                         ASTTemplateArgsPtr TemplateArgsIn,
                         SourceLocation RAngleLoc) {
@@ -8543,6 +8561,17 @@ Sema::ActOnTypenameType(Scope *S,
            diag::ext_typename_outside_of_template)
       << FixItHint::CreateRemoval(TypenameLoc);
 
+  // Strangely, non-type results are not ignored by this lookup, so the
+  // program is ill-formed if it finds an injected-class-name.
+  auto *LookupRD =
+      dyn_cast_or_null<CXXRecordDecl>(computeDeclContext(SS, true));
+  if (LookupRD && LookupRD->getIdentifier() == TemplateII) {
+    Diag(TemplateIILoc,
+         diag::ext_out_of_line_qualified_id_type_names_constructor)
+      << TemplateII << 0 /*injected-class-name used as template name*/
+      << (TemplateKWLoc.isValid() ? 1 : 0 /*'template'/'typename' keyword*/);
+  }
+
   // Translate the parser's template argument list in our AST format.
   TemplateArgumentListInfo TemplateArgs(LAngleLoc, RAngleLoc);
   translateTemplateArguments(TemplateArgsIn, TemplateArgs);
@@ -8564,7 +8593,7 @@ Sema::ActOnTypenameType(Scope *S,
     SpecTL.setElaboratedKeywordLoc(TypenameLoc);
     SpecTL.setQualifierLoc(SS.getWithLocInContext(Context));
     SpecTL.setTemplateKeywordLoc(TemplateKWLoc);
-    SpecTL.setTemplateNameLoc(TemplateNameLoc);
+    SpecTL.setTemplateNameLoc(TemplateIILoc);
     SpecTL.setLAngleLoc(LAngleLoc);
     SpecTL.setRAngleLoc(RAngleLoc);
     for (unsigned I = 0, N = TemplateArgs.size(); I != N; ++I)
@@ -8572,7 +8601,7 @@ Sema::ActOnTypenameType(Scope *S,
     return CreateParsedType(T, Builder.getTypeSourceInfo(Context, T));
   }
 
-  QualType T = CheckTemplateIdType(Template, TemplateNameLoc, TemplateArgs);
+  QualType T = CheckTemplateIdType(Template, TemplateIILoc, TemplateArgs);
   if (T.isNull())
     return true;
 
@@ -8581,7 +8610,7 @@ Sema::ActOnTypenameType(Scope *S,
   TemplateSpecializationTypeLoc SpecTL
     = Builder.push<TemplateSpecializationTypeLoc>(T);
   SpecTL.setTemplateKeywordLoc(TemplateKWLoc);
-  SpecTL.setTemplateNameLoc(TemplateNameLoc);
+  SpecTL.setTemplateNameLoc(TemplateIILoc);
   SpecTL.setLAngleLoc(LAngleLoc);
   SpecTL.setRAngleLoc(RAngleLoc);
   for (unsigned I = 0, N = TemplateArgs.size(); I != N; ++I)
@@ -8708,10 +8737,32 @@ Sema::CheckTypenameType(ElaboratedTypeKe
 
   case LookupResult::Found:
     if (TypeDecl *Type = dyn_cast<TypeDecl>(Result.getFoundDecl())) {
+      // C++ [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
+      //   after the nested-name-specifier, when looked up in C, is the
+      //   injected-class-name of C [...] then the name is instead considered
+      //   to name the constructor of class C.
+      //
+      // Unlike in an elaborated-type-specifier, function names are not ignored
+      // in typename-specifier lookup. However, they are ignored in all the
+      // contexts where we form a typename type with no keyword (that is, in
+      // mem-initializer-ids, base-specifiers, and elaborated-type-specifiers).
+      //
+      // FIXME: That's not strictly true: mem-initializer-id lookup does not
+      // ignore functions, but that appears to be an oversight.
+      auto *LookupRD = dyn_cast_or_null<CXXRecordDecl>(Ctx);
+      auto *FoundRD = dyn_cast<CXXRecordDecl>(Type);
+      if (Keyword == ETK_Typename && LookupRD && FoundRD &&
+          FoundRD->isInjectedClassName() &&
+          declaresSameEntity(LookupRD, cast<Decl>(FoundRD->getParent())))
+        Diag(IILoc, diag::ext_out_of_line_qualified_id_type_names_constructor)
+            << &II << 1 << 0 /*'typename' keyword used*/;
+
       // We found a type. Build an ElaboratedType, since the
       // typename-specifier was just sugar.
       MarkAnyDeclReferenced(Type->getLocation(), Type, /*OdrUse=*/false);
-      return Context.getElaboratedType(ETK_Typename,
+      return Context.getElaboratedType(Keyword,
                                        QualifierLoc.getNestedNameSpecifier(),
                                        Context.getTypeDeclType(Type));
     }

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=292518&r1=292517&r2=292518&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 15:00:13 2017
@@ -1,17 +1,23 @@
 // RUN: %clang_cc1 -fsyntax-only -verify -std=c++98 %s
 // RUN: %clang_cc1 -fsyntax-only -verify -std=c++11 %s
 struct X0 {
+  X0();
+  X0(int);
   X0 f1();
   X0 f2();
+  typedef int A;
+  typedef X0 B;
 };
 
 template<typename T>
-struct X1 {
+struct X1 : X0 {
+  X1();
   X1<T>(int);
   (X1<T>)(float);
   X1 f2();
   X1 f2(int);
   X1 f2(float);
+  X1 f2(double);
 };
 
 // Error recovery: out-of-line constructors whose names have template arguments.
@@ -19,13 +25,88 @@ template<typename T> X1<T>::X1<T>(int) {
 template<typename T> (X1<T>::X1<T>)(float) { } // expected-error{{out-of-line constructor for 'X1' cannot have template arguments}}
 
 // Error recovery: out-of-line constructor names intended to be types
-X0::X0 X0::f1() { return X0(); } // expected-error{{qualified reference to 'X0' is a constructor name rather than a type wherever a constructor can be declared}}
+X0::X0 X0::f1() { return X0(); } // expected-error{{qualified reference to 'X0' is a constructor name rather than a type in this context}}
 
 struct X0::X0 X0::f2() { return X0(); }
 
-template<typename T> X1<T>::X1<T> X1<T>::f2() { } // expected-error{{qualified reference to 'X1' is a constructor name rather than a template name wherever a constructor can be declared}}
-template<typename T> X1<T>::X1<T> (X1<T>::f2)(int) { } // expected-error{{qualified reference to 'X1' is a constructor name rather than a template name wherever a constructor can be declared}}
+template<typename T> X1<T>::X1<T> X1<T>::f2() { } // expected-error{{qualified reference to 'X1' is a constructor name rather than a template name in this context}}
+template<typename T> X1<T>::X1<T> (X1<T>::f2)(int) { } // expected-error{{qualified reference to 'X1' is a constructor name rather than a template name in this context}}
 template<typename T> struct X1<T>::X1<T> (X1<T>::f2)(float) { }
+template<typename T> struct X1<T>::X1 (X1<T>::f2)(double) { }
+
+void x1test(X1<int> x1i) {
+  x1i.f2();
+  x1i.f2(0);
+  x1i.f2(0.f);
+  x1i.f2(0.);
+}
+
+void other_contexts() {
+  X0::X0 x0; // expected-error{{qualified reference to 'X0' is a constructor name rather than a type in this context}}
+  X1<int>::X1 x1a; // expected-error{{qualified reference to 'X1' is a constructor name rather than a type in this context}}
+  X1<int>::X1<float> x1b; // expected-error{{qualified reference to 'X1' is a constructor name rather than a template name in this context}}
+
+  X0::B ok1;
+  X0::X0::A ok2;
+  X0::X0::X0 x0b; // expected-error{{qualified reference to 'X0' is a constructor name rather than a type in this context}}
+  X1<int>::X0 ok3;
+  X1<int>::X0::X0 x0c; // expected-error{{qualified reference to 'X0' is a constructor name rather than a type in this context}}
+  X1<int>::X1<float>::X0 ok4;
+
+  {
+    typename X0::X0 tn1; // expected-warning{{qualified reference to 'X0' is a constructor name rather than a type in this context}} expected-warning 0-1{{typename}}
+    typename X1<int>::X1<float> tn2; // expected-warning{{qualified reference to 'X1' is a constructor name rather than a template name in this context}} expected-warning 0-1{{typename}}
+    typename X0::B ok1; // expected-warning 0-1{{typename}}
+    typename X1<int>::X0 ok2; // expected-warning 0-1{{typename}}
+  }
+
+  {
+    struct X0::X0 tag1;
+    struct X1<int>::X1 tag2;
+    struct X1<int>::X1<int> tag3;
+  }
+
+  int a;
+  {
+    X0::X0(a); // expected-error{{qualified reference to 'X0' is a constructor name rather than a type in this context}}
+  }
+}
+
+template<typename T> void in_instantiation_x0() {
+  typename T::X0 x0; // expected-warning{{qualified reference to 'X0' is a constructor name rather than a type in this context}}
+  typename T::A a;
+  typename T::B b;
+}
+template void in_instantiation_x0<X0>(); // expected-note {{instantiation of}}
+
+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::X0 x0;
+}
+template void in_instantiation_x1<X1<int> >(); // expected-note {{instantiation of}}
+
+namespace sfinae {
+  template<typename T> void f(typename T::X0 *) = delete; // expected-warning 0-1{{extension}}
+  template<typename T> void f(...);
+  void g() { f<X0>(0); }
+}
+
+namespace versus_injected_class_name {
+  template <typename T> struct A : T::B {
+    struct T::B *p;
+    typename T::B::type a;
+    A() : T::B() {}
+
+    typename T::B b; // expected-warning {{qualified reference to 'B' is a constructor name rather than a type in this context}}
+  };
+  struct B {
+    typedef int type;
+  };
+  template struct A<B>; // expected-note {{in instantiation of}}
+}
 
 // We have a special case for lookup within using-declarations that are
 // member-declarations: foo::bar::baz::baz always names baz's constructor

Modified: cfe/trunk/test/CXX/drs/dr13xx.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/CXX/drs/dr13xx.cpp?rev=292518&r1=292517&r2=292518&view=diff
==============================================================================
--- cfe/trunk/test/CXX/drs/dr13xx.cpp (original)
+++ cfe/trunk/test/CXX/drs/dr13xx.cpp Thu Jan 19 15:00:13 2017
@@ -13,6 +13,59 @@ namespace std {
   };
 }
 
+namespace dr1310 { // dr1310: partial
+  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}}
+  }
+  struct T { int n; typedef int U; typedef T V; };
+  int k = T().T::T::n;
+  T::V v;
+
+  struct U { int U; };
+  int u = U().U::U;
+  struct U::U w;
+
+  struct V : T::T {
+    // FIXME: This is technically ill-formed, but we consider that to be a defect.
+    V() : T::T() {}
+  };
+  template<typename T> struct VT : T::T {
+    VT() : T::T() {}
+  };
+  template struct VT<T>;
+
+  template<template<typename> class> class TT {};
+
+  template<typename T> struct W {};
+
+  void w_test() {
+    W<int>::W w1a; // expected-error {{qualified reference to 'W' is a constructor name}}
+    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}}
+  }
+
+  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}}
+  }
+  template void wt_test<W<int> >(); // expected-note {{instantiation of}}
+}
+
 namespace dr1315 { // dr1315: partial
   template <int I, int J> struct A {};
   template <int I> // expected-note {{non-deducible template parameter 'I'}}

Modified: cfe/trunk/test/CXX/drs/dr1xx.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/CXX/drs/dr1xx.cpp?rev=292518&r1=292517&r2=292518&view=diff
==============================================================================
--- cfe/trunk/test/CXX/drs/dr1xx.cpp (original)
+++ cfe/trunk/test/CXX/drs/dr1xx.cpp Thu Jan 19 15:00:13 2017
@@ -535,13 +535,15 @@ namespace dr145 { // dr145: yes
   }
 }
 
-namespace dr147 { // dr147: no
+namespace dr147 { // dr147: yes
   namespace example1 {
     template<typename> struct A {
       template<typename T> A(T);
     };
-    // FIXME: This appears to be valid, and EDG and G++ accept.
+    // Per core issue 1435, this is ill-formed because A<int>::A<int> does not
+    // name the injected-class-name. (A<int>::A does, though.)
     template<> template<> A<int>::A<int>(int) {} // expected-error {{out-of-line constructor for 'A' cannot have template arguments}}
+    template<> template<> A<float>::A(float) {}
   }
   namespace example2 {
     struct A { A(); };

Modified: cfe/trunk/test/Driver/response-file.c
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/Driver/response-file.c?rev=292518&r1=292517&r2=292518&view=diff
==============================================================================
--- cfe/trunk/test/Driver/response-file.c (original)
+++ cfe/trunk/test/Driver/response-file.c Thu Jan 19 15:00:13 2017
@@ -1,5 +1,7 @@
 // REQUIRES: long_tests
 
+// RUN: false
+
 // Check that clang is able to process short response files
 // Since this is a short response file, clang must not use a response file
 // to pass its parameters to other tools. This is only necessary for a large

Modified: cfe/trunk/test/Index/annotate-nested-name-specifier.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/Index/annotate-nested-name-specifier.cpp?rev=292518&r1=292517&r2=292518&view=diff
==============================================================================
--- cfe/trunk/test/Index/annotate-nested-name-specifier.cpp (original)
+++ cfe/trunk/test/Index/annotate-nested-name-specifier.cpp Thu Jan 19 15:00:13 2017
@@ -266,7 +266,7 @@ struct X9 : X8 {
 // CHECK: Identifier: "vector" [57:51 - 57:57] TemplateRef=vector:4:12
 // CHECK: Punctuation: "<" [57:57 - 57:58] MemberRefExpr=
 // CHECK: Identifier: "T" [57:58 - 57:59] TypeRef=T:54:19
-// CHECK: Punctuation: ">" [57:59 - 57:60] CallExpr=
+// CHECK: Punctuation: ">" [57:59 - 57:60] MemberRefExpr=
 // CHECK: Punctuation: "(" [57:60 - 57:61] CallExpr=
 // CHECK: Punctuation: ")" [57:61 - 57:62] CallExpr=
 

Modified: cfe/trunk/test/Parser/cxx0x-ambig.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/Parser/cxx0x-ambig.cpp?rev=292518&r1=292517&r2=292518&view=diff
==============================================================================
--- cfe/trunk/test/Parser/cxx0x-ambig.cpp (original)
+++ cfe/trunk/test/Parser/cxx0x-ambig.cpp Thu Jan 19 15:00:13 2017
@@ -109,7 +109,7 @@ namespace trailing_return {
 namespace ellipsis {
   template<typename...T>
   struct S {
-    void e(S::S());
+    void e(S::S()); // expected-error {{is a constructor name}}
     void f(S(...args[sizeof(T)])); // expected-note {{here}} expected-note {{here}}
     void f(S(...args)[sizeof(T)]); // expected-error {{redeclared}}
     void f(S ...args[sizeof(T)]); // expected-error {{redeclared}}

Modified: cfe/trunk/test/SemaTemplate/injected-class-name.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/SemaTemplate/injected-class-name.cpp?rev=292518&r1=292517&r2=292518&view=diff
==============================================================================
--- cfe/trunk/test/SemaTemplate/injected-class-name.cpp (original)
+++ cfe/trunk/test/SemaTemplate/injected-class-name.cpp Thu Jan 19 15:00:13 2017
@@ -11,7 +11,10 @@ struct X<int***> {
   typedef X<int***> *ptr;
 };
 
-X<float>::X<int> xi = x; // expected-error{{qualified reference to 'X' is a constructor name rather than a template name wherever a constructor can be declared}}
+X<float>::X<int> xi = x; // expected-error{{qualified reference to 'X' is a constructor name rather than a template name}}
+void f() {
+  X<float>::X<int> xi = x; // expected-error{{qualified reference to 'X' is a constructor name rather than a template name}}
+}
 
 // [temp.local]p1:
 

Modified: cfe/trunk/test/SemaTemplate/instantiate-enum.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/SemaTemplate/instantiate-enum.cpp?rev=292518&r1=292517&r2=292518&view=diff
==============================================================================
--- cfe/trunk/test/SemaTemplate/instantiate-enum.cpp (original)
+++ cfe/trunk/test/SemaTemplate/instantiate-enum.cpp Thu Jan 19 15:00:13 2017
@@ -29,13 +29,14 @@ namespace PR6375 {
 namespace EnumScoping {
 
 template <typename T>
-class C {
+struct C {
+  struct X {};
   enum {
     value = 42
   };
 };
 
-void f(int i, C<int>::C c) {
+void f(int i, C<int>::X c) {
   int value;
 }
 

Modified: cfe/trunk/test/SemaTemplate/instantiate-member-class.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/SemaTemplate/instantiate-member-class.cpp?rev=292518&r1=292517&r2=292518&view=diff
==============================================================================
--- cfe/trunk/test/SemaTemplate/instantiate-member-class.cpp (original)
+++ cfe/trunk/test/SemaTemplate/instantiate-member-class.cpp Thu Jan 19 15:00:13 2017
@@ -39,8 +39,8 @@ public:
 X<int>::C *c1;
 X<float>::C *c2;
 
-X<int>::X *xi; // expected-error{{qualified reference to 'X' is a constructor name rather than a type wherever a constructor can be declared}}
-X<float>::X *xf; // expected-error{{qualified reference to 'X' is a constructor name rather than a type wherever a constructor can be declared}}
+X<int>::X *xi; // expected-error{{qualified reference to 'X' is a constructor name rather than a type}}
+X<float>::X *xf; // expected-error{{qualified reference to 'X' is a constructor name rather than a type}}
 
 void test_naming() {
   c1 = c2; // expected-error{{assigning to 'X<int>::C *' from incompatible type 'X<float>::C *'}}

Modified: cfe/trunk/test/SemaTemplate/ms-sizeof-missing-typename.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/SemaTemplate/ms-sizeof-missing-typename.cpp?rev=292518&r1=292517&r2=292518&view=diff
==============================================================================
--- cfe/trunk/test/SemaTemplate/ms-sizeof-missing-typename.cpp (original)
+++ cfe/trunk/test/SemaTemplate/ms-sizeof-missing-typename.cpp Thu Jan 19 15:00:13 2017
@@ -53,7 +53,7 @@ namespace ambiguous_missing_parens {
 // expected-error at +1 {{'Q::U' instantiated to a class template, not a function template}}
 template <typename T> void f() { int a = sizeof T::template U<0> + 4; }
 struct Q {
-  // expected-error at +1 {{class template declared here}}
+  // expected-note at +1 {{class template declared here}}
   template <int> struct U {};
 };
 // expected-note-re at +1 {{in instantiation {{.*}} requested here}}

Modified: cfe/trunk/www/cxx_dr_status.html
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/www/cxx_dr_status.html?rev=292518&r1=292517&r2=292518&view=diff
==============================================================================
--- cfe/trunk/www/cxx_dr_status.html (original)
+++ cfe/trunk/www/cxx_dr_status.html Thu Jan 19 15:00:13 2017
@@ -921,7 +921,7 @@
     <td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_defects.html#147">147</a></td>
     <td>TC1</td>
     <td>Naming the constructor</td>
-    <td class="none" align="center">No</td>
+    <td class="full" align="center">Yes</td>
   </tr>
   <tr id="148">
     <td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_defects.html#148">148</a></td>
@@ -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="none" align="center">Superseded by <a href="#1310">1310</a></td>
+    <td class="partial" 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="none" align="center">Unknown</td>
+    <td class="partial" align="center">Partial</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