summaryrefslogtreecommitdiffstats
path: root/clang/lib
diff options
context:
space:
mode:
Diffstat (limited to 'clang/lib')
-rw-r--r--clang/lib/AST/DeclBase.cpp40
-rw-r--r--clang/lib/Sema/Sema.h22
-rw-r--r--clang/lib/Sema/SemaDecl.cpp11
-rw-r--r--clang/lib/Sema/SemaDeclCXX.cpp306
-rw-r--r--clang/lib/Sema/SemaLookup.cpp11
-rw-r--r--clang/lib/Sema/SemaOverload.cpp15
-rw-r--r--clang/lib/Sema/SemaTemplateInstantiateDecl.cpp73
-rw-r--r--clang/lib/Sema/TreeTransform.h20
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)) {
OpenPOWER on IntegriCloud