diff --git a/clang/lib/Sema/SemaSYCL.cpp b/clang/lib/Sema/SemaSYCL.cpp index c2c11765a8bc2..602a92b52817b 100644 --- a/clang/lib/Sema/SemaSYCL.cpp +++ b/clang/lib/Sema/SemaSYCL.cpp @@ -61,6 +61,8 @@ static constexpr llvm::StringLiteral InitESIMDMethodName = "__init_esimd"; static constexpr llvm::StringLiteral InitSpecConstantsBuffer = "__init_specialization_constants_buffer"; static constexpr llvm::StringLiteral FinalizeMethodName = "__finalize"; +static constexpr llvm::StringLiteral LibstdcxxFailedAssertion = + "__failed_assertion"; constexpr unsigned MaxKernelArgsSize = 2048; namespace { @@ -320,6 +322,21 @@ static bool isSYCLKernelBodyFunction(FunctionDecl *FD) { return FD->getOverloadedOperator() == OO_Call; } +static bool isSYCLUndefinedAllowed(const FunctionDecl *Callee, + const SourceManager &SrcMgr) { + if (!Callee) + return false; + + // libstdc++-11 introduced an undefined function "void __failed_assertion()" + // which may lead to SemaSYCL check failure. However, this undefined function + // is used to trigger some compilation error when the check fails at compile + // time and will be ignored when the check succeeds. We allow calls to this + // function to support some important std functions in SYCL device. + return (Callee->getName() == LibstdcxxFailedAssertion) && + Callee->getNumParams() == 0 && Callee->getReturnType()->isVoidType() && + SrcMgr.isInSystemHeader(Callee->getLocation()); +} + // Helper function to report conflicting function attributes. // F - the function, A1 - function attribute, A2 - the attribute it conflicts // with. @@ -4122,7 +4139,10 @@ void Sema::finalizeSYCLDelayedAnalysis(const FunctionDecl *Caller, return; // Diagnose if this is an undefined function and it is not a builtin. - if (!Callee->isDefined() && !Callee->getBuiltinID()) { + // Currently, there is an exception of "__failed_assertion" in libstdc++-11, + // this undefined function is used to trigger a compiling error. + if (!Callee->isDefined() && !Callee->getBuiltinID() && + !isSYCLUndefinedAllowed(Callee, getSourceManager())) { Diag(Loc, diag::err_sycl_restrict) << Sema::KernelCallUndefinedFunction; Diag(Callee->getLocation(), diag::note_previous_decl) << Callee; Diag(Caller->getLocation(), diag::note_called_by) << Caller; diff --git a/clang/test/SemaSYCL/Inputs/dummy_failed_assert b/clang/test/SemaSYCL/Inputs/dummy_failed_assert new file mode 100644 index 0000000000000..e1561f0f48dbe --- /dev/null +++ b/clang/test/SemaSYCL/Inputs/dummy_failed_assert @@ -0,0 +1 @@ +void __failed_assertion(); diff --git a/clang/test/SemaSYCL/__failed_assertion.cpp b/clang/test/SemaSYCL/__failed_assertion.cpp new file mode 100644 index 0000000000000..c8985158cc02b --- /dev/null +++ b/clang/test/SemaSYCL/__failed_assertion.cpp @@ -0,0 +1,29 @@ +// RUN: %clang_cc1 -fsycl-is-device -internal-isystem %S/Inputs -sycl-std=2020 -verify -DUSR -fsyntax-only %s +// RUN: %clang_cc1 -fsycl-is-device -internal-isystem %S/Inputs -sycl-std=2020 -verify -fsyntax-only %s +// UNSUPPORTED: system-windows +// This test checks that an undefined "__failed_assertion" without SYCL_EXTERNAL will lead to SYCL sema check +// failure if it is not declared in a system header otherwise no SYCL sema check failure will be triggered. + +#include "sycl.hpp" +#ifdef USR +void __failed_assertion(); +// expected-note@-1 {{'__failed_assertion' declared here}} +#else +#include +#endif + +#ifdef USR +SYCL_EXTERNAL +void call_failed_assertion() { + // expected-note@-1 {{called by 'call_failed_assertion'}} + __failed_assertion(); + // expected-error@-1 {{SYCL kernel cannot call an undefined function without SYCL_EXTERNAL attribute}} +} +#else +// expected-no-diagnostics +SYCL_EXTERNAL +void call_failed_assertion() { + __failed_assertion(); +} +#endif +