diff options
Diffstat (limited to 'clang/lib')
-rw-r--r-- | clang/lib/AST/DeclBase.cpp | 40 | ||||
-rw-r--r-- | clang/lib/Sema/Sema.h | 22 | ||||
-rw-r--r-- | clang/lib/Sema/SemaDecl.cpp | 11 | ||||
-rw-r--r-- | clang/lib/Sema/SemaDeclCXX.cpp | 306 | ||||
-rw-r--r-- | clang/lib/Sema/SemaLookup.cpp | 11 | ||||
-rw-r--r-- | clang/lib/Sema/SemaOverload.cpp | 15 | ||||
-rw-r--r-- | clang/lib/Sema/SemaTemplateInstantiateDecl.cpp | 73 | ||||
-rw-r--r-- | clang/lib/Sema/TreeTransform.h | 20 |
8 files changed, 423 insertions, 75 deletions
diff --git a/clang/lib/AST/DeclBase.cpp b/clang/lib/AST/DeclBase.cpp index c557e615e78..2022b4a28cd 100644 --- a/clang/lib/AST/DeclBase.cpp +++ b/clang/lib/AST/DeclBase.cpp @@ -636,6 +636,46 @@ bool DeclContext::decls_empty() const { return !FirstDecl; } +void DeclContext::removeDecl(Decl *D) { + assert(D->getLexicalDeclContext() == this && + "decl being removed from non-lexical context"); + assert((D->NextDeclInContext || D == LastDecl) && + "decl is not in decls list"); + + // Remove D from the decl chain. This is O(n) but hopefully rare. + if (D == FirstDecl) { + if (D == LastDecl) + FirstDecl = LastDecl = 0; + else + FirstDecl = D->NextDeclInContext; + } else { + for (Decl *I = FirstDecl; true; I = I->NextDeclInContext) { + assert(I && "decl not found in linked list"); + if (I->NextDeclInContext == D) { + I->NextDeclInContext = D->NextDeclInContext; + if (D == LastDecl) LastDecl = I; + break; + } + } + } + + // Mark that D is no longer in the decl chain. + D->NextDeclInContext = 0; + + // Remove D from the lookup table if necessary. + if (isa<NamedDecl>(D)) { + NamedDecl *ND = cast<NamedDecl>(D); + + void *OpaqueMap = getPrimaryContext()->LookupPtr; + if (!OpaqueMap) return; + + StoredDeclsMap *Map = static_cast<StoredDeclsMap*>(OpaqueMap); + StoredDeclsMap::iterator Pos = Map->find(ND->getDeclName()); + assert(Pos != Map->end() && "no lookup entry for decl"); + Pos->second.remove(ND); + } +} + void DeclContext::addHiddenDecl(Decl *D) { assert(D->getLexicalDeclContext() == this && "Decl inserted into wrong lexical context"); diff --git a/clang/lib/Sema/Sema.h b/clang/lib/Sema/Sema.h index ad903a0816b..22e6b144213 100644 --- a/clang/lib/Sema/Sema.h +++ b/clang/lib/Sema/Sema.h @@ -616,7 +616,8 @@ public: bool IsFunctionDefinition, bool &Redeclaration); void AddOverriddenMethods(CXXRecordDecl *DC, CXXMethodDecl *MD); - void CheckFunctionDeclaration(FunctionDecl *NewFD, LookupResult &Previous, + void CheckFunctionDeclaration(Scope *S, + FunctionDecl *NewFD, LookupResult &Previous, bool IsExplicitSpecialization, bool &Redeclaration, bool &OverloadableAttrRequired); @@ -839,7 +840,7 @@ public: Ovl_NonFunction }; OverloadKind CheckOverload(FunctionDecl *New, - LookupResult &OldDecls, + const LookupResult &OldDecls, NamedDecl *&OldDecl); bool IsOverload(FunctionDecl *New, FunctionDecl *Old); @@ -1123,6 +1124,10 @@ public: /// namespace alias definition, ignoring non-namespace names (C++ /// [basic.lookup.udir]p1). LookupNamespaceName, + /// Look up all declarations in a scope with the given name, + /// including resolved using declarations. This is appropriate + /// for checking redeclarations for a using declaration. + LookupUsingDeclName, /// Look up an ordinary name that is going to be redeclared as a /// name with linkage. This lookup ignores any declarations that /// are outside of the current scope unless they have linkage. See @@ -1154,6 +1159,7 @@ public: case Sema::LookupTagName: case Sema::LookupMemberName: case Sema::LookupRedeclarationWithLinkage: // FIXME: check linkage, scoping + case Sema::LookupUsingDeclName: case Sema::LookupObjCProtocolName: case Sema::LookupObjCImplementationName: case Sema::LookupObjCCategoryImplName: @@ -1739,9 +1745,17 @@ public: SourceLocation IdentLoc, IdentifierInfo *Ident); - UsingShadowDecl *BuildUsingShadowDecl(Scope *S, AccessSpecifier AS, - UsingDecl *UD, NamedDecl *Target); + void HideUsingShadowDecl(Scope *S, UsingShadowDecl *Shadow); + bool CheckUsingShadowDecl(UsingDecl *UD, NamedDecl *Target, + const LookupResult &PreviousDecls); + UsingShadowDecl *BuildUsingShadowDecl(Scope *S, UsingDecl *UD, + NamedDecl *Target); + bool CheckUsingDeclRedeclaration(SourceLocation UsingLoc, + bool isTypeName, + const CXXScopeSpec &SS, + SourceLocation NameLoc, + const LookupResult &Previous); bool CheckUsingDeclQualifier(SourceLocation UsingLoc, const CXXScopeSpec &SS, SourceLocation NameLoc); diff --git a/clang/lib/Sema/SemaDecl.cpp b/clang/lib/Sema/SemaDecl.cpp index 55a5e7b0635..3fa7e6558b7 100644 --- a/clang/lib/Sema/SemaDecl.cpp +++ b/clang/lib/Sema/SemaDecl.cpp @@ -3015,7 +3015,7 @@ Sema::ActOnFunctionDeclarator(Scope* S, Declarator& D, DeclContext* DC, // Perform semantic checking on the function declaration. bool OverloadableAttrRequired = false; // FIXME: HACK! - CheckFunctionDeclaration(NewFD, Previous, isExplicitSpecialization, + CheckFunctionDeclaration(S, NewFD, Previous, isExplicitSpecialization, Redeclaration, /*FIXME:*/OverloadableAttrRequired); assert((NewFD->isInvalidDecl() || !Redeclaration || @@ -3137,7 +3137,7 @@ Sema::ActOnFunctionDeclarator(Scope* S, Declarator& D, DeclContext* DC, /// an explicit specialization of the previous declaration. /// /// This sets NewFD->isInvalidDecl() to true if there was an error. -void Sema::CheckFunctionDeclaration(FunctionDecl *NewFD, +void Sema::CheckFunctionDeclaration(Scope *S, FunctionDecl *NewFD, LookupResult &Previous, bool IsExplicitSpecialization, bool &Redeclaration, @@ -3202,8 +3202,11 @@ void Sema::CheckFunctionDeclaration(FunctionDecl *NewFD, switch (CheckOverload(NewFD, Previous, OldDecl)) { case Ovl_Match: - // FIXME: hide or conflict with using shadow decls as appropriate - Redeclaration = !isa<UsingShadowDecl>(OldDecl); + Redeclaration = true; + if (isa<UsingShadowDecl>(OldDecl) && CurContext->isRecord()) { + HideUsingShadowDecl(S, cast<UsingShadowDecl>(OldDecl)); + Redeclaration = false; + } break; case Ovl_NonFunction: diff --git a/clang/lib/Sema/SemaDeclCXX.cpp b/clang/lib/Sema/SemaDeclCXX.cpp index d977ad6000d..f97b7637451 100644 --- a/clang/lib/Sema/SemaDeclCXX.cpp +++ b/clang/lib/Sema/SemaDeclCXX.cpp @@ -2925,12 +2925,146 @@ Sema::DeclPtrTy Sema::ActOnUsingDeclaration(Scope *S, return DeclPtrTy::make(UD); } +/// 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) { + // 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 + // will pre-empt further diagnostics. + // + // We don't need to do this in C++0x because we do the check once on + // the qualifier. + // + // FIXME: diagnose the following if we care enough: + // struct A { int foo; }; + // struct B : A { using A::foo; }; + // template <class T> struct C : A {}; + // template <class T> struct D : C<T> { using B::foo; } // <--- + // This is invalid (during instantiation) in C++03 because B::foo + // resolves to the using decl in B, which is not a base class of D<T>. + // We can't diagnose it immediately because C<T> is an unknown + // specialization. The UsingShadowDecl in D<T> then points directly + // to A::foo, which will look well-formed when we instantiate. + // The right solution is to not collapse the shadow-decl chain. + if (!getLangOptions().CPlusPlus0x && CurContext->isRecord()) { + DeclContext *OrigDC = Orig->getDeclContext(); + + // Handle enums and anonymous structs. + if (isa<EnumDecl>(OrigDC)) OrigDC = OrigDC->getParent(); + CXXRecordDecl *OrigRec = cast<CXXRecordDecl>(OrigDC); + while (OrigRec->isAnonymousStructOrUnion()) + OrigRec = cast<CXXRecordDecl>(OrigRec->getDeclContext()); + + if (cast<CXXRecordDecl>(CurContext)->isProvablyNotDerivedFrom(OrigRec)) { + if (OrigDC == CurContext) { + Diag(Using->getLocation(), + diag::err_using_decl_nested_name_specifier_is_current_class) + << Using->getNestedNameRange(); + Diag(Orig->getLocation(), diag::note_using_decl_target); + return true; + } + + Diag(Using->getNestedNameRange().getBegin(), + diag::err_using_decl_nested_name_specifier_is_not_base_class) + << Using->getTargetNestedNameDecl() + << cast<CXXRecordDecl>(CurContext) + << Using->getNestedNameRange(); + Diag(Orig->getLocation(), diag::note_using_decl_target); + return true; + } + } + + if (Previous.empty()) return false; + + NamedDecl *Target = Orig; + if (isa<UsingShadowDecl>(Target)) + Target = cast<UsingShadowDecl>(Target)->getTargetDecl(); + + if (Target->isFunctionOrFunctionTemplate()) { + FunctionDecl *FD; + if (isa<FunctionTemplateDecl>(Target)) + FD = cast<FunctionTemplateDecl>(Target)->getTemplatedDecl(); + else + FD = cast<FunctionDecl>(Target); + + NamedDecl *OldDecl = 0; + switch (CheckOverload(FD, Previous, OldDecl)) { + case Ovl_Overload: + return false; + + case Ovl_NonFunction: + Diag(Using->getLocation(), diag::err_using_decl_conflict) + << 0 // target decl is a function + << 1; // other decl is not a function + break; + + // We found a decl with the exact signature. + case Ovl_Match: + if (isa<UsingShadowDecl>(OldDecl)) { + // Silently ignore the possible conflict. + return false; + } + + // If we're in a record, we want to hide the target, so we + // return true (without a diagnostic) to tell the caller not to + // build a shadow decl. + if (CurContext->isRecord()) + return true; + + // If we're not in a record, this is an error. + Diag(Using->getLocation(), diag::err_using_decl_conflict) + << 0 // target decl is a function + << 0; // other decl is a function + break; + } + + Diag(Target->getLocation(), diag::note_using_decl_target); + Diag(OldDecl->getLocation(), diag::note_using_decl_conflict); + return true; + } + + // Target is not a function. + + // If the target happens to be one of the previous declarations, we + // don't have a conflict. + NamedDecl *NonTag = 0, *Tag = 0; + for (LookupResult::iterator I = Previous.begin(), E = Previous.end(); + I != E; ++I) { + NamedDecl *D = (*I)->getUnderlyingDecl(); + if (D->getCanonicalDecl() == Target->getCanonicalDecl()) + return false; + + (isa<TagDecl>(D) ? Tag : NonTag) = D; + } + + if (isa<TagDecl>(Target)) { + // No conflict between a tag and a non-tag. + if (!Tag) return false; + + Diag(Using->getLocation(), diag::err_using_decl_conflict) + << 1 << 1; // both non-functions + Diag(Target->getLocation(), diag::note_using_decl_target); + Diag(Tag->getLocation(), diag::note_using_decl_conflict); + return true; + } + + // No conflict between a tag and a non-tag. + if (!NonTag) return false; + + Diag(Using->getLocation(), diag::err_using_decl_conflict) + << 1 // target not a function + << int(NonTag->isFunctionOrFunctionTemplate()); + Diag(Target->getLocation(), diag::note_using_decl_target); + Diag(NonTag->getLocation(), diag::note_using_decl_conflict); + return true; +} + /// Builds a shadow declaration corresponding to a 'using' declaration. UsingShadowDecl *Sema::BuildUsingShadowDecl(Scope *S, - AccessSpecifier AS, UsingDecl *UD, NamedDecl *Orig) { - // FIXME: diagnose hiding, collisions // If we resolved to another shadow declaration, just coalesce them. NamedDecl *Target = Orig; @@ -2948,47 +3082,58 @@ UsingShadowDecl *Sema::BuildUsingShadowDecl(Scope *S, PushOnScopeChains(Shadow, S); else CurContext->addDecl(Shadow); - Shadow->setAccess(AS); + Shadow->setAccess(UD->getAccess()); if (Orig->isInvalidDecl() || UD->isInvalidDecl()) Shadow->setInvalidDecl(); - // If we haven't already declared the shadow decl invalid, check - // whether the decl comes from a base class of the current class. - // We don't have to do this in C++0x because we do the check once on - // the qualifier. - else if (!getLangOptions().CPlusPlus0x && CurContext->isRecord()) { - DeclContext *OrigDC = Orig->getDeclContext(); - - // Handle enums and anonymous structs. - if (isa<EnumDecl>(OrigDC)) OrigDC = OrigDC->getParent(); - CXXRecordDecl *OrigRec = cast<CXXRecordDecl>(OrigDC); - while (OrigRec->isAnonymousStructOrUnion()) - OrigRec = cast<CXXRecordDecl>(OrigRec->getDeclContext()); - - if (cast<CXXRecordDecl>(CurContext)->isProvablyNotDerivedFrom(OrigRec)) { - if (OrigDC == CurContext) { - Diag(UD->getLocation(), - diag::err_using_decl_nested_name_specifier_is_current_class) - << UD->getNestedNameRange(); - Diag(Orig->getLocation(), diag::note_using_decl_target); - Shadow->setInvalidDecl(); - return Shadow; - } - - Diag(UD->getNestedNameRange().getBegin(), - diag::err_using_decl_nested_name_specifier_is_not_base_class) - << UD->getTargetNestedNameDecl() - << cast<CXXRecordDecl>(CurContext) - << UD->getNestedNameRange(); - Diag(Orig->getLocation(), diag::note_using_decl_target); - return Shadow; - } - } - return Shadow; } +/// Hides a using shadow declaration. This is required by the current +/// using-decl implementation when a resolvable using declaration in a +/// class is followed by a declaration which would hide or override +/// one or more of the using decl's targets; for example: +/// +/// struct Base { void foo(int); }; +/// struct Derived : Base { +/// using Base::foo; +/// void foo(int); +/// }; +/// +/// The governing language is C++03 [namespace.udecl]p12: +/// +/// When a using-declaration brings names from a base class into a +/// derived class scope, member functions in the derived class +/// override and/or hide member functions with the same name and +/// parameter types in a base class (rather than conflicting). +/// +/// There are two ways to implement this: +/// (1) optimistically create shadow decls when they're not hidden +/// by existing declarations, or +/// (2) don't create any shadow decls (or at least don't make them +/// visible) until we've fully parsed/instantiated the class. +/// The problem with (1) is that we might have to retroactively remove +/// a shadow decl, which requires several O(n) operations because the +/// decl structures are (very reasonably) not designed for removal. +/// (2) avoids this but is very fiddly and phase-dependent. +void Sema::HideUsingShadowDecl(Scope *S, UsingShadowDecl *Shadow) { + // Remove it from the DeclContext... + Shadow->getDeclContext()->removeDecl(Shadow); + + // ...and the scope, if applicable... + if (S) { + S->RemoveDecl(DeclPtrTy::make(static_cast<Decl*>(Shadow))); + IdResolver.RemoveDecl(Shadow); + } + + // ...and the using decl. + Shadow->getUsingDecl()->removeShadowDecl(Shadow); + + // TODO: complain somehow if Shadow was used. It shouldn't + // be possible for this to happen, because +} + /// Builds a using declaration. /// /// \param IsInstantiation - Whether this call arises from an @@ -3014,9 +3159,35 @@ NamedDecl *Sema::BuildUsingDeclaration(Scope *S, AccessSpecifier AS, return 0; } + // Do the redeclaration lookup in the current scope. + LookupResult Previous(*this, Name, IdentLoc, LookupUsingDeclName, + ForRedeclaration); + Previous.setHideTags(false); + if (S) { + LookupName(Previous, S); + + // It is really dumb that we have to do this. + LookupResult::Filter F = Previous.makeFilter(); + while (F.hasNext()) { + NamedDecl *D = F.next(); + if (!isDeclInScope(D, CurContext, S)) + F.erase(); + } + F.done(); + } else { + assert(IsInstantiation && "no scope in non-instantiation"); + assert(CurContext->isRecord() && "scope not record in instantiation"); + LookupQualifiedName(Previous, CurContext); + } + NestedNameSpecifier *NNS = static_cast<NestedNameSpecifier *>(SS.getScopeRep()); + // Check for invalid redeclarations. + if (CheckUsingDeclRedeclaration(UsingLoc, IsTypeName, SS, IdentLoc, Previous)) + return 0; + + // Check for bad qualifiers. if (CheckUsingDeclQualifier(UsingLoc, SS, IdentLoc)) return 0; @@ -3106,12 +3277,71 @@ NamedDecl *Sema::BuildUsingDeclaration(Scope *S, AccessSpecifier AS, return UD; } - for (LookupResult::iterator I = R.begin(), E = R.end(); I != E; ++I) - BuildUsingShadowDecl(S, AS, UD, *I); + for (LookupResult::iterator I = R.begin(), E = R.end(); I != E; ++I) { + if (!CheckUsingShadowDecl(UD, *I, Previous)) + BuildUsingShadowDecl(S, UD, *I); + } return UD; } +/// Checks that the given using declaration is not an invalid +/// redeclaration. Note that this is checking only for the using decl +/// itself, not for any ill-formedness among the UsingShadowDecls. +bool Sema::CheckUsingDeclRedeclaration(SourceLocation UsingLoc, + bool isTypeName, + const CXXScopeSpec &SS, + SourceLocation NameLoc, + const LookupResult &Prev) { + // C++03 [namespace.udecl]p8: + // C++0x [namespace.udecl]p10: + // A using-declaration is a declaration and can therefore be used + // repeatedly where (and only where) multiple declarations are + // allowed. + // That's only in file contexts. + if (CurContext->getLookupContext()->isFileContext()) + return false; + + NestedNameSpecifier *Qual + = static_cast<NestedNameSpecifier*>(SS.getScopeRep()); + + for (LookupResult::iterator I = Prev.begin(), E = Prev.end(); I != E; ++I) { + NamedDecl *D = *I; + + bool DTypename; + NestedNameSpecifier *DQual; + if (UsingDecl *UD = dyn_cast<UsingDecl>(D)) { + DTypename = UD->isTypeName(); + DQual = UD->getTargetNestedNameDecl(); + } else if (UnresolvedUsingValueDecl *UD + = dyn_cast<UnresolvedUsingValueDecl>(D)) { + DTypename = false; + DQual = UD->getTargetNestedNameSpecifier(); + } else if (UnresolvedUsingTypenameDecl *UD + = dyn_cast<UnresolvedUsingTypenameDecl>(D)) { + DTypename = true; + DQual = UD->getTargetNestedNameSpecifier(); + } else continue; + + // using decls differ if one says 'typename' and the other doesn't. + // FIXME: non-dependent using decls? + if (isTypeName != DTypename) continue; + + // using decls differ if they name different scopes (but note that + // template instantiation can cause this check to trigger when it + // didn't before instantiation). + if (Context.getCanonicalNestedNameSpecifier(Qual) != + Context.getCanonicalNestedNameSpecifier(DQual)) + continue; + + Diag(NameLoc, diag::err_using_decl_redeclaration) << SS.getRange(); + Diag(D->getLocation(), diag::note_previous_using_decl); + return true; + } + + return false; +} + /// Checks that the given nested-name qualifier used in a using decl /// in the current context is appropriately related to the current diff --git a/clang/lib/Sema/SemaLookup.cpp b/clang/lib/Sema/SemaLookup.cpp index 48d7320d2e9..66c846b078f 100644 --- a/clang/lib/Sema/SemaLookup.cpp +++ b/clang/lib/Sema/SemaLookup.cpp @@ -222,6 +222,11 @@ getIdentifierNamespacesFromLookupNameKind(Sema::LookupNameKind NameKind, IDNS = Decl::IDNS_Ordinary | Decl::IDNS_Tag | Decl::IDNS_Member; break; + case Sema::LookupUsingDeclName: + IDNS = Decl::IDNS_Ordinary | Decl::IDNS_Tag + | Decl::IDNS_Member | Decl::IDNS_Using; + break; + case Sema::LookupObjCProtocolName: IDNS = Decl::IDNS_ObjCProtocol; break; @@ -245,7 +250,7 @@ void LookupResult::deletePaths(CXXBasePaths *Paths) { /// Resolves the result kind of this lookup. void LookupResult::resolveKind() { unsigned N = Decls.size(); - + // Fast case: no possible ambiguity. if (N == 0) { assert(ResultKind == NotFound); @@ -613,6 +618,7 @@ bool Sema::LookupName(LookupResult &R, Scope *S, bool AllowBuiltinCreation) { case Sema::LookupOperatorName: case Sema::LookupNestedNameSpecifierName: case Sema::LookupNamespaceName: + case Sema::LookupUsingDeclName: assert(false && "C does not perform these kinds of name lookup"); break; @@ -928,6 +934,9 @@ bool Sema::LookupQualifiedName(LookupResult &R, DeclContext *LookupCtx) { case LookupTagName: BaseCallback = &CXXRecordDecl::FindTagMember; break; + + case LookupUsingDeclName: + // This lookup is for redeclarations only. case LookupOperatorName: case LookupNamespaceName: diff --git a/clang/lib/Sema/SemaOverload.cpp b/clang/lib/Sema/SemaOverload.cpp index 9ca8d767835..522272ee7c3 100644 --- a/clang/lib/Sema/SemaOverload.cpp +++ b/clang/lib/Sema/SemaOverload.cpp @@ -287,7 +287,8 @@ void ImplicitConversionSequence::DebugPrint() const { // signature), IsOverload returns false and MatchedDecl will be set to // point to the FunctionDecl for #2. Sema::OverloadKind -Sema::CheckOverload(FunctionDecl *New, LookupResult &Old, NamedDecl *&Match) { +Sema::CheckOverload(FunctionDecl *New, const LookupResult &Old, + NamedDecl *&Match) { for (LookupResult::iterator I = Old.begin(), E = Old.end(); I != E; ++I) { NamedDecl *OldD = (*I)->getUnderlyingDecl(); @@ -301,12 +302,18 @@ Sema::CheckOverload(FunctionDecl *New, LookupResult &Old, NamedDecl *&Match) { Match = *I; return Ovl_Match; } - } else if (!isa<UnresolvedUsingValueDecl>(OldD)) { + } else if (isa<UsingDecl>(OldD) || isa<TagDecl>(OldD)) { + // We can overload with these, which can show up when doing + // redeclaration checks for UsingDecls. + assert(Old.getLookupKind() == LookupUsingDeclName); + } else if (isa<UnresolvedUsingValueDecl>(OldD)) { + // Optimistically assume that an unresolved using decl will + // overload; if it doesn't, we'll have to diagnose during + // template instantiation. + } else { // (C++ 13p1): // Only function declarations can be overloaded; object and type // declarations cannot be overloaded. - // But we permit unresolved using value decls and diagnose the error - // during template instantiation. Match = *I; return Ovl_NonFunction; } diff --git a/clang/lib/Sema/SemaTemplateInstantiateDecl.cpp b/clang/lib/Sema/SemaTemplateInstantiateDecl.cpp index 80dcfd4e6d2..07e97117cbf 100644 --- a/clang/lib/Sema/SemaTemplateInstantiateDecl.cpp +++ b/clang/lib/Sema/SemaTemplateInstantiateDecl.cpp @@ -708,7 +708,8 @@ Decl *TemplateDeclInstantiator::VisitCXXRecordDecl(CXXRecordDecl *D) { Previous.clear(); } - SemaRef.CheckFunctionDeclaration(Function, Previous, false, Redeclaration, + SemaRef.CheckFunctionDeclaration(/*Scope*/ 0, Function, Previous, + false, Redeclaration, /*FIXME:*/OverloadableAttrRequired); // If the original function was part of a friend declaration, @@ -868,7 +869,7 @@ TemplateDeclInstantiator::VisitCXXMethodDecl(CXXMethodDecl *D, bool Redeclaration = false; bool OverloadableAttrRequired = false; - SemaRef.CheckFunctionDeclaration(Method, Previous, false, Redeclaration, + SemaRef.CheckFunctionDeclaration(0, Method, Previous, false, Redeclaration, /*FIXME:*/OverloadableAttrRequired); if (D->isPure()) @@ -1040,6 +1041,14 @@ Decl *TemplateDeclInstantiator::VisitUsingDecl(UsingDecl *D) { // The nested name specifier is non-dependent, so no transformation // is required. + // We only need to do redeclaration lookups if we're in a class + // scope (in fact, it's not really even possible in non-class + // scopes). + bool CheckRedeclaration = Owner->isRecord(); + + LookupResult Prev(SemaRef, D->getDeclName(), D->getLocation(), + Sema::LookupUsingDeclName, Sema::ForRedeclaration); + UsingDecl *NewUD = UsingDecl::Create(SemaRef.Context, Owner, D->getLocation(), D->getNestedNameRange(), @@ -1051,34 +1060,55 @@ Decl *TemplateDeclInstantiator::VisitUsingDecl(UsingDecl *D) { CXXScopeSpec SS; SS.setScopeRep(D->getTargetNestedNameDecl()); SS.setRange(D->getNestedNameRange()); - if (SemaRef.CheckUsingDeclQualifier(D->getUsingLocation(), SS, + + if (CheckRedeclaration) { + Prev.setHideTags(false); + SemaRef.LookupQualifiedName(Prev, Owner); + + // Check for invalid redeclarations. + if (SemaRef.CheckUsingDeclRedeclaration(D->getUsingLocation(), + D->isTypeName(), SS, + D->getLocation(), Prev)) + NewUD->setInvalidDecl(); + + } + + if (!NewUD->isInvalidDecl() && + SemaRef.CheckUsingDeclQualifier(D->getUsingLocation(), SS, D->getLocation())) NewUD->setInvalidDecl(); + SemaRef.Context.setInstantiatedFromUsingDecl(NewUD, D); NewUD->setAccess(D->getAccess()); Owner->addDecl(NewUD); - // We'll transform the UsingShadowDecls as we reach them. + // Don't process the shadow decls for an invalid decl. + if (NewUD->isInvalidDecl()) + return NewUD; - return NewUD; -} + // Process the shadow decls. + for (UsingDecl::shadow_iterator I = D->shadow_begin(), E = D->shadow_end(); + I != E; ++I) { + UsingShadowDecl *Shadow = *I; + NamedDecl *InstTarget = + cast<NamedDecl>(SemaRef.FindInstantiatedDecl(Shadow->getTargetDecl(), + TemplateArgs)); -Decl *TemplateDeclInstantiator::VisitUsingShadowDecl(UsingShadowDecl *D) { - UsingDecl *InstUsing = - cast<UsingDecl>(SemaRef.FindInstantiatedDecl(D->getUsingDecl(), - TemplateArgs)); - NamedDecl *InstTarget = - cast<NamedDecl>(SemaRef.FindInstantiatedDecl(D->getTargetDecl(), - TemplateArgs)); + if (CheckRedeclaration && + SemaRef.CheckUsingShadowDecl(NewUD, InstTarget, Prev)) + continue; - UsingShadowDecl *InstD = SemaRef.BuildUsingShadowDecl(/*Scope*/ 0, - D->getAccess(), - InstUsing, - InstTarget); + UsingShadowDecl *InstShadow + = SemaRef.BuildUsingShadowDecl(/*Scope*/ 0, NewUD, InstTarget); + SemaRef.Context.setInstantiatedFromUsingShadowDecl(InstShadow, Shadow); + } - SemaRef.Context.setInstantiatedFromUsingShadowDecl(InstD, D); + return NewUD; +} - return InstD; +Decl *TemplateDeclInstantiator::VisitUsingShadowDecl(UsingShadowDecl *D) { + // Ignore these; we handle them in bulk when processing the UsingDecl. + return 0; } Decl * TemplateDeclInstantiator @@ -2087,7 +2117,10 @@ NamedDecl *Sema::FindInstantiatedDecl(NamedDecl *D, ParentDC->decls_end()); } - assert(Result && "Unable to find instantiation of declaration!"); + // UsingShadowDecls can instantiate to nothing because of using hiding. + assert((Result || isa<UsingShadowDecl>(D)) + && "Unable to find instantiation of declaration!"); + D = Result; } diff --git a/clang/lib/Sema/TreeTransform.h b/clang/lib/Sema/TreeTransform.h index 73ca797ce9b..be3c04302e3 100644 --- a/clang/lib/Sema/TreeTransform.h +++ b/clang/lib/Sema/TreeTransform.h @@ -4506,8 +4506,14 @@ TreeTransform<Derived>::TransformUnresolvedLookupExpr( for (UnresolvedLookupExpr::decls_iterator I = Old->decls_begin(), E = Old->decls_end(); I != E; ++I) { NamedDecl *InstD = static_cast<NamedDecl*>(getDerived().TransformDecl(*I)); - if (!InstD) - return SemaRef.ExprError(); + if (!InstD) { + // Silently ignore these if a UsingShadowDecl instantiated to nothing. + // This can happen because of dependent hiding. + if (isa<UsingShadowDecl>(*I)) + continue; + else + return SemaRef.ExprError(); + } // Expand using declarations. if (isa<UsingDecl>(InstD)) { @@ -4913,8 +4919,14 @@ TreeTransform<Derived>::TransformUnresolvedMemberExpr(UnresolvedMemberExpr *Old) for (UnresolvedMemberExpr::decls_iterator I = Old->decls_begin(), E = Old->decls_end(); I != E; ++I) { NamedDecl *InstD = static_cast<NamedDecl*>(getDerived().TransformDecl(*I)); - if (!InstD) - return SemaRef.ExprError(); + if (!InstD) { + // Silently ignore these if a UsingShadowDecl instantiated to nothing. + // This can happen because of dependent hiding. + if (isa<UsingShadowDecl>(*I)) + continue; + else + return SemaRef.ExprError(); + } // Expand using declarations. if (isa<UsingDecl>(InstD)) { |