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@+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@+1 {{class template declared here}} + // expected-note@+1 {{class template declared here}} template <int> struct U {}; }; // expected-note-re@+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> _______________________________________________ cfe-commits mailing list cfe-commits@lists.llvm.org http://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits