diff --git a/include/clang/AST/ASTContext.h b/include/clang/AST/ASTContext.h index a07f41268267bd318fdd25999167d389b5087e95..f2aceab41c77803b59680ed552b6ee7a757bb3d0 100644 --- a/include/clang/AST/ASTContext.h +++ b/include/clang/AST/ASTContext.h @@ -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); diff --git a/include/clang/Sema/Sema.h b/include/clang/Sema/Sema.h index 2b54d5ee142dcc39b715617015243ee4ddbad0e1..136f848338802ae0fd75d31fba7fdc0e763a388b 100644 --- a/include/clang/Sema/Sema.h +++ b/include/clang/Sema/Sema.h @@ -4317,6 +4317,7 @@ public: SourceLocation NameLoc, const LookupResult &Previous); bool CheckUsingDeclQualifier(SourceLocation UsingLoc, + bool HasTypename, const CXXScopeSpec &SS, const DeclarationNameInfo &NameInfo, SourceLocation NameLoc); diff --git a/lib/AST/ASTContext.cpp b/lib/AST/ASTContext.cpp index 7a98ac4c6e97d9f3ff804308ce9727d232b6d90f..0ad663fdf964eac69ab53828f53521a65276917c 100644 --- a/lib/AST/ASTContext.cpp +++ b/lib/AST/ASTContext.cpp @@ -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; } diff --git a/lib/Sema/SemaDeclCXX.cpp b/lib/Sema/SemaDeclCXX.cpp index 8b1c2340616d02ee72b5b1b7d852f0f587d1cf47..4742995926fd1f1866627f4223cdb76760666442 100644 --- a/lib/Sema/SemaDeclCXX.cpp +++ b/lib/Sema/SemaDeclCXX.cpp @@ -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; } diff --git a/lib/Sema/SemaOverload.cpp b/lib/Sema/SemaOverload.cpp index 1899e41ba966ea51725de24394c7e2d9ddd6681b..d49142b8d8532638cc8bab19bf55acd88331ea35 100644 --- a/lib/Sema/SemaOverload.cpp +++ b/lib/Sema/SemaOverload.cpp @@ -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 diff --git a/lib/Sema/SemaTemplateInstantiateDecl.cpp b/lib/Sema/SemaTemplateInstantiateDecl.cpp index 6b6abc7af6f2d9c7bbee21dc3fae151e3e833d51..0956a1cc502c94b3e7e6bb39784f919d88606289 100644 --- a/lib/Sema/SemaTemplateInstantiateDecl.cpp +++ b/lib/Sema/SemaTemplateInstantiateDecl.cpp @@ -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> diff --git a/test/CXX/dcl.dcl/basic.namespace/namespace.udecl/p8-cxx0x.cpp b/test/CXX/dcl.dcl/basic.namespace/namespace.udecl/p8-cxx0x.cpp index 6c63f061ab0f1106e7c007548f3b81ae91c10f38..8f6638e69438ce26791abe1fe05e3955080ac6c8 100644 --- a/test/CXX/dcl.dcl/basic.namespace/namespace.udecl/p8-cxx0x.cpp +++ b/test/CXX/dcl.dcl/basic.namespace/namespace.udecl/p8-cxx0x.cpp @@ -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;