diff options
Diffstat (limited to 'clang/lib/Sema')
-rw-r--r-- | clang/lib/Sema/SemaDecl.cpp | 44 | ||||
-rw-r--r-- | clang/lib/Sema/SemaDeclCXX.cpp | 4 | ||||
-rw-r--r-- | clang/lib/Sema/SemaTemplate.cpp | 121 | ||||
-rw-r--r-- | clang/lib/Sema/SemaTemplateInstantiateDecl.cpp | 3 |
4 files changed, 49 insertions, 123 deletions
diff --git a/clang/lib/Sema/SemaDecl.cpp b/clang/lib/Sema/SemaDecl.cpp index db598b05b3f..612761177cd 100644 --- a/clang/lib/Sema/SemaDecl.cpp +++ b/clang/lib/Sema/SemaDecl.cpp @@ -5231,10 +5231,13 @@ bool Sema::DiagnoseClassNameShadow(DeclContext *DC, /// /// \param Loc The location of the name of the entity being declared. /// +/// \param IsTemplateId Whether the name is a (simple-)template-id, and thus +/// we're declaring an explicit / partial specialization / instantiation. +/// /// \returns true if we cannot safely recover from this error, false otherwise. bool Sema::diagnoseQualifiedDeclaration(CXXScopeSpec &SS, DeclContext *DC, DeclarationName Name, - SourceLocation Loc) { + SourceLocation Loc, bool IsTemplateId) { DeclContext *Cur = CurContext; while (isa<LinkageSpecDecl>(Cur) || isa<CapturedDecl>(Cur)) Cur = Cur->getParent(); @@ -5261,8 +5264,9 @@ bool Sema::diagnoseQualifiedDeclaration(CXXScopeSpec &SS, DeclContext *DC, } // Check whether the qualifying scope encloses the scope of the original - // declaration. - if (!Cur->Encloses(DC)) { + // declaration. For a template-id, we perform the checks in + // CheckTemplateSpecializationScope. + if (!Cur->Encloses(DC) && !IsTemplateId) { if (Cur->isRecord()) Diag(Loc, diag::err_member_qualification) << Name << SS.getRange(); @@ -5374,8 +5378,9 @@ NamedDecl *Sema::HandleDeclarator(Scope *S, Declarator &D, return nullptr; } if (!D.getDeclSpec().isFriendSpecified()) { - if (diagnoseQualifiedDeclaration(D.getCXXScopeSpec(), DC, - Name, D.getIdentifierLoc())) { + if (diagnoseQualifiedDeclaration( + D.getCXXScopeSpec(), DC, Name, D.getIdentifierLoc(), + D.getName().getKind() == UnqualifiedIdKind::IK_TemplateId)) { if (DC->isRecord()) return nullptr; @@ -8828,10 +8833,6 @@ Sema::ActOnFunctionDeclarator(Scope *S, Declarator &D, DeclContext *DC, if (CurContext->isDependentContext() && CurContext->isRecord() && !isFriend) { isDependentClassScopeExplicitSpecialization = true; - Diag(NewFD->getLocation(), getLangOpts().MicrosoftExt ? - diag::ext_function_specialization_in_class : - diag::err_function_specialization_in_class) - << NewFD->getDeclName(); } else if (!NewFD->isInvalidDecl() && CheckFunctionTemplateSpecialization( NewFD, (HasExplicitTemplateArgs ? &TemplateArgs : nullptr), @@ -9117,12 +9118,12 @@ Sema::ActOnFunctionDeclarator(Scope *S, Declarator &D, DeclContext *DC, } // Here we have an function template explicit specialization at class scope. - // The actually specialization will be postponed to template instatiation + // The actual specialization will be postponed to template instatiation // time via the ClassScopeFunctionSpecializationDecl node. if (isDependentClassScopeExplicitSpecialization) { ClassScopeFunctionSpecializationDecl *NewSpec = ClassScopeFunctionSpecializationDecl::Create( - Context, CurContext, SourceLocation(), + Context, CurContext, NewFD->getLocation(), cast<CXXMethodDecl>(NewFD), HasExplicitTemplateArgs, TemplateArgs); CurContext->addDecl(NewSpec); @@ -9633,16 +9634,16 @@ bool Sema::CheckFunctionDeclaration(Scope *S, FunctionDecl *NewFD, Previous.clear(); Previous.addDecl(OldDecl); - if (FunctionTemplateDecl *OldTemplateDecl - = dyn_cast<FunctionTemplateDecl>(OldDecl)) { + if (FunctionTemplateDecl *OldTemplateDecl = + dyn_cast<FunctionTemplateDecl>(OldDecl)) { auto *OldFD = OldTemplateDecl->getTemplatedDecl(); NewFD->setPreviousDeclaration(OldFD); adjustDeclContextForDeclaratorDecl(NewFD, OldFD); FunctionTemplateDecl *NewTemplateDecl = NewFD->getDescribedFunctionTemplate(); assert(NewTemplateDecl && "Template/non-template mismatch"); - if (auto *Method = dyn_cast<CXXMethodDecl>(NewFD)) { - Method->setAccess(OldTemplateDecl->getAccess()); + if (NewFD->isCXXClassMember()) { + NewFD->setAccess(OldTemplateDecl->getAccess()); NewTemplateDecl->setAccess(OldTemplateDecl->getAccess()); } @@ -9668,7 +9669,7 @@ bool Sema::CheckFunctionDeclaration(Scope *S, FunctionDecl *NewFD, // This needs to happen first so that 'inline' propagates. NewFD->setPreviousDeclaration(OldFD); adjustDeclContextForDeclaratorDecl(NewFD, OldFD); - if (isa<CXXMethodDecl>(NewFD)) + if (NewFD->isCXXClassMember()) NewFD->setAccess(OldFD->getAccess()); } } @@ -14310,13 +14311,10 @@ CreateNewDecl: if (SS.isNotEmpty()) { if (SS.isSet()) { // If this is either a declaration or a definition, check the - // nested-name-specifier against the current context. We don't do this - // for explicit specializations, because they have similar checking - // (with more specific diagnostics) in the call to - // CheckMemberSpecialization, below. - if (!isMemberSpecialization && - (TUK == TUK_Definition || TUK == TUK_Declaration) && - diagnoseQualifiedDeclaration(SS, DC, OrigName, Loc)) + // nested-name-specifier against the current context. + if ((TUK == TUK_Definition || TUK == TUK_Declaration) && + diagnoseQualifiedDeclaration(SS, DC, OrigName, Loc, + isMemberSpecialization)) Invalid = true; New->setQualifierInfo(SS.getWithLocInContext(Context)); diff --git a/clang/lib/Sema/SemaDeclCXX.cpp b/clang/lib/Sema/SemaDeclCXX.cpp index 9e3647548be..6160eccabe8 100644 --- a/clang/lib/Sema/SemaDeclCXX.cpp +++ b/clang/lib/Sema/SemaDeclCXX.cpp @@ -3051,7 +3051,9 @@ Sema::ActOnCXXMemberDeclarator(Scope *S, AccessSpecifier AS, Declarator &D, // int X::member; // }; if (DeclContext *DC = computeDeclContext(SS, false)) - diagnoseQualifiedDeclaration(SS, DC, Name, D.getIdentifierLoc()); + diagnoseQualifiedDeclaration(SS, DC, Name, D.getIdentifierLoc(), + D.getName().getKind() == + UnqualifiedIdKind::IK_TemplateId); else Diag(D.getIdentifierLoc(), diag::err_member_qualification) << Name << SS.getRange(); diff --git a/clang/lib/Sema/SemaTemplate.cpp b/clang/lib/Sema/SemaTemplate.cpp index 12a74c1b64b..b5583d13951 100644 --- a/clang/lib/Sema/SemaTemplate.cpp +++ b/clang/lib/Sema/SemaTemplate.cpp @@ -1262,7 +1262,7 @@ Sema::CheckClassTemplate(Scope *S, unsigned TagSpec, TagUseKind TUK, if (RebuildTemplateParamsInCurrentInstantiation(TemplateParams)) Invalid = true; } else if (TUK != TUK_Friend && TUK != TUK_Reference) - diagnoseQualifiedDeclaration(SS, SemanticContext, Name, NameLoc); + diagnoseQualifiedDeclaration(SS, SemanticContext, Name, NameLoc, false); LookupQualifiedName(Previous, SemanticContext); } else { @@ -7124,120 +7124,43 @@ static bool CheckTemplateSpecializationScope(Sema &S, } // C++ [temp.expl.spec]p2: - // An explicit specialization shall be declared in the namespace - // of which the template is a member, or, for member templates, in - // the namespace of which the enclosing class or enclosing class - // template is a member. An explicit specialization of a member - // function, member class or static data member of a class - // template shall be declared in the namespace of which the class - // template is a member. Such a declaration may also be a - // definition. If the declaration is not a definition, the - // specialization may be defined later in the name- space in which - // the explicit specialization was declared, or in a namespace - // that encloses the one in which the explicit specialization was - // declared. + // An explicit specialization may be declared in any scope in which + // the corresponding primary template may be defined. if (S.CurContext->getRedeclContext()->isFunctionOrMethod()) { S.Diag(Loc, diag::err_template_spec_decl_function_scope) << Specialized; return true; } - if (S.CurContext->isRecord() && !IsPartialSpecialization) { - if (S.getLangOpts().MicrosoftExt) { - // Do not warn for class scope explicit specialization during - // instantiation, warning was already emitted during pattern - // semantic analysis. - if (!S.inTemplateInstantiation()) - S.Diag(Loc, diag::ext_function_specialization_in_class) - << Specialized; - } else { - S.Diag(Loc, diag::err_template_spec_decl_class_scope) - << Specialized; - return true; - } - } - - if (S.CurContext->isRecord() && - !S.CurContext->Equals(Specialized->getDeclContext())) { - // Make sure that we're specializing in the right record context. - // Otherwise, things can go horribly wrong. - S.Diag(Loc, diag::err_template_spec_decl_class_scope) - << Specialized; - return true; - } - // C++ [temp.class.spec]p6: - // A class template partial specialization may be declared or redeclared - // in any namespace scope in which its definition may be defined (14.5.1 - // and 14.5.2). - DeclContext *SpecializedContext - = Specialized->getDeclContext()->getEnclosingNamespaceContext(); - DeclContext *DC = S.CurContext->getEnclosingNamespaceContext(); - - // Make sure that this redeclaration (or definition) occurs in an enclosing - // namespace. - // Note that HandleDeclarator() performs this check for explicit - // specializations of function templates, static data members, and member - // functions, so we skip the check here for those kinds of entities. - // FIXME: HandleDeclarator's diagnostics aren't quite as good, though. - // Should we refactor that check, so that it occurs later? - if (!DC->Encloses(SpecializedContext) && - !(isa<FunctionTemplateDecl>(Specialized) || - isa<FunctionDecl>(Specialized) || - isa<VarTemplateDecl>(Specialized) || - isa<VarDecl>(Specialized))) { + // A class template partial specialization may be declared in any + // scope in which the primary template may be defined. + DeclContext *SpecializedContext = + Specialized->getDeclContext()->getRedeclContext(); + DeclContext *DC = S.CurContext->getRedeclContext(); + + // Make sure that this redeclaration (or definition) occurs in the same + // scope or an enclosing namespace. + if (!(DC->isFileContext() ? DC->Encloses(SpecializedContext) + : DC->Equals(SpecializedContext))) { if (isa<TranslationUnitDecl>(SpecializedContext)) S.Diag(Loc, diag::err_template_spec_redecl_global_scope) << EntityKind << Specialized; - else if (isa<NamespaceDecl>(SpecializedContext)) { + else { + auto *ND = cast<NamedDecl>(SpecializedContext); int Diag = diag::err_template_spec_redecl_out_of_scope; - if (S.getLangOpts().MicrosoftExt) + if (S.getLangOpts().MicrosoftExt && !DC->isRecord()) Diag = diag::ext_ms_template_spec_redecl_out_of_scope; S.Diag(Loc, Diag) << EntityKind << Specialized - << cast<NamedDecl>(SpecializedContext); - } else - llvm_unreachable("unexpected namespace context for specialization"); + << ND << isa<CXXRecordDecl>(ND); + } S.Diag(Specialized->getLocation(), diag::note_specialized_entity); - } else if ((!PrevDecl || - getTemplateSpecializationKind(PrevDecl) == TSK_Undeclared || - getTemplateSpecializationKind(PrevDecl) == - TSK_ImplicitInstantiation)) { - // C++ [temp.exp.spec]p2: - // An explicit specialization shall be declared in the namespace of which - // the template is a member, or, for member templates, in the namespace - // of which the enclosing class or enclosing class template is a member. - // An explicit specialization of a member function, member class or - // static data member of a class template shall be declared in the - // namespace of which the class template is a member. - // - // C++11 [temp.expl.spec]p2: - // An explicit specialization shall be declared in a namespace enclosing - // the specialized template. - // C++11 [temp.explicit]p3: - // An explicit instantiation shall appear in an enclosing namespace of its - // template. - if (!DC->InEnclosingNamespaceSetOf(SpecializedContext)) { - bool IsCPlusPlus11Extension = DC->Encloses(SpecializedContext); - if (isa<TranslationUnitDecl>(SpecializedContext)) { - assert(!IsCPlusPlus11Extension && - "DC encloses TU but isn't in enclosing namespace set"); - S.Diag(Loc, diag::err_template_spec_decl_out_of_scope_global) - << EntityKind << Specialized; - } else if (isa<NamespaceDecl>(SpecializedContext)) { - int Diag; - if (!IsCPlusPlus11Extension) - Diag = diag::err_template_spec_decl_out_of_scope; - else if (!S.getLangOpts().CPlusPlus11) - Diag = diag::ext_template_spec_decl_out_of_scope; - else - Diag = diag::warn_cxx98_compat_template_spec_decl_out_of_scope; - S.Diag(Loc, Diag) - << EntityKind << Specialized << cast<NamedDecl>(SpecializedContext); - } - S.Diag(Specialized->getLocation(), diag::note_specialized_entity); - } + // Don't allow specializing in the wrong class during error recovery. + // Otherwise, things can go horribly wrong. + if (DC->isRecord()) + return true; } return false; diff --git a/clang/lib/Sema/SemaTemplateInstantiateDecl.cpp b/clang/lib/Sema/SemaTemplateInstantiateDecl.cpp index df11315cbe6..6f04dedeed5 100644 --- a/clang/lib/Sema/SemaTemplateInstantiateDecl.cpp +++ b/clang/lib/Sema/SemaTemplateInstantiateDecl.cpp @@ -1653,6 +1653,7 @@ Decl *TemplateDeclInstantiator::VisitFunctionDecl(FunctionDecl *D, NameInfo, T, TInfo, D->getSourceRange().getEnd()); if (DGuide->isCopyDeductionCandidate()) cast<CXXDeductionGuideDecl>(Function)->setIsCopyDeductionCandidate(); + Function->setAccess(D->getAccess()); } else { Function = FunctionDecl::Create( SemaRef.Context, DC, D->getInnerLocStart(), NameInfo, T, TInfo, @@ -2711,6 +2712,8 @@ Decl *TemplateDeclInstantiator::VisitClassScopeFunctionSpecializationDecl( assert(Specialization && "Class scope Specialization is null"); SemaRef.Context.setClassScopeSpecializationPattern(Specialization, OldFD); + // FIXME: If this is a definition, check for redefinition errors! + return NewFD; } |