[c++1z] P0195R2: Support pack-expansion of using-declarations.

This change introduces UsingPackDecl as a marker for the set of UsingDecls
produced by pack expansion of a single (unresolved) using declaration. This is
not strictly necessary (we just need to be able to map from the original using
declaration to its expansions somehow), but it's useful to maintain the
invariant that each declaration reference instantiates to refer to one
declaration.

This is a re-commit of r290080 (reverted in r290092) with a fix for a
use-after-lifetime bug.


git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@290203 91177308-0d34-0410-b5e6-96231b3b80d8
This commit is contained in:
Richard Smith 2016-12-20 21:35:28 +00:00
parent a966b1fd6c
commit c8c1a1961a
26 changed files with 809 additions and 262 deletions

View File

@ -3140,6 +3140,77 @@ public:
friend class ASTDeclWriter; 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 /// \brief Represents a dependent using declaration which was not marked with
/// \c typename. /// \c typename.
/// ///
@ -3158,6 +3229,9 @@ class UnresolvedUsingValueDecl : public ValueDecl,
/// \brief The source location of the 'using' keyword /// \brief The source location of the 'using' keyword
SourceLocation UsingLocation; SourceLocation UsingLocation;
/// \brief If this is a pack expansion, the location of the '...'.
SourceLocation EllipsisLoc;
/// \brief The nested-name-specifier that precedes the name. /// \brief The nested-name-specifier that precedes the name.
NestedNameSpecifierLoc QualifierLoc; NestedNameSpecifierLoc QualifierLoc;
@ -3168,11 +3242,12 @@ class UnresolvedUsingValueDecl : public ValueDecl,
UnresolvedUsingValueDecl(DeclContext *DC, QualType Ty, UnresolvedUsingValueDecl(DeclContext *DC, QualType Ty,
SourceLocation UsingLoc, SourceLocation UsingLoc,
NestedNameSpecifierLoc QualifierLoc, NestedNameSpecifierLoc QualifierLoc,
const DeclarationNameInfo &NameInfo) const DeclarationNameInfo &NameInfo,
SourceLocation EllipsisLoc)
: ValueDecl(UnresolvedUsingValue, DC, : ValueDecl(UnresolvedUsingValue, DC,
NameInfo.getLoc(), NameInfo.getName(), Ty), NameInfo.getLoc(), NameInfo.getName(), Ty),
UsingLocation(UsingLoc), QualifierLoc(QualifierLoc), UsingLocation(UsingLoc), EllipsisLoc(EllipsisLoc),
DNLoc(NameInfo.getInfo()) QualifierLoc(QualifierLoc), DNLoc(NameInfo.getInfo())
{ } { }
public: public:
@ -3198,10 +3273,20 @@ public:
return DeclarationNameInfo(getDeclName(), getLocation(), DNLoc); 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 * static UnresolvedUsingValueDecl *
Create(ASTContext &C, DeclContext *DC, SourceLocation UsingLoc, Create(ASTContext &C, DeclContext *DC, SourceLocation UsingLoc,
NestedNameSpecifierLoc QualifierLoc, NestedNameSpecifierLoc QualifierLoc,
const DeclarationNameInfo &NameInfo); const DeclarationNameInfo &NameInfo, SourceLocation EllipsisLoc);
static UnresolvedUsingValueDecl * static UnresolvedUsingValueDecl *
CreateDeserialized(ASTContext &C, unsigned ID); CreateDeserialized(ASTContext &C, unsigned ID);
@ -3242,6 +3327,9 @@ class UnresolvedUsingTypenameDecl
/// \brief The source location of the 'typename' keyword /// \brief The source location of the 'typename' keyword
SourceLocation TypenameLocation; SourceLocation TypenameLocation;
/// \brief If this is a pack expansion, the location of the '...'.
SourceLocation EllipsisLoc;
/// \brief The nested-name-specifier that precedes the name. /// \brief The nested-name-specifier that precedes the name.
NestedNameSpecifierLoc QualifierLoc; NestedNameSpecifierLoc QualifierLoc;
@ -3249,10 +3337,12 @@ class UnresolvedUsingTypenameDecl
SourceLocation TypenameLoc, SourceLocation TypenameLoc,
NestedNameSpecifierLoc QualifierLoc, NestedNameSpecifierLoc QualifierLoc,
SourceLocation TargetNameLoc, SourceLocation TargetNameLoc,
IdentifierInfo *TargetName) IdentifierInfo *TargetName,
SourceLocation EllipsisLoc)
: TypeDecl(UnresolvedUsingTypename, DC, TargetNameLoc, TargetName, : TypeDecl(UnresolvedUsingTypename, DC, TargetNameLoc, TargetName,
UsingLoc), UsingLoc),
TypenameLocation(TypenameLoc), QualifierLoc(QualifierLoc) { } TypenameLocation(TypenameLoc), EllipsisLoc(EllipsisLoc),
QualifierLoc(QualifierLoc) { }
friend class ASTDeclReader; friend class ASTDeclReader;
@ -3272,10 +3362,25 @@ public:
return QualifierLoc.getNestedNameSpecifier(); 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 * static UnresolvedUsingTypenameDecl *
Create(ASTContext &C, DeclContext *DC, SourceLocation UsingLoc, Create(ASTContext &C, DeclContext *DC, SourceLocation UsingLoc,
SourceLocation TypenameLoc, NestedNameSpecifierLoc QualifierLoc, SourceLocation TypenameLoc, NestedNameSpecifierLoc QualifierLoc,
SourceLocation TargetNameLoc, DeclarationName TargetName); SourceLocation TargetNameLoc, DeclarationName TargetName,
SourceLocation EllipsisLoc);
static UnresolvedUsingTypenameDecl * static UnresolvedUsingTypenameDecl *
CreateDeserialized(ASTContext &C, unsigned ID); CreateDeserialized(ASTContext &C, unsigned ID);

View File

@ -1505,6 +1505,8 @@ DEF_TRAVERSE_DECL(UsingDecl, {
TRY_TO(TraverseDeclarationNameInfo(D->getNameInfo())); TRY_TO(TraverseDeclarationNameInfo(D->getNameInfo()));
}) })
DEF_TRAVERSE_DECL(UsingPackDecl, {})
DEF_TRAVERSE_DECL(UsingDirectiveDecl, { DEF_TRAVERSE_DECL(UsingDirectiveDecl, {
TRY_TO(TraverseNestedNameSpecifierLoc(D->getQualifierLoc())); TRY_TO(TraverseNestedNameSpecifierLoc(D->getQualifierLoc()));
}) })

View File

@ -67,6 +67,7 @@ def Named : Decl<1>;
def TemplateTemplateParm : DDecl<Template>; def TemplateTemplateParm : DDecl<Template>;
def BuiltinTemplate : DDecl<Template>; def BuiltinTemplate : DDecl<Template>;
def Using : DDecl<Named>; def Using : DDecl<Named>;
def UsingPack : DDecl<Named>;
def UsingShadow : DDecl<Named>; def UsingShadow : DDecl<Named>;
def ConstructorUsingShadow : DDecl<UsingShadow>; def ConstructorUsingShadow : DDecl<UsingShadow>;
def ObjCMethod : DDecl<Named>, DeclContext; def ObjCMethod : DDecl<Named>, DeclContext;

View File

@ -740,6 +740,8 @@ def err_alias_declaration_not_identifier : Error<
"name defined in alias declaration must be an identifier">; "name defined in alias declaration must be an identifier">;
def err_alias_declaration_specialization : Error< def err_alias_declaration_specialization : Error<
"%select{partial specialization|explicit specialization|explicit instantiation}0 of alias templates is not permitted">; "%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 // C++1z using-declaration pack expansions
def ext_multi_using_declaration : ExtWarn< 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 " "use of multiple declarators in a single using declaration is "
"incompatible with C++ standards before C++1z">, "incompatible with C++ standards before C++1z">,
InGroup<CXXPre1zCompat>, DefaultIgnore; 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 // C++11 override control
def ext_override_control_keyword : ExtWarn< def ext_override_control_keyword : ExtWarn<

View File

@ -474,6 +474,8 @@ def err_using_decl_conflict : Error<
def err_using_decl_conflict_reverse : Error< def err_using_decl_conflict_reverse : Error<
"declaration conflicts with target of using declaration already in scope">; "declaration conflicts with target of using declaration already in scope">;
def note_using_decl : Note<"%select{|previous }0using declaration">; 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< def warn_access_decl_deprecated : Warning<
"access declarations are deprecated; use using declarations instead">, "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< def err_nested_name_spec_non_tag : Error<
"type %0 cannot be used prior to '::' because it has no members">; "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 // C++ Explicit Instantiation
def err_explicit_instantiation_duplicate : Error< def err_explicit_instantiation_duplicate : Error<
"duplicate explicit instantiation of %0">; "duplicate explicit instantiation of %0">;

View File

@ -2436,9 +2436,10 @@ private:
CXXScopeSpec SS; CXXScopeSpec SS;
SourceLocation TemplateKWLoc; SourceLocation TemplateKWLoc;
UnqualifiedId Name; UnqualifiedId Name;
SourceLocation EllipsisLoc;
void clear() { void clear() {
TypenameLoc = TemplateKWLoc = SourceLocation(); TypenameLoc = TemplateKWLoc = EllipsisLoc = SourceLocation();
SS.clear(); SS.clear();
Name.clear(); Name.clear();
} }
@ -2450,9 +2451,6 @@ private:
SourceLocation UsingLoc, SourceLocation UsingLoc,
SourceLocation &DeclEnd, SourceLocation &DeclEnd,
AccessSpecifier AS = AS_none); AccessSpecifier AS = AS_none);
Decl *ParseAliasTemplate(const ParsedTemplateInfo &TemplateInfo,
SourceLocation &DeclEnd, AccessSpecifier AS,
ParsedAttributesWithRange &MisplacedAttrs1);
Decl *ParseAliasDeclarationAfterDeclarator( Decl *ParseAliasDeclarationAfterDeclarator(
const ParsedTemplateInfo &TemplateInfo, SourceLocation UsingLoc, const ParsedTemplateInfo &TemplateInfo, SourceLocation UsingLoc,
UsingDeclarator &D, SourceLocation &DeclEnd, AccessSpecifier AS, UsingDeclarator &D, SourceLocation &DeclEnd, AccessSpecifier AS,

View File

@ -4324,12 +4324,15 @@ public:
NamedDecl *BuildUsingDeclaration(Scope *S, AccessSpecifier AS, NamedDecl *BuildUsingDeclaration(Scope *S, AccessSpecifier AS,
SourceLocation UsingLoc, SourceLocation UsingLoc,
bool HasTypenameKeyword,
SourceLocation TypenameLoc,
CXXScopeSpec &SS, CXXScopeSpec &SS,
DeclarationNameInfo NameInfo, DeclarationNameInfo NameInfo,
SourceLocation EllipsisLoc,
AttributeList *AttrList, AttributeList *AttrList,
bool IsInstantiation, bool IsInstantiation);
bool HasTypenameKeyword, NamedDecl *BuildUsingPackDecl(NamedDecl *InstantiatedFrom,
SourceLocation TypenameLoc); ArrayRef<NamedDecl *> Expansions);
bool CheckInheritingConstructorUsingDecl(UsingDecl *UD); bool CheckInheritingConstructorUsingDecl(UsingDecl *UD);
@ -4343,10 +4346,11 @@ public:
Decl *ActOnUsingDeclaration(Scope *CurScope, Decl *ActOnUsingDeclaration(Scope *CurScope,
AccessSpecifier AS, AccessSpecifier AS,
SourceLocation UsingLoc, SourceLocation UsingLoc,
SourceLocation TypenameLoc,
CXXScopeSpec &SS, CXXScopeSpec &SS,
UnqualifiedId &Name, UnqualifiedId &Name,
AttributeList *AttrList, SourceLocation EllipsisLoc,
SourceLocation TypenameLoc); AttributeList *AttrList);
Decl *ActOnAliasDeclaration(Scope *CurScope, Decl *ActOnAliasDeclaration(Scope *CurScope,
AccessSpecifier AS, AccessSpecifier AS,
MultiTemplateParamsArg TemplateParams, MultiTemplateParamsArg TemplateParams,
@ -6351,7 +6355,7 @@ public:
/// ///
/// \param SS The nested-name-specifier that will be traversed to find /// \param SS The nested-name-specifier that will be traversed to find
/// unexpanded parameter packs. /// unexpanded parameter packs.
void collectUnexpandedParameterPacks(CXXScopeSpec &SS, void collectUnexpandedParameterPacks(NestedNameSpecifierLoc NNS,
SmallVectorImpl<UnexpandedParameterPack> &Unexpanded); SmallVectorImpl<UnexpandedParameterPack> &Unexpanded);
/// \brief Collect the set of unexpanded parameter packs within the given /// \brief Collect the set of unexpanded parameter packs within the given

View File

@ -515,6 +515,11 @@ namespace clang {
VarTemplateDecl *VarTemplate, VarTemplateDecl *VarTemplate,
VarTemplatePartialSpecializationDecl *PartialSpec); VarTemplatePartialSpecializationDecl *PartialSpec);
void InstantiateEnumDefinition(EnumDecl *Enum, EnumDecl *Pattern); void InstantiateEnumDefinition(EnumDecl *Enum, EnumDecl *Pattern);
private:
template<typename T>
Decl *instantiateUnresolvedUsingDecl(T *D,
bool InstantiatingPackElement = false);
}; };
} }

View File

@ -1103,6 +1103,8 @@ namespace clang {
DECL_NAMESPACE_ALIAS, DECL_NAMESPACE_ALIAS,
/// \brief A UsingDecl record. /// \brief A UsingDecl record.
DECL_USING, DECL_USING,
/// \brief A UsingPackDecl record.
DECL_USING_PACK,
/// \brief A UsingShadowDecl record. /// \brief A UsingShadowDecl record.
DECL_USING_SHADOW, DECL_USING_SHADOW,
/// \brief A ConstructorUsingShadowDecl record. /// \brief A ConstructorUsingShadowDecl record.

View File

@ -651,11 +651,13 @@ unsigned Decl::getIdentifierNamespaceForKind(Kind DeclKind) {
case Typedef: case Typedef:
case TypeAlias: case TypeAlias:
case TypeAliasTemplate: case TypeAliasTemplate:
case UnresolvedUsingTypename:
case TemplateTypeParm: case TemplateTypeParm:
case ObjCTypeParam: case ObjCTypeParam:
return IDNS_Ordinary | IDNS_Type; return IDNS_Ordinary | IDNS_Type;
case UnresolvedUsingTypename:
return IDNS_Ordinary | IDNS_Type | IDNS_Using;
case UsingShadow: case UsingShadow:
return 0; // we'll actually overwrite this later return 0; // we'll actually overwrite this later
@ -663,6 +665,7 @@ unsigned Decl::getIdentifierNamespaceForKind(Kind DeclKind) {
return IDNS_Ordinary | IDNS_Using; return IDNS_Ordinary | IDNS_Using;
case Using: case Using:
case UsingPack:
return IDNS_Using; return IDNS_Using;
case ObjCProtocol: case ObjCProtocol:

View File

@ -2250,15 +2250,37 @@ SourceRange UsingDecl::getSourceRange() const {
return SourceRange(Begin, getNameInfo().getEndLoc()); 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() { } void UnresolvedUsingValueDecl::anchor() { }
UnresolvedUsingValueDecl * UnresolvedUsingValueDecl *
UnresolvedUsingValueDecl::Create(ASTContext &C, DeclContext *DC, UnresolvedUsingValueDecl::Create(ASTContext &C, DeclContext *DC,
SourceLocation UsingLoc, SourceLocation UsingLoc,
NestedNameSpecifierLoc QualifierLoc, NestedNameSpecifierLoc QualifierLoc,
const DeclarationNameInfo &NameInfo) { const DeclarationNameInfo &NameInfo,
SourceLocation EllipsisLoc) {
return new (C, DC) UnresolvedUsingValueDecl(DC, C.DependentTy, UsingLoc, return new (C, DC) UnresolvedUsingValueDecl(DC, C.DependentTy, UsingLoc,
QualifierLoc, NameInfo); QualifierLoc, NameInfo,
EllipsisLoc);
} }
UnresolvedUsingValueDecl * UnresolvedUsingValueDecl *
@ -2266,7 +2288,8 @@ UnresolvedUsingValueDecl::CreateDeserialized(ASTContext &C, unsigned ID) {
return new (C, ID) UnresolvedUsingValueDecl(nullptr, QualType(), return new (C, ID) UnresolvedUsingValueDecl(nullptr, QualType(),
SourceLocation(), SourceLocation(),
NestedNameSpecifierLoc(), NestedNameSpecifierLoc(),
DeclarationNameInfo()); DeclarationNameInfo(),
SourceLocation());
} }
SourceRange UnresolvedUsingValueDecl::getSourceRange() const { SourceRange UnresolvedUsingValueDecl::getSourceRange() const {
@ -2283,17 +2306,18 @@ UnresolvedUsingTypenameDecl::Create(ASTContext &C, DeclContext *DC,
SourceLocation TypenameLoc, SourceLocation TypenameLoc,
NestedNameSpecifierLoc QualifierLoc, NestedNameSpecifierLoc QualifierLoc,
SourceLocation TargetNameLoc, SourceLocation TargetNameLoc,
DeclarationName TargetName) { DeclarationName TargetName,
SourceLocation EllipsisLoc) {
return new (C, DC) UnresolvedUsingTypenameDecl( return new (C, DC) UnresolvedUsingTypenameDecl(
DC, UsingLoc, TypenameLoc, QualifierLoc, TargetNameLoc, DC, UsingLoc, TypenameLoc, QualifierLoc, TargetNameLoc,
TargetName.getAsIdentifierInfo()); TargetName.getAsIdentifierInfo(), EllipsisLoc);
} }
UnresolvedUsingTypenameDecl * UnresolvedUsingTypenameDecl *
UnresolvedUsingTypenameDecl::CreateDeserialized(ASTContext &C, unsigned ID) { UnresolvedUsingTypenameDecl::CreateDeserialized(ASTContext &C, unsigned ID) {
return new (C, ID) UnresolvedUsingTypenameDecl( return new (C, ID) UnresolvedUsingTypenameDecl(
nullptr, SourceLocation(), SourceLocation(), NestedNameSpecifierLoc(), nullptr, SourceLocation(), SourceLocation(), NestedNameSpecifierLoc(),
SourceLocation(), nullptr); SourceLocation(), nullptr, SourceLocation());
} }
void StaticAssertDecl::anchor() { } void StaticAssertDecl::anchor() { }

View File

@ -113,6 +113,10 @@ void CodeGenFunction::EmitDecl(const Decl &D) {
if (CGDebugInfo *DI = getDebugInfo()) if (CGDebugInfo *DI = getDebugInfo())
DI->EmitUsingDecl(cast<UsingDecl>(D)); DI->EmitUsingDecl(cast<UsingDecl>(D));
return; return;
case Decl::UsingPack:
for (auto *Using : cast<UsingPackDecl>(D).expansions())
EmitDecl(*Using);
return;
case Decl::UsingDirective: // using namespace X; [C++] case Decl::UsingDirective: // using namespace X; [C++]
if (CGDebugInfo *DI = getDebugInfo()) if (CGDebugInfo *DI = getDebugInfo())
DI->EmitUsingDirective(cast<UsingDirectiveDecl>(D)); DI->EmitUsingDirective(cast<UsingDirectiveDecl>(D));

View File

@ -560,7 +560,9 @@ bool Parser::ParseUsingDeclarator(unsigned Context, UsingDeclarator &D) {
// nested-name-specifier, the name is [...] considered to name the // nested-name-specifier, the name is [...] considered to name the
// constructor. // constructor.
if (getLangOpts().CPlusPlus11 && Context == Declarator::MemberContext && 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.isNotEmpty() && LastII == Tok.getIdentifierInfo() &&
!D.SS.getScopeRep()->getAsNamespace() && !D.SS.getScopeRep()->getAsNamespace() &&
!D.SS.getScopeRep()->getAsNamespaceAlias()) { !D.SS.getScopeRep()->getAsNamespaceAlias()) {
@ -578,7 +580,10 @@ bool Parser::ParseUsingDeclarator(unsigned Context, UsingDeclarator &D) {
return true; 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; return false;
} }
@ -678,9 +683,9 @@ Parser::ParseUsingDeclaration(unsigned Context,
D.TypenameLoc = SourceLocation(); D.TypenameLoc = SourceLocation();
} }
Decl *UD = Decl *UD = Actions.ActOnUsingDeclaration(getCurScope(), AS, UsingLoc,
Actions.ActOnUsingDeclaration(getCurScope(), AS, UsingLoc, D.SS, D.TypenameLoc, D.SS, D.Name,
D.Name, Attrs.getList(), D.TypenameLoc); D.EllipsisLoc, Attrs.getList());
if (UD) if (UD)
DeclsInGroup.push_back(UD); DeclsInGroup.push_back(UD);
} }
@ -708,62 +713,6 @@ Parser::ParseUsingDeclaration(unsigned Context,
return Actions.BuildDeclaratorGroup(DeclsInGroup, /*MayContainAuto*/false); 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( Decl *Parser::ParseAliasDeclarationAfterDeclarator(
const ParsedTemplateInfo &TemplateInfo, SourceLocation UsingLoc, const ParsedTemplateInfo &TemplateInfo, SourceLocation UsingLoc,
UsingDeclarator &D, SourceLocation &DeclEnd, AccessSpecifier AS, UsingDeclarator &D, SourceLocation &DeclEnd, AccessSpecifier AS,
@ -813,6 +762,9 @@ Decl *Parser::ParseAliasDeclarationAfterDeclarator(
else if (D.SS.isNotEmpty()) else if (D.SS.isNotEmpty())
Diag(D.SS.getBeginLoc(), diag::err_alias_declaration_not_identifier) Diag(D.SS.getBeginLoc(), diag::err_alias_declaration_not_identifier)
<< FixItHint::CreateRemoval(D.SS.getRange()); << 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; Decl *DeclFromDeclSpec = nullptr;
TypeResult TypeAlias = TypeResult TypeAlias =
@ -2487,8 +2439,9 @@ Parser::ParseCXXClassMemberDeclaration(AccessSpecifier AS,
} }
return DeclGroupPtrTy::make(DeclGroupRef(Actions.ActOnUsingDeclaration( return DeclGroupPtrTy::make(DeclGroupRef(Actions.ActOnUsingDeclaration(
getCurScope(), AS, /*UsingLoc*/SourceLocation(), SS, Name, getCurScope(), AS, /*UsingLoc*/ SourceLocation(),
/*AttrList*/nullptr, /*TypenameLoc*/SourceLocation()))); /*TypenameLoc*/ SourceLocation(), SS, Name,
/*EllipsisLoc*/ SourceLocation(), /*AttrList*/ nullptr)));
} }
} }

View File

@ -8533,12 +8533,18 @@ void Sema::PushUsingDirective(Scope *S, UsingDirectiveDecl *UDir) {
Decl *Sema::ActOnUsingDeclaration(Scope *S, Decl *Sema::ActOnUsingDeclaration(Scope *S,
AccessSpecifier AS, AccessSpecifier AS,
SourceLocation UsingLoc, SourceLocation UsingLoc,
SourceLocation TypenameLoc,
CXXScopeSpec &SS, CXXScopeSpec &SS,
UnqualifiedId &Name, UnqualifiedId &Name,
AttributeList *AttrList, SourceLocation EllipsisLoc,
SourceLocation TypenameLoc) { AttributeList *AttrList) {
assert(S->getFlags() & Scope::DeclScope && "Invalid Scope."); assert(S->getFlags() & Scope::DeclScope && "Invalid Scope.");
if (SS.isEmpty()) {
Diag(Name.getLocStart(), diag::err_using_requires_qualname);
return nullptr;
}
switch (Name.getKind()) { switch (Name.getKind()) {
case UnqualifiedId::IK_ImplicitSelfParam: case UnqualifiedId::IK_ImplicitSelfParam:
case UnqualifiedId::IK_Identifier: case UnqualifiedId::IK_Identifier:
@ -8584,14 +8590,23 @@ Decl *Sema::ActOnUsingDeclaration(Scope *S,
<< FixItHint::CreateInsertion(SS.getRange().getBegin(), "using "); << FixItHint::CreateInsertion(SS.getRange().getBegin(), "using ");
} }
if (DiagnoseUnexpandedParameterPack(SS, UPPC_UsingDeclaration) || if (EllipsisLoc.isInvalid()) {
DiagnoseUnexpandedParameterPack(TargetNameInfo, UPPC_UsingDeclaration)) if (DiagnoseUnexpandedParameterPack(SS, UPPC_UsingDeclaration) ||
return nullptr; 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, NamedDecl *UD =
TargetNameInfo, AttrList, BuildUsingDeclaration(S, AS, UsingLoc, TypenameLoc.isValid(), TypenameLoc,
/* IsInstantiation */ false, SS, TargetNameInfo, EllipsisLoc, AttrList,
TypenameLoc.isValid(), TypenameLoc); /*IsInstantiation*/false);
if (UD) if (UD)
PushOnScopeChains(UD, S, /*AddToContext*/ false); 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) diag::err_using_decl_nested_name_specifier_is_current_class)
<< Using->getQualifierLoc().getSourceRange(); << Using->getQualifierLoc().getSourceRange();
Diag(Orig->getLocation(), diag::note_using_decl_target); Diag(Orig->getLocation(), diag::note_using_decl_target);
Using->setInvalidDecl();
return true; return true;
} }
@ -8663,6 +8679,7 @@ bool Sema::CheckUsingShadowDecl(UsingDecl *Using, NamedDecl *Orig,
<< cast<CXXRecordDecl>(CurContext) << cast<CXXRecordDecl>(CurContext)
<< Using->getQualifierLoc().getSourceRange(); << Using->getQualifierLoc().getSourceRange();
Diag(Orig->getLocation(), diag::note_using_decl_target); Diag(Orig->getLocation(), diag::note_using_decl_target);
Using->setInvalidDecl();
return true; 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 // We can have UsingDecls in our Previous results because we use the same
// LookupResult for checking whether the UsingDecl itself is a valid // LookupResult for checking whether the UsingDecl itself is a valid
// redeclaration. // redeclaration.
if (isa<UsingDecl>(D)) if (isa<UsingDecl>(D) || isa<UsingPackDecl>(D))
continue; continue;
if (IsEquivalentForUsingDecl(Context, D, Target)) { 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(Target->getLocation(), diag::note_using_decl_target);
Diag(OldDecl->getLocation(), diag::note_using_decl_conflict); Diag(OldDecl->getLocation(), diag::note_using_decl_conflict);
Using->setInvalidDecl();
return true; return true;
} }
@ -8744,6 +8762,7 @@ bool Sema::CheckUsingShadowDecl(UsingDecl *Using, NamedDecl *Orig,
Diag(Using->getLocation(), diag::err_using_decl_conflict); Diag(Using->getLocation(), diag::err_using_decl_conflict);
Diag(Target->getLocation(), diag::note_using_decl_target); Diag(Target->getLocation(), diag::note_using_decl_target);
Diag(Tag->getLocation(), diag::note_using_decl_conflict); Diag(Tag->getLocation(), diag::note_using_decl_conflict);
Using->setInvalidDecl();
return true; return true;
} }
@ -8753,6 +8772,7 @@ bool Sema::CheckUsingShadowDecl(UsingDecl *Using, NamedDecl *Orig,
Diag(Using->getLocation(), diag::err_using_decl_conflict); Diag(Using->getLocation(), diag::err_using_decl_conflict);
Diag(Target->getLocation(), diag::note_using_decl_target); Diag(Target->getLocation(), diag::note_using_decl_target);
Diag(NonTag->getLocation(), diag::note_using_decl_conflict); Diag(NonTag->getLocation(), diag::note_using_decl_conflict);
Using->setInvalidDecl();
return true; return true;
} }
@ -8960,23 +8980,19 @@ private:
/// the lookup differently for these declarations. /// the lookup differently for these declarations.
NamedDecl *Sema::BuildUsingDeclaration(Scope *S, AccessSpecifier AS, NamedDecl *Sema::BuildUsingDeclaration(Scope *S, AccessSpecifier AS,
SourceLocation UsingLoc, SourceLocation UsingLoc,
bool HasTypenameKeyword,
SourceLocation TypenameLoc,
CXXScopeSpec &SS, CXXScopeSpec &SS,
DeclarationNameInfo NameInfo, DeclarationNameInfo NameInfo,
SourceLocation EllipsisLoc,
AttributeList *AttrList, AttributeList *AttrList,
bool IsInstantiation, bool IsInstantiation) {
bool HasTypenameKeyword,
SourceLocation TypenameLoc) {
assert(!SS.isInvalid() && "Invalid CXXScopeSpec."); assert(!SS.isInvalid() && "Invalid CXXScopeSpec.");
SourceLocation IdentLoc = NameInfo.getLoc(); SourceLocation IdentLoc = NameInfo.getLoc();
assert(IdentLoc.isValid() && "Invalid TargetName location."); assert(IdentLoc.isValid() && "Invalid TargetName location.");
// FIXME: We ignore attributes for now. // 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 // For an inheriting constructor declaration, the name of the using
// declaration is the name of a constructor in this class, not in the // declaration is the name of a constructor in this class, not in the
// base class. // base class.
@ -9042,16 +9058,17 @@ NamedDecl *Sema::BuildUsingDeclaration(Scope *S, AccessSpecifier AS,
DeclContext *LookupContext = computeDeclContext(SS); DeclContext *LookupContext = computeDeclContext(SS);
NamedDecl *D; NamedDecl *D;
NestedNameSpecifierLoc QualifierLoc = SS.getWithLocInContext(Context); NestedNameSpecifierLoc QualifierLoc = SS.getWithLocInContext(Context);
if (!LookupContext) { if (!LookupContext || EllipsisLoc.isValid()) {
if (HasTypenameKeyword) { if (HasTypenameKeyword) {
// FIXME: not all declaration name kinds are legal here // FIXME: not all declaration name kinds are legal here
D = UnresolvedUsingTypenameDecl::Create(Context, CurContext, D = UnresolvedUsingTypenameDecl::Create(Context, CurContext,
UsingLoc, TypenameLoc, UsingLoc, TypenameLoc,
QualifierLoc, QualifierLoc,
IdentLoc, NameInfo.getName()); IdentLoc, NameInfo.getName(),
EllipsisLoc);
} else { } else {
D = UnresolvedUsingValueDecl::Create(Context, CurContext, UsingLoc, D = UnresolvedUsingValueDecl::Create(Context, CurContext, UsingLoc,
QualifierLoc, NameInfo); QualifierLoc, NameInfo, EllipsisLoc);
} }
D->setAccess(AS); D->setAccess(AS);
CurContext->addDecl(D); CurContext->addDecl(D);
@ -9211,6 +9228,19 @@ NamedDecl *Sema::BuildUsingDeclaration(Scope *S, AccessSpecifier AS,
return UD; 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. /// Additional checks for a using declaration referring to a constructor name.
bool Sema::CheckInheritingConstructorUsingDecl(UsingDecl *UD) { bool Sema::CheckInheritingConstructorUsingDecl(UsingDecl *UD) {
assert(!UD->hasTypename() && "expecting a constructor name"); assert(!UD->hasTypename() && "expecting a constructor name");
@ -9264,7 +9294,7 @@ bool Sema::CheckUsingDeclRedeclaration(SourceLocation UsingLoc,
// scope? // scope?
if (Qual->isDependent() && !HasTypenameKeyword) { if (Qual->isDependent() && !HasTypenameKeyword) {
for (auto *D : Prev) { for (auto *D : Prev) {
if (!isa<TypeDecl>(D) && !isa<UsingDecl>(D)) { if (!isa<TypeDecl>(D) && !isa<UsingDecl>(D) && !isa<UsingPackDecl>(D)) {
bool OldCouldBeEnumerator = bool OldCouldBeEnumerator =
isa<UnresolvedUsingValueDecl>(D) || isa<EnumConstantDecl>(D); isa<UnresolvedUsingValueDecl>(D) || isa<EnumConstantDecl>(D);
Diag(NameLoc, Diag(NameLoc,

View File

@ -7462,17 +7462,11 @@ Sema::CheckMicrosoftIfExistsSymbol(Scope *S, SourceLocation KeywordLoc,
UnqualifiedId &Name) { UnqualifiedId &Name) {
DeclarationNameInfo TargetNameInfo = GetNameFromUnqualifiedId(Name); DeclarationNameInfo TargetNameInfo = GetNameFromUnqualifiedId(Name);
// Check for unexpanded parameter packs. // Check for an unexpanded parameter pack.
SmallVector<UnexpandedParameterPack, 4> Unexpanded; auto UPPC = IsIfExists ? UPPC_IfExists : UPPC_IfNotExists;
collectUnexpandedParameterPacks(SS, Unexpanded); if (DiagnoseUnexpandedParameterPack(SS, UPPC) ||
collectUnexpandedParameterPacks(TargetNameInfo, Unexpanded); DiagnoseUnexpandedParameterPack(TargetNameInfo, UPPC))
if (!Unexpanded.empty()) {
DiagnoseUnexpandedParameterPacks(KeywordLoc,
IsIfExists? UPPC_IfExists
: UPPC_IfNotExists,
Unexpanded);
return IER_Error; return IER_Error;
}
return CheckMicrosoftIfExistsSymbol(S, SS, TargetNameInfo); return CheckMicrosoftIfExistsSymbol(S, SS, TargetNameInfo);
} }

View File

@ -981,7 +981,7 @@ Sema::CheckOverload(Scope *S, FunctionDecl *New, const LookupResult &Old,
Match = *I; Match = *I;
return Ovl_Match; 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 // We can overload with these, which can show up when doing
// redeclaration checks for UsingDecls. // redeclaration checks for UsingDecls.
assert(Old.getLookupKind() == LookupUsingDeclName); assert(Old.getLookupKind() == LookupUsingDeclName);
@ -11420,6 +11420,12 @@ BuildRecoveryCallExpr(Sema &SemaRef, Scope *S, Expr *Fn,
assert(!R.empty() && "lookup results empty despite recovery"); 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 // Build an implicit member call if appropriate. Just drop the
// casts and such from the call, we don't really care. // casts and such from the call, we don't really care.
ExprResult NewFn = ExprError(); ExprResult NewFn = ExprError();

View File

@ -2495,8 +2495,73 @@ Decl *TemplateDeclInstantiator::VisitConstructorUsingShadowDecl(
return nullptr; return nullptr;
} }
Decl * TemplateDeclInstantiator template <typename T>
::VisitUnresolvedUsingTypenameDecl(UnresolvedUsingTypenameDecl *D) { 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);
// 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;
// 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");
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();
NestedNameSpecifierLoc QualifierLoc NestedNameSpecifierLoc QualifierLoc
= SemaRef.SubstNestedNameSpecifierLoc(D->getQualifierLoc(), = SemaRef.SubstNestedNameSpecifierLoc(D->getQualifierLoc(),
TemplateArgs); TemplateArgs);
@ -2506,44 +2571,51 @@ Decl * TemplateDeclInstantiator
CXXScopeSpec SS; CXXScopeSpec SS;
SS.Adopt(QualifierLoc); SS.Adopt(QualifierLoc);
// 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);
return UD;
}
Decl * TemplateDeclInstantiator
::VisitUnresolvedUsingValueDecl(UnresolvedUsingValueDecl *D) {
NestedNameSpecifierLoc QualifierLoc
= SemaRef.SubstNestedNameSpecifierLoc(D->getQualifierLoc(), TemplateArgs);
if (!QualifierLoc)
return nullptr;
CXXScopeSpec SS;
SS.Adopt(QualifierLoc);
DeclarationNameInfo NameInfo DeclarationNameInfo NameInfo
= SemaRef.SubstDeclarationNameInfo(D->getNameInfo(), TemplateArgs); = SemaRef.SubstDeclarationNameInfo(D->getNameInfo(), TemplateArgs);
NamedDecl *UD = // Produce a pack expansion only if we're not instantiating a particular
SemaRef.BuildUsingDeclaration(/*Scope*/ nullptr, D->getAccess(), // slice of a pack expansion.
D->getUsingLoc(), SS, NameInfo, nullptr, bool InstantiatingSlice = D->getEllipsisLoc().isValid() &&
/*instantiation*/ true, SemaRef.ArgumentPackSubstitutionIndex != -1;
/*typename*/ false, SourceLocation()); 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) if (UD)
SemaRef.Context.setInstantiatedFromUsingDecl(UD, D); SemaRef.Context.setInstantiatedFromUsingDecl(UD, D);
return UD; 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( Decl *TemplateDeclInstantiator::VisitClassScopeFunctionSpecializationDecl(
ClassScopeFunctionSpecializationDecl *Decl) { ClassScopeFunctionSpecializationDecl *Decl) {
@ -4513,22 +4585,36 @@ static bool isInstantiationOf(UsingShadowDecl *Pattern,
Pattern); Pattern);
} }
static bool isInstantiationOf(UsingDecl *Pattern, static bool isInstantiationOf(UsingDecl *Pattern, UsingDecl *Instance,
UsingDecl *Instance,
ASTContext &C) { ASTContext &C) {
return declaresSameEntity(C.getInstantiatedFromUsingDecl(Instance), Pattern); return declaresSameEntity(C.getInstantiatedFromUsingDecl(Instance), Pattern);
} }
static bool isInstantiationOf(UnresolvedUsingValueDecl *Pattern, template<typename T>
NamedDecl *Instance, static bool isInstantiationOfUnresolvedUsingDecl(T *Pattern, Decl *Other,
ASTContext &C) { ASTContext &Ctx) {
return declaresSameEntity(C.getInstantiatedFromUsingDecl(Instance), Pattern); // An unresolved using declaration can instantiate to an unresolved using
} // declaration, or to a using declaration or a using declaration pack.
//
static bool isInstantiationOf(UnresolvedUsingTypenameDecl *Pattern, // Multiple declarations can claim to be instantiated from an unresolved
NamedDecl *Instance, // using declaration if it's a pack expansion. We want the UsingPackDecl
ASTContext &C) { // in that case, not the individual UsingDecls within the pack.
return declaresSameEntity(C.getInstantiatedFromUsingDecl(Instance), Pattern); 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, static bool isInstantiationOfStaticDataMember(VarDecl *Pattern,
@ -4549,21 +4635,14 @@ static bool isInstantiationOfStaticDataMember(VarDecl *Pattern,
// Other is the prospective instantiation // Other is the prospective instantiation
// D is the prospective pattern // D is the prospective pattern
static bool isInstantiationOf(ASTContext &Ctx, NamedDecl *D, Decl *Other) { static bool isInstantiationOf(ASTContext &Ctx, NamedDecl *D, Decl *Other) {
if (D->getKind() != Other->getKind()) { if (auto *UUD = dyn_cast<UnresolvedUsingTypenameDecl>(D))
if (auto *UUD = dyn_cast<UnresolvedUsingTypenameDecl>(D)) { return isInstantiationOfUnresolvedUsingDecl(UUD, Other, Ctx);
if (UsingDecl *UD = dyn_cast<UsingDecl>(Other)) {
return isInstantiationOf(UUD, UD, Ctx);
}
}
if (auto *UUD = dyn_cast<UnresolvedUsingValueDecl>(D)) { if (auto *UUD = dyn_cast<UnresolvedUsingValueDecl>(D))
if (UsingDecl *UD = dyn_cast<UsingDecl>(Other)) { return isInstantiationOfUnresolvedUsingDecl(UUD, Other, Ctx);
return isInstantiationOf(UUD, UD, Ctx);
}
}
if (D->getKind() != Other->getKind())
return false; return false;
}
if (auto *Record = dyn_cast<CXXRecordDecl>(Other)) if (auto *Record = dyn_cast<CXXRecordDecl>(Other))
return isInstantiationOf(cast<CXXRecordDecl>(D), Record); 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)) if (auto *Using = dyn_cast<UsingDecl>(Other))
return isInstantiationOf(cast<UsingDecl>(D), Using, Ctx); 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)) if (auto *Shadow = dyn_cast<UsingShadowDecl>(Other))
return isInstantiationOf(cast<UsingShadowDecl>(D), Shadow, Ctx); return isInstantiationOf(cast<UsingShadowDecl>(D), Shadow, Ctx);
@ -4846,6 +4919,8 @@ NamedDecl *Sema::FindInstantiatedDecl(SourceLocation Loc, NamedDecl *D,
} }
NamedDecl *Result = nullptr; 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()) { if (D->getDeclName()) {
DeclContext::lookup_result Found = ParentDC->lookup(D->getDeclName()); DeclContext::lookup_result Found = ParentDC->lookup(D->getDeclName());
Result = findInstantiationOf(Context, D, Found.begin(), Found.end()); Result = findInstantiationOf(Context, D, Found.begin(), Found.end());

View File

@ -390,21 +390,18 @@ void Sema::collectUnexpandedParameterPacks(QualType T,
void Sema::collectUnexpandedParameterPacks(TypeLoc TL, void Sema::collectUnexpandedParameterPacks(TypeLoc TL,
SmallVectorImpl<UnexpandedParameterPack> &Unexpanded) { SmallVectorImpl<UnexpandedParameterPack> &Unexpanded) {
CollectUnexpandedParameterPacksVisitor(Unexpanded).TraverseTypeLoc(TL); 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());
CollectUnexpandedParameterPacksVisitor(Unexpanded)
.TraverseNestedNameSpecifierLoc(QualifierLoc);
} }
void Sema::collectUnexpandedParameterPacks(const DeclarationNameInfo &NameInfo, void Sema::collectUnexpandedParameterPacks(
SmallVectorImpl<UnexpandedParameterPack> &Unexpanded) { NestedNameSpecifierLoc NNS,
SmallVectorImpl<UnexpandedParameterPack> &Unexpanded) {
CollectUnexpandedParameterPacksVisitor(Unexpanded)
.TraverseNestedNameSpecifierLoc(NNS);
}
void Sema::collectUnexpandedParameterPacks(
const DeclarationNameInfo &NameInfo,
SmallVectorImpl<UnexpandedParameterPack> &Unexpanded) {
CollectUnexpandedParameterPacksVisitor(Unexpanded) CollectUnexpandedParameterPacksVisitor(Unexpanded)
.TraverseDeclarationNameInfo(NameInfo); .TraverseDeclarationNameInfo(NameInfo);
} }

View File

@ -457,6 +457,10 @@ public:
return cast_or_null<NamedDecl>(getDerived().TransformDecl(Loc, D)); 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 /// \brief Transform the given nested-name-specifier with source-location
/// information. /// information.
/// ///
@ -821,7 +825,7 @@ public:
/// \brief Rebuild an unresolved typename type, given the decl that /// \brief Rebuild an unresolved typename type, given the decl that
/// the UnresolvedUsingTypenameDecl was transformed to. /// the UnresolvedUsingTypenameDecl was transformed to.
QualType RebuildUnresolvedUsingType(Decl *D); QualType RebuildUnresolvedUsingType(SourceLocation NameLoc, Decl *D);
/// \brief Build a new typedef type. /// \brief Build a new typedef type.
QualType RebuildTypedefType(TypedefNameDecl *Typedef) { QualType RebuildTypedefType(TypedefNameDecl *Typedef) {
@ -5161,7 +5165,7 @@ TreeTransform<Derived>::TransformUnresolvedUsingType(TypeLocBuilder &TLB,
QualType Result = TL.getType(); QualType Result = TL.getType();
if (getDerived().AlwaysRebuild() || D != T->getDecl()) { if (getDerived().AlwaysRebuild() || D != T->getDecl()) {
Result = getDerived().RebuildUnresolvedUsingType(D); Result = getDerived().RebuildUnresolvedUsingType(TL.getNameLoc(), D);
if (Result.isNull()) if (Result.isNull())
return QualType(); return QualType();
} }
@ -9794,6 +9798,62 @@ TreeTransform<Derived>::TransformCXXPseudoDestructorExpr(
Destroyed); Destroyed);
} }
template <typename Derived>
bool TreeTransform<Derived>::TransformOverloadExprDecls(OverloadExpr *Old,
bool RequiresADL,
LookupResult &R) {
// Transform all the decls.
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>(OldD))
continue;
else {
R.clear();
return true;
}
}
// Expand using pack declarations.
NamedDecl *SingleDecl = cast<NamedDecl>(InstD);
ArrayRef<NamedDecl*> Decls = SingleDecl;
if (auto *UPD = dyn_cast<UsingPackDecl>(InstD))
Decls = UPD->expansions();
// Expand using declarations.
for (auto *D : Decls) {
if (auto *UD = dyn_cast<UsingDecl>(D)) {
for (auto *SD : UD->shadows())
R.addDecl(SD);
} else {
R.addDecl(D);
}
}
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> template<typename Derived>
ExprResult ExprResult
TreeTransform<Derived>::TransformUnresolvedLookupExpr( TreeTransform<Derived>::TransformUnresolvedLookupExpr(
@ -9801,37 +9861,9 @@ TreeTransform<Derived>::TransformUnresolvedLookupExpr(
LookupResult R(SemaRef, Old->getName(), Old->getNameLoc(), LookupResult R(SemaRef, Old->getName(), Old->getNameLoc(),
Sema::LookupOrdinaryName); Sema::LookupOrdinaryName);
// Transform all the decls. // Transform the declaration set.
for (UnresolvedLookupExpr::decls_iterator I = Old->decls_begin(), if (TransformOverloadExprDecls(Old, Old->requiresADL(), R))
E = Old->decls_end(); I != E; ++I) { return ExprError();
NamedDecl *InstD = static_cast<NamedDecl*>(
getDerived().TransformDecl(Old->getNameLoc(),
*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);
}
// Resolve a kind, but don't do any further analysis. If it's
// ambiguous, the callee needs to deal with it.
R.resolveKind();
// Rebuild the nested-name qualifier, if present. // Rebuild the nested-name qualifier, if present.
CXXScopeSpec SS; CXXScopeSpec SS;
@ -10699,35 +10731,9 @@ TreeTransform<Derived>::TransformUnresolvedMemberExpr(UnresolvedMemberExpr *Old)
LookupResult R(SemaRef, Old->getMemberNameInfo(), LookupResult R(SemaRef, Old->getMemberNameInfo(),
Sema::LookupOrdinaryName); Sema::LookupOrdinaryName);
// Transform all the decls. // Transform the declaration set.
for (UnresolvedMemberExpr::decls_iterator I = Old->decls_begin(), if (TransformOverloadExprDecls(Old, /*RequiresADL*/false, R))
E = Old->decls_end(); I != E; ++I) { return ExprError();
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();
// Determine the naming class. // Determine the naming class.
if (Old->getNamingClass()) { if (Old->getNamingClass()) {
@ -11842,21 +11848,48 @@ QualType TreeTransform<Derived>::RebuildFunctionNoProtoType(QualType T) {
} }
template<typename Derived> template<typename Derived>
QualType TreeTransform<Derived>::RebuildUnresolvedUsingType(Decl *D) { QualType TreeTransform<Derived>::RebuildUnresolvedUsingType(SourceLocation Loc,
Decl *D) {
assert(D && "no decl found"); assert(D && "no decl found");
if (D->isInvalidDecl()) return QualType(); if (D->isInvalidDecl()) return QualType();
// FIXME: Doesn't account for ObjCInterfaceDecl! // FIXME: Doesn't account for ObjCInterfaceDecl!
TypeDecl *Ty; TypeDecl *Ty;
if (isa<UsingDecl>(D)) { if (auto *UPD = dyn_cast<UsingPackDecl>(D)) {
UsingDecl *Using = cast<UsingDecl>(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() && assert(Using->hasTypename() &&
"UnresolvedUsingTypenameDecl transformed to non-typename using"); "UnresolvedUsingTypenameDecl transformed to non-typename using");
// A valid resolved using typename decl points to exactly one type decl. // A valid resolved using typename decl points to exactly one type decl.
assert(++Using->shadow_begin() == Using->shadow_end()); assert(++Using->shadow_begin() == Using->shadow_end());
Ty = cast<TypeDecl>((*Using->shadow_begin())->getTargetDecl()); Ty = cast<TypeDecl>((*Using->shadow_begin())->getTargetDecl());
} else { } else {
assert(isa<UnresolvedUsingTypenameDecl>(D) && assert(isa<UnresolvedUsingTypenameDecl>(D) &&
"UnresolvedUsingTypenameDecl transformed to non-using decl"); "UnresolvedUsingTypenameDecl transformed to non-using decl");

View File

@ -285,6 +285,7 @@ bool serialization::isRedeclarableDeclKind(unsigned Kind) {
case Decl::NonTypeTemplateParm: case Decl::NonTypeTemplateParm:
case Decl::TemplateTemplateParm: case Decl::TemplateTemplateParm:
case Decl::Using: case Decl::Using:
case Decl::UsingPack:
case Decl::ObjCMethod: case Decl::ObjCMethod:
case Decl::ObjCCategory: case Decl::ObjCCategory:
case Decl::ObjCCategoryImpl: case Decl::ObjCCategoryImpl:

View File

@ -322,6 +322,7 @@ namespace clang {
void VisitTemplateTemplateParmDecl(TemplateTemplateParmDecl *D); void VisitTemplateTemplateParmDecl(TemplateTemplateParmDecl *D);
void VisitTypeAliasTemplateDecl(TypeAliasTemplateDecl *D); void VisitTypeAliasTemplateDecl(TypeAliasTemplateDecl *D);
void VisitUsingDecl(UsingDecl *D); void VisitUsingDecl(UsingDecl *D);
void VisitUsingPackDecl(UsingPackDecl *D);
void VisitUsingShadowDecl(UsingShadowDecl *D); void VisitUsingShadowDecl(UsingShadowDecl *D);
void VisitConstructorUsingShadowDecl(ConstructorUsingShadowDecl *D); void VisitConstructorUsingShadowDecl(ConstructorUsingShadowDecl *D);
void VisitLinkageSpecDecl(LinkageSpecDecl *D); void VisitLinkageSpecDecl(LinkageSpecDecl *D);
@ -1419,6 +1420,15 @@ void ASTDeclReader::VisitUsingDecl(UsingDecl *D) {
mergeMergeable(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) { void ASTDeclReader::VisitUsingShadowDecl(UsingShadowDecl *D) {
RedeclarableResult Redecl = VisitRedeclarable(D); RedeclarableResult Redecl = VisitRedeclarable(D);
VisitNamedDecl(D); VisitNamedDecl(D);
@ -1452,6 +1462,7 @@ void ASTDeclReader::VisitUnresolvedUsingValueDecl(UnresolvedUsingValueDecl *D) {
D->setUsingLoc(ReadSourceLocation()); D->setUsingLoc(ReadSourceLocation());
D->QualifierLoc = Record.ReadNestedNameSpecifierLoc(Idx); D->QualifierLoc = Record.ReadNestedNameSpecifierLoc(Idx);
ReadDeclarationNameLoc(D->DNLoc, D->getDeclName()); ReadDeclarationNameLoc(D->DNLoc, D->getDeclName());
D->EllipsisLoc = ReadSourceLocation();
mergeMergeable(D); mergeMergeable(D);
} }
@ -1460,6 +1471,7 @@ void ASTDeclReader::VisitUnresolvedUsingTypenameDecl(
VisitTypeDecl(D); VisitTypeDecl(D);
D->TypenameLocation = ReadSourceLocation(); D->TypenameLocation = ReadSourceLocation();
D->QualifierLoc = Record.ReadNestedNameSpecifierLoc(Idx); D->QualifierLoc = Record.ReadNestedNameSpecifierLoc(Idx);
D->EllipsisLoc = ReadSourceLocation();
mergeMergeable(D); mergeMergeable(D);
} }
@ -3297,6 +3309,9 @@ Decl *ASTReader::ReadDeclRecord(DeclID ID) {
case DECL_USING: case DECL_USING:
D = UsingDecl::CreateDeserialized(Context, ID); D = UsingDecl::CreateDeserialized(Context, ID);
break; break;
case DECL_USING_PACK:
D = UsingPackDecl::CreateDeserialized(Context, ID, Record[Idx++]);
break;
case DECL_USING_SHADOW: case DECL_USING_SHADOW:
D = UsingShadowDecl::CreateDeserialized(Context, ID); D = UsingShadowDecl::CreateDeserialized(Context, ID);
break; break;

View File

@ -107,6 +107,7 @@ namespace clang {
void VisitTemplateTemplateParmDecl(TemplateTemplateParmDecl *D); void VisitTemplateTemplateParmDecl(TemplateTemplateParmDecl *D);
void VisitTypeAliasTemplateDecl(TypeAliasTemplateDecl *D); void VisitTypeAliasTemplateDecl(TypeAliasTemplateDecl *D);
void VisitUsingDecl(UsingDecl *D); void VisitUsingDecl(UsingDecl *D);
void VisitUsingPackDecl(UsingPackDecl *D);
void VisitUsingShadowDecl(UsingShadowDecl *D); void VisitUsingShadowDecl(UsingShadowDecl *D);
void VisitConstructorUsingShadowDecl(ConstructorUsingShadowDecl *D); void VisitConstructorUsingShadowDecl(ConstructorUsingShadowDecl *D);
void VisitLinkageSpecDecl(LinkageSpecDecl *D); void VisitLinkageSpecDecl(LinkageSpecDecl *D);
@ -1142,6 +1143,15 @@ void ASTDeclWriter::VisitUsingDecl(UsingDecl *D) {
Code = serialization::DECL_USING; 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) { void ASTDeclWriter::VisitUsingShadowDecl(UsingShadowDecl *D) {
VisitRedeclarable(D); VisitRedeclarable(D);
VisitNamedDecl(D); VisitNamedDecl(D);
@ -1175,6 +1185,7 @@ void ASTDeclWriter::VisitUnresolvedUsingValueDecl(UnresolvedUsingValueDecl *D) {
Record.AddSourceLocation(D->getUsingLoc()); Record.AddSourceLocation(D->getUsingLoc());
Record.AddNestedNameSpecifierLoc(D->getQualifierLoc()); Record.AddNestedNameSpecifierLoc(D->getQualifierLoc());
Record.AddDeclarationNameLoc(D->DNLoc, D->getDeclName()); Record.AddDeclarationNameLoc(D->DNLoc, D->getDeclName());
Record.AddSourceLocation(D->getEllipsisLoc());
Code = serialization::DECL_UNRESOLVED_USING_VALUE; Code = serialization::DECL_UNRESOLVED_USING_VALUE;
} }
@ -1183,6 +1194,7 @@ void ASTDeclWriter::VisitUnresolvedUsingTypenameDecl(
VisitTypeDecl(D); VisitTypeDecl(D);
Record.AddSourceLocation(D->getTypenameLoc()); Record.AddSourceLocation(D->getTypenameLoc());
Record.AddNestedNameSpecifierLoc(D->getQualifierLoc()); Record.AddNestedNameSpecifierLoc(D->getQualifierLoc());
Record.AddSourceLocation(D->getEllipsisLoc());
Code = serialization::DECL_UNRESOLVED_USING_TYPENAME; Code = serialization::DECL_UNRESOLVED_USING_TYPENAME;
} }

View File

@ -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

View File

@ -10,10 +10,10 @@ namespace B {
} }
struct X { struct X {
int x1, x2, y, z; // expected-note {{conflicting}} int x1, x2, y, z; // expected-note 2{{conflicting}}
}; };
struct Y { struct Y {
int x1, x2, y, z; // expected-note {{target}} int x1, x2, y, z; // expected-note 2{{target}}
}; };
struct Z : X, Y { struct Z : X, Y {
using X::x1, using X::x1,
@ -28,3 +28,8 @@ int X::*px1 = &Z::x1;
int X::*px2 = &Z::x2; int X::*px2 = &Z::x2;
int Y::*py = &Z::y; int Y::*py = &Z::y;
int X::*pz = &Z::z; 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}}

View File

@ -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}}
}
}

View File

@ -5738,6 +5738,7 @@ CXCursor clang_getCursorDefinition(CXCursor C) {
case Decl::BuiltinTemplate: case Decl::BuiltinTemplate:
case Decl::PragmaComment: case Decl::PragmaComment:
case Decl::PragmaDetectMismatch: case Decl::PragmaDetectMismatch:
case Decl::UsingPack:
return C; return C;
// Declaration kinds that don't make any sense here, but are // Declaration kinds that don't make any sense here, but are