diff --git a/clang/docs/ReleaseNotes.rst b/clang/docs/ReleaseNotes.rst index 0bd4857077879..35406bc274873 100644 --- a/clang/docs/ReleaseNotes.rst +++ b/clang/docs/ReleaseNotes.rst @@ -126,6 +126,8 @@ Improvements to Clang's diagnostics - Fixed fix-it hint for fold expressions. Clang now correctly places the suggested right parenthesis when diagnosing malformed fold expressions. (#GH151787) +- Improved diagnostic location for templates declared inside local classes. + Improvements to Clang's time-trace ---------------------------------- diff --git a/clang/lib/Sema/SemaTemplate.cpp b/clang/lib/Sema/SemaTemplate.cpp index 21fed2e8f6ca7..c39acc073fa11 100644 --- a/clang/lib/Sema/SemaTemplate.cpp +++ b/clang/lib/Sema/SemaTemplate.cpp @@ -8229,24 +8229,37 @@ Sema::CheckTemplateDeclScope(Scope *S, TemplateParameterList *TemplateParams) { // C++ [temp.class.spec]p6: [P2096] // A partial specialization may be declared in any scope in which the // corresponding primary template may be defined. + auto FindTemplateParamsLoc = [](TemplateParameterList *TemplateParams, + SourceLocation Fallback) { + SourceLocation DiagLoc = TemplateParams->getTemplateLoc(); + if (DiagLoc.isValid()) + return DiagLoc; + + for (const NamedDecl *Param : *TemplateParams) + if (Param && Param->getLocation().isValid()) + return Param->getLocation(); + + return Fallback; + }; + if (Ctx) { if (Ctx->isFileContext()) return false; if (CXXRecordDecl *RD = dyn_cast(Ctx)) { // C++ [temp.mem]p2: // A local class shall not have member templates. - if (RD->isLocalClass()) - return Diag(TemplateParams->getTemplateLoc(), + if (RD->isLocalClass()) { + return Diag(FindTemplateParamsLoc(TemplateParams, RD->getLocation()), diag::err_template_inside_local_class) - << TemplateParams->getSourceRange(); - else - return false; + << TemplateParams->getSourceRange(); + } + return false; } } - return Diag(TemplateParams->getTemplateLoc(), + return Diag(FindTemplateParamsLoc(TemplateParams, SourceLocation()), diag::err_template_outside_namespace_or_class_scope) - << TemplateParams->getSourceRange(); + << TemplateParams->getSourceRange(); } /// Determine what kind of template specialization the given declaration diff --git a/clang/test/SemaCXX/template-local-class.cpp b/clang/test/SemaCXX/template-local-class.cpp new file mode 100644 index 0000000000000..10f819f4d0ea0 --- /dev/null +++ b/clang/test/SemaCXX/template-local-class.cpp @@ -0,0 +1,9 @@ +// RUN: %clang_cc1 -fsyntax-only -verify %s + +void foo() { + struct Local { + template // expected-error {{member templates are not allowed inside local classes}} + void bar(); + }; +} +