From: Richard Smith Date: Wed, 20 May 2015 17:50:35 +0000 (+0000) Subject: [modules] Support merging a parsed default function/template argument with an importe... X-Git-Url: https://granicus.if.org/sourcecode?a=commitdiff_plain;h=399b8bf979e19c7e905a655b70f33fbb1b96f761;p=clang [modules] Support merging a parsed default function/template argument with an imported but hidden one. git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@237814 91177308-0d34-0410-b5e6-96231b3b80d8 --- diff --git a/lib/Sema/SemaDeclCXX.cpp b/lib/Sema/SemaDeclCXX.cpp index c5d5d8f2e6..2833717171 100644 --- a/lib/Sema/SemaDeclCXX.cpp +++ b/lib/Sema/SemaDeclCXX.cpp @@ -438,6 +438,45 @@ bool Sema::MergeCXXFunctionDecl(FunctionDecl *New, FunctionDecl *Old, Scope *S) { bool Invalid = false; + // The declaration context corresponding to the scope is the semantic + // parent, unless this is a local function declaration, in which case + // it is that surrounding function. + DeclContext *ScopeDC = New->isLocalExternDecl() + ? New->getLexicalDeclContext() + : New->getDeclContext(); + + // Find the previous declaration for the purpose of default arguments. + FunctionDecl *PrevForDefaultArgs = Old; + for (/**/; PrevForDefaultArgs; + // Don't bother looking back past the latest decl if this is a local + // extern declaration; nothing else could work. + PrevForDefaultArgs = New->isLocalExternDecl() + ? nullptr + : PrevForDefaultArgs->getPreviousDecl()) { + // Ignore hidden declarations. + if (!LookupResult::isVisible(*this, PrevForDefaultArgs)) + continue; + + if (S && !isDeclInScope(PrevForDefaultArgs, ScopeDC, S) && + !New->isCXXClassMember()) { + // Ignore default arguments of old decl if they are not in + // the same scope and this is not an out-of-line definition of + // a member function. + continue; + } + + if (PrevForDefaultArgs->isLocalExternDecl() != New->isLocalExternDecl()) { + // If only one of these is a local function declaration, then they are + // declared in different scopes, even though isDeclInScope may think + // they're in the same scope. (If both are local, the scope check is + // sufficent, and if neither is local, then they are in the same scope.) + continue; + } + + // We found our guy. + break; + } + // C++ [dcl.fct.default]p4: // For non-template functions, default arguments can be added in // later declarations of a function in the same @@ -456,34 +495,17 @@ bool Sema::MergeCXXFunctionDecl(FunctionDecl *New, FunctionDecl *Old, // in a member function definition that appears outside of the class // definition are added to the set of default arguments provided by the // member function declaration in the class definition. - for (unsigned p = 0, NumParams = Old->getNumParams(); p < NumParams; ++p) { - ParmVarDecl *OldParam = Old->getParamDecl(p); + for (unsigned p = 0, NumParams = PrevForDefaultArgs + ? PrevForDefaultArgs->getNumParams() + : 0; + p < NumParams; ++p) { + ParmVarDecl *OldParam = PrevForDefaultArgs->getParamDecl(p); ParmVarDecl *NewParam = New->getParamDecl(p); - bool OldParamHasDfl = OldParam->hasDefaultArg(); + bool OldParamHasDfl = OldParam ? OldParam->hasDefaultArg() : false; bool NewParamHasDfl = NewParam->hasDefaultArg(); - // The declaration context corresponding to the scope is the semantic - // parent, unless this is a local function declaration, in which case - // it is that surrounding function. - DeclContext *ScopeDC = New->isLocalExternDecl() - ? New->getLexicalDeclContext() - : New->getDeclContext(); - if (S && !isDeclInScope(Old, ScopeDC, S) && - !New->getDeclContext()->isRecord()) - // Ignore default parameters of old decl if they are not in - // the same scope and this is not an out-of-line definition of - // a member function. - OldParamHasDfl = false; - if (New->isLocalExternDecl() != Old->isLocalExternDecl()) - // If only one of these is a local function declaration, then they are - // declared in different scopes, even though isDeclInScope may think - // they're in the same scope. (If both are local, the scope check is - // sufficent, and if neither is local, then they are in the same scope.) - OldParamHasDfl = false; - if (OldParamHasDfl && NewParamHasDfl) { - unsigned DiagDefaultParamID = diag::err_param_default_argument_redefinition; @@ -491,7 +513,7 @@ bool Sema::MergeCXXFunctionDecl(FunctionDecl *New, FunctionDecl *Old, // of template class. The new default parameter's value is ignored. Invalid = true; if (getLangOpts().MicrosoftExt) { - CXXMethodDecl* MD = dyn_cast(New); + CXXMethodDecl *MD = dyn_cast(New); if (MD && MD->getParent()->getDescribedClassTemplate()) { // Merge the old default argument into the new parameter. NewParam->setHasInheritedDefaultArg(); @@ -518,7 +540,8 @@ bool Sema::MergeCXXFunctionDecl(FunctionDecl *New, FunctionDecl *Old, // Look for the function declaration where the default argument was // actually written, which may be a declaration prior to Old. - for (auto Older = Old; OldParam->hasInheritedDefaultArg();) { + for (auto Older = PrevForDefaultArgs; + OldParam->hasInheritedDefaultArg(); /**/) { Older = Older->getPreviousDecl(); OldParam = Older->getParamDecl(p); } @@ -543,8 +566,9 @@ bool Sema::MergeCXXFunctionDecl(FunctionDecl *New, FunctionDecl *Old, Diag(NewParam->getLocation(), diag::err_param_default_argument_template_redecl) << NewParam->getDefaultArgRange(); - Diag(Old->getLocation(), diag::note_template_prev_declaration) - << false; + Diag(PrevForDefaultArgs->getLocation(), + diag::note_template_prev_declaration) + << false; } else if (New->getTemplateSpecializationKind() != TSK_ImplicitInstantiation && New->getTemplateSpecializationKind() != TSK_Undeclared) { diff --git a/lib/Sema/SemaLookup.cpp b/lib/Sema/SemaLookup.cpp index a8a143fa9a..c745b136be 100644 --- a/lib/Sema/SemaLookup.cpp +++ b/lib/Sema/SemaLookup.cpp @@ -1304,7 +1304,12 @@ bool LookupResult::isVisibleSlow(Sema &SemaRef, NamedDecl *D) { DeclContext *DC = D->getLexicalDeclContext(); if (!D->isModulePrivate() && DC && !DC->isFileContext() && !isa(DC)) { - if (SemaRef.hasVisibleDefinition(cast(DC))) { + // For a parameter, check whether our current template declaration's + // lexical context is visible, not whether there's some other visible + // definition of it, because parameters aren't "within" the definition. + if ((D->isTemplateParameter() || isa(D)) + ? isVisible(SemaRef, cast(DC)) + : SemaRef.hasVisibleDefinition(cast(DC))) { if (SemaRef.ActiveTemplateInstantiations.empty() && // FIXME: Do something better in this case. !SemaRef.getLangOpts().ModulesLocalVisibility) { diff --git a/lib/Sema/SemaTemplate.cpp b/lib/Sema/SemaTemplate.cpp index 5319836c24..9546d38fc3 100644 --- a/lib/Sema/SemaTemplate.cpp +++ b/lib/Sema/SemaTemplate.cpp @@ -1310,6 +1310,9 @@ bool Sema::CheckTemplateParameterList(TemplateParameterList *NewParams, // Merge default arguments for template type parameters. TemplateTypeParmDecl *OldTypeParm = OldParams? cast(*OldParam) : nullptr; + // FIXME: There might be a visible declaration of this template parameter. + if (OldTypeParm && !LookupResult::isVisible(*this, OldTypeParm)) + OldTypeParm = nullptr; if (NewTypeParm->isParameterPack()) { assert(!NewTypeParm->hasDefaultArgument() && diff --git a/test/Modules/Inputs/submodules-merge-defs/defs.h b/test/Modules/Inputs/submodules-merge-defs/defs.h index f864d5762d..2ec56027ad 100644 --- a/test/Modules/Inputs/submodules-merge-defs/defs.h +++ b/test/Modules/Inputs/submodules-merge-defs/defs.h @@ -43,3 +43,5 @@ namespace G { typedef enum { i, j } k; typedef enum {} l; } + +template int H(int a = 1);