diff --git a/include/clang/AST/DeclCXX.h b/include/clang/AST/DeclCXX.h index 46434c4c7bb5ee79115fa2d449be5151b2a2a0e9..06ecd3c37342fd295401096be5d9f0ff62e219ea 100644 --- a/include/clang/AST/DeclCXX.h +++ b/include/clang/AST/DeclCXX.h @@ -3140,6 +3140,77 @@ public: friend class ASTDeclWriter; }; +/// Represents a pack of using declarations that a single +/// using-declarator pack-expanded into. +/// +/// \code +/// template<typename ...T> struct X : T... { +/// using T::operator()...; +/// using T::operator T...; +/// }; +/// \endcode +/// +/// In the second case above, the UsingPackDecl will have the name +/// 'operator T' (which contains an unexpanded pack), but the individual +/// UsingDecls and UsingShadowDecls will have more reasonable names. +class UsingPackDecl final + : public NamedDecl, public Mergeable<UsingPackDecl>, + private llvm::TrailingObjects<UsingPackDecl, NamedDecl *> { + void anchor() override; + + /// The UnresolvedUsingValueDecl or UnresolvedUsingTypenameDecl from + /// which this waas instantiated. + NamedDecl *InstantiatedFrom; + + /// The number of using-declarations created by this pack expansion. + unsigned NumExpansions; + + UsingPackDecl(DeclContext *DC, NamedDecl *InstantiatedFrom, + ArrayRef<NamedDecl *> UsingDecls) + : NamedDecl(UsingPack, DC, + InstantiatedFrom ? InstantiatedFrom->getLocation() + : SourceLocation(), + InstantiatedFrom ? InstantiatedFrom->getDeclName() + : DeclarationName()), + InstantiatedFrom(InstantiatedFrom), NumExpansions(UsingDecls.size()) { + std::uninitialized_copy(UsingDecls.begin(), UsingDecls.end(), + getTrailingObjects<NamedDecl *>()); + } + +public: + /// Get the using declaration from which this was instantiated. This will + /// always be an UnresolvedUsingValueDecl or an UnresolvedUsingTypenameDecl + /// that is a pack expansion. + NamedDecl *getInstantiatedFromUsingDecl() { return InstantiatedFrom; } + + /// Get the set of using declarations that this pack expanded into. Note that + /// some of these may still be unresolved. + ArrayRef<NamedDecl *> expansions() const { + return llvm::makeArrayRef(getTrailingObjects<NamedDecl *>(), NumExpansions); + } + + static UsingPackDecl *Create(ASTContext &C, DeclContext *DC, + NamedDecl *InstantiatedFrom, + ArrayRef<NamedDecl *> UsingDecls); + + static UsingPackDecl *CreateDeserialized(ASTContext &C, unsigned ID, + unsigned NumExpansions); + + SourceRange getSourceRange() const override LLVM_READONLY { + return InstantiatedFrom->getSourceRange(); + } + + UsingPackDecl *getCanonicalDecl() override { return getFirstDecl(); } + const UsingPackDecl *getCanonicalDecl() const { return getFirstDecl(); } + + static bool classof(const Decl *D) { return classofKind(D->getKind()); } + static bool classofKind(Kind K) { return K == UsingPack; } + + friend class ASTDeclReader; + friend class ASTDeclWriter; + friend TrailingObjects; +}; + /// \brief Represents a dependent using declaration which was not marked with /// \c typename. /// @@ -3158,6 +3229,9 @@ class UnresolvedUsingValueDecl : public ValueDecl, /// \brief The source location of the 'using' keyword SourceLocation UsingLocation; + /// \brief If this is a pack expansion, the location of the '...'. + SourceLocation EllipsisLoc; + /// \brief The nested-name-specifier that precedes the name. NestedNameSpecifierLoc QualifierLoc; @@ -3168,11 +3242,12 @@ class UnresolvedUsingValueDecl : public ValueDecl, UnresolvedUsingValueDecl(DeclContext *DC, QualType Ty, SourceLocation UsingLoc, NestedNameSpecifierLoc QualifierLoc, - const DeclarationNameInfo &NameInfo) + const DeclarationNameInfo &NameInfo, + SourceLocation EllipsisLoc) : ValueDecl(UnresolvedUsingValue, DC, NameInfo.getLoc(), NameInfo.getName(), Ty), - UsingLocation(UsingLoc), QualifierLoc(QualifierLoc), - DNLoc(NameInfo.getInfo()) + UsingLocation(UsingLoc), EllipsisLoc(EllipsisLoc), + QualifierLoc(QualifierLoc), DNLoc(NameInfo.getInfo()) { } public: @@ -3198,10 +3273,20 @@ public: return DeclarationNameInfo(getDeclName(), getLocation(), DNLoc); } + /// \brief Determine whether this is a pack expansion. + bool isPackExpansion() const { + return EllipsisLoc.isValid(); + } + + /// \brief Get the location of the ellipsis if this is a pack expansion. + SourceLocation getEllipsisLoc() const { + return EllipsisLoc; + } + static UnresolvedUsingValueDecl * Create(ASTContext &C, DeclContext *DC, SourceLocation UsingLoc, NestedNameSpecifierLoc QualifierLoc, - const DeclarationNameInfo &NameInfo); + const DeclarationNameInfo &NameInfo, SourceLocation EllipsisLoc); static UnresolvedUsingValueDecl * CreateDeserialized(ASTContext &C, unsigned ID); @@ -3242,6 +3327,9 @@ class UnresolvedUsingTypenameDecl /// \brief The source location of the 'typename' keyword SourceLocation TypenameLocation; + /// \brief If this is a pack expansion, the location of the '...'. + SourceLocation EllipsisLoc; + /// \brief The nested-name-specifier that precedes the name. NestedNameSpecifierLoc QualifierLoc; @@ -3249,10 +3337,12 @@ class UnresolvedUsingTypenameDecl SourceLocation TypenameLoc, NestedNameSpecifierLoc QualifierLoc, SourceLocation TargetNameLoc, - IdentifierInfo *TargetName) + IdentifierInfo *TargetName, + SourceLocation EllipsisLoc) : TypeDecl(UnresolvedUsingTypename, DC, TargetNameLoc, TargetName, UsingLoc), - TypenameLocation(TypenameLoc), QualifierLoc(QualifierLoc) { } + TypenameLocation(TypenameLoc), EllipsisLoc(EllipsisLoc), + QualifierLoc(QualifierLoc) { } friend class ASTDeclReader; @@ -3272,10 +3362,25 @@ public: return QualifierLoc.getNestedNameSpecifier(); } + DeclarationNameInfo getNameInfo() const { + return DeclarationNameInfo(getDeclName(), getLocation()); + } + + /// \brief Determine whether this is a pack expansion. + bool isPackExpansion() const { + return EllipsisLoc.isValid(); + } + + /// \brief Get the location of the ellipsis if this is a pack expansion. + SourceLocation getEllipsisLoc() const { + return EllipsisLoc; + } + static UnresolvedUsingTypenameDecl * Create(ASTContext &C, DeclContext *DC, SourceLocation UsingLoc, SourceLocation TypenameLoc, NestedNameSpecifierLoc QualifierLoc, - SourceLocation TargetNameLoc, DeclarationName TargetName); + SourceLocation TargetNameLoc, DeclarationName TargetName, + SourceLocation EllipsisLoc); static UnresolvedUsingTypenameDecl * CreateDeserialized(ASTContext &C, unsigned ID); diff --git a/include/clang/AST/RecursiveASTVisitor.h b/include/clang/AST/RecursiveASTVisitor.h index 058ab1fcbe9314ebf5f8c07e3bd4482e9a34f7fa..afacfd57231e6357f28119255e573bcd51b4465b 100644 --- a/include/clang/AST/RecursiveASTVisitor.h +++ b/include/clang/AST/RecursiveASTVisitor.h @@ -1505,6 +1505,8 @@ DEF_TRAVERSE_DECL(UsingDecl, { TRY_TO(TraverseDeclarationNameInfo(D->getNameInfo())); }) +DEF_TRAVERSE_DECL(UsingPackDecl, {}) + DEF_TRAVERSE_DECL(UsingDirectiveDecl, { TRY_TO(TraverseNestedNameSpecifierLoc(D->getQualifierLoc())); }) diff --git a/include/clang/Basic/DeclNodes.td b/include/clang/Basic/DeclNodes.td index 6da2c2c3d6c9cf22210e270f49cd1a68749c912d..7b581d3eec0fc8ade68692159be727914ef0376a 100644 --- a/include/clang/Basic/DeclNodes.td +++ b/include/clang/Basic/DeclNodes.td @@ -67,6 +67,7 @@ def Named : Decl<1>; def TemplateTemplateParm : DDecl<Template>; def BuiltinTemplate : DDecl<Template>; def Using : DDecl<Named>; + def UsingPack : DDecl<Named>; def UsingShadow : DDecl<Named>; def ConstructorUsingShadow : DDecl<UsingShadow>; def ObjCMethod : DDecl<Named>, DeclContext; diff --git a/include/clang/Basic/DiagnosticParseKinds.td b/include/clang/Basic/DiagnosticParseKinds.td index 0ebf34802bf8c66c086b0e3d5afdf98c72d4a01a..b5f3246e5302b04a551a9b2857453d38ccf4c725 100644 --- a/include/clang/Basic/DiagnosticParseKinds.td +++ b/include/clang/Basic/DiagnosticParseKinds.td @@ -740,6 +740,8 @@ def err_alias_declaration_not_identifier : Error< "name defined in alias declaration must be an identifier">; def err_alias_declaration_specialization : Error< "%select{partial specialization|explicit specialization|explicit instantiation}0 of alias templates is not permitted">; +def err_alias_declaration_pack_expansion : Error< + "alias declaration cannot be a pack expansion">; // C++1z using-declaration pack expansions def ext_multi_using_declaration : ExtWarn< @@ -749,6 +751,11 @@ def warn_cxx1z_compat_multi_using_declaration : Warning< "use of multiple declarators in a single using declaration is " "incompatible with C++ standards before C++1z">, InGroup<CXXPre1zCompat>, DefaultIgnore; +def ext_using_declaration_pack : ExtWarn< + "pack expansion of using declaration is a C++1z extension">, InGroup<CXX1z>; +def warn_cxx1z_compat_using_declaration_pack : Warning< + "pack expansion using declaration is incompatible with C++ standards " + "before C++1z">, InGroup<CXXPre1zCompat>, DefaultIgnore; // C++11 override control def ext_override_control_keyword : ExtWarn< diff --git a/include/clang/Basic/DiagnosticSemaKinds.td b/include/clang/Basic/DiagnosticSemaKinds.td index 73f7f4ddd6899992d8fb5025501bd7b708e1beb3..e98d282a21c134838e30543416a58ac7d87e2952 100644 --- a/include/clang/Basic/DiagnosticSemaKinds.td +++ b/include/clang/Basic/DiagnosticSemaKinds.td @@ -474,6 +474,8 @@ def err_using_decl_conflict : Error< def err_using_decl_conflict_reverse : Error< "declaration conflicts with target of using declaration already in scope">; def note_using_decl : Note<"%select{|previous }0using declaration">; +def err_using_decl_redeclaration_expansion : Error< + "using declaration pack expansion at block scope produces multiple values">; def warn_access_decl_deprecated : Warning< "access declarations are deprecated; use using declarations instead">, @@ -4155,6 +4157,9 @@ def err_variable_instantiates_to_function : Error< def err_nested_name_spec_non_tag : Error< "type %0 cannot be used prior to '::' because it has no members">; +def err_using_pack_expansion_empty : Error< + "%select{|member}0 using declaration %1 instantiates to an empty pack">; + // C++ Explicit Instantiation def err_explicit_instantiation_duplicate : Error< "duplicate explicit instantiation of %0">; diff --git a/include/clang/Parse/Parser.h b/include/clang/Parse/Parser.h index 3d098fab84a1d593157ead9327b536272801617b..972f13daca46b3a17949cfb1db15724ccd202f30 100644 --- a/include/clang/Parse/Parser.h +++ b/include/clang/Parse/Parser.h @@ -2436,9 +2436,10 @@ private: CXXScopeSpec SS; SourceLocation TemplateKWLoc; UnqualifiedId Name; + SourceLocation EllipsisLoc; void clear() { - TypenameLoc = TemplateKWLoc = SourceLocation(); + TypenameLoc = TemplateKWLoc = EllipsisLoc = SourceLocation(); SS.clear(); Name.clear(); } @@ -2450,9 +2451,6 @@ private: SourceLocation UsingLoc, SourceLocation &DeclEnd, AccessSpecifier AS = AS_none); - Decl *ParseAliasTemplate(const ParsedTemplateInfo &TemplateInfo, - SourceLocation &DeclEnd, AccessSpecifier AS, - ParsedAttributesWithRange &MisplacedAttrs1); Decl *ParseAliasDeclarationAfterDeclarator( const ParsedTemplateInfo &TemplateInfo, SourceLocation UsingLoc, UsingDeclarator &D, SourceLocation &DeclEnd, AccessSpecifier AS, diff --git a/include/clang/Sema/Sema.h b/include/clang/Sema/Sema.h index 136f848338802ae0fd75d31fba7fdc0e763a388b..ebbc1e1b3e821b48a370eb654e927f844484d9bf 100644 --- a/include/clang/Sema/Sema.h +++ b/include/clang/Sema/Sema.h @@ -4324,12 +4324,15 @@ public: NamedDecl *BuildUsingDeclaration(Scope *S, AccessSpecifier AS, SourceLocation UsingLoc, + bool HasTypenameKeyword, + SourceLocation TypenameLoc, CXXScopeSpec &SS, DeclarationNameInfo NameInfo, + SourceLocation EllipsisLoc, AttributeList *AttrList, - bool IsInstantiation, - bool HasTypenameKeyword, - SourceLocation TypenameLoc); + bool IsInstantiation); + NamedDecl *BuildUsingPackDecl(NamedDecl *InstantiatedFrom, + ArrayRef<NamedDecl *> Expansions); bool CheckInheritingConstructorUsingDecl(UsingDecl *UD); @@ -4343,10 +4346,11 @@ public: Decl *ActOnUsingDeclaration(Scope *CurScope, AccessSpecifier AS, SourceLocation UsingLoc, + SourceLocation TypenameLoc, CXXScopeSpec &SS, UnqualifiedId &Name, - AttributeList *AttrList, - SourceLocation TypenameLoc); + SourceLocation EllipsisLoc, + AttributeList *AttrList); Decl *ActOnAliasDeclaration(Scope *CurScope, AccessSpecifier AS, MultiTemplateParamsArg TemplateParams, @@ -6351,7 +6355,7 @@ public: /// /// \param SS The nested-name-specifier that will be traversed to find /// unexpanded parameter packs. - void collectUnexpandedParameterPacks(CXXScopeSpec &SS, + void collectUnexpandedParameterPacks(NestedNameSpecifierLoc NNS, SmallVectorImpl<UnexpandedParameterPack> &Unexpanded); /// \brief Collect the set of unexpanded parameter packs within the given diff --git a/include/clang/Sema/Template.h b/include/clang/Sema/Template.h index 0d128803541e25869853008414b4b1b7b63a1478..401bbbf1e5661c651b1b4063449948e98a0d691e 100644 --- a/include/clang/Sema/Template.h +++ b/include/clang/Sema/Template.h @@ -515,6 +515,11 @@ namespace clang { VarTemplateDecl *VarTemplate, VarTemplatePartialSpecializationDecl *PartialSpec); void InstantiateEnumDefinition(EnumDecl *Enum, EnumDecl *Pattern); + + private: + template<typename T> + Decl *instantiateUnresolvedUsingDecl(T *D, + bool InstantiatingPackElement = false); }; } diff --git a/include/clang/Serialization/ASTBitCodes.h b/include/clang/Serialization/ASTBitCodes.h index 611c00d0e9ede6af0ca19924e4eaea2d667d186c..4e29ad6a02ab909e999e4617b83a341f33f9a75a 100644 --- a/include/clang/Serialization/ASTBitCodes.h +++ b/include/clang/Serialization/ASTBitCodes.h @@ -1103,6 +1103,8 @@ namespace clang { DECL_NAMESPACE_ALIAS, /// \brief A UsingDecl record. DECL_USING, + /// \brief A UsingPackDecl record. + DECL_USING_PACK, /// \brief A UsingShadowDecl record. DECL_USING_SHADOW, /// \brief A ConstructorUsingShadowDecl record. diff --git a/lib/AST/DeclBase.cpp b/lib/AST/DeclBase.cpp index 8deef3343dbdb77b5d5f39b47da30c4796cac012..6111abab646e9c6a8130786adc7c0f01ce0ae8c1 100644 --- a/lib/AST/DeclBase.cpp +++ b/lib/AST/DeclBase.cpp @@ -651,11 +651,13 @@ unsigned Decl::getIdentifierNamespaceForKind(Kind DeclKind) { case Typedef: case TypeAlias: case TypeAliasTemplate: - case UnresolvedUsingTypename: case TemplateTypeParm: case ObjCTypeParam: return IDNS_Ordinary | IDNS_Type; + case UnresolvedUsingTypename: + return IDNS_Ordinary | IDNS_Type | IDNS_Using; + case UsingShadow: return 0; // we'll actually overwrite this later @@ -663,6 +665,7 @@ unsigned Decl::getIdentifierNamespaceForKind(Kind DeclKind) { return IDNS_Ordinary | IDNS_Using; case Using: + case UsingPack: return IDNS_Using; case ObjCProtocol: diff --git a/lib/AST/DeclCXX.cpp b/lib/AST/DeclCXX.cpp index 8563416a480a35f8c2a34d6d0b28add7b6371301..1860b948d6095fc4d95c4aac7d8a205fecec4f31 100644 --- a/lib/AST/DeclCXX.cpp +++ b/lib/AST/DeclCXX.cpp @@ -2250,15 +2250,37 @@ SourceRange UsingDecl::getSourceRange() const { return SourceRange(Begin, getNameInfo().getEndLoc()); } +void UsingPackDecl::anchor() { } + +UsingPackDecl *UsingPackDecl::Create(ASTContext &C, DeclContext *DC, + NamedDecl *InstantiatedFrom, + ArrayRef<NamedDecl *> UsingDecls) { + size_t Extra = additionalSizeToAlloc<NamedDecl *>(UsingDecls.size()); + return new (C, DC, Extra) UsingPackDecl(DC, InstantiatedFrom, UsingDecls); +} + +UsingPackDecl *UsingPackDecl::CreateDeserialized(ASTContext &C, unsigned ID, + unsigned NumExpansions) { + size_t Extra = additionalSizeToAlloc<NamedDecl *>(NumExpansions); + auto *Result = new (C, ID, Extra) UsingPackDecl(nullptr, nullptr, None); + Result->NumExpansions = NumExpansions; + auto *Trail = Result->getTrailingObjects<NamedDecl *>(); + for (unsigned I = 0; I != NumExpansions; ++I) + new (Trail + I) NamedDecl*(nullptr); + return Result; +} + void UnresolvedUsingValueDecl::anchor() { } UnresolvedUsingValueDecl * UnresolvedUsingValueDecl::Create(ASTContext &C, DeclContext *DC, SourceLocation UsingLoc, NestedNameSpecifierLoc QualifierLoc, - const DeclarationNameInfo &NameInfo) { + const DeclarationNameInfo &NameInfo, + SourceLocation EllipsisLoc) { return new (C, DC) UnresolvedUsingValueDecl(DC, C.DependentTy, UsingLoc, - QualifierLoc, NameInfo); + QualifierLoc, NameInfo, + EllipsisLoc); } UnresolvedUsingValueDecl * @@ -2266,7 +2288,8 @@ UnresolvedUsingValueDecl::CreateDeserialized(ASTContext &C, unsigned ID) { return new (C, ID) UnresolvedUsingValueDecl(nullptr, QualType(), SourceLocation(), NestedNameSpecifierLoc(), - DeclarationNameInfo()); + DeclarationNameInfo(), + SourceLocation()); } SourceRange UnresolvedUsingValueDecl::getSourceRange() const { @@ -2283,17 +2306,18 @@ UnresolvedUsingTypenameDecl::Create(ASTContext &C, DeclContext *DC, SourceLocation TypenameLoc, NestedNameSpecifierLoc QualifierLoc, SourceLocation TargetNameLoc, - DeclarationName TargetName) { + DeclarationName TargetName, + SourceLocation EllipsisLoc) { return new (C, DC) UnresolvedUsingTypenameDecl( DC, UsingLoc, TypenameLoc, QualifierLoc, TargetNameLoc, - TargetName.getAsIdentifierInfo()); + TargetName.getAsIdentifierInfo(), EllipsisLoc); } UnresolvedUsingTypenameDecl * UnresolvedUsingTypenameDecl::CreateDeserialized(ASTContext &C, unsigned ID) { return new (C, ID) UnresolvedUsingTypenameDecl( nullptr, SourceLocation(), SourceLocation(), NestedNameSpecifierLoc(), - SourceLocation(), nullptr); + SourceLocation(), nullptr, SourceLocation()); } void StaticAssertDecl::anchor() { } diff --git a/lib/CodeGen/CGDecl.cpp b/lib/CodeGen/CGDecl.cpp index 46573477580af57bb7767733d42897adac858b05..d76136380160bfb8b878bd583d62ff0ba7cbc6a7 100644 --- a/lib/CodeGen/CGDecl.cpp +++ b/lib/CodeGen/CGDecl.cpp @@ -113,6 +113,10 @@ void CodeGenFunction::EmitDecl(const Decl &D) { if (CGDebugInfo *DI = getDebugInfo()) DI->EmitUsingDecl(cast<UsingDecl>(D)); return; + case Decl::UsingPack: + for (auto *Using : cast<UsingPackDecl>(D).expansions()) + EmitDecl(*Using); + return; case Decl::UsingDirective: // using namespace X; [C++] if (CGDebugInfo *DI = getDebugInfo()) DI->EmitUsingDirective(cast<UsingDirectiveDecl>(D)); diff --git a/lib/Parse/ParseDeclCXX.cpp b/lib/Parse/ParseDeclCXX.cpp index d31d1142374e62168a8d8026dbfdbd5ca02055a5..4002b09d2bc4908d8edc34343047fb03675ba7cf 100644 --- a/lib/Parse/ParseDeclCXX.cpp +++ b/lib/Parse/ParseDeclCXX.cpp @@ -560,7 +560,9 @@ bool Parser::ParseUsingDeclarator(unsigned Context, UsingDeclarator &D) { // nested-name-specifier, the name is [...] considered to name the // constructor. if (getLangOpts().CPlusPlus11 && Context == Declarator::MemberContext && - Tok.is(tok::identifier) && NextToken().is(tok::semi) && + Tok.is(tok::identifier) && + (NextToken().is(tok::semi) || NextToken().is(tok::comma) || + NextToken().is(tok::ellipsis)) && D.SS.isNotEmpty() && LastII == Tok.getIdentifierInfo() && !D.SS.getScopeRep()->getAsNamespace() && !D.SS.getScopeRep()->getAsNamespaceAlias()) { @@ -578,7 +580,10 @@ bool Parser::ParseUsingDeclarator(unsigned Context, UsingDeclarator &D) { return true; } - // FIXME: Parse optional ellipsis + if (TryConsumeToken(tok::ellipsis, D.EllipsisLoc)) + Diag(Tok.getLocation(), getLangOpts().CPlusPlus1z ? + diag::warn_cxx1z_compat_using_declaration_pack : + diag::ext_using_declaration_pack); return false; } @@ -678,9 +683,9 @@ Parser::ParseUsingDeclaration(unsigned Context, D.TypenameLoc = SourceLocation(); } - Decl *UD = - Actions.ActOnUsingDeclaration(getCurScope(), AS, UsingLoc, D.SS, - D.Name, Attrs.getList(), D.TypenameLoc); + Decl *UD = Actions.ActOnUsingDeclaration(getCurScope(), AS, UsingLoc, + D.TypenameLoc, D.SS, D.Name, + D.EllipsisLoc, Attrs.getList()); if (UD) DeclsInGroup.push_back(UD); } @@ -708,62 +713,6 @@ Parser::ParseUsingDeclaration(unsigned Context, return Actions.BuildDeclaratorGroup(DeclsInGroup, /*MayContainAuto*/false); } -Decl *Parser::ParseAliasTemplate(const ParsedTemplateInfo &TemplateInfo, - SourceLocation &DeclEnd, AccessSpecifier AS, - ParsedAttributesWithRange &MisplacedAttrs1) { - assert(Tok.is(tok::kw_using) && "Not using token"); - ObjCDeclContextSwitch ObjCDC(*this); - - // Eat 'using'. - SourceLocation UsingLoc = ConsumeToken(); - if (Tok.is(tok::code_completion)) { - Actions.CodeCompleteUsing(getCurScope()); - cutOffParsing(); - return nullptr; - } - - // 'using namespace' means this is a using-directive. - if (Tok.is(tok::kw_namespace)) { - SourceRange R = TemplateInfo.getSourceRange(); - Diag(UsingLoc, diag::err_templated_using_directive_declaration) - << 0 /* directive */ << R; - SkipUntil(tok::semi); - return nullptr; - } - - // Check for misplaced attributes before the identifier. - ParsedAttributesWithRange MisplacedAttrs2(AttrFactory); - MaybeParseCXX11Attributes(MisplacedAttrs2); - - // FIXME: Just parse an identifier here? - UsingDeclarator D; - if (ParseUsingDeclarator(Declarator::FileContext, D)) { - SkipUntil(tok::semi); - return nullptr; - } - - ParsedAttributesWithRange Attrs(AttrFactory); - - // If we had any misplaced attributes from earlier, this is where they - // should have been written. - for (auto *MisplacedAttrs : {&MisplacedAttrs1, &MisplacedAttrs2}) { - if (MisplacedAttrs->Range.isValid()) { - Diag(MisplacedAttrs->Range.getBegin(), diag::err_attributes_not_allowed) - << FixItHint::CreateInsertionFromRange( - Tok.getLocation(), - CharSourceRange::getTokenRange(MisplacedAttrs->Range)) - << FixItHint::CreateRemoval(MisplacedAttrs->Range); - Attrs.takeAllFrom(*MisplacedAttrs); - } - } - - MaybeParseGNUAttributes(Attrs); - MaybeParseCXX11Attributes(Attrs); - - return ParseAliasDeclarationAfterDeclarator(TemplateInfo, UsingLoc, D, - DeclEnd, AS, Attrs); -} - Decl *Parser::ParseAliasDeclarationAfterDeclarator( const ParsedTemplateInfo &TemplateInfo, SourceLocation UsingLoc, UsingDeclarator &D, SourceLocation &DeclEnd, AccessSpecifier AS, @@ -813,6 +762,9 @@ Decl *Parser::ParseAliasDeclarationAfterDeclarator( else if (D.SS.isNotEmpty()) Diag(D.SS.getBeginLoc(), diag::err_alias_declaration_not_identifier) << FixItHint::CreateRemoval(D.SS.getRange()); + if (D.EllipsisLoc.isValid()) + Diag(D.EllipsisLoc, diag::err_alias_declaration_pack_expansion) + << FixItHint::CreateRemoval(SourceRange(D.EllipsisLoc)); Decl *DeclFromDeclSpec = nullptr; TypeResult TypeAlias = @@ -2487,8 +2439,9 @@ Parser::ParseCXXClassMemberDeclaration(AccessSpecifier AS, } return DeclGroupPtrTy::make(DeclGroupRef(Actions.ActOnUsingDeclaration( - getCurScope(), AS, /*UsingLoc*/SourceLocation(), SS, Name, - /*AttrList*/nullptr, /*TypenameLoc*/SourceLocation()))); + getCurScope(), AS, /*UsingLoc*/ SourceLocation(), + /*TypenameLoc*/ SourceLocation(), SS, Name, + /*EllipsisLoc*/ SourceLocation(), /*AttrList*/ nullptr))); } } diff --git a/lib/Sema/SemaDeclCXX.cpp b/lib/Sema/SemaDeclCXX.cpp index ac643af149077731aa3a8d62dbd7e9f051bbbf9b..21bdd945f06c509ee587210911f92b5557f30164 100644 --- a/lib/Sema/SemaDeclCXX.cpp +++ b/lib/Sema/SemaDeclCXX.cpp @@ -8533,12 +8533,18 @@ void Sema::PushUsingDirective(Scope *S, UsingDirectiveDecl *UDir) { Decl *Sema::ActOnUsingDeclaration(Scope *S, AccessSpecifier AS, SourceLocation UsingLoc, + SourceLocation TypenameLoc, CXXScopeSpec &SS, UnqualifiedId &Name, - AttributeList *AttrList, - SourceLocation TypenameLoc) { + SourceLocation EllipsisLoc, + AttributeList *AttrList) { assert(S->getFlags() & Scope::DeclScope && "Invalid Scope."); + if (SS.isEmpty()) { + Diag(Name.getLocStart(), diag::err_using_requires_qualname); + return nullptr; + } + switch (Name.getKind()) { case UnqualifiedId::IK_ImplicitSelfParam: case UnqualifiedId::IK_Identifier: @@ -8584,14 +8590,23 @@ Decl *Sema::ActOnUsingDeclaration(Scope *S, << FixItHint::CreateInsertion(SS.getRange().getBegin(), "using "); } - if (DiagnoseUnexpandedParameterPack(SS, UPPC_UsingDeclaration) || - DiagnoseUnexpandedParameterPack(TargetNameInfo, UPPC_UsingDeclaration)) - return nullptr; + if (EllipsisLoc.isInvalid()) { + if (DiagnoseUnexpandedParameterPack(SS, UPPC_UsingDeclaration) || + DiagnoseUnexpandedParameterPack(TargetNameInfo, UPPC_UsingDeclaration)) + return nullptr; + } else { + if (!SS.getScopeRep()->containsUnexpandedParameterPack() && + !TargetNameInfo.containsUnexpandedParameterPack()) { + Diag(EllipsisLoc, diag::err_pack_expansion_without_parameter_packs) + << SourceRange(SS.getBeginLoc(), TargetNameInfo.getEndLoc()); + EllipsisLoc = SourceLocation(); + } + } - NamedDecl *UD = BuildUsingDeclaration(S, AS, UsingLoc, SS, - TargetNameInfo, AttrList, - /* IsInstantiation */ false, - TypenameLoc.isValid(), TypenameLoc); + NamedDecl *UD = + BuildUsingDeclaration(S, AS, UsingLoc, TypenameLoc.isValid(), TypenameLoc, + SS, TargetNameInfo, EllipsisLoc, AttrList, + /*IsInstantiation*/false); if (UD) PushOnScopeChains(UD, S, /*AddToContext*/ false); @@ -8654,6 +8669,7 @@ bool Sema::CheckUsingShadowDecl(UsingDecl *Using, NamedDecl *Orig, diag::err_using_decl_nested_name_specifier_is_current_class) << Using->getQualifierLoc().getSourceRange(); Diag(Orig->getLocation(), diag::note_using_decl_target); + Using->setInvalidDecl(); return true; } @@ -8663,6 +8679,7 @@ bool Sema::CheckUsingShadowDecl(UsingDecl *Using, NamedDecl *Orig, << cast<CXXRecordDecl>(CurContext) << Using->getQualifierLoc().getSourceRange(); Diag(Orig->getLocation(), diag::note_using_decl_target); + Using->setInvalidDecl(); return true; } } @@ -8686,7 +8703,7 @@ bool Sema::CheckUsingShadowDecl(UsingDecl *Using, NamedDecl *Orig, // We can have UsingDecls in our Previous results because we use the same // LookupResult for checking whether the UsingDecl itself is a valid // redeclaration. - if (isa<UsingDecl>(D)) + if (isa<UsingDecl>(D) || isa<UsingPackDecl>(D)) continue; if (IsEquivalentForUsingDecl(Context, D, Target)) { @@ -8732,6 +8749,7 @@ bool Sema::CheckUsingShadowDecl(UsingDecl *Using, NamedDecl *Orig, Diag(Target->getLocation(), diag::note_using_decl_target); Diag(OldDecl->getLocation(), diag::note_using_decl_conflict); + Using->setInvalidDecl(); return true; } @@ -8744,6 +8762,7 @@ bool Sema::CheckUsingShadowDecl(UsingDecl *Using, NamedDecl *Orig, Diag(Using->getLocation(), diag::err_using_decl_conflict); Diag(Target->getLocation(), diag::note_using_decl_target); Diag(Tag->getLocation(), diag::note_using_decl_conflict); + Using->setInvalidDecl(); return true; } @@ -8753,6 +8772,7 @@ bool Sema::CheckUsingShadowDecl(UsingDecl *Using, NamedDecl *Orig, Diag(Using->getLocation(), diag::err_using_decl_conflict); Diag(Target->getLocation(), diag::note_using_decl_target); Diag(NonTag->getLocation(), diag::note_using_decl_conflict); + Using->setInvalidDecl(); return true; } @@ -8960,23 +8980,19 @@ private: /// the lookup differently for these declarations. NamedDecl *Sema::BuildUsingDeclaration(Scope *S, AccessSpecifier AS, SourceLocation UsingLoc, + bool HasTypenameKeyword, + SourceLocation TypenameLoc, CXXScopeSpec &SS, DeclarationNameInfo NameInfo, + SourceLocation EllipsisLoc, AttributeList *AttrList, - bool IsInstantiation, - bool HasTypenameKeyword, - SourceLocation TypenameLoc) { + bool IsInstantiation) { assert(!SS.isInvalid() && "Invalid CXXScopeSpec."); SourceLocation IdentLoc = NameInfo.getLoc(); assert(IdentLoc.isValid() && "Invalid TargetName location."); // FIXME: We ignore attributes for now. - if (SS.isEmpty()) { - Diag(IdentLoc, diag::err_using_requires_qualname); - return nullptr; - } - // For an inheriting constructor declaration, the name of the using // declaration is the name of a constructor in this class, not in the // base class. @@ -9042,16 +9058,17 @@ NamedDecl *Sema::BuildUsingDeclaration(Scope *S, AccessSpecifier AS, DeclContext *LookupContext = computeDeclContext(SS); NamedDecl *D; NestedNameSpecifierLoc QualifierLoc = SS.getWithLocInContext(Context); - if (!LookupContext) { + if (!LookupContext || EllipsisLoc.isValid()) { if (HasTypenameKeyword) { // FIXME: not all declaration name kinds are legal here D = UnresolvedUsingTypenameDecl::Create(Context, CurContext, UsingLoc, TypenameLoc, QualifierLoc, - IdentLoc, NameInfo.getName()); + IdentLoc, NameInfo.getName(), + EllipsisLoc); } else { D = UnresolvedUsingValueDecl::Create(Context, CurContext, UsingLoc, - QualifierLoc, NameInfo); + QualifierLoc, NameInfo, EllipsisLoc); } D->setAccess(AS); CurContext->addDecl(D); @@ -9211,6 +9228,19 @@ NamedDecl *Sema::BuildUsingDeclaration(Scope *S, AccessSpecifier AS, return UD; } +NamedDecl *Sema::BuildUsingPackDecl(NamedDecl *InstantiatedFrom, + ArrayRef<NamedDecl *> Expansions) { + assert(isa<UnresolvedUsingValueDecl>(InstantiatedFrom) || + isa<UnresolvedUsingTypenameDecl>(InstantiatedFrom) || + isa<UsingPackDecl>(InstantiatedFrom)); + + auto *UPD = + UsingPackDecl::Create(Context, CurContext, InstantiatedFrom, Expansions); + UPD->setAccess(InstantiatedFrom->getAccess()); + CurContext->addDecl(UPD); + return UPD; +} + /// Additional checks for a using declaration referring to a constructor name. bool Sema::CheckInheritingConstructorUsingDecl(UsingDecl *UD) { assert(!UD->hasTypename() && "expecting a constructor name"); @@ -9264,7 +9294,7 @@ bool Sema::CheckUsingDeclRedeclaration(SourceLocation UsingLoc, // scope? if (Qual->isDependent() && !HasTypenameKeyword) { for (auto *D : Prev) { - if (!isa<TypeDecl>(D) && !isa<UsingDecl>(D)) { + if (!isa<TypeDecl>(D) && !isa<UsingDecl>(D) && !isa<UsingPackDecl>(D)) { bool OldCouldBeEnumerator = isa<UnresolvedUsingValueDecl>(D) || isa<EnumConstantDecl>(D); Diag(NameLoc, diff --git a/lib/Sema/SemaExprCXX.cpp b/lib/Sema/SemaExprCXX.cpp index 74beeac724413c12b73e4dca5087901905dcfba8..5c3900adbde10385918bc625cab8ca4f4ff68ff5 100644 --- a/lib/Sema/SemaExprCXX.cpp +++ b/lib/Sema/SemaExprCXX.cpp @@ -7462,17 +7462,11 @@ Sema::CheckMicrosoftIfExistsSymbol(Scope *S, SourceLocation KeywordLoc, UnqualifiedId &Name) { DeclarationNameInfo TargetNameInfo = GetNameFromUnqualifiedId(Name); - // Check for unexpanded parameter packs. - SmallVector<UnexpandedParameterPack, 4> Unexpanded; - collectUnexpandedParameterPacks(SS, Unexpanded); - collectUnexpandedParameterPacks(TargetNameInfo, Unexpanded); - if (!Unexpanded.empty()) { - DiagnoseUnexpandedParameterPacks(KeywordLoc, - IsIfExists? UPPC_IfExists - : UPPC_IfNotExists, - Unexpanded); + // Check for an unexpanded parameter pack. + auto UPPC = IsIfExists ? UPPC_IfExists : UPPC_IfNotExists; + if (DiagnoseUnexpandedParameterPack(SS, UPPC) || + DiagnoseUnexpandedParameterPack(TargetNameInfo, UPPC)) return IER_Error; - } return CheckMicrosoftIfExistsSymbol(S, SS, TargetNameInfo); } diff --git a/lib/Sema/SemaOverload.cpp b/lib/Sema/SemaOverload.cpp index d49142b8d8532638cc8bab19bf55acd88331ea35..2129729dab9f3119164f63c9446687ca501ec5c4 100644 --- a/lib/Sema/SemaOverload.cpp +++ b/lib/Sema/SemaOverload.cpp @@ -981,7 +981,7 @@ Sema::CheckOverload(Scope *S, FunctionDecl *New, const LookupResult &Old, Match = *I; return Ovl_Match; } - } else if (isa<UsingDecl>(OldD)) { + } else if (isa<UsingDecl>(OldD) || isa<UsingPackDecl>(OldD)) { // We can overload with these, which can show up when doing // redeclaration checks for UsingDecls. assert(Old.getLookupKind() == LookupUsingDeclName); @@ -11420,6 +11420,12 @@ BuildRecoveryCallExpr(Sema &SemaRef, Scope *S, Expr *Fn, assert(!R.empty() && "lookup results empty despite recovery"); + // If recovery created an ambiguity, just bail out. + if (R.isAmbiguous()) { + R.suppressDiagnostics(); + return ExprError(); + } + // Build an implicit member call if appropriate. Just drop the // casts and such from the call, we don't really care. ExprResult NewFn = ExprError(); diff --git a/lib/Sema/SemaTemplateInstantiateDecl.cpp b/lib/Sema/SemaTemplateInstantiateDecl.cpp index 0956a1cc502c94b3e7e6bb39784f919d88606289..dbc322ebfdc938b6e02018901219554ed6b4e51c 100644 --- a/lib/Sema/SemaTemplateInstantiateDecl.cpp +++ b/lib/Sema/SemaTemplateInstantiateDecl.cpp @@ -2495,35 +2495,76 @@ Decl *TemplateDeclInstantiator::VisitConstructorUsingShadowDecl( return nullptr; } -Decl * TemplateDeclInstantiator - ::VisitUnresolvedUsingTypenameDecl(UnresolvedUsingTypenameDecl *D) { - NestedNameSpecifierLoc QualifierLoc - = SemaRef.SubstNestedNameSpecifierLoc(D->getQualifierLoc(), - TemplateArgs); - if (!QualifierLoc) - return nullptr; +template <typename T> +Decl *TemplateDeclInstantiator::instantiateUnresolvedUsingDecl( + T *D, bool InstantiatingPackElement) { + // If this is a pack expansion, expand it now. + if (D->isPackExpansion() && !InstantiatingPackElement) { + SmallVector<UnexpandedParameterPack, 2> Unexpanded; + SemaRef.collectUnexpandedParameterPacks(D->getQualifierLoc(), Unexpanded); + SemaRef.collectUnexpandedParameterPacks(D->getNameInfo(), Unexpanded); - CXXScopeSpec SS; - SS.Adopt(QualifierLoc); + // Determine whether the set of unexpanded parameter packs can and should + // be expanded. + bool Expand = true; + bool RetainExpansion = false; + Optional<unsigned> NumExpansions; + if (SemaRef.CheckParameterPacksForExpansion( + D->getEllipsisLoc(), D->getSourceRange(), Unexpanded, TemplateArgs, + Expand, RetainExpansion, NumExpansions)) + return nullptr; - // Since NameInfo refers to a typename, it cannot be a C++ special name. - // Hence, no transformation is required for it. - DeclarationNameInfo NameInfo(D->getDeclName(), D->getLocation()); - NamedDecl *UD = - SemaRef.BuildUsingDeclaration(/*Scope*/ nullptr, D->getAccess(), - D->getUsingLoc(), SS, NameInfo, nullptr, - /*instantiation*/ true, - /*typename*/ true, D->getTypenameLoc()); - if (UD) - SemaRef.Context.setInstantiatedFromUsingDecl(UD, D); + // This declaration cannot appear within a function template signature, + // so we can't have a partial argument list for a parameter pack. + assert(!RetainExpansion && + "should never need to retain an expansion for UsingPackDecl"); - return UD; -} + if (!Expand) { + // We cannot fully expand the pack expansion now, so substitute into the + // pattern and create a new pack expansion. + Sema::ArgumentPackSubstitutionIndexRAII SubstIndex(SemaRef, -1); + return instantiateUnresolvedUsingDecl(D, true); + } + + // Within a function, we don't have any normal way to check for conflicts + // between shadow declarations from different using declarations in the + // same pack expansion, but this is always ill-formed because all expansions + // must produce (conflicting) enumerators. + // + // Sadly we can't just reject this in the template definition because it + // could be valid if the pack is empty or has exactly one expansion. + if (D->getDeclContext()->isFunctionOrMethod() && *NumExpansions > 1) { + SemaRef.Diag(D->getEllipsisLoc(), + diag::err_using_decl_redeclaration_expansion); + return nullptr; + } + + // Instantiate the slices of this pack and build a UsingPackDecl. + SmallVector<NamedDecl*, 8> Expansions; + for (unsigned I = 0; I != *NumExpansions; ++I) { + Sema::ArgumentPackSubstitutionIndexRAII SubstIndex(SemaRef, I); + Decl *Slice = instantiateUnresolvedUsingDecl(D, true); + if (!Slice) + return nullptr; + // Note that we can still get unresolved using declarations here, if we + // had arguments for all packs but the pattern also contained other + // template arguments (this only happens during partial substitution, eg + // into the body of a generic lambda in a function template). + Expansions.push_back(cast<NamedDecl>(Slice)); + } + + auto *NewD = SemaRef.BuildUsingPackDecl(D, Expansions); + if (isDeclWithinFunction(D)) + SemaRef.CurrentInstantiationScope->InstantiatedLocal(D, NewD); + return NewD; + } + + UnresolvedUsingTypenameDecl *TD = dyn_cast<UnresolvedUsingTypenameDecl>(D); + SourceLocation TypenameLoc = TD ? TD->getTypenameLoc() : SourceLocation(); -Decl * TemplateDeclInstantiator - ::VisitUnresolvedUsingValueDecl(UnresolvedUsingValueDecl *D) { NestedNameSpecifierLoc QualifierLoc - = SemaRef.SubstNestedNameSpecifierLoc(D->getQualifierLoc(), TemplateArgs); + = SemaRef.SubstNestedNameSpecifierLoc(D->getQualifierLoc(), + TemplateArgs); if (!QualifierLoc) return nullptr; @@ -2533,17 +2574,48 @@ Decl * TemplateDeclInstantiator DeclarationNameInfo NameInfo = SemaRef.SubstDeclarationNameInfo(D->getNameInfo(), TemplateArgs); - NamedDecl *UD = - SemaRef.BuildUsingDeclaration(/*Scope*/ nullptr, D->getAccess(), - D->getUsingLoc(), SS, NameInfo, nullptr, - /*instantiation*/ true, - /*typename*/ false, SourceLocation()); + // Produce a pack expansion only if we're not instantiating a particular + // slice of a pack expansion. + bool InstantiatingSlice = D->getEllipsisLoc().isValid() && + SemaRef.ArgumentPackSubstitutionIndex != -1; + SourceLocation EllipsisLoc = + InstantiatingSlice ? SourceLocation() : D->getEllipsisLoc(); + + NamedDecl *UD = SemaRef.BuildUsingDeclaration( + /*Scope*/ nullptr, D->getAccess(), D->getUsingLoc(), + /*HasTypename*/ TD, TypenameLoc, SS, NameInfo, EllipsisLoc, nullptr, + /*IsInstantiation*/ true); if (UD) SemaRef.Context.setInstantiatedFromUsingDecl(UD, D); return UD; } +Decl *TemplateDeclInstantiator::VisitUnresolvedUsingTypenameDecl( + UnresolvedUsingTypenameDecl *D) { + return instantiateUnresolvedUsingDecl(D); +} + +Decl *TemplateDeclInstantiator::VisitUnresolvedUsingValueDecl( + UnresolvedUsingValueDecl *D) { + return instantiateUnresolvedUsingDecl(D); +} + +Decl *TemplateDeclInstantiator::VisitUsingPackDecl(UsingPackDecl *D) { + SmallVector<NamedDecl*, 8> Expansions; + for (auto *UD : D->expansions()) { + if (auto *NewUD = + SemaRef.FindInstantiatedDecl(D->getLocation(), UD, TemplateArgs)) + Expansions.push_back(cast<NamedDecl>(NewUD)); + else + return nullptr; + } + + auto *NewD = SemaRef.BuildUsingPackDecl(D, Expansions); + if (isDeclWithinFunction(D)) + SemaRef.CurrentInstantiationScope->InstantiatedLocal(D, NewD); + return NewD; +} Decl *TemplateDeclInstantiator::VisitClassScopeFunctionSpecializationDecl( ClassScopeFunctionSpecializationDecl *Decl) { @@ -4513,22 +4585,36 @@ static bool isInstantiationOf(UsingShadowDecl *Pattern, Pattern); } -static bool isInstantiationOf(UsingDecl *Pattern, - UsingDecl *Instance, - ASTContext &C) { - return declaresSameEntity(C.getInstantiatedFromUsingDecl(Instance), Pattern); -} - -static bool isInstantiationOf(UnresolvedUsingValueDecl *Pattern, - NamedDecl *Instance, +static bool isInstantiationOf(UsingDecl *Pattern, UsingDecl *Instance, ASTContext &C) { return declaresSameEntity(C.getInstantiatedFromUsingDecl(Instance), Pattern); } -static bool isInstantiationOf(UnresolvedUsingTypenameDecl *Pattern, - NamedDecl *Instance, - ASTContext &C) { - return declaresSameEntity(C.getInstantiatedFromUsingDecl(Instance), Pattern); +template<typename T> +static bool isInstantiationOfUnresolvedUsingDecl(T *Pattern, Decl *Other, + ASTContext &Ctx) { + // An unresolved using declaration can instantiate to an unresolved using + // declaration, or to a using declaration or a using declaration pack. + // + // Multiple declarations can claim to be instantiated from an unresolved + // using declaration if it's a pack expansion. We want the UsingPackDecl + // in that case, not the individual UsingDecls within the pack. + bool OtherIsPackExpansion; + NamedDecl *OtherFrom; + if (auto *OtherUUD = dyn_cast<T>(Other)) { + OtherIsPackExpansion = OtherUUD->isPackExpansion(); + OtherFrom = Ctx.getInstantiatedFromUsingDecl(OtherUUD); + } else if (auto *OtherUPD = dyn_cast<UsingPackDecl>(Other)) { + OtherIsPackExpansion = true; + OtherFrom = OtherUPD->getInstantiatedFromUsingDecl(); + } else if (auto *OtherUD = dyn_cast<UsingDecl>(Other)) { + OtherIsPackExpansion = false; + OtherFrom = Ctx.getInstantiatedFromUsingDecl(OtherUD); + } else { + return false; + } + return Pattern->isPackExpansion() == OtherIsPackExpansion && + declaresSameEntity(OtherFrom, Pattern); } static bool isInstantiationOfStaticDataMember(VarDecl *Pattern, @@ -4549,21 +4635,14 @@ static bool isInstantiationOfStaticDataMember(VarDecl *Pattern, // Other is the prospective instantiation // D is the prospective pattern static bool isInstantiationOf(ASTContext &Ctx, NamedDecl *D, Decl *Other) { - if (D->getKind() != Other->getKind()) { - if (auto *UUD = dyn_cast<UnresolvedUsingTypenameDecl>(D)) { - if (UsingDecl *UD = dyn_cast<UsingDecl>(Other)) { - return isInstantiationOf(UUD, UD, Ctx); - } - } + if (auto *UUD = dyn_cast<UnresolvedUsingTypenameDecl>(D)) + return isInstantiationOfUnresolvedUsingDecl(UUD, Other, Ctx); - if (auto *UUD = dyn_cast<UnresolvedUsingValueDecl>(D)) { - if (UsingDecl *UD = dyn_cast<UsingDecl>(Other)) { - return isInstantiationOf(UUD, UD, Ctx); - } - } + if (auto *UUD = dyn_cast<UnresolvedUsingValueDecl>(D)) + return isInstantiationOfUnresolvedUsingDecl(UUD, Other, Ctx); + if (D->getKind() != Other->getKind()) return false; - } if (auto *Record = dyn_cast<CXXRecordDecl>(Other)) return isInstantiationOf(cast<CXXRecordDecl>(D), Record); @@ -4600,12 +4679,6 @@ static bool isInstantiationOf(ASTContext &Ctx, NamedDecl *D, Decl *Other) { if (auto *Using = dyn_cast<UsingDecl>(Other)) return isInstantiationOf(cast<UsingDecl>(D), Using, Ctx); - if (auto *Using = dyn_cast<UnresolvedUsingValueDecl>(Other)) - return isInstantiationOf(cast<UnresolvedUsingValueDecl>(D), Using, Ctx); - - if (auto *Using = dyn_cast<UnresolvedUsingTypenameDecl>(Other)) - return isInstantiationOf(cast<UnresolvedUsingTypenameDecl>(D), Using, Ctx); - if (auto *Shadow = dyn_cast<UsingShadowDecl>(Other)) return isInstantiationOf(cast<UsingShadowDecl>(D), Shadow, Ctx); @@ -4846,6 +4919,8 @@ NamedDecl *Sema::FindInstantiatedDecl(SourceLocation Loc, NamedDecl *D, } NamedDecl *Result = nullptr; + // FIXME: If the name is a dependent name, this lookup won't necessarily + // find it. Does that ever matter? if (D->getDeclName()) { DeclContext::lookup_result Found = ParentDC->lookup(D->getDeclName()); Result = findInstantiationOf(Context, D, Found.begin(), Found.end()); diff --git a/lib/Sema/SemaTemplateVariadic.cpp b/lib/Sema/SemaTemplateVariadic.cpp index c8bc2c3880974baf180df4c16f4b92ce99f11a1b..54556b505ee0f0bf84adede6d8627c9754b2dafe 100644 --- a/lib/Sema/SemaTemplateVariadic.cpp +++ b/lib/Sema/SemaTemplateVariadic.cpp @@ -390,21 +390,18 @@ void Sema::collectUnexpandedParameterPacks(QualType T, void Sema::collectUnexpandedParameterPacks(TypeLoc TL, SmallVectorImpl<UnexpandedParameterPack> &Unexpanded) { CollectUnexpandedParameterPacksVisitor(Unexpanded).TraverseTypeLoc(TL); -} +} -void Sema::collectUnexpandedParameterPacks(CXXScopeSpec &SS, - SmallVectorImpl<UnexpandedParameterPack> &Unexpanded) { - NestedNameSpecifier *Qualifier = SS.getScopeRep(); - if (!Qualifier) - return; - - NestedNameSpecifierLoc QualifierLoc(Qualifier, SS.location_data()); +void Sema::collectUnexpandedParameterPacks( + NestedNameSpecifierLoc NNS, + SmallVectorImpl<UnexpandedParameterPack> &Unexpanded) { CollectUnexpandedParameterPacksVisitor(Unexpanded) - .TraverseNestedNameSpecifierLoc(QualifierLoc); + .TraverseNestedNameSpecifierLoc(NNS); } -void Sema::collectUnexpandedParameterPacks(const DeclarationNameInfo &NameInfo, - SmallVectorImpl<UnexpandedParameterPack> &Unexpanded) { +void Sema::collectUnexpandedParameterPacks( + const DeclarationNameInfo &NameInfo, + SmallVectorImpl<UnexpandedParameterPack> &Unexpanded) { CollectUnexpandedParameterPacksVisitor(Unexpanded) .TraverseDeclarationNameInfo(NameInfo); } diff --git a/lib/Sema/TreeTransform.h b/lib/Sema/TreeTransform.h index a76a078fd006b742944f3d77b259cb257f88f4ce..849fdac7ec61c5ef46a1691e128ecbb3b208634a 100644 --- a/lib/Sema/TreeTransform.h +++ b/lib/Sema/TreeTransform.h @@ -457,6 +457,10 @@ public: return cast_or_null<NamedDecl>(getDerived().TransformDecl(Loc, D)); } + /// Transform the set of declarations in an OverloadExpr. + bool TransformOverloadExprDecls(OverloadExpr *Old, bool RequiresADL, + LookupResult &R); + /// \brief Transform the given nested-name-specifier with source-location /// information. /// @@ -821,7 +825,7 @@ public: /// \brief Rebuild an unresolved typename type, given the decl that /// the UnresolvedUsingTypenameDecl was transformed to. - QualType RebuildUnresolvedUsingType(Decl *D); + QualType RebuildUnresolvedUsingType(SourceLocation NameLoc, Decl *D); /// \brief Build a new typedef type. QualType RebuildTypedefType(TypedefNameDecl *Typedef) { @@ -5161,7 +5165,7 @@ TreeTransform<Derived>::TransformUnresolvedUsingType(TypeLocBuilder &TLB, QualType Result = TL.getType(); if (getDerived().AlwaysRebuild() || D != T->getDecl()) { - Result = getDerived().RebuildUnresolvedUsingType(D); + Result = getDerived().RebuildUnresolvedUsingType(TL.getNameLoc(), D); if (Result.isNull()) return QualType(); } @@ -9794,44 +9798,71 @@ TreeTransform<Derived>::TransformCXXPseudoDestructorExpr( Destroyed); } -template<typename Derived> -ExprResult -TreeTransform<Derived>::TransformUnresolvedLookupExpr( - UnresolvedLookupExpr *Old) { - LookupResult R(SemaRef, Old->getName(), Old->getNameLoc(), - Sema::LookupOrdinaryName); - +template <typename Derived> +bool TreeTransform<Derived>::TransformOverloadExprDecls(OverloadExpr *Old, + bool RequiresADL, + LookupResult &R) { // Transform all the decls. - for (UnresolvedLookupExpr::decls_iterator I = Old->decls_begin(), - E = Old->decls_end(); I != E; ++I) { - NamedDecl *InstD = static_cast<NamedDecl*>( - getDerived().TransformDecl(Old->getNameLoc(), - *I)); + bool AllEmptyPacks = true; + for (auto *OldD : Old->decls()) { + Decl *InstD = getDerived().TransformDecl(Old->getNameLoc(), OldD); if (!InstD) { // Silently ignore these if a UsingShadowDecl instantiated to nothing. // This can happen because of dependent hiding. - if (isa<UsingShadowDecl>(*I)) + if (isa<UsingShadowDecl>(OldD)) continue; else { R.clear(); - return ExprError(); + return true; } } + // Expand using pack declarations. + ArrayRef<NamedDecl*> Decls = cast<NamedDecl>(InstD); + if (auto *UPD = dyn_cast<UsingPackDecl>(InstD)) + Decls = UPD->expansions(); + // Expand using declarations. - if (isa<UsingDecl>(InstD)) { - UsingDecl *UD = cast<UsingDecl>(InstD); - for (auto *I : UD->shadows()) - R.addDecl(I); - continue; + for (auto *D : Decls) { + if (auto *UD = dyn_cast<UsingDecl>(D)) { + for (auto *SD : UD->shadows()) + R.addDecl(SD); + } else { + R.addDecl(D); + } } - R.addDecl(InstD); + AllEmptyPacks &= Decls.empty(); + }; + + // C++ [temp.res]/8.4.2: + // The program is ill-formed, no diagnostic required, if [...] lookup for + // a name in the template definition found a using-declaration, but the + // lookup in the corresponding scope in the instantiation odoes not find + // any declarations because the using-declaration was a pack expansion and + // the corresponding pack is empty + if (AllEmptyPacks && !RequiresADL) { + getSema().Diag(Old->getNameLoc(), diag::err_using_pack_expansion_empty) + << isa<UnresolvedMemberExpr>(Old) << Old->getNameInfo().getName(); + return true; } // Resolve a kind, but don't do any further analysis. If it's // ambiguous, the callee needs to deal with it. R.resolveKind(); + return false; +} + +template<typename Derived> +ExprResult +TreeTransform<Derived>::TransformUnresolvedLookupExpr( + UnresolvedLookupExpr *Old) { + LookupResult R(SemaRef, Old->getName(), Old->getNameLoc(), + Sema::LookupOrdinaryName); + + // Transform the declaration set. + if (TransformOverloadExprDecls(Old, Old->requiresADL(), R)) + return ExprError(); // Rebuild the nested-name qualifier, if present. CXXScopeSpec SS; @@ -10699,35 +10730,9 @@ TreeTransform<Derived>::TransformUnresolvedMemberExpr(UnresolvedMemberExpr *Old) LookupResult R(SemaRef, Old->getMemberNameInfo(), Sema::LookupOrdinaryName); - // Transform all the decls. - for (UnresolvedMemberExpr::decls_iterator I = Old->decls_begin(), - E = Old->decls_end(); I != E; ++I) { - NamedDecl *InstD = static_cast<NamedDecl*>( - getDerived().TransformDecl(Old->getMemberLoc(), - *I)); - if (!InstD) { - // Silently ignore these if a UsingShadowDecl instantiated to nothing. - // This can happen because of dependent hiding. - if (isa<UsingShadowDecl>(*I)) - continue; - else { - R.clear(); - return ExprError(); - } - } - - // Expand using declarations. - if (isa<UsingDecl>(InstD)) { - UsingDecl *UD = cast<UsingDecl>(InstD); - for (auto *I : UD->shadows()) - R.addDecl(I); - continue; - } - - R.addDecl(InstD); - } - - R.resolveKind(); + // Transform the declaration set. + if (TransformOverloadExprDecls(Old, /*RequiresADL*/false, R)) + return ExprError(); // Determine the naming class. if (Old->getNamingClass()) { @@ -11842,21 +11847,48 @@ QualType TreeTransform<Derived>::RebuildFunctionNoProtoType(QualType T) { } template<typename Derived> -QualType TreeTransform<Derived>::RebuildUnresolvedUsingType(Decl *D) { +QualType TreeTransform<Derived>::RebuildUnresolvedUsingType(SourceLocation Loc, + Decl *D) { assert(D && "no decl found"); if (D->isInvalidDecl()) return QualType(); // FIXME: Doesn't account for ObjCInterfaceDecl! TypeDecl *Ty; - if (isa<UsingDecl>(D)) { - UsingDecl *Using = cast<UsingDecl>(D); + if (auto *UPD = dyn_cast<UsingPackDecl>(D)) { + // A valid resolved using typename pack expansion decl can have multiple + // UsingDecls, but they must each have exactly one type, and it must be + // the same type in every case. But we must have at least one expansion! + if (UPD->expansions().empty()) { + getSema().Diag(Loc, diag::err_using_pack_expansion_empty) + << UPD->isCXXClassMember() << UPD; + return QualType(); + } + + // We might still have some unresolved types. Try to pick a resolved type + // if we can. The final instantiation will check that the remaining + // unresolved types instantiate to the type we pick. + QualType FallbackT; + QualType T; + for (auto *E : UPD->expansions()) { + QualType ThisT = RebuildUnresolvedUsingType(Loc, E); + if (ThisT.isNull()) + continue; + else if (ThisT->getAs<UnresolvedUsingType>()) + FallbackT = ThisT; + else if (T.isNull()) + T = ThisT; + else + assert(getSema().Context.hasSameType(ThisT, T) && + "mismatched resolved types in using pack expansion"); + } + return T.isNull() ? FallbackT : T; + } else if (auto *Using = dyn_cast<UsingDecl>(D)) { assert(Using->hasTypename() && "UnresolvedUsingTypenameDecl transformed to non-typename using"); // A valid resolved using typename decl points to exactly one type decl. assert(++Using->shadow_begin() == Using->shadow_end()); Ty = cast<TypeDecl>((*Using->shadow_begin())->getTargetDecl()); - } else { assert(isa<UnresolvedUsingTypenameDecl>(D) && "UnresolvedUsingTypenameDecl transformed to non-using decl"); diff --git a/lib/Serialization/ASTCommon.cpp b/lib/Serialization/ASTCommon.cpp index 79ccffc5abbbb28c098fc6f29c107635201cf7d9..ecd249cc50259e307b92c4310425cc4cfd89831e 100644 --- a/lib/Serialization/ASTCommon.cpp +++ b/lib/Serialization/ASTCommon.cpp @@ -285,6 +285,7 @@ bool serialization::isRedeclarableDeclKind(unsigned Kind) { case Decl::NonTypeTemplateParm: case Decl::TemplateTemplateParm: case Decl::Using: + case Decl::UsingPack: case Decl::ObjCMethod: case Decl::ObjCCategory: case Decl::ObjCCategoryImpl: diff --git a/lib/Serialization/ASTReaderDecl.cpp b/lib/Serialization/ASTReaderDecl.cpp index 913a1419b3f105a290a312f7a9234d893b38d14f..dc29a61c0a923755c566b966965cff513c5613af 100644 --- a/lib/Serialization/ASTReaderDecl.cpp +++ b/lib/Serialization/ASTReaderDecl.cpp @@ -322,6 +322,7 @@ namespace clang { void VisitTemplateTemplateParmDecl(TemplateTemplateParmDecl *D); void VisitTypeAliasTemplateDecl(TypeAliasTemplateDecl *D); void VisitUsingDecl(UsingDecl *D); + void VisitUsingPackDecl(UsingPackDecl *D); void VisitUsingShadowDecl(UsingShadowDecl *D); void VisitConstructorUsingShadowDecl(ConstructorUsingShadowDecl *D); void VisitLinkageSpecDecl(LinkageSpecDecl *D); @@ -1419,6 +1420,15 @@ void ASTDeclReader::VisitUsingDecl(UsingDecl *D) { mergeMergeable(D); } +void ASTDeclReader::VisitUsingPackDecl(UsingPackDecl *D) { + VisitNamedDecl(D); + D->InstantiatedFrom = ReadDeclAs<NamedDecl>(); + NamedDecl **Expansions = D->getTrailingObjects<NamedDecl*>(); + for (unsigned I = 0; I != D->NumExpansions; ++I) + Expansions[I] = ReadDeclAs<NamedDecl>(); + mergeMergeable(D); +} + void ASTDeclReader::VisitUsingShadowDecl(UsingShadowDecl *D) { RedeclarableResult Redecl = VisitRedeclarable(D); VisitNamedDecl(D); @@ -1452,6 +1462,7 @@ void ASTDeclReader::VisitUnresolvedUsingValueDecl(UnresolvedUsingValueDecl *D) { D->setUsingLoc(ReadSourceLocation()); D->QualifierLoc = Record.ReadNestedNameSpecifierLoc(Idx); ReadDeclarationNameLoc(D->DNLoc, D->getDeclName()); + D->EllipsisLoc = ReadSourceLocation(); mergeMergeable(D); } @@ -1460,6 +1471,7 @@ void ASTDeclReader::VisitUnresolvedUsingTypenameDecl( VisitTypeDecl(D); D->TypenameLocation = ReadSourceLocation(); D->QualifierLoc = Record.ReadNestedNameSpecifierLoc(Idx); + D->EllipsisLoc = ReadSourceLocation(); mergeMergeable(D); } @@ -3297,6 +3309,9 @@ Decl *ASTReader::ReadDeclRecord(DeclID ID) { case DECL_USING: D = UsingDecl::CreateDeserialized(Context, ID); break; + case DECL_USING_PACK: + D = UsingPackDecl::CreateDeserialized(Context, ID, Record[Idx++]); + break; case DECL_USING_SHADOW: D = UsingShadowDecl::CreateDeserialized(Context, ID); break; diff --git a/lib/Serialization/ASTWriterDecl.cpp b/lib/Serialization/ASTWriterDecl.cpp index 21468619dba994afb003cb595bd45627229ac231..ee220f00a81ff0c6008155fee91b7934d80dc7fb 100644 --- a/lib/Serialization/ASTWriterDecl.cpp +++ b/lib/Serialization/ASTWriterDecl.cpp @@ -107,6 +107,7 @@ namespace clang { void VisitTemplateTemplateParmDecl(TemplateTemplateParmDecl *D); void VisitTypeAliasTemplateDecl(TypeAliasTemplateDecl *D); void VisitUsingDecl(UsingDecl *D); + void VisitUsingPackDecl(UsingPackDecl *D); void VisitUsingShadowDecl(UsingShadowDecl *D); void VisitConstructorUsingShadowDecl(ConstructorUsingShadowDecl *D); void VisitLinkageSpecDecl(LinkageSpecDecl *D); @@ -1142,6 +1143,15 @@ void ASTDeclWriter::VisitUsingDecl(UsingDecl *D) { Code = serialization::DECL_USING; } +void ASTDeclWriter::VisitUsingPackDecl(UsingPackDecl *D) { + Record.push_back(D->NumExpansions); + VisitNamedDecl(D); + Record.AddDeclRef(D->getInstantiatedFromUsingDecl()); + for (auto *E : D->expansions()) + Record.AddDeclRef(E); + Code = serialization::DECL_USING_PACK; +} + void ASTDeclWriter::VisitUsingShadowDecl(UsingShadowDecl *D) { VisitRedeclarable(D); VisitNamedDecl(D); @@ -1175,6 +1185,7 @@ void ASTDeclWriter::VisitUnresolvedUsingValueDecl(UnresolvedUsingValueDecl *D) { Record.AddSourceLocation(D->getUsingLoc()); Record.AddNestedNameSpecifierLoc(D->getQualifierLoc()); Record.AddDeclarationNameLoc(D->DNLoc, D->getDeclName()); + Record.AddSourceLocation(D->getEllipsisLoc()); Code = serialization::DECL_UNRESOLVED_USING_VALUE; } @@ -1183,6 +1194,7 @@ void ASTDeclWriter::VisitUnresolvedUsingTypenameDecl( VisitTypeDecl(D); Record.AddSourceLocation(D->getTypenameLoc()); Record.AddNestedNameSpecifierLoc(D->getQualifierLoc()); + Record.AddSourceLocation(D->getEllipsisLoc()); Code = serialization::DECL_UNRESOLVED_USING_TYPENAME; } diff --git a/test/PCH/cxx1z-using-declaration.cpp b/test/PCH/cxx1z-using-declaration.cpp new file mode 100644 index 0000000000000000000000000000000000000000..a185ff1740466b3ebe5bf64dfb67a90e5ee29e2c --- /dev/null +++ b/test/PCH/cxx1z-using-declaration.cpp @@ -0,0 +1,35 @@ +// No PCH: +// RUN: %clang_cc1 -pedantic -std=c++1z -include %s -verify %s +// +// With PCH: +// RUN: %clang_cc1 -pedantic -std=c++1z -emit-pch %s -o %t +// RUN: %clang_cc1 -pedantic -std=c++1z -include-pch %t -verify %s + +#ifndef HEADER +#define HEADER + +template<typename ...T> struct A : T... { + using T::f ...; + template<typename ...U> void g(U ...u) { f(u...); } +}; + +struct X { void f(); }; +struct Y { void f(int); }; +struct Z { void f(int, int); }; + +inline A<X, Y, Z> a; + +#else + +void test() { + a.g(); + a.g(0); + a.g(0, 0); + // expected-error@13 {{no match}} + // expected-note@16 {{candidate}} + // expected-note@17 {{candidate}} + // expected-note@18 {{candidate}} + a.g(0, 0, 0); // expected-note {{instantiation of}} +} + +#endif diff --git a/test/Parser/cxx1z-using-declaration.cpp b/test/Parser/cxx1z-using-declaration.cpp index dab1ca82c2a59e2ba74bf78807c76a72f7da93b8..0be81677d9fbbe68052ac94bbfe7860a02123930 100644 --- a/test/Parser/cxx1z-using-declaration.cpp +++ b/test/Parser/cxx1z-using-declaration.cpp @@ -10,10 +10,10 @@ namespace B { } struct X { - int x1, x2, y, z; // expected-note {{conflicting}} + int x1, x2, y, z; // expected-note 2{{conflicting}} }; struct Y { - int x1, x2, y, z; // expected-note {{target}} + int x1, x2, y, z; // expected-note 2{{target}} }; struct Z : X, Y { using X::x1, @@ -28,3 +28,8 @@ int X::*px1 = &Z::x1; int X::*px2 = &Z::x2; int Y::*py = &Z::y; int X::*pz = &Z::z; + +template<typename ...T> struct Q : T... { + using T::z...; // expected-error {{conflicts}} +}; +Q<X,Y> q; // expected-note {{instantiation of}} diff --git a/test/SemaTemplate/cxx1z-using-declaration.cpp b/test/SemaTemplate/cxx1z-using-declaration.cpp new file mode 100644 index 0000000000000000000000000000000000000000..7bef36db1f47a4c3520157a025497c19388f081e --- /dev/null +++ b/test/SemaTemplate/cxx1z-using-declaration.cpp @@ -0,0 +1,230 @@ +// RUN: %clang_cc1 -std=c++1z -verify %s + +// Test that we cope with failure to expand a pack. +template<typename ...T> struct Unexpanded : T... { + using T::f; // expected-error {{unexpanded}} + using typename T::type; // expected-error {{unexpanded}} + template<typename ...U> void g(U ...u) { f(u...); } // expected-error {{undeclared identifier 'f'}} + void h() { + Unexpanded<type...> *p; // expected-error {{undeclared identifier 'type'}} + } +}; +void test_Unexpanded() { + struct A { void f(); }; // expected-note {{must qualify}} + struct B { void f(int); }; // expected-note {{must qualify}} + Unexpanded<A, B>().g(0); // expected-note {{instantiation of}} +} + +// Test using non-type members from pack of base classes. +template<typename ...T> struct A : T... { // expected-note 2{{candidate}} + using T::T ...; // expected-note 6{{inherited here}} + using T::operator() ...; + using T::operator T* ...; + using T::h ...; + + void f(int n) { h(n); } // expected-error {{ambiguous}} + void f(int n, int m) { h(n, m); } // expected-error {{member using declaration 'h' instantiates to an empty pack}} + void g(int n) { (*this)(n); } // expected-error {{ambiguous}} + void g(int n, int m) { (*this)(n, m); } // expected-error {{does not provide a call operator}} +}; + +namespace test_A { + struct X { // expected-note 2{{candidate}} + X(); + X(int); // expected-note {{candidate}} + void operator()(int); // expected-note 2{{candidate}} + operator X *(); + void h(int); // expected-note {{candidate}} + }; + struct Y { + Y(); + Y(int, int); + void operator()(int, int); + operator Y *(); + void h(int, int); // expected-note {{not viable}} + }; + struct Z { // expected-note 2{{candidate}} + Z(); + Z(int); // expected-note {{candidate}} + void operator()(int); // expected-note 2{{candidate}} + operator Z *(); + void h(int); // expected-note {{candidate}} + }; + + void f() { + A<> a; + a.f(0, 0); // expected-note {{instantiation of}} + a.g(0, 0); // expected-note {{instantiation of}} + + A<X, Y> axy(0); + A<X, Y>(0, 0); + axy.f(0); + axy.f(0, 0); + axy.g(0); + axy.g(0, 0); + axy(0); + axy(0, 0); + + A<X, Y, Z>(0); // expected-error {{ambiguous}} + A<X, Y, Z> axyz(0, 0); + axyz.f(0); // expected-note {{instantiation of}} + axyz.f(0, 0); + axyz.g(0); // expected-note {{instantiation of}} + axyz.g(0, 0); + axyz(0); // expected-error {{ambiguous}} + axyz(0, 0); + + X *x; + x = a; // expected-error {{incompatible}} + x = axy; + x = axyz; + x = a.operator X*(); // expected-error {{no member}} + x = axy.operator X*(); + x = axyz.operator X*(); + + Z *z; + z = axyz; + z = axyz.operator Z*(); + } +} + +// Test using pack of non-type members from single base class. +template<typename X, typename Y, typename ...T> struct B : X, Y { + using X::operator T* ...; +}; + +namespace test_B { + struct X { operator int*(); operator float*(); operator char*(); }; // expected-note {{candidate}} + struct Y { operator int*(); operator float*(); operator char*(); }; // expected-note {{candidate}} + B<X, Y, int, float> bif; + int *pi = bif; + float *pf = bif; + char *pc = bif; // expected-error {{ambiguous}} +} + +// Test using type member from pack of base classes. +template<typename ...T> struct C : T... { + using typename T::type ...; // expected-error {{target of using declaration conflicts}} + void f() { type value; } // expected-error {{member using declaration 'type' instantiates to an empty pack}} +}; + +namespace test_C { + struct X { typedef int type; }; + struct Y { typedef int type; }; // expected-note {{conflicting}} + struct Z { typedef float type; }; // expected-note {{target}} + + void f() { + C<> c; + c.f(); // expected-note {{instantiation of}} + + C<X, Y> cxy; + cxy.f(); + + C<X, Y, Z> cxyz; // expected-note {{instantiation of}} + cxyz.f(); + } +} + +// Test using pack of non-types at block scope. +template<typename ...T> int fn1() { + using T::e ...; // expected-error 2{{class member}} expected-note 2{{instead}} + // expected-error@-1 2{{produces multiple values}} + return e; // expected-error {{using declaration 'e' instantiates to an empty pack}} +} + +namespace test_fn1 { + struct X { static int e; }; + struct Y { typedef int e; }; + inline namespace P { enum E { e }; } + inline namespace Q { enum F { e }; } + void f() { + fn1<>(); // expected-note {{instantiation of}} + fn1<X>(); // expected-note {{instantiation of}} + fn1<Y>(); // expected-note {{instantiation of}} + fn1<E>(); + fn1<E, F>(); // expected-note {{instantiation of}} + fn1<E, X>(); // expected-note {{instantiation of}} + } +} + +// Test using pack of types at block scope. +template<typename ...T> void fn2() { + // This cannot ever be valid: in order for T::type to be a type, T must be a + // class, and a class member cannot be named by a block-scope using declaration. + using typename T::type ...; // expected-error {{class member}} + type x; // expected-error {{unknown type name 'type'}} +} + +// Test partial substitution into class-scope pack. +template<typename ...T> auto lambda1() { + return [](auto x) { + struct A : T::template X<decltype(x)>... { // expected-note 1+{{instantiation of}} + using T::template X<decltype(x)>::f ...; + using typename T::template X<decltype(x)>::type ...; + void g(int n) { f(n); } // expected-error {{empty pack}} expected-error {{expected 2, have 1}} expected-error {{ambiguous}} + void h() { type value; } // expected-error {{empty pack}} + }; + return A(); + }; +} + +namespace test_lambda1 { + struct A { + template<typename> struct X { + void f(int); // expected-note {{candidate}} + using type = int; + }; + }; + struct B { + template<typename> struct X { + void f(int, int); // expected-note {{declared here}} expected-note {{not viable}} + using type = int; + }; + }; + struct C { + template<typename> struct X { + void f(int); // expected-note {{candidate}} + void f(int, int); // expected-note {{not viable}} + using type = int; + }; + }; + + void f() { + lambda1<>() // expected-note 2{{instantiation of}} + (0) + // FIXME: This is poor error recovery + .g(0); // expected-error {{no member named 'g'}} + lambda1<A>() + (0) + .g(0); + lambda1<B>() + (0) // expected-note {{instantiation of}} + .g(0); + lambda1<A, B, C>() + (0) // expected-note {{instantiation of}} + .g(0); + } +} + +namespace p0195r2_example { + template<typename ...Ts> + struct Overloader : Ts... { + using Ts::operator() ...; + }; + + template<typename ...Ts> + constexpr auto make_overloader(Ts &&...ts) { + return Overloader<Ts...>{static_cast<Ts&&>(ts)...}; + } + + void test() { + auto o = make_overloader( + [&](int &r) -> int & { return r; }, // expected-note {{candidate function}} + [&](float &r) -> float & { return r; } // expected-note {{candidate function}} + ); + int a; float f; double d; + int &ra = o(a); + float &rf = o(f); + double &rd = o(d); // expected-error {{no matching function}} + } +} diff --git a/tools/libclang/CIndex.cpp b/tools/libclang/CIndex.cpp index bc5aa1f25370185a88da4e3a1ae7a9bd47b83a7b..cb4ff0966a6c9cceb8a030af93c1a0dac8eb86fd 100644 --- a/tools/libclang/CIndex.cpp +++ b/tools/libclang/CIndex.cpp @@ -5733,6 +5733,7 @@ CXCursor clang_getCursorDefinition(CXCursor C) { case Decl::BuiltinTemplate: case Decl::PragmaComment: case Decl::PragmaDetectMismatch: + case Decl::UsingPack: return C; // Declaration kinds that don't make any sense here, but are