diff --git a/include/clang/AST/DeclCXX.h b/include/clang/AST/DeclCXX.h index bbf35604402ffa8ae3974fa12e724dd1707995c3..bb97b55f123c7ed4732a2fc11817ccc0a6cedb56 100644 --- a/include/clang/AST/DeclCXX.h +++ b/include/clang/AST/DeclCXX.h @@ -2676,7 +2676,7 @@ public: /// // Also creates a UsingShadowDecl for A::foo() in B /// } /// \endcode -class UsingShadowDecl : public NamedDecl { +class UsingShadowDecl : public NamedDecl, public Redeclarable<UsingShadowDecl> { virtual void anchor(); /// The referenced declaration. @@ -2699,6 +2699,17 @@ class UsingShadowDecl : public NamedDecl { setImplicit(); } + typedef Redeclarable<UsingShadowDecl> redeclarable_base; + virtual UsingShadowDecl *getNextRedeclaration() { + return RedeclLink.getNext(); + } + virtual UsingShadowDecl *getPreviousDeclImpl() { + return getPreviousDecl(); + } + virtual UsingShadowDecl *getMostRecentDeclImpl() { + return getMostRecentDecl(); + } + public: static UsingShadowDecl *Create(ASTContext &C, DeclContext *DC, SourceLocation Loc, UsingDecl *Using, @@ -2707,7 +2718,20 @@ public: } static UsingShadowDecl *CreateDeserialized(ASTContext &C, unsigned ID); - + + typedef redeclarable_base::redecl_iterator redecl_iterator; + using redeclarable_base::redecls_begin; + using redeclarable_base::redecls_end; + using redeclarable_base::getPreviousDecl; + using redeclarable_base::getMostRecentDecl; + + virtual UsingShadowDecl *getCanonicalDecl() { + return getFirstDecl(); + } + virtual const UsingShadowDecl *getCanonicalDecl() const { + return getFirstDecl(); + } + /// \brief Gets the underlying declaration which has been brought into the /// local scope. NamedDecl *getTargetDecl() const { return Underlying; } diff --git a/include/clang/Sema/Sema.h b/include/clang/Sema/Sema.h index 0c68e5c37a0b682a3aa106966c7872b3535e155b..abbf512f3c15f0c6d6bbd791d6cee6bd9999d743 100644 --- a/include/clang/Sema/Sema.h +++ b/include/clang/Sema/Sema.h @@ -3640,9 +3640,11 @@ public: void HideUsingShadowDecl(Scope *S, UsingShadowDecl *Shadow); bool CheckUsingShadowDecl(UsingDecl *UD, NamedDecl *Target, - const LookupResult &PreviousDecls); + const LookupResult &PreviousDecls, + UsingShadowDecl *&PrevShadow); UsingShadowDecl *BuildUsingShadowDecl(Scope *S, UsingDecl *UD, - NamedDecl *Target); + NamedDecl *Target, + UsingShadowDecl *PrevDecl); bool CheckUsingDeclRedeclaration(SourceLocation UsingLoc, bool HasTypenameKeyword, diff --git a/lib/Sema/SemaDeclCXX.cpp b/lib/Sema/SemaDeclCXX.cpp index f5bb3511f22561908d72445ac08b98a9e8ed3230..221c53f03f6a37894b59abdfa1e4a285067d0d10 100644 --- a/lib/Sema/SemaDeclCXX.cpp +++ b/lib/Sema/SemaDeclCXX.cpp @@ -7073,20 +7073,15 @@ Decl *Sema::ActOnUsingDeclaration(Scope *S, /// \brief Determine whether a using declaration considers the given /// declarations as "equivalent", e.g., if they are redeclarations of /// the same entity or are both typedefs of the same type. -static bool -IsEquivalentForUsingDecl(ASTContext &Context, NamedDecl *D1, NamedDecl *D2, - bool &SuppressRedeclaration) { - if (D1->getCanonicalDecl() == D2->getCanonicalDecl()) { - SuppressRedeclaration = false; +static bool +IsEquivalentForUsingDecl(ASTContext &Context, NamedDecl *D1, NamedDecl *D2) { + if (D1->getCanonicalDecl() == D2->getCanonicalDecl()) return true; - } if (TypedefNameDecl *TD1 = dyn_cast<TypedefNameDecl>(D1)) - if (TypedefNameDecl *TD2 = dyn_cast<TypedefNameDecl>(D2)) { - SuppressRedeclaration = true; + if (TypedefNameDecl *TD2 = dyn_cast<TypedefNameDecl>(D2)) return Context.hasSameType(TD1->getUnderlyingType(), TD2->getUnderlyingType()); - } return false; } @@ -7095,7 +7090,8 @@ IsEquivalentForUsingDecl(ASTContext &Context, NamedDecl *D1, NamedDecl *D2, /// Determines whether to create a using shadow decl for a particular /// decl, given the set of decls existing prior to this using lookup. bool Sema::CheckUsingShadowDecl(UsingDecl *Using, NamedDecl *Orig, - const LookupResult &Previous) { + const LookupResult &Previous, + UsingShadowDecl *&PrevShadow) { // Diagnose finding a decl which is not from a base class of the // current class. We do this now because there are cases where this // function will silently decide not to build a shadow decl, which @@ -7155,16 +7151,22 @@ bool Sema::CheckUsingShadowDecl(UsingDecl *Using, NamedDecl *Orig, // FIXME: but we might be increasing its access, in which case we // should redeclare it. NamedDecl *NonTag = 0, *Tag = 0; + bool FoundEquivalentDecl = false; for (LookupResult::iterator I = Previous.begin(), E = Previous.end(); I != E; ++I) { NamedDecl *D = (*I)->getUnderlyingDecl(); - bool Result; - if (IsEquivalentForUsingDecl(Context, D, Target, Result)) - return Result; + if (IsEquivalentForUsingDecl(Context, D, Target)) { + if (UsingShadowDecl *Shadow = dyn_cast<UsingShadowDecl>(*I)) + PrevShadow = Shadow; + FoundEquivalentDecl = true; + } (isa<TagDecl>(D) ? Tag : NonTag) = D; } + if (FoundEquivalentDecl) + return false; + if (Target->isFunctionOrFunctionTemplate()) { FunctionDecl *FD; if (isa<FunctionTemplateDecl>(Target)) @@ -7223,7 +7225,8 @@ bool Sema::CheckUsingShadowDecl(UsingDecl *Using, NamedDecl *Orig, /// Builds a shadow declaration corresponding to a 'using' declaration. UsingShadowDecl *Sema::BuildUsingShadowDecl(Scope *S, UsingDecl *UD, - NamedDecl *Orig) { + NamedDecl *Orig, + UsingShadowDecl *PrevDecl) { // If we resolved to another shadow declaration, just coalesce them. NamedDecl *Target = Orig; @@ -7231,16 +7234,18 @@ UsingShadowDecl *Sema::BuildUsingShadowDecl(Scope *S, Target = cast<UsingShadowDecl>(Target)->getTargetDecl(); assert(!isa<UsingShadowDecl>(Target) && "nested shadow declaration"); } - + UsingShadowDecl *Shadow = UsingShadowDecl::Create(Context, CurContext, UD->getLocation(), UD, Target); UD->addShadowDecl(Shadow); - + Shadow->setAccess(UD->getAccess()); if (Orig->isInvalidDecl() || UD->isInvalidDecl()) Shadow->setInvalidDecl(); - + + Shadow->setPreviousDecl(PrevDecl); + if (S) PushOnScopeChains(Shadow, S); else @@ -7504,8 +7509,9 @@ NamedDecl *Sema::BuildUsingDeclaration(Scope *S, AccessSpecifier AS, } for (LookupResult::iterator I = R.begin(), E = R.end(); I != E; ++I) { - if (!CheckUsingShadowDecl(UD, *I, Previous)) - BuildUsingShadowDecl(S, UD, *I); + UsingShadowDecl *PrevDecl = 0; + if (!CheckUsingShadowDecl(UD, *I, Previous, PrevDecl)) + BuildUsingShadowDecl(S, UD, *I, PrevDecl); } return UD; diff --git a/lib/Sema/SemaTemplateInstantiateDecl.cpp b/lib/Sema/SemaTemplateInstantiateDecl.cpp index b517164000910fe9fb24d122996b6a9c00107684..d0c3ac69144e79178f3f7b915c9ba807a96b0e0e 100644 --- a/lib/Sema/SemaTemplateInstantiateDecl.cpp +++ b/lib/Sema/SemaTemplateInstantiateDecl.cpp @@ -2152,19 +2152,22 @@ Decl *TemplateDeclInstantiator::VisitUsingDecl(UsingDecl *D) { I != E; ++I) { UsingShadowDecl *Shadow = *I; NamedDecl *InstTarget = - cast_or_null<NamedDecl>(SemaRef.FindInstantiatedDecl( - Shadow->getLocation(), - Shadow->getTargetDecl(), - TemplateArgs)); + cast_or_null<NamedDecl>(SemaRef.FindInstantiatedDecl( + Shadow->getLocation(), Shadow->getTargetDecl(), TemplateArgs)); if (!InstTarget) return 0; - if (CheckRedeclaration && - SemaRef.CheckUsingShadowDecl(NewUD, InstTarget, Prev)) - continue; + UsingShadowDecl *PrevDecl = 0; + if (CheckRedeclaration) { + if (SemaRef.CheckUsingShadowDecl(NewUD, InstTarget, Prev, PrevDecl)) + continue; + } else if (UsingShadowDecl *OldPrev = Shadow->getPreviousDecl()) { + PrevDecl = cast_or_null<UsingShadowDecl>(SemaRef.FindInstantiatedDecl( + Shadow->getLocation(), OldPrev, TemplateArgs)); + } - UsingShadowDecl *InstShadow - = SemaRef.BuildUsingShadowDecl(/*Scope*/ 0, NewUD, InstTarget); + UsingShadowDecl *InstShadow = + SemaRef.BuildUsingShadowDecl(/*Scope*/0, NewUD, InstTarget, PrevDecl); SemaRef.Context.setInstantiatedFromUsingShadowDecl(InstShadow, Shadow); if (isFunctionScope) diff --git a/lib/Serialization/ASTCommon.cpp b/lib/Serialization/ASTCommon.cpp index 79bba0cb94f990e93755f830ece6c3501f5d85ac..a8176878dc4ee87d853a25b9fcf0ac6597825f3e 100644 --- a/lib/Serialization/ASTCommon.cpp +++ b/lib/Serialization/ASTCommon.cpp @@ -165,6 +165,7 @@ bool serialization::isRedeclarableDeclKind(unsigned Kind) { case Decl::CXXConstructor: case Decl::CXXDestructor: case Decl::CXXConversion: + case Decl::UsingShadow: case Decl::Var: case Decl::FunctionTemplate: case Decl::ClassTemplate: @@ -192,7 +193,6 @@ bool serialization::isRedeclarableDeclKind(unsigned Kind) { case Decl::NonTypeTemplateParm: case Decl::TemplateTemplateParm: case Decl::Using: - case Decl::UsingShadow: case Decl::ObjCMethod: case Decl::ObjCCategory: case Decl::ObjCCategoryImpl: diff --git a/lib/Serialization/ASTReaderDecl.cpp b/lib/Serialization/ASTReaderDecl.cpp index e68c7fc6f9fb1b34c9b83c9c393ac9f4761ef8a8..463af777986f9cb212f9b8f4a0913dd3dc13378f 100644 --- a/lib/Serialization/ASTReaderDecl.cpp +++ b/lib/Serialization/ASTReaderDecl.cpp @@ -1134,12 +1134,14 @@ void ASTDeclReader::VisitUsingDecl(UsingDecl *D) { } void ASTDeclReader::VisitUsingShadowDecl(UsingShadowDecl *D) { + RedeclarableResult Redecl = VisitRedeclarable(D); VisitNamedDecl(D); D->setTargetDecl(ReadDeclAs<NamedDecl>(Record, Idx)); D->UsingOrNextShadow = ReadDeclAs<NamedDecl>(Record, Idx); UsingShadowDecl *Pattern = ReadDeclAs<UsingShadowDecl>(Record, Idx); if (Pattern) Reader.getContext().setInstantiatedFromUsingShadowDecl(D, Pattern); + mergeRedeclarable(D, Redecl); } void ASTDeclReader::VisitUsingDirectiveDecl(UsingDirectiveDecl *D) { @@ -2151,6 +2153,12 @@ static bool isSameEntity(NamedDecl *X, NamedDecl *Y) { // FIXME: Also check the value is odr-equivalent. return true; + // Using shadow declarations with the same target match. + if (UsingShadowDecl *USX = dyn_cast<UsingShadowDecl>(X)) { + UsingShadowDecl *USY = cast<UsingShadowDecl>(Y); + return USX->getTargetDecl() == USY->getTargetDecl(); + } + // FIXME: Many other cases to implement. return false; } @@ -2258,6 +2266,8 @@ void ASTDeclReader::attachPreviousDecl(Decl *D, Decl *previous) { VD->RedeclLink.setNext(cast<VarDecl>(previous)); } else if (TypedefNameDecl *TD = dyn_cast<TypedefNameDecl>(D)) { TD->RedeclLink.setNext(cast<TypedefNameDecl>(previous)); + } else if (UsingShadowDecl *USD = dyn_cast<UsingShadowDecl>(D)) { + USD->RedeclLink.setNext(cast<UsingShadowDecl>(previous)); } else if (ObjCInterfaceDecl *ID = dyn_cast<ObjCInterfaceDecl>(D)) { ID->RedeclLink.setNext(cast<ObjCInterfaceDecl>(previous)); } else if (ObjCProtocolDecl *PD = dyn_cast<ObjCProtocolDecl>(D)) { @@ -2285,7 +2295,7 @@ void ASTDeclReader::attachLatestDecl(Decl *D, Decl *Latest) { TD->RedeclLink = Redeclarable<TagDecl>::LatestDeclLink(cast<TagDecl>(Latest)); } else if (FunctionDecl *FD = dyn_cast<FunctionDecl>(D)) { - FD->RedeclLink + FD->RedeclLink = Redeclarable<FunctionDecl>::LatestDeclLink(cast<FunctionDecl>(Latest)); } else if (VarDecl *VD = dyn_cast<VarDecl>(D)) { VD->RedeclLink @@ -2294,6 +2304,10 @@ void ASTDeclReader::attachLatestDecl(Decl *D, Decl *Latest) { TD->RedeclLink = Redeclarable<TypedefNameDecl>::LatestDeclLink( cast<TypedefNameDecl>(Latest)); + } else if (UsingShadowDecl *USD = dyn_cast<UsingShadowDecl>(D)) { + USD->RedeclLink + = Redeclarable<UsingShadowDecl>::LatestDeclLink( + cast<UsingShadowDecl>(Latest)); } else if (ObjCInterfaceDecl *ID = dyn_cast<ObjCInterfaceDecl>(D)) { ID->RedeclLink = Redeclarable<ObjCInterfaceDecl>::LatestDeclLink( diff --git a/lib/Serialization/ASTWriterDecl.cpp b/lib/Serialization/ASTWriterDecl.cpp index 2d5ab7bb3a09075c1d01da137ce05022b5ae410b..bee1786a0ac68230ee5e1ce674f39f0101a8e95c 100644 --- a/lib/Serialization/ASTWriterDecl.cpp +++ b/lib/Serialization/ASTWriterDecl.cpp @@ -938,6 +938,7 @@ void ASTDeclWriter::VisitUsingDecl(UsingDecl *D) { } void ASTDeclWriter::VisitUsingShadowDecl(UsingShadowDecl *D) { + VisitRedeclarable(D); VisitNamedDecl(D); Writer.AddDeclRef(D->getTargetDecl(), Record); Writer.AddDeclRef(D->UsingOrNextShadow, Record); diff --git a/test/Modules/Inputs/module.map b/test/Modules/Inputs/module.map index 12da7a649adce684592cc9ea0b68b9d0a719f5f8..cb4d339f7e41414a41b253a022edac7ce270cce5 100644 --- a/test/Modules/Inputs/module.map +++ b/test/Modules/Inputs/module.map @@ -258,3 +258,8 @@ module warning { module initializer_list { header "initializer_list" } + +module using_decl { + module a { header "using-decl-a.h" export * } + module b { header "using-decl-b.h" export * } +} diff --git a/test/Modules/Inputs/using-decl-a.h b/test/Modules/Inputs/using-decl-a.h new file mode 100644 index 0000000000000000000000000000000000000000..85a4788e76473f52cb199749595cf3467a213d94 --- /dev/null +++ b/test/Modules/Inputs/using-decl-a.h @@ -0,0 +1,10 @@ +typedef int using_decl_type; +int using_decl_var; + +namespace UsingDecl { + using ::using_decl_type; + using ::using_decl_var; + + namespace A { typedef int inner; } + using A::inner; +} diff --git a/test/Modules/Inputs/using-decl-b.h b/test/Modules/Inputs/using-decl-b.h new file mode 100644 index 0000000000000000000000000000000000000000..b82526f39ff448e6830e4d4330286c81c9cd93a8 --- /dev/null +++ b/test/Modules/Inputs/using-decl-b.h @@ -0,0 +1,11 @@ +namespace UsingDecl { + namespace B { typedef int inner; } + using B::inner; +} + +#include "using-decl-a.h" + +namespace UsingDecl { + using ::using_decl_type; + using ::using_decl_var; +} diff --git a/test/Modules/using-decl.cpp b/test/Modules/using-decl.cpp new file mode 100644 index 0000000000000000000000000000000000000000..4432738f060a00fc9f3c8edf32ae0e1967bd3bfb --- /dev/null +++ b/test/Modules/using-decl.cpp @@ -0,0 +1,8 @@ +// RUN: rm -rf %t +// RUN: %clang_cc1 -x objective-c++ -fmodules -fmodules-cache-path=%t -I %S/Inputs %s -verify + +@import using_decl.a; + +// expected-no-diagnostics +UsingDecl::using_decl_type x = UsingDecl::using_decl_var; +UsingDecl::inner y = x;