-
Notifications
You must be signed in to change notification settings - Fork 14.3k
[CUDA][HIP] Fix overriding of constexpr virtual function #121986
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Conversation
@llvm/pr-subscribers-clang Author: Yaxun (Sam) Liu (yxsamliu) ChangesIn C++20 constexpr virtual function is allowed. In C++17 although non-pure virtual function is not allowed to be constexpr, pure virtual function is allowed to be constexpr and is allowed to be overriden by non-constexpr virtual function in the derived class. The following code compiles as C++:
However, it fails to compile as CUDA or HIP code. The reason: A::f() is implicitly host device function whereas B::f() is a host function. Since they have different targets, clang does not treat B::f() as an override of A::f(). Instead, it treats B::f() as a name-hiding non-virtual function for A::f(), and diagnoses it. This causes any CUDA/HIP program using C++ standard header file <format> from g++-13 to fail to compile since such usage patten show up there:
This is a serious issue and there is no workaround. This patch allows non-constexpr function to override constexpr virtual function for CUDA and HIP. This should be OK since non-constexpr function without explicit host or device attribute can only be called in host functions. Fixes: SWDEV-507350 Full diff: https://github.com/llvm/llvm-project/pull/121986.diff 2 Files Affected:
diff --git a/clang/lib/Sema/SemaOverload.cpp b/clang/lib/Sema/SemaOverload.cpp
index 7589701fb81de9..ed44a7666b0e28 100644
--- a/clang/lib/Sema/SemaOverload.cpp
+++ b/clang/lib/Sema/SemaOverload.cpp
@@ -1309,6 +1309,16 @@ Sema::CheckOverload(Scope *S, FunctionDecl *New, const LookupResult &Old,
return Ovl_Overload;
}
+template <typename AttrT> static bool hasExplicitAttr(const FunctionDecl *D) {
+ if (!D)
+ return false;
+ if (auto *A = D->getAttr<AttrT>())
+ return !A->isImplicit();
+ return false;
+}
+/// Assuming \p New is either an overload or override of \p Old.
+/// \returns true if \p New is an overload of \p Old,
+/// false if \p New is an override of \p Old.
static bool IsOverloadOrOverrideImpl(Sema &SemaRef, FunctionDecl *New,
FunctionDecl *Old,
bool UseMemberUsingDeclRules,
@@ -1583,6 +1593,7 @@ static bool IsOverloadOrOverrideImpl(Sema &SemaRef, FunctionDecl *New,
return true;
}
+ // At this point, it is known that the two functions have the same signature.
if (SemaRef.getLangOpts().CUDA && ConsiderCudaAttrs) {
// Don't allow overloading of destructors. (In theory we could, but it
// would be a giant change to clang.)
@@ -1595,8 +1606,21 @@ static bool IsOverloadOrOverrideImpl(Sema &SemaRef, FunctionDecl *New,
// Allow overloading of functions with same signature and different CUDA
// target attributes.
- if (NewTarget != OldTarget)
+ if (NewTarget != OldTarget) {
+ // Special case: non-constexpr function is allowed to override
+ // constexpr virtual function
+ const auto *OldMethod = dyn_cast<CXXMethodDecl>(Old);
+ const auto *NewMethod = dyn_cast<CXXMethodDecl>(New);
+ if (OldMethod && NewMethod && OldMethod->isVirtual() &&
+ OldMethod->isConstexpr() && !NewMethod->isConstexpr() &&
+ !hasExplicitAttr<CUDAHostAttr>(Old) &&
+ !hasExplicitAttr<CUDADeviceAttr>(Old) &&
+ !hasExplicitAttr<CUDAHostAttr>(New) &&
+ !hasExplicitAttr<CUDADeviceAttr>(New)) {
+ return false;
+ }
return true;
+ }
}
}
}
diff --git a/clang/test/SemaCUDA/constexpr-virtual-func.cu b/clang/test/SemaCUDA/constexpr-virtual-func.cu
new file mode 100644
index 00000000000000..89d909181cd94d
--- /dev/null
+++ b/clang/test/SemaCUDA/constexpr-virtual-func.cu
@@ -0,0 +1,28 @@
+// RUN: %clang_cc1 -triple nvptx64-nvidia-cuda -fsyntax-only \
+// RUN: -fcuda-is-device %s
+// RUN: %clang_cc1 -triple x86_64-unknown-linux-gnu -fsyntax-only %s
+
+// expected-no-diagnostics
+
+#include "Inputs/cuda.h"
+
+class A
+{
+public:
+ constexpr virtual int f() = 0;
+};
+
+class B : public A
+{
+public:
+ int f() override
+ {
+ return 42;
+ }
+};
+
+int test()
+{
+ B b;
+ return b.f();
+}
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This needs a release note
fa0df07
to
ae55b59
Compare
added |
In C++20 constexpr virtual function is allowed. In C++17 although non-pure virtual function is not allowed to be constexpr, pure virtual function is allowed to be constexpr and is allowed to be overriden by non-constexpr virtual function in the derived class. The following code compiles as C++: ``` class A { public: constexpr virtual int f() = 0; }; class B : public A { public: int f() override { return 42; } }; ``` However, it fails to compile as CUDA or HIP code. The reason: A::f() is implicitly host device function whereas B::f() is a host function. Since they have different targets, clang does not treat B::f() as an override of A::f(). Instead, it treats B::f() as a name-hiding non-virtual function for A::f(), and diagnoses it. This causes any CUDA/HIP program using C++ standard header file <format> from g++-13 to fail to compile since such usage patten show up there: ``` /usr/lib/gcc/x86_64-linux-gnu/13/../../../../include/c++/13/format:3564:34: error: non-virtual member function marked 'override' hides virtual member function 3564 | _M_format_arg(size_t __id) override | ^ /usr/lib/gcc/x86_64-linux-gnu/13/../../../../include/c++/13/format:3538:30: note: hidden overloaded virtual function 'std::__format::_Scanner<char>::_M_format_arg' declared here 3538 | constexpr virtual void _M_format_arg(size_t __id) = 0; | ^ ``` This is a serious issue and there is no workaround. This patch allows non-constexpr function to override constexpr virtual function for CUDA and HIP. This should be OK since non-constexpr function without explicit host or device attribute can only be called in host functions. Fixes: SWDEV-507350
ae55b59
to
21485f0
Compare
In C++20 constexpr virtual function is allowed. In C++17 although non-pure virtual function is not allowed to be constexpr, pure virtual function is allowed to be constexpr and is allowed to be overriden by non-constexpr virtual function in the derived class. The following code compiles as C++: ``` class A { public: constexpr virtual int f() = 0; }; class B : public A { public: int f() override { return 42; } }; ``` However, it fails to compile as CUDA or HIP code. The reason: A::f() is implicitly host device function whereas B::f() is a host function. Since they have different targets, clang does not treat B::f() as an override of A::f(). Instead, it treats B::f() as a name-hiding non-virtual function for A::f(), and diagnoses it. This causes any CUDA/HIP program using C++ standard header file `<format>` from g++-13 to fail to compile since such usage patten show up there: ``` /usr/lib/gcc/x86_64-linux-gnu/13/../../../../include/c++/13/format:3564:34: error: non-virtual member function marked 'override' hides virtual member function 3564 | _M_format_arg(size_t __id) override | ^ /usr/lib/gcc/x86_64-linux-gnu/13/../../../../include/c++/13/format:3538:30: note: hidden overloaded virtual function 'std::__format::_Scanner<char>::_M_format_arg' declared here 3538 | constexpr virtual void _M_format_arg(size_t __id) = 0; | ^ ``` This is a serious issue and there is no workaround. This patch allows non-constexpr function to override constexpr virtual function for CUDA and HIP. This should be OK since non-constexpr function without explicit host or device attribute can only be called in host functions. Fixes: SWDEV-507350 Change-Id: Iebd472bfe94a5f447748ec63171678cca151c5a9
In C++20 constexpr virtual function is allowed. In C++17 although non-pure virtual function is not allowed to be constexpr, pure virtual function is allowed to be constexpr and is allowed to be overriden by non-constexpr virtual function in the derived class. The following code compiles as C++: ``` class A { public: constexpr virtual int f() = 0; }; class B : public A { public: int f() override { return 42; } }; ``` However, it fails to compile as CUDA or HIP code. The reason: A::f() is implicitly host device function whereas B::f() is a host function. Since they have different targets, clang does not treat B::f() as an override of A::f(). Instead, it treats B::f() as a name-hiding non-virtual function for A::f(), and diagnoses it. This causes any CUDA/HIP program using C++ standard header file `<format>` from g++-13 to fail to compile since such usage patten show up there: ``` /usr/lib/gcc/x86_64-linux-gnu/13/../../../../include/c++/13/format:3564:34: error: non-virtual member function marked 'override' hides virtual member function 3564 | _M_format_arg(size_t __id) override | ^ /usr/lib/gcc/x86_64-linux-gnu/13/../../../../include/c++/13/format:3538:30: note: hidden overloaded virtual function 'std::__format::_Scanner<char>::_M_format_arg' declared here 3538 | constexpr virtual void _M_format_arg(size_t __id) = 0; | ^ ``` This is a serious issue and there is no workaround. This patch allows non-constexpr function to override constexpr virtual function for CUDA and HIP. This should be OK since non-constexpr function without explicit host or device attribute can only be called in host functions. Fixes: SWDEV-507350
In C++20 constexpr virtual function is allowed. In C++17 although non-pure virtual function is not allowed to be constexpr, pure virtual function is allowed to be constexpr and is allowed to be overriden by non-constexpr virtual function in the derived class.
The following code compiles as C++:
However, it fails to compile as CUDA or HIP code. The reason: A::f() is implicitly host device function whereas B::f() is a host function. Since they have different targets, clang does not treat B::f() as an override of A::f(). Instead, it treats B::f() as a name-hiding non-virtual function for A::f(), and diagnoses it.
This causes any CUDA/HIP program using C++ standard header file
<format>
from g++-13 to fail to compile since such usage patten show up there:This is a serious issue and there is no workaround.
This patch allows non-constexpr function to override constexpr virtual function for CUDA and HIP. This should be OK since non-constexpr function without explicit host or device attribute can only be called in host functions.
Fixes: SWDEV-507350