summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorRichard Smith <richard-llvm@metafoo.co.uk>2016-12-20 21:35:28 +0000
committerRichard Smith <richard-llvm@metafoo.co.uk>2016-12-20 21:35:28 +0000
commitc8c1a1961a459f5f79ba8dfb08a2d53d5443bf32 (patch)
treec042187cdc68b1038bde77c652ded7a849bd53d3
parenta966b1fd6ce257ab259c534488003e7aef57a0ff (diff)
[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
-rw-r--r--include/clang/AST/DeclCXX.h119
-rw-r--r--include/clang/AST/RecursiveASTVisitor.h2
-rw-r--r--include/clang/Basic/DeclNodes.td1
-rw-r--r--include/clang/Basic/DiagnosticParseKinds.td7
-rw-r--r--include/clang/Basic/DiagnosticSemaKinds.td5
-rw-r--r--include/clang/Parse/Parser.h6
-rw-r--r--include/clang/Sema/Sema.h16
-rw-r--r--include/clang/Sema/Template.h5
-rw-r--r--include/clang/Serialization/ASTBitCodes.h2
-rw-r--r--lib/AST/DeclBase.cpp5
-rw-r--r--lib/AST/DeclCXX.cpp36
-rw-r--r--lib/CodeGen/CGDecl.cpp4
-rw-r--r--lib/Parse/ParseDeclCXX.cpp79
-rw-r--r--lib/Sema/SemaDeclCXX.cpp74
-rw-r--r--lib/Sema/SemaExprCXX.cpp14
-rw-r--r--lib/Sema/SemaOverload.cpp8
-rw-r--r--lib/Sema/SemaTemplateInstantiateDecl.cpp193
-rw-r--r--lib/Sema/SemaTemplateVariadic.cpp19
-rw-r--r--lib/Sema/TreeTransform.h143
-rw-r--r--lib/Serialization/ASTCommon.cpp1
-rw-r--r--lib/Serialization/ASTReaderDecl.cpp15
-rw-r--r--lib/Serialization/ASTWriterDecl.cpp12
-rw-r--r--test/PCH/cxx1z-using-declaration.cpp35
-rw-r--r--test/Parser/cxx1z-using-declaration.cpp9
-rw-r--r--test/SemaTemplate/cxx1z-using-declaration.cpp230
-rw-r--r--tools/libclang/CIndex.cpp1
26 files changed, 794 insertions, 247 deletions
diff --git a/include/clang/AST/DeclCXX.h b/include/clang/AST/DeclCXX.h
index 46434c4c7b..06ecd3c373 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 058ab1fcbe..afacfd5723 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 6da2c2c3d6..7b581d3eec 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 31e55b4aff..0943feae95 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 69322f0f75..f32364e9af 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 3d098fab84..972f13daca 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 136f848338..ebbc1e1b3e 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 0d12880354..401bbbf1e5 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 611c00d0e9..4e29ad6a02 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 8deef3343d..6111abab64 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 8563416a48..1860b948d6 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 4657347758..d761363801 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 d31d114237..4002b09d2b 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 ac643af149..21bdd945f0 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 74beeac724..5c3900adbd 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 d49142b8d8..2129729dab 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 0956a1cc50..dbc322ebfd 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 c8bc2c3880..54556b505e 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 a76a078fd0..9671b9b35d 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,72 @@ 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.
+ NamedDecl *SingleDecl = cast<NamedDecl>(InstD);
+ ArrayRef<NamedDecl*> Decls = SingleDecl;
+ 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 +10731,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 +11848,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 79ccffc5ab..ecd249cc50 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 913a1419b3..dc29a61c0a 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 21468619db..ee220f00a8 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 0000000000..a185ff1740
--- /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 dab1ca82c2..0be81677d9 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 0000000000..7bef36db1f
--- /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 df048994b2..210e74bf59 100644
--- a/tools/libclang/CIndex.cpp
+++ b/tools/libclang/CIndex.cpp
@@ -5738,6 +5738,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