diff --git a/clang/include/clang/Basic/DiagnosticSemaKinds.td b/clang/include/clang/Basic/DiagnosticSemaKinds.td index e19b169513411..89ca3e9d7ed54 100644 --- a/clang/include/clang/Basic/DiagnosticSemaKinds.td +++ b/clang/include/clang/Basic/DiagnosticSemaKinds.td @@ -12197,7 +12197,7 @@ def err_sycl_entry_point_on_main : Error< def err_sycl_kernel_name_type : Error< "'sycl_kernel_entry_point' kernel name argument must be a class type">; def err_sycl_kernel_name_conflict : Error< - "'sycl_kernel_entry_point' kernel name argument conflicts with a previous" + "'sycl_kernel_entry_point' kernel name %0 conflicts with a previous" " declaration">; def warn_cuda_maxclusterrank_sm_90 : Warning< diff --git a/clang/include/clang/Sema/Sema.h b/clang/include/clang/Sema/Sema.h index 4d4579fcfd456..26e06630f2adf 100644 --- a/clang/include/clang/Sema/Sema.h +++ b/clang/include/clang/Sema/Sema.h @@ -10348,6 +10348,8 @@ class Sema final : public SemaBase { PrintPragmaAttributeInstantiationPoint(); } void PrintInstantiationStack(); + void + PrintInstantiationStack(std::function); /// Determines whether we are currently in a context where /// template argument substitution failures are not considered diff --git a/clang/include/clang/Sema/SemaSYCL.h b/clang/include/clang/Sema/SemaSYCL.h index 4016c1dd0a90f..6cc7b4ebf82f1 100644 --- a/clang/include/clang/Sema/SemaSYCL.h +++ b/clang/include/clang/Sema/SemaSYCL.h @@ -28,6 +28,19 @@ class SemaSYCL : public SemaBase { public: SemaSYCL(Sema &S); + using ContextNotes = SmallVector; + llvm::DenseMap, ContextNotes> + SYCLKernelEntryContextNotes; + // Similar to SuppressedDiagnostics, + // we don't emit diagnostics straight away in case of template instantiation. + // This is to work around the fact that during overload resolution we end up + // instantiating decls without commiting to use them. During attribute checks + // we can not tell if the decl will actually be selected and therefore needed. + // We emit the diagnostic and raise them iff they are required. + typedef llvm::DenseMap> + SuppressedDiagnosticsMap; + SuppressedDiagnosticsMap EntryPointSuppressedDiagnostics; + /// Creates a SemaDiagnosticBuilder that emits the diagnostic if the current /// context is "used as device code". /// @@ -66,6 +79,7 @@ class SemaSYCL : public SemaBase { void CheckSYCLEntryPointFunctionDecl(FunctionDecl *FD); StmtResult BuildSYCLKernelCallStmt(FunctionDecl *FD, Stmt *Body); + bool EmitDelayedKernelEntryPointDiagnostics(Decl *FD); }; } // namespace clang diff --git a/clang/lib/Sema/SemaDecl.cpp b/clang/lib/Sema/SemaDecl.cpp index bc5b5a6cfb06f..6674af0b5f3e8 100644 --- a/clang/lib/Sema/SemaDecl.cpp +++ b/clang/lib/Sema/SemaDecl.cpp @@ -16049,38 +16049,39 @@ Decl *Sema::ActOnFinishFunctionBody(Decl *dcl, Stmt *Body, CheckCoroutineWrapper(FD); } - // Create SYCL kernel entry point function outline. - if (FD && !FD->isInvalidDecl() && !FD->isDependentContext() && - FD->hasAttr()) { - if (FD->isDeleted()) { - Diag(FD->getAttr()->getLocation(), - diag::err_sycl_entry_point_invalid) - << /*deleted function*/2; - FD->setInvalidDecl(); - } else if (FD->isDefaulted()) { - Diag(FD->getAttr()->getLocation(), - diag::err_sycl_entry_point_invalid) - << /*defaulted function*/3; - FD->setInvalidDecl(); - } else if (FSI->isCoroutine()) { - Diag(FD->getAttr()->getLocation(), - diag::err_sycl_entry_point_invalid) - << /*coroutine*/7; - FD->setInvalidDecl(); - } else if (Body) { - StmtResult SR = SYCL().BuildSYCLKernelCallStmt(FD, Body); - if (SR.isInvalid()) - return nullptr; - Body = SR.get(); - } - } - { // Do not call PopExpressionEvaluationContext() if it is a lambda because // one is already popped when finishing the lambda in BuildLambdaExpr(). // This is meant to pop the context added in ActOnStartOfFunctionDef(). ExitFunctionBodyRAII ExitRAII(*this, isLambdaCallOperator(FD)); if (FD) { + // Create SYCL kernel entry point function outline. + if (!FD->isInvalidDecl() && !FD->isDependentContext() && + FD->hasAttr()) { + if (FD->isDeleted()) { + Diag(FD->getAttr()->getLocation(), + diag::err_sycl_entry_point_invalid) + << /*deleted function*/2; + FD->setInvalidDecl(); + } else if (FD->isDefaulted()) { + Diag(FD->getAttr()->getLocation(), + diag::err_sycl_entry_point_invalid) + << /*defaulted function*/3; + FD->setInvalidDecl(); + } else if (FSI->isCoroutine()) { + Diag(FD->getAttr()->getLocation(), + diag::err_sycl_entry_point_invalid) + << /*coroutine*/7; + FD->setInvalidDecl(); + } else if (Body) { + StmtResult SR = SYCL().BuildSYCLKernelCallStmt(FD, Body); + if (SR.isInvalid()) { + FD->setInvalidDecl(); + return nullptr; + } + Body = SR.get(); + } + } // If this is called by Parser::ParseFunctionDefinition() after marking // the declaration as deleted, and if the deleted-function-body contains // a message (C++26), then a DefaultedOrDeletedInfo will have already been diff --git a/clang/lib/Sema/SemaExpr.cpp b/clang/lib/Sema/SemaExpr.cpp index 54185c6c9225b..e2c0f01d4c68d 100644 --- a/clang/lib/Sema/SemaExpr.cpp +++ b/clang/lib/Sema/SemaExpr.cpp @@ -255,6 +255,7 @@ bool Sema::DiagnoseUseOfDecl(NamedDecl *D, ArrayRef Locs, diagnoseUnavailableAlignedAllocation(*cast(D), Loc); } + SYCL().EmitDelayedKernelEntryPointDiagnostics(D->getCanonicalDecl()); // See if this is an auto-typed variable whose initializer we are parsing. if (ParsingInitForAutoVars.count(D)) { diff --git a/clang/lib/Sema/SemaSYCL.cpp b/clang/lib/Sema/SemaSYCL.cpp index 559b8351a5e9e..d8834ea1c0e05 100644 --- a/clang/lib/Sema/SemaSYCL.cpp +++ b/clang/lib/Sema/SemaSYCL.cpp @@ -208,8 +208,41 @@ void SemaSYCL::handleKernelEntryPointAttr(Decl *D, const ParsedAttr &AL) { TypeSourceInfo *TSI = nullptr; (void)SemaRef.GetTypeFromParser(PT, &TSI); assert(TSI && "no type source info for attribute argument"); - D->addAttr(::new (SemaRef.Context) SYCLKernelEntryPointAttr(SemaRef.Context, - AL, TSI)); + + FunctionDecl *FD = dyn_cast(D); + assert(FD && "Not a function decl"); + + bool hasError = false; + if (auto *MD = dyn_cast(D)) { + if (!MD->isStatic()) { + Diag(AL.getLoc(), diag::err_sycl_entry_point_invalid) + << /*non-static member function*/ 0; + hasError = true; + } + } + if (FD->isVariadic()) { + Diag(AL.getLoc(), diag::err_sycl_entry_point_invalid) + << /*variadic function*/ 1; + hasError = true; + } + if (FD->isConsteval()) { + Diag(AL.getLoc(), diag::err_sycl_entry_point_invalid) + << /*consteval function*/ 5; + hasError = true; + } else if (FD->isConstexpr()) { + Diag(AL.getLoc(), diag::err_sycl_entry_point_invalid) + << /*constexpr function*/ 4; + hasError = true; + } + QualType Ret = FD->getReturnType(); + if (!Ret->isDependentType() && !Ret->isVoidType()) { + Diag(AL.getLoc(), diag::err_sycl_entry_point_return_type); + hasError = true; + } + + if (!hasError) + D->addAttr(::new (SemaRef.Context) + SYCLKernelEntryPointAttr(SemaRef.Context, AL, TSI)); } namespace { @@ -259,6 +292,23 @@ class OutlinedFunctionDeclBodyInstantiator ParmDeclMap &MapRef; }; +void DiagnoseSYCLEntryPoint(Sema &S, FunctionDecl *FD, + const PartialDiagnosticAt &Diag) { + if (S.inTemplateInstantiation()) { + // We are synthesizing decls but we may not commit to use at all. + // Delay diagnostics until we know it is needed. + auto &SuppressedDiags = S.SYCL().EntryPointSuppressedDiagnostics[FD]; + SuppressedDiags.push_back(Diag); + if (S.getDiagnostics().getDiagnosticLevel( + Diag.second.getDiagID(), Diag.first) >= DiagnosticsEngine::Warning) + S.PrintInstantiationStack([&](const PartialDiagnosticAt &PD) { + SuppressedDiags.push_back(PD); + }); + } else { + S.Diag(Diag.first, Diag.second); + } +} + } // unnamed namespace void SemaSYCL::CheckSYCLEntryPointFunctionDecl(FunctionDecl *FD) { @@ -266,22 +316,29 @@ void SemaSYCL::CheckSYCLEntryPointFunctionDecl(FunctionDecl *FD) { // and warn about any redundant ones. const SYCLKernelEntryPointAttr *SKEPAttr = nullptr; for (auto SAI = FD->specific_attr_begin(); - SAI != FD->specific_attr_end(); - ++SAI) { + SAI != FD->specific_attr_end(); ++SAI) { if (!SKEPAttr) { SKEPAttr = *SAI; continue; } if (!getASTContext().hasSameType(SAI->getKernelName(), SKEPAttr->getKernelName())) { - Diag(SAI->getLocation(), diag::err_sycl_entry_point_invalid_redeclaration) - << SAI->getKernelName() << SKEPAttr->getKernelName(); - Diag(SKEPAttr->getLocation(), diag::note_previous_attribute); - FD->setInvalidDecl(); + DiagnoseSYCLEntryPoint( + SemaRef, FD, + {SAI->getLocation(), + PDiag(diag::err_sycl_entry_point_invalid_redeclaration) + << SAI->getKernelName() << SKEPAttr->getKernelName()}); + DiagnoseSYCLEntryPoint( + SemaRef, FD, + {SKEPAttr->getLocation(), PDiag(diag::note_previous_attribute)}); } else { - Diag(SAI->getLocation(), - diag::warn_sycl_entry_point_redundant_declaration); - Diag(SKEPAttr->getLocation(), diag::note_previous_attribute); + DiagnoseSYCLEntryPoint( + SemaRef, FD, + {SAI->getLocation(), + PDiag(diag::warn_sycl_entry_point_redundant_declaration)}); + DiagnoseSYCLEntryPoint( + SemaRef, FD, + {SKEPAttr->getLocation(), PDiag(diag::note_previous_attribute)}); } } assert(SKEPAttr && "Missing sycl_kernel_entry_point attribute"); @@ -289,8 +346,9 @@ void SemaSYCL::CheckSYCLEntryPointFunctionDecl(FunctionDecl *FD) { // Ensure the kernel name type is a class type. if (!SKEPAttr->getKernelName()->isDependentType() && !SKEPAttr->getKernelName()->isStructureOrClassType()) { - Diag(SKEPAttr->getLocation(), diag::err_sycl_kernel_name_type); - FD->setInvalidDecl(); + DiagnoseSYCLEntryPoint( + SemaRef, FD, + {SKEPAttr->getLocation(), PDiag(diag::err_sycl_kernel_name_type)}); } // Ensure that an attribute present on the previous declaration @@ -301,46 +359,30 @@ void SemaSYCL::CheckSYCLEntryPointFunctionDecl(FunctionDecl *FD) { if (PrevSKEPAttr) { if (!getASTContext().hasSameType(SKEPAttr->getKernelName(), PrevSKEPAttr->getKernelName())) { - Diag(SKEPAttr->getLocation(), - diag::err_sycl_entry_point_invalid_redeclaration) - << SKEPAttr->getKernelName() << PrevSKEPAttr->getKernelName(); - Diag(PrevSKEPAttr->getLocation(), diag::note_previous_decl) - << PrevFD;; - FD->setInvalidDecl(); + DiagnoseSYCLEntryPoint( + SemaRef, FD, + {SKEPAttr->getLocation(), + PDiag(diag::err_sycl_entry_point_invalid_redeclaration) + << SKEPAttr->getKernelName() + << PrevSKEPAttr->getKernelName()}); + DiagnoseSYCLEntryPoint(SemaRef, FD, + {PrevSKEPAttr->getLocation(), + PDiag(diag::note_previous_decl) << PrevFD}); } } } - if (auto *MD = dyn_cast(FD)) { - if (!MD->isStatic()) { - Diag(SKEPAttr->getLocation(), diag::err_sycl_entry_point_invalid) - << /*non-static member function*/0; - FD->setInvalidDecl(); - } - } - if (FD->isVariadic()) { - Diag(SKEPAttr->getLocation(), diag::err_sycl_entry_point_invalid) - << /*variadic function*/1; - FD->setInvalidDecl(); - } - if (FD->isConsteval()) { - Diag(SKEPAttr->getLocation(), diag::err_sycl_entry_point_invalid) - << /*consteval function*/5; - FD->setInvalidDecl(); - } else if (FD->isConstexpr()) { - Diag(SKEPAttr->getLocation(), diag::err_sycl_entry_point_invalid) - << /*constexpr function*/4; - FD->setInvalidDecl(); - } if (FD->isNoReturn()) { - Diag(SKEPAttr->getLocation(), diag::err_sycl_entry_point_invalid) - << /*noreturn function*/6; - FD->setInvalidDecl(); + DiagnoseSYCLEntryPoint( + SemaRef, FD, + {SKEPAttr->getLocation(), PDiag(diag::err_sycl_entry_point_invalid) + << /*noreturn function*/ 6}); } if (!FD->getReturnType()->isVoidType()) { - Diag(SKEPAttr->getLocation(), diag::err_sycl_entry_point_return_type); - FD->setInvalidDecl(); + DiagnoseSYCLEntryPoint(SemaRef, FD, + {SKEPAttr->getLocation(), + PDiag(diag::err_sycl_entry_point_return_type)}); } if (!FD->isInvalidDecl() && !FD->isDependentContext()) { @@ -348,14 +390,24 @@ void SemaSYCL::CheckSYCLEntryPointFunctionDecl(FunctionDecl *FD) { getASTContext().findSYCLKernelInfo(SKEPAttr->getKernelName()); if (SKI) { if (!declaresSameEntity(FD, SKI->GetKernelEntryPointDecl())) { - // FIXME: This diagnostic should include the origin of the kernel - // FIXME: names; not just the locations of the conflicting declarations. - Diag(FD->getLocation(), diag::err_sycl_kernel_name_conflict); - Diag(SKI->GetKernelEntryPointDecl()->getLocation(), - diag::note_previous_declaration); - FD->setInvalidDecl(); + DiagnoseSYCLEntryPoint( + SemaRef, FD, + {FD->getLocation(), PDiag(diag::err_sycl_kernel_name_conflict) + << SKEPAttr->getKernelName()}); + DiagnoseSYCLEntryPoint(SemaRef, FD, + {SKI->GetKernelEntryPointDecl()->getLocation(), + PDiag(diag::note_previous_declaration)}); + for (const PartialDiagnosticAt &PD : + SYCLKernelEntryContextNotes.at(SKI->GetKernelEntryPointDecl())) { + DiagnoseSYCLEntryPoint(SemaRef, FD, PD); + } } } else { + // Note: In order to not interfere with SFINAE, we delay the diagnostic of + // conflicting names to when we act on the attribute. + ContextNotes &Notes = SYCLKernelEntryContextNotes[FD]; + SemaRef.PrintInstantiationStack( + [&](const PartialDiagnosticAt &PD) { Notes.push_back(PD); }); getASTContext().registerSYCLEntryPointFunction(FD); } } @@ -373,8 +425,10 @@ StmtResult SemaSYCL::BuildSYCLKernelCallStmt(FunctionDecl *FD, Stmt *Body) { // stored declaration matches. const SYCLKernelInfo &SKI = getASTContext().getSYCLKernelInfo(SKEPAttr->getKernelName()); - if (!declaresSameEntity(SKI.GetKernelEntryPointDecl(), FD)) - llvm::report_fatal_error("SYCL kernel name conflict"); + if (!declaresSameEntity(SKI.GetKernelEntryPointDecl(), FD)) { + FD->setInvalidDecl(); + return {/*Invalid=*/true}; + } using ParmDeclMap = OutlinedFunctionDeclBodyInstantiator::ParmDeclMap; ParmDeclMap ParmMap; @@ -401,3 +455,17 @@ StmtResult SemaSYCL::BuildSYCLKernelCallStmt(FunctionDecl *FD, Stmt *Body) { return NewBody; } + +bool SemaSYCL::EmitDelayedKernelEntryPointDiagnostics(Decl *FD) { + auto Pos = EntryPointSuppressedDiagnostics.find(FD); + if (Pos != EntryPointSuppressedDiagnostics.end()) { + for (const PartialDiagnosticAt &Suppressed : Pos->second) { + DiagnosticBuilder Builder(SemaRef.Diags.Report( + Suppressed.first, Suppressed.second.getDiagID())); + Suppressed.second.Emit(Builder); + } + Pos->second.clear(); + return true; + } + return false; +} diff --git a/clang/lib/Sema/SemaTemplate.cpp b/clang/lib/Sema/SemaTemplate.cpp index a032e3ec6f635..9e090f61e2727 100644 --- a/clang/lib/Sema/SemaTemplate.cpp +++ b/clang/lib/Sema/SemaTemplate.cpp @@ -11684,6 +11684,8 @@ DeclResult Sema::ActOnExplicitInstantiation(Scope *S, diag::ext_explicit_instantiation_without_qualified_id) << Specialization << D.getCXXScopeSpec().getRange(); + SYCL().EmitDelayedKernelEntryPointDiagnostics(Specialization); + CheckExplicitInstantiation( *this, FunTmpl ? (NamedDecl *)FunTmpl diff --git a/clang/lib/Sema/SemaTemplateInstantiate.cpp b/clang/lib/Sema/SemaTemplateInstantiate.cpp index 863cc53c55afa..4a415a645f1f2 100644 --- a/clang/lib/Sema/SemaTemplateInstantiate.cpp +++ b/clang/lib/Sema/SemaTemplateInstantiate.cpp @@ -923,10 +923,16 @@ bool Sema::InstantiatingTemplate::CheckInstantiationDepth( << SemaRef.getLangOpts().InstantiationDepth; return true; } - +void Sema::PrintInstantiationStack() { + PrintInstantiationStack([&, this](const PartialDiagnosticAt &PD) { + DiagnosticBuilder Builder(Diags.Report(PD.first, PD.second.getDiagID())); + PD.second.Emit(Builder); + }); +} /// Prints the current instantiation stack through a series of /// notes. -void Sema::PrintInstantiationStack() { +void Sema::PrintInstantiationStack( + std::function EmitDiag) { // Determine which template instantiations to skip, if any. unsigned SkipStart = CodeSynthesisContexts.size(), SkipEnd = SkipStart; unsigned Limit = Diags.getTemplateBacktraceLimit(); @@ -946,9 +952,9 @@ void Sema::PrintInstantiationStack() { if (InstantiationIdx >= SkipStart && InstantiationIdx < SkipEnd) { if (InstantiationIdx == SkipStart) { // Note that we're skipping instantiations. - Diags.Report(Active->PointOfInstantiation, - diag::note_instantiation_contexts_suppressed) - << unsigned(CodeSynthesisContexts.size() - Limit); + EmitDiag({Active->PointOfInstantiation, + PDiag(diag::note_instantiation_contexts_suppressed) + << unsigned(CodeSynthesisContexts.size() - Limit)}); } continue; } @@ -960,37 +966,34 @@ void Sema::PrintInstantiationStack() { unsigned DiagID = diag::note_template_member_class_here; if (isa(Record)) DiagID = diag::note_template_class_instantiation_here; - Diags.Report(Active->PointOfInstantiation, DiagID) - << Record << Active->InstantiationRange; + EmitDiag({Active->PointOfInstantiation, + PDiag(DiagID) << Record << Active->InstantiationRange}); } else if (FunctionDecl *Function = dyn_cast(D)) { unsigned DiagID; if (Function->getPrimaryTemplate()) DiagID = diag::note_function_template_spec_here; else DiagID = diag::note_template_member_function_here; - Diags.Report(Active->PointOfInstantiation, DiagID) - << Function - << Active->InstantiationRange; + EmitDiag({Active->PointOfInstantiation, + PDiag(DiagID) << Function << Active->InstantiationRange}); } else if (VarDecl *VD = dyn_cast(D)) { - Diags.Report(Active->PointOfInstantiation, - VD->isStaticDataMember()? - diag::note_template_static_data_member_def_here - : diag::note_template_variable_def_here) - << VD - << Active->InstantiationRange; + EmitDiag({Active->PointOfInstantiation, + PDiag(VD->isStaticDataMember() + ? diag::note_template_static_data_member_def_here + : diag::note_template_variable_def_here) + << VD << Active->InstantiationRange}); } else if (EnumDecl *ED = dyn_cast(D)) { - Diags.Report(Active->PointOfInstantiation, - diag::note_template_enum_def_here) - << ED - << Active->InstantiationRange; + EmitDiag({Active->PointOfInstantiation, + PDiag(diag::note_template_enum_def_here) + << ED << Active->InstantiationRange}); } else if (FieldDecl *FD = dyn_cast(D)) { - Diags.Report(Active->PointOfInstantiation, - diag::note_template_nsdmi_here) - << FD << Active->InstantiationRange; + EmitDiag({Active->PointOfInstantiation, + PDiag(diag::note_template_nsdmi_here) + << FD << Active->InstantiationRange}); } else if (ClassTemplateDecl *CTD = dyn_cast(D)) { - Diags.Report(Active->PointOfInstantiation, - diag::note_template_class_instantiation_here) - << CTD << Active->InstantiationRange; + EmitDiag({Active->PointOfInstantiation, + PDiag(diag::note_template_class_instantiation_here) + << CTD << Active->InstantiationRange}); } break; } @@ -1002,35 +1005,35 @@ void Sema::PrintInstantiationStack() { Template->printName(OS, getPrintingPolicy()); printTemplateArgumentList(OS, Active->template_arguments(), getPrintingPolicy()); - Diags.Report(Active->PointOfInstantiation, - diag::note_default_arg_instantiation_here) - << OS.str() - << Active->InstantiationRange; + EmitDiag({Active->PointOfInstantiation, + PDiag(diag::note_default_arg_instantiation_here) + << OS.str() << Active->InstantiationRange}); break; } case CodeSynthesisContext::ExplicitTemplateArgumentSubstitution: { FunctionTemplateDecl *FnTmpl = cast(Active->Entity); - Diags.Report(Active->PointOfInstantiation, - diag::note_explicit_template_arg_substitution_here) - << FnTmpl - << getTemplateArgumentBindingsText(FnTmpl->getTemplateParameters(), - Active->TemplateArgs, - Active->NumTemplateArgs) - << Active->InstantiationRange; + EmitDiag({Active->PointOfInstantiation, + PDiag(diag::note_explicit_template_arg_substitution_here) + << FnTmpl + << getTemplateArgumentBindingsText( + FnTmpl->getTemplateParameters(), + Active->TemplateArgs, Active->NumTemplateArgs) + << Active->InstantiationRange}); break; } case CodeSynthesisContext::DeducedTemplateArgumentSubstitution: { if (FunctionTemplateDecl *FnTmpl = dyn_cast(Active->Entity)) { - Diags.Report(Active->PointOfInstantiation, - diag::note_function_template_deduction_instantiation_here) - << FnTmpl - << getTemplateArgumentBindingsText(FnTmpl->getTemplateParameters(), - Active->TemplateArgs, - Active->NumTemplateArgs) - << Active->InstantiationRange; + EmitDiag( + {Active->PointOfInstantiation, + PDiag(diag::note_function_template_deduction_instantiation_here) + << FnTmpl + << getTemplateArgumentBindingsText( + FnTmpl->getTemplateParameters(), Active->TemplateArgs, + Active->NumTemplateArgs) + << Active->InstantiationRange}); } else { bool IsVar = isa(Active->Entity) || isa(Active->Entity); @@ -1049,12 +1052,13 @@ void Sema::PrintInstantiationStack() { llvm_unreachable("unexpected template kind"); } - Diags.Report(Active->PointOfInstantiation, - diag::note_deduced_template_arg_substitution_here) - << IsVar << IsTemplate << cast(Active->Entity) - << getTemplateArgumentBindingsText(Params, Active->TemplateArgs, - Active->NumTemplateArgs) - << Active->InstantiationRange; + EmitDiag( + {Active->PointOfInstantiation, + PDiag(diag::note_deduced_template_arg_substitution_here) + << IsVar << IsTemplate << cast(Active->Entity) + << getTemplateArgumentBindingsText( + Params, Active->TemplateArgs, Active->NumTemplateArgs) + << Active->InstantiationRange}); } break; } @@ -1068,10 +1072,9 @@ void Sema::PrintInstantiationStack() { FD->printName(OS, getPrintingPolicy()); printTemplateArgumentList(OS, Active->template_arguments(), getPrintingPolicy()); - Diags.Report(Active->PointOfInstantiation, - diag::note_default_function_arg_instantiation_here) - << OS.str() - << Active->InstantiationRange; + EmitDiag({Active->PointOfInstantiation, + PDiag(diag::note_default_function_arg_instantiation_here) + << OS.str() << Active->InstantiationRange}); break; } @@ -1088,14 +1091,13 @@ void Sema::PrintInstantiationStack() { TemplateParams = cast(Active->Template) ->getTemplateParameters(); - Diags.Report(Active->PointOfInstantiation, - diag::note_prior_template_arg_substitution) - << isa(Parm) - << Name - << getTemplateArgumentBindingsText(TemplateParams, - Active->TemplateArgs, - Active->NumTemplateArgs) - << Active->InstantiationRange; + EmitDiag({Active->PointOfInstantiation, + PDiag(diag::note_prior_template_arg_substitution) + << isa(Parm) << Name + << getTemplateArgumentBindingsText(TemplateParams, + Active->TemplateArgs, + Active->NumTemplateArgs) + << Active->InstantiationRange}); break; } @@ -1108,55 +1110,56 @@ void Sema::PrintInstantiationStack() { cast(Active->Template) ->getTemplateParameters(); - Diags.Report(Active->PointOfInstantiation, - diag::note_template_default_arg_checking) - << getTemplateArgumentBindingsText(TemplateParams, - Active->TemplateArgs, - Active->NumTemplateArgs) - << Active->InstantiationRange; + EmitDiag({Active->PointOfInstantiation, + PDiag(diag::note_template_default_arg_checking) + << getTemplateArgumentBindingsText(TemplateParams, + Active->TemplateArgs, + Active->NumTemplateArgs) + << Active->InstantiationRange}); break; } case CodeSynthesisContext::ExceptionSpecEvaluation: - Diags.Report(Active->PointOfInstantiation, - diag::note_evaluating_exception_spec_here) - << cast(Active->Entity); + EmitDiag({Active->PointOfInstantiation, + PDiag(diag::note_evaluating_exception_spec_here) + << cast(Active->Entity)}); break; case CodeSynthesisContext::ExceptionSpecInstantiation: - Diags.Report(Active->PointOfInstantiation, - diag::note_template_exception_spec_instantiation_here) - << cast(Active->Entity) - << Active->InstantiationRange; + EmitDiag({Active->PointOfInstantiation, + PDiag(diag::note_template_exception_spec_instantiation_here) + << cast(Active->Entity) + << Active->InstantiationRange}); break; case CodeSynthesisContext::RequirementInstantiation: - Diags.Report(Active->PointOfInstantiation, - diag::note_template_requirement_instantiation_here) - << Active->InstantiationRange; + EmitDiag({Active->PointOfInstantiation, + PDiag(diag::note_template_requirement_instantiation_here) + << Active->InstantiationRange}); break; case CodeSynthesisContext::RequirementParameterInstantiation: - Diags.Report(Active->PointOfInstantiation, - diag::note_template_requirement_params_instantiation_here) - << Active->InstantiationRange; + EmitDiag({Active->PointOfInstantiation, + PDiag(diag::note_template_requirement_params_instantiation_here) + << Active->InstantiationRange}); break; case CodeSynthesisContext::NestedRequirementConstraintsCheck: - Diags.Report(Active->PointOfInstantiation, - diag::note_nested_requirement_here) - << Active->InstantiationRange; + EmitDiag({Active->PointOfInstantiation, + PDiag(diag::note_nested_requirement_here) + << Active->InstantiationRange}); break; case CodeSynthesisContext::DeclaringSpecialMember: - Diags.Report(Active->PointOfInstantiation, - diag::note_in_declaration_of_implicit_special_member) - << cast(Active->Entity) - << llvm::to_underlying(Active->SpecialMember); + EmitDiag({Active->PointOfInstantiation, + PDiag(diag::note_in_declaration_of_implicit_special_member) + << cast(Active->Entity) + << llvm::to_underlying(Active->SpecialMember)}); break; case CodeSynthesisContext::DeclaringImplicitEqualityComparison: - Diags.Report(Active->Entity->getLocation(), - diag::note_in_declaration_of_implicit_equality_comparison); + EmitDiag( + {Active->Entity->getLocation(), + PDiag(diag::note_in_declaration_of_implicit_equality_comparison)}); break; case CodeSynthesisContext::DefiningSynthesizedFunction: { @@ -1167,60 +1170,62 @@ void Sema::PrintInstantiationStack() { FD ? getDefaultedFunctionKind(FD) : DefaultedFunctionKind(); if (DFK.isSpecialMember()) { auto *MD = cast(FD); - Diags.Report(Active->PointOfInstantiation, - diag::note_member_synthesized_at) - << MD->isExplicitlyDefaulted() - << llvm::to_underlying(DFK.asSpecialMember()) - << Context.getTagDeclType(MD->getParent()); + EmitDiag({Active->PointOfInstantiation, + PDiag(diag::note_member_synthesized_at) + << MD->isExplicitlyDefaulted() + << llvm::to_underlying(DFK.asSpecialMember()) + << Context.getTagDeclType(MD->getParent())}); } else if (DFK.isComparison()) { QualType RecordType = FD->getParamDecl(0) ->getType() .getNonReferenceType() .getUnqualifiedType(); - Diags.Report(Active->PointOfInstantiation, - diag::note_comparison_synthesized_at) - << (int)DFK.asComparison() << RecordType; + EmitDiag({Active->PointOfInstantiation, + PDiag(diag::note_comparison_synthesized_at) + << (int)DFK.asComparison() << RecordType}); } break; } case CodeSynthesisContext::RewritingOperatorAsSpaceship: - Diags.Report(Active->Entity->getLocation(), - diag::note_rewriting_operator_as_spaceship); + EmitDiag({Active->Entity->getLocation(), + PDiag(diag::note_rewriting_operator_as_spaceship)}); break; case CodeSynthesisContext::InitializingStructuredBinding: - Diags.Report(Active->PointOfInstantiation, - diag::note_in_binding_decl_init) - << cast(Active->Entity); + EmitDiag({Active->PointOfInstantiation, + PDiag(diag::note_in_binding_decl_init) + << cast(Active->Entity)}); break; case CodeSynthesisContext::MarkingClassDllexported: - Diags.Report(Active->PointOfInstantiation, - diag::note_due_to_dllexported_class) - << cast(Active->Entity) << !getLangOpts().CPlusPlus11; + EmitDiag({Active->PointOfInstantiation, + PDiag(diag::note_due_to_dllexported_class) + << cast(Active->Entity) + << !getLangOpts().CPlusPlus11}); break; case CodeSynthesisContext::BuildingBuiltinDumpStructCall: - Diags.Report(Active->PointOfInstantiation, - diag::note_building_builtin_dump_struct_call) - << convertCallArgsToString( - *this, llvm::ArrayRef(Active->CallArgs, Active->NumCallArgs)); + EmitDiag({Active->PointOfInstantiation, + PDiag(diag::note_building_builtin_dump_struct_call) + << convertCallArgsToString( + *this, llvm::ArrayRef(Active->CallArgs, + Active->NumCallArgs))}); break; case CodeSynthesisContext::Memoization: break; case CodeSynthesisContext::LambdaExpressionSubstitution: - Diags.Report(Active->PointOfInstantiation, - diag::note_lambda_substitution_here); + EmitDiag({Active->PointOfInstantiation, + PDiag(diag::note_lambda_substitution_here)}); break; case CodeSynthesisContext::ConstraintsCheck: { unsigned DiagID = 0; if (!Active->Entity) { - Diags.Report(Active->PointOfInstantiation, - diag::note_nested_requirement_here) - << Active->InstantiationRange; + EmitDiag({Active->PointOfInstantiation, + PDiag(diag::note_nested_requirement_here) + << Active->InstantiationRange}); break; } if (isa(Active->Entity)) @@ -1242,35 +1247,35 @@ void Sema::PrintInstantiationStack() { printTemplateArgumentList(OS, Active->template_arguments(), getPrintingPolicy()); } - Diags.Report(Active->PointOfInstantiation, DiagID) << OS.str() - << Active->InstantiationRange; + EmitDiag({Active->PointOfInstantiation, + PDiag(DiagID) << OS.str() << Active->InstantiationRange}); break; } case CodeSynthesisContext::ConstraintSubstitution: - Diags.Report(Active->PointOfInstantiation, - diag::note_constraint_substitution_here) - << Active->InstantiationRange; + EmitDiag({Active->PointOfInstantiation, + PDiag(diag::note_constraint_substitution_here) + << Active->InstantiationRange}); break; case CodeSynthesisContext::ConstraintNormalization: - Diags.Report(Active->PointOfInstantiation, - diag::note_constraint_normalization_here) - << cast(Active->Entity)->getName() - << Active->InstantiationRange; + EmitDiag({Active->PointOfInstantiation, + PDiag(diag::note_constraint_normalization_here) + << cast(Active->Entity)->getName() + << Active->InstantiationRange}); break; case CodeSynthesisContext::ParameterMappingSubstitution: - Diags.Report(Active->PointOfInstantiation, - diag::note_parameter_mapping_substitution_here) - << Active->InstantiationRange; + EmitDiag({Active->PointOfInstantiation, + PDiag(diag::note_parameter_mapping_substitution_here) + << Active->InstantiationRange}); break; case CodeSynthesisContext::BuildingDeductionGuides: - Diags.Report(Active->PointOfInstantiation, - diag::note_building_deduction_guide_here); + EmitDiag({Active->PointOfInstantiation, + PDiag(diag::note_building_deduction_guide_here)}); break; case CodeSynthesisContext::TypeAliasTemplateInstantiation: - Diags.Report(Active->PointOfInstantiation, - diag::note_template_type_alias_instantiation_here) - << cast(Active->Entity) - << Active->InstantiationRange; + EmitDiag({Active->PointOfInstantiation, + PDiag(diag::note_template_type_alias_instantiation_here) + << cast(Active->Entity) + << Active->InstantiationRange}); break; } } diff --git a/clang/test/SemaSYCL/sycl-kernel-entry-point-attr-appertainment.cpp b/clang/test/SemaSYCL/sycl-kernel-entry-point-attr-appertainment.cpp index 77f26544000c4..317a9e72554d7 100644 --- a/clang/test/SemaSYCL/sycl-kernel-entry-point-attr-appertainment.cpp +++ b/clang/test/SemaSYCL/sycl-kernel-entry-point-attr-appertainment.cpp @@ -103,7 +103,7 @@ const void ok11(); //////////////////////////////////////////////////////////////////////////////// struct Smain; -// expected-error@+1 {{'main' cannot be declared with the 'sycl_kernel_entry_point' attribute}} +// expected-error@+1 {{'sycl_kernel_entry_point' attribute only applies to functions with a 'void' return type}} [[clang::sycl_kernel_entry_point(Smain)]] int main(); diff --git a/clang/test/SemaSYCL/sycl-kernel-entry-point-attr-argument.cpp b/clang/test/SemaSYCL/sycl-kernel-entry-point-attr-argument.cpp index e104c19499451..19b3123fd043e 100644 --- a/clang/test/SemaSYCL/sycl-kernel-entry-point-attr-argument.cpp +++ b/clang/test/SemaSYCL/sycl-kernel-entry-point-attr-argument.cpp @@ -209,8 +209,57 @@ struct B25_2; clang::sycl_kernel_entry_point(B25_2)]] void bad25(); +// Validate that conflicting kernel names are diagnosed for non-defining declarations. struct B26; -// expected-error@+3 {{'sycl_kernel_entry_point' kernel name argument conflicts with a previous declaration}} +// expected-error@+3 {{'sycl_kernel_entry_point' kernel name 'B26' conflicts with a previous declaration}} // expected-note@+1 {{previous declaration is here}} -[[clang::sycl_kernel_entry_point(B26)]] void bad26_1(); -[[clang::sycl_kernel_entry_point(B26)]] void bad24_2(); +[[clang::sycl_kernel_entry_point(B26)]] void bad26_1(B26 k); +[[clang::sycl_kernel_entry_point(B26)]] void bad26_2(B26 k); + + +struct B27; + +template +[[clang::sycl_kernel_entry_point(KN)]] +void bad27(K ker, int i) { ker(); } // #bad27-decl + +// Overload to ensure attribute checks don't affect overload resolution. +template +void bad27(K ker, long i) { ker(); } + +void test_bad27_1() { + int i = 0; + long l = 0; + // expected-error@#bad27-decl {{'sycl_kernel_entry_point' kernel name 'B27' conflicts with a previous declaration}} + // expected-note-re@+4 {{in instantiation of function template specialization 'bad27([]{}, i); // #bad27-FirstUse + bad27([]{}, i); + // this doesn't trigger any error as overload doesn't have the attribute. + bad27([]{}, l); +} + +void test_bad27_2() { + int i = 0; + // expected-error@#bad27-decl {{'sycl_kernel_entry_point' kernel name 'B27' conflicts with a previous declaration}} + // expected-note-re@+3 {{in instantiation of function template specialization 'bad27([]{}, i); +} + +template +void test_bad27_3() { + int i = 0; + // expected-error@#bad27-decl {{'sycl_kernel_entry_point' kernel name 'B27' conflicts with a previous declaration}} + // expected-note-re@+4 {{in instantiation of function template specialization 'bad27' requested here}} + // expected-note@#bad27-decl {{previous declaration is here}} + // expected-note-re@#bad27-FirstUse {{in instantiation of function template specialization 'bad27([]{}, i); +} + +void test_bad27_4() { + test_bad27_3(); // #test_bad27_3-call +}