forked from OSchip/llvm-project
Fix some interactions between C++11 and C++14 features and using-declarations:
* a dependent non-type using-declaration within a function template can be valid, as it can refer to an enumerator, so don't reject it in the template definition * we can partially substitute into a dependent using-declaration if it appears within a (local class in a) generic lambda within a function template, which means an UnresolvedUsing*Decl doesn't necessarily instantiate to a UsingDecl. llvm-svn: 290071
This commit is contained in:
parent
601d5bafb2
commit
d8a9e37558
|
@ -398,11 +398,11 @@ private:
|
|||
llvm::DenseMap<const VarDecl *, TemplateOrSpecializationInfo>
|
||||
TemplateOrInstantiation;
|
||||
|
||||
/// \brief Keeps track of the declaration from which a UsingDecl was
|
||||
/// \brief Keeps track of the declaration from which a using declaration was
|
||||
/// created during instantiation.
|
||||
///
|
||||
/// The source declaration is always a UsingDecl, an UnresolvedUsingValueDecl,
|
||||
/// or an UnresolvedUsingTypenameDecl.
|
||||
/// The source and target declarations are always a UsingDecl, an
|
||||
/// UnresolvedUsingValueDecl, or an UnresolvedUsingTypenameDecl.
|
||||
///
|
||||
/// For example:
|
||||
/// \code
|
||||
|
@ -421,7 +421,7 @@ private:
|
|||
///
|
||||
/// This mapping will contain an entry that maps from the UsingDecl in
|
||||
/// B<int> to the UnresolvedUsingDecl in B<T>.
|
||||
llvm::DenseMap<UsingDecl *, NamedDecl *> InstantiatedFromUsingDecl;
|
||||
llvm::DenseMap<NamedDecl *, NamedDecl *> InstantiatedFromUsingDecl;
|
||||
|
||||
llvm::DenseMap<UsingShadowDecl*, UsingShadowDecl*>
|
||||
InstantiatedFromUsingShadowDecl;
|
||||
|
@ -849,11 +849,11 @@ public:
|
|||
/// \brief If the given using decl \p Inst is an instantiation of a
|
||||
/// (possibly unresolved) using decl from a template instantiation,
|
||||
/// return it.
|
||||
NamedDecl *getInstantiatedFromUsingDecl(UsingDecl *Inst);
|
||||
NamedDecl *getInstantiatedFromUsingDecl(NamedDecl *Inst);
|
||||
|
||||
/// \brief Remember that the using decl \p Inst is an instantiation
|
||||
/// of the using decl \p Pattern of a class template.
|
||||
void setInstantiatedFromUsingDecl(UsingDecl *Inst, NamedDecl *Pattern);
|
||||
void setInstantiatedFromUsingDecl(NamedDecl *Inst, NamedDecl *Pattern);
|
||||
|
||||
void setInstantiatedFromUsingShadowDecl(UsingShadowDecl *Inst,
|
||||
UsingShadowDecl *Pattern);
|
||||
|
|
|
@ -4317,6 +4317,7 @@ public:
|
|||
SourceLocation NameLoc,
|
||||
const LookupResult &Previous);
|
||||
bool CheckUsingDeclQualifier(SourceLocation UsingLoc,
|
||||
bool HasTypename,
|
||||
const CXXScopeSpec &SS,
|
||||
const DeclarationNameInfo &NameInfo,
|
||||
SourceLocation NameLoc);
|
||||
|
|
|
@ -1270,9 +1270,8 @@ void ASTContext::setClassScopeSpecializationPattern(FunctionDecl *FD,
|
|||
}
|
||||
|
||||
NamedDecl *
|
||||
ASTContext::getInstantiatedFromUsingDecl(UsingDecl *UUD) {
|
||||
llvm::DenseMap<UsingDecl *, NamedDecl *>::const_iterator Pos
|
||||
= InstantiatedFromUsingDecl.find(UUD);
|
||||
ASTContext::getInstantiatedFromUsingDecl(NamedDecl *UUD) {
|
||||
auto Pos = InstantiatedFromUsingDecl.find(UUD);
|
||||
if (Pos == InstantiatedFromUsingDecl.end())
|
||||
return nullptr;
|
||||
|
||||
|
@ -1280,11 +1279,15 @@ ASTContext::getInstantiatedFromUsingDecl(UsingDecl *UUD) {
|
|||
}
|
||||
|
||||
void
|
||||
ASTContext::setInstantiatedFromUsingDecl(UsingDecl *Inst, NamedDecl *Pattern) {
|
||||
ASTContext::setInstantiatedFromUsingDecl(NamedDecl *Inst, NamedDecl *Pattern) {
|
||||
assert((isa<UsingDecl>(Pattern) ||
|
||||
isa<UnresolvedUsingValueDecl>(Pattern) ||
|
||||
isa<UnresolvedUsingTypenameDecl>(Pattern)) &&
|
||||
"pattern decl is not a using decl");
|
||||
assert((isa<UsingDecl>(Inst) ||
|
||||
isa<UnresolvedUsingValueDecl>(Inst) ||
|
||||
isa<UnresolvedUsingTypenameDecl>(Inst)) &&
|
||||
"instantiation did not produce a using decl");
|
||||
assert(!InstantiatedFromUsingDecl[Inst] && "pattern already exists");
|
||||
InstantiatedFromUsingDecl[Inst] = Pattern;
|
||||
}
|
||||
|
|
|
@ -9010,8 +9010,23 @@ NamedDecl *Sema::BuildUsingDeclaration(Scope *S, AccessSpecifier AS,
|
|||
F.done();
|
||||
} else {
|
||||
assert(IsInstantiation && "no scope in non-instantiation");
|
||||
assert(CurContext->isRecord() && "scope not record in instantiation");
|
||||
LookupQualifiedName(Previous, CurContext);
|
||||
if (CurContext->isRecord())
|
||||
LookupQualifiedName(Previous, CurContext);
|
||||
else {
|
||||
// No redeclaration check is needed here; in non-member contexts we
|
||||
// diagnosed all possible conflicts with other using-declarations when
|
||||
// building the template:
|
||||
//
|
||||
// For a dependent non-type using declaration, the only valid case is
|
||||
// if we instantiate to a single enumerator. We check for conflicts
|
||||
// between shadow declarations we introduce, and we check in the template
|
||||
// definition for conflicts between a non-type using declaration and any
|
||||
// other declaration, which together covers all cases.
|
||||
//
|
||||
// A dependent typename using declaration will never successfully
|
||||
// instantiate, since it will always name a class member, so we reject
|
||||
// that in the template definition.
|
||||
}
|
||||
}
|
||||
|
||||
// Check for invalid redeclarations.
|
||||
|
@ -9020,7 +9035,8 @@ NamedDecl *Sema::BuildUsingDeclaration(Scope *S, AccessSpecifier AS,
|
|||
return nullptr;
|
||||
|
||||
// Check for bad qualifiers.
|
||||
if (CheckUsingDeclQualifier(UsingLoc, SS, NameInfo, IdentLoc))
|
||||
if (CheckUsingDeclQualifier(UsingLoc, HasTypenameKeyword, SS, NameInfo,
|
||||
IdentLoc))
|
||||
return nullptr;
|
||||
|
||||
DeclContext *LookupContext = computeDeclContext(SS);
|
||||
|
@ -9259,7 +9275,19 @@ bool Sema::CheckUsingDeclRedeclaration(SourceLocation UsingLoc,
|
|||
= dyn_cast<UnresolvedUsingTypenameDecl>(D)) {
|
||||
DTypename = true;
|
||||
DQual = UD->getQualifier();
|
||||
} else continue;
|
||||
} else if (!isa<TypeDecl>(D) && Qual->isDependent() &&
|
||||
!HasTypenameKeyword) {
|
||||
// A dependent qualifier outside a class can only ever resolve to an
|
||||
// enumeration type. Therefore it conflicts with any other non-type
|
||||
// declaration in the same scope.
|
||||
// FIXME: How should we check for dependent type-type conflicts at block
|
||||
// scope?
|
||||
Diag(NameLoc, diag::err_redefinition_different_kind)
|
||||
<< Prev.getLookupName();
|
||||
Diag(D->getLocation(), diag::note_previous_definition);
|
||||
return true;
|
||||
}
|
||||
else continue;
|
||||
|
||||
// using decls differ if one says 'typename' and the other doesn't.
|
||||
// FIXME: non-dependent using decls?
|
||||
|
@ -9285,6 +9313,7 @@ bool Sema::CheckUsingDeclRedeclaration(SourceLocation UsingLoc,
|
|||
/// in the current context is appropriately related to the current
|
||||
/// scope. If an error is found, diagnoses it and returns true.
|
||||
bool Sema::CheckUsingDeclQualifier(SourceLocation UsingLoc,
|
||||
bool HasTypename,
|
||||
const CXXScopeSpec &SS,
|
||||
const DeclarationNameInfo &NameInfo,
|
||||
SourceLocation NameLoc) {
|
||||
|
@ -9295,9 +9324,11 @@ bool Sema::CheckUsingDeclQualifier(SourceLocation UsingLoc,
|
|||
// C++0x [namespace.udecl]p8:
|
||||
// A using-declaration for a class member shall be a member-declaration.
|
||||
|
||||
// If we weren't able to compute a valid scope, it must be a
|
||||
// dependent class scope.
|
||||
if (!NamedContext || NamedContext->getRedeclContext()->isRecord()) {
|
||||
// If we weren't able to compute a valid scope, it might validly be a
|
||||
// dependent class scope or a dependent enumeration unscoped scope. If
|
||||
// we have a 'typename' keyword, the scope must resolve to a class type.
|
||||
if ((HasTypename && !NamedContext) ||
|
||||
(NamedContext && NamedContext->getRedeclContext()->isRecord())) {
|
||||
auto *RD = NamedContext
|
||||
? cast<CXXRecordDecl>(NamedContext->getRedeclContext())
|
||||
: nullptr;
|
||||
|
@ -9357,7 +9388,8 @@ bool Sema::CheckUsingDeclQualifier(SourceLocation UsingLoc,
|
|||
if (getLangOpts().CPlusPlus11) {
|
||||
// Convert 'using X::Y;' to 'auto &Y = X::Y;'.
|
||||
FixIt = FixItHint::CreateReplacement(
|
||||
UsingLoc, "constexpr auto " + NameInfo.getName().getAsString() + " = ");
|
||||
UsingLoc,
|
||||
"constexpr auto " + NameInfo.getName().getAsString() + " = ");
|
||||
}
|
||||
|
||||
Diag(UsingLoc, diag::note_using_decl_class_member_workaround)
|
||||
|
@ -9367,7 +9399,7 @@ bool Sema::CheckUsingDeclQualifier(SourceLocation UsingLoc,
|
|||
return true;
|
||||
}
|
||||
|
||||
// Otherwise, everything is known to be fine.
|
||||
// Otherwise, this might be valid.
|
||||
return false;
|
||||
}
|
||||
|
||||
|
|
|
@ -987,10 +987,17 @@ Sema::CheckOverload(Scope *S, FunctionDecl *New, const LookupResult &Old,
|
|||
assert(Old.getLookupKind() == LookupUsingDeclName);
|
||||
} else if (isa<TagDecl>(OldD)) {
|
||||
// We can always overload with tags by hiding them.
|
||||
} else if (isa<UnresolvedUsingValueDecl>(OldD)) {
|
||||
} else if (auto *UUD = dyn_cast<UnresolvedUsingValueDecl>(OldD)) {
|
||||
// Optimistically assume that an unresolved using decl will
|
||||
// overload; if it doesn't, we'll have to diagnose during
|
||||
// template instantiation.
|
||||
//
|
||||
// Exception: if the scope is dependent and this is not a class
|
||||
// member, the using declaration can only introduce an enumerator.
|
||||
if (UUD->getQualifier()->isDependent() && !UUD->isCXXClassMember()) {
|
||||
Match = *I;
|
||||
return Ovl_NonFunction;
|
||||
}
|
||||
} else {
|
||||
// (C++ 13p1):
|
||||
// Only function declarations can be overloaded; object and type
|
||||
|
|
|
@ -2430,8 +2430,8 @@ Decl *TemplateDeclInstantiator::VisitUsingDecl(UsingDecl *D) {
|
|||
}
|
||||
|
||||
if (!NewUD->isInvalidDecl() &&
|
||||
SemaRef.CheckUsingDeclQualifier(D->getUsingLoc(), SS, NameInfo,
|
||||
D->getLocation()))
|
||||
SemaRef.CheckUsingDeclQualifier(D->getUsingLoc(), D->hasTypename(),
|
||||
SS, NameInfo, D->getLocation()))
|
||||
NewUD->setInvalidDecl();
|
||||
|
||||
SemaRef.Context.setInstantiatedFromUsingDecl(NewUD, D);
|
||||
|
@ -2515,7 +2515,7 @@ Decl * TemplateDeclInstantiator
|
|||
/*instantiation*/ true,
|
||||
/*typename*/ true, D->getTypenameLoc());
|
||||
if (UD)
|
||||
SemaRef.Context.setInstantiatedFromUsingDecl(cast<UsingDecl>(UD), D);
|
||||
SemaRef.Context.setInstantiatedFromUsingDecl(UD, D);
|
||||
|
||||
return UD;
|
||||
}
|
||||
|
@ -2539,7 +2539,7 @@ Decl * TemplateDeclInstantiator
|
|||
/*instantiation*/ true,
|
||||
/*typename*/ false, SourceLocation());
|
||||
if (UD)
|
||||
SemaRef.Context.setInstantiatedFromUsingDecl(cast<UsingDecl>(UD), D);
|
||||
SemaRef.Context.setInstantiatedFromUsingDecl(UD, D);
|
||||
|
||||
return UD;
|
||||
}
|
||||
|
@ -4520,13 +4520,13 @@ static bool isInstantiationOf(UsingDecl *Pattern,
|
|||
}
|
||||
|
||||
static bool isInstantiationOf(UnresolvedUsingValueDecl *Pattern,
|
||||
UsingDecl *Instance,
|
||||
NamedDecl *Instance,
|
||||
ASTContext &C) {
|
||||
return declaresSameEntity(C.getInstantiatedFromUsingDecl(Instance), Pattern);
|
||||
}
|
||||
|
||||
static bool isInstantiationOf(UnresolvedUsingTypenameDecl *Pattern,
|
||||
UsingDecl *Instance,
|
||||
NamedDecl *Instance,
|
||||
ASTContext &C) {
|
||||
return declaresSameEntity(C.getInstantiatedFromUsingDecl(Instance), Pattern);
|
||||
}
|
||||
|
@ -4550,15 +4550,13 @@ static bool isInstantiationOfStaticDataMember(VarDecl *Pattern,
|
|||
// D is the prospective pattern
|
||||
static bool isInstantiationOf(ASTContext &Ctx, NamedDecl *D, Decl *Other) {
|
||||
if (D->getKind() != Other->getKind()) {
|
||||
if (UnresolvedUsingTypenameDecl *UUD
|
||||
= dyn_cast<UnresolvedUsingTypenameDecl>(D)) {
|
||||
if (auto *UUD = dyn_cast<UnresolvedUsingTypenameDecl>(D)) {
|
||||
if (UsingDecl *UD = dyn_cast<UsingDecl>(Other)) {
|
||||
return isInstantiationOf(UUD, UD, Ctx);
|
||||
}
|
||||
}
|
||||
|
||||
if (UnresolvedUsingValueDecl *UUD
|
||||
= dyn_cast<UnresolvedUsingValueDecl>(D)) {
|
||||
if (auto *UUD = dyn_cast<UnresolvedUsingValueDecl>(D)) {
|
||||
if (UsingDecl *UD = dyn_cast<UsingDecl>(Other)) {
|
||||
return isInstantiationOf(UUD, UD, Ctx);
|
||||
}
|
||||
|
@ -4567,31 +4565,31 @@ static bool isInstantiationOf(ASTContext &Ctx, NamedDecl *D, Decl *Other) {
|
|||
return false;
|
||||
}
|
||||
|
||||
if (CXXRecordDecl *Record = dyn_cast<CXXRecordDecl>(Other))
|
||||
if (auto *Record = dyn_cast<CXXRecordDecl>(Other))
|
||||
return isInstantiationOf(cast<CXXRecordDecl>(D), Record);
|
||||
|
||||
if (FunctionDecl *Function = dyn_cast<FunctionDecl>(Other))
|
||||
if (auto *Function = dyn_cast<FunctionDecl>(Other))
|
||||
return isInstantiationOf(cast<FunctionDecl>(D), Function);
|
||||
|
||||
if (EnumDecl *Enum = dyn_cast<EnumDecl>(Other))
|
||||
if (auto *Enum = dyn_cast<EnumDecl>(Other))
|
||||
return isInstantiationOf(cast<EnumDecl>(D), Enum);
|
||||
|
||||
if (VarDecl *Var = dyn_cast<VarDecl>(Other))
|
||||
if (auto *Var = dyn_cast<VarDecl>(Other))
|
||||
if (Var->isStaticDataMember())
|
||||
return isInstantiationOfStaticDataMember(cast<VarDecl>(D), Var);
|
||||
|
||||
if (ClassTemplateDecl *Temp = dyn_cast<ClassTemplateDecl>(Other))
|
||||
if (auto *Temp = dyn_cast<ClassTemplateDecl>(Other))
|
||||
return isInstantiationOf(cast<ClassTemplateDecl>(D), Temp);
|
||||
|
||||
if (FunctionTemplateDecl *Temp = dyn_cast<FunctionTemplateDecl>(Other))
|
||||
if (auto *Temp = dyn_cast<FunctionTemplateDecl>(Other))
|
||||
return isInstantiationOf(cast<FunctionTemplateDecl>(D), Temp);
|
||||
|
||||
if (ClassTemplatePartialSpecializationDecl *PartialSpec
|
||||
= dyn_cast<ClassTemplatePartialSpecializationDecl>(Other))
|
||||
if (auto *PartialSpec =
|
||||
dyn_cast<ClassTemplatePartialSpecializationDecl>(Other))
|
||||
return isInstantiationOf(cast<ClassTemplatePartialSpecializationDecl>(D),
|
||||
PartialSpec);
|
||||
|
||||
if (FieldDecl *Field = dyn_cast<FieldDecl>(Other)) {
|
||||
if (auto *Field = dyn_cast<FieldDecl>(Other)) {
|
||||
if (!Field->getDeclName()) {
|
||||
// This is an unnamed field.
|
||||
return declaresSameEntity(Ctx.getInstantiatedFromUnnamedFieldDecl(Field),
|
||||
|
@ -4599,14 +4597,20 @@ static bool isInstantiationOf(ASTContext &Ctx, NamedDecl *D, Decl *Other) {
|
|||
}
|
||||
}
|
||||
|
||||
if (UsingDecl *Using = dyn_cast<UsingDecl>(Other))
|
||||
if (auto *Using = dyn_cast<UsingDecl>(Other))
|
||||
return isInstantiationOf(cast<UsingDecl>(D), Using, Ctx);
|
||||
|
||||
if (UsingShadowDecl *Shadow = dyn_cast<UsingShadowDecl>(Other))
|
||||
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);
|
||||
|
||||
return D->getDeclName() && isa<NamedDecl>(Other) &&
|
||||
D->getDeclName() == cast<NamedDecl>(Other)->getDeclName();
|
||||
return D->getDeclName() &&
|
||||
D->getDeclName() == cast<NamedDecl>(Other)->getDeclName();
|
||||
}
|
||||
|
||||
template<typename ForwardIterator>
|
||||
|
|
|
@ -1,5 +1,6 @@
|
|||
// RUN: %clang_cc1 -fsyntax-only -std=c++98 -verify %s
|
||||
// RUN: %clang_cc1 -fsyntax-only -std=c++11 -verify %s
|
||||
// RUN: %clang_cc1 -fsyntax-only -std=c++14 -verify %s
|
||||
// RUN: not %clang_cc1 -fsyntax-only -std=c++98 -fdiagnostics-parseable-fixits %s 2>&1 | FileCheck --check-prefix=CXX98 %s
|
||||
// RUN: not %clang_cc1 -fsyntax-only -std=c++11 -fdiagnostics-parseable-fixits %s 2>&1 | FileCheck --check-prefix=CXX11 %s
|
||||
// C++0x N2914.
|
||||
|
@ -44,10 +45,159 @@ void f() {
|
|||
#endif
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
struct PR21933 : T {
|
||||
static void StaticFun() { using T::member; } // expected-error{{using declaration cannot refer to class member}}
|
||||
};
|
||||
namespace PR21933 {
|
||||
struct A { int member; };
|
||||
struct B { static int member; };
|
||||
enum C { member };
|
||||
|
||||
template <typename T>
|
||||
struct X {
|
||||
static void StaticFun() {
|
||||
using T::member; // expected-error 2{{class member}} expected-note {{use a reference instead}}
|
||||
#if __cplusplus < 201103L
|
||||
// expected-error@-2 {{cannot be used prior to '::'}}
|
||||
#endif
|
||||
(void)member;
|
||||
}
|
||||
};
|
||||
template<typename T>
|
||||
struct Y : T {
|
||||
static void StaticFun() {
|
||||
using T::member; // expected-error 2{{class member}} expected-note {{use a reference instead}}
|
||||
(void)member;
|
||||
}
|
||||
};
|
||||
|
||||
void f() {
|
||||
X<A>::StaticFun(); // expected-note {{instantiation of}}
|
||||
X<B>::StaticFun(); // expected-note {{instantiation of}}
|
||||
X<C>::StaticFun();
|
||||
#if __cplusplus < 201103L
|
||||
// expected-note@-2 {{instantiation of}}
|
||||
#endif
|
||||
Y<A>::StaticFun(); // expected-note {{instantiation of}}
|
||||
Y<B>::StaticFun(); // expected-note {{instantiation of}}
|
||||
}
|
||||
|
||||
template<typename T, typename U> void value_vs_value() {
|
||||
using T::a; // expected-note {{previous}}
|
||||
#if __cplusplus < 201103L
|
||||
// expected-error@-2 {{cannot be used prior to '::'}}
|
||||
#endif
|
||||
extern int a(); // expected-error {{different kind of symbol}}
|
||||
a();
|
||||
|
||||
extern int b();
|
||||
using T::b;
|
||||
b();
|
||||
|
||||
using T::c;
|
||||
using U::c;
|
||||
c();
|
||||
}
|
||||
|
||||
template<typename T, typename U> void value_vs_type() {
|
||||
using T::Xt; // expected-note {{previous}}
|
||||
typedef struct {} Xt; // expected-error {{different kind of symbol}}
|
||||
(void)Xt;
|
||||
|
||||
using T::Xs; // expected-note {{candidate}}
|
||||
struct Xs {}; // expected-note {{candidate}}
|
||||
// FIXME: This is wrong, the using declaration hides the type.
|
||||
Xs xs; // expected-error {{ambiguous}}
|
||||
|
||||
using T::Xe; // expected-note {{candidate}}
|
||||
enum Xe {}; // expected-note {{candidate}}
|
||||
// FIXME: This is wrong, the using declaration hides the type.
|
||||
Xe xe; // expected-error {{ambiguous}}
|
||||
|
||||
typedef struct {} Yt; // expected-note {{candidate}}
|
||||
using T::Yt; // eypected-error {{different kind of symbol}} expected-note {{candidate}}
|
||||
Yt yt; // expected-error {{ambiguous}}
|
||||
|
||||
struct Ys {}; // expected-note {{candidate}}
|
||||
using T::Ys; // expected-note {{candidate}}
|
||||
// FIXME: This is wrong, the using declaration hides the type.
|
||||
Ys ys; // expected-error {{ambiguous}}
|
||||
|
||||
enum Ye {}; // expected-note {{candidate}}
|
||||
using T::Ye; // expected-note {{candidate}}
|
||||
// FIXME: This is wrong, the using declaration hides the type.
|
||||
Ye ye; // expected-error {{ambiguous}}
|
||||
}
|
||||
|
||||
template<typename T> void type() {
|
||||
// Must be a class member because T:: can only name a class or enum,
|
||||
// and an enum cannot have a type member.
|
||||
using typename T::X; // expected-error {{cannot refer to class member}}
|
||||
}
|
||||
|
||||
namespace N1 { enum E { a, b, c }; }
|
||||
namespace N2 { enum E { a, b, c }; }
|
||||
void g() { value_vs_value<N1::E, N2::E>(); }
|
||||
#if __cplusplus < 201103L
|
||||
// expected-note@-2 {{in instantiation of}}
|
||||
#endif
|
||||
|
||||
#if __cplusplus >= 201402L
|
||||
namespace partial_substitute {
|
||||
template<typename T> auto f() {
|
||||
return [](auto x) {
|
||||
using A = typename T::template U<decltype(x)>;
|
||||
using A::E::e;
|
||||
struct S : A {
|
||||
using A::f;
|
||||
using typename A::type;
|
||||
type f(int) { return e; }
|
||||
};
|
||||
return S();
|
||||
};
|
||||
}
|
||||
enum Enum { e };
|
||||
struct X {
|
||||
template<typename T> struct U {
|
||||
int f(int, int);
|
||||
using type = int;
|
||||
using E = Enum;
|
||||
};
|
||||
};
|
||||
int test() {
|
||||
auto s = f<X>()(0);
|
||||
return s.f(0) + s.f(0, 0);
|
||||
}
|
||||
|
||||
template<typename T, typename U> auto g() {
|
||||
return [](auto x) {
|
||||
using X = decltype(x);
|
||||
struct S : T::template Q<X>, U::template Q<X> {
|
||||
using T::template Q<X>::f;
|
||||
using U::template Q<X>::f;
|
||||
void h() { f(); }
|
||||
void h(int n) { f(n); }
|
||||
};
|
||||
return S();
|
||||
};
|
||||
}
|
||||
struct A { template<typename> struct Q { int f(); }; };
|
||||
struct B { template<typename> struct Q { int f(int); }; };
|
||||
int test2() {
|
||||
auto s = g<A, B>()(0);
|
||||
s.f();
|
||||
s.f(0);
|
||||
s.h();
|
||||
s.h(0);
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
template<typename T, typename U> struct RepeatedMember : T, U {
|
||||
// FIXME: This is the wrong error: we should complain that a member type
|
||||
// cannot be redeclared at class scope.
|
||||
using typename T::type; // expected-note {{candidate}}
|
||||
using typename U::type; // expected-note {{candidate}}
|
||||
type x; // expected-error {{ambiguous}}
|
||||
};
|
||||
}
|
||||
|
||||
struct S {
|
||||
static int n;
|
||||
|
|
Loading…
Reference in New Issue