-
Notifications
You must be signed in to change notification settings - Fork 3.5k
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
[build][tir] suppress -Woverloaded-virtual warning #13267
Conversation
Thanks for contributing to TVM! Please refer to the contributing guidelines https://tvm.apache.org/docs/contribute/ for useful information and tips. Please request code reviews from Reviewers by @-ing them in a comment.
Generated by tvm-bot |
CC: @Lunderberg |
@@ -187,6 +187,11 @@ class DataTypeVisitor final : public StmtExprVisitor { | |||
arith::ConstIntBoundAnalyzer::BoundMapType bound_; | |||
}; | |||
|
|||
#if __clang__ |
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.
Instead of suppressing the warning altogether, could we instead add a using Parent::VisitStmt_;
and using Parent::VisitExpr_
? That would allow the parent's virtual functions to participate in overload resolution, avoiding the case that the warning is trying to catch.
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.
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.
It only overrides some methods, for the rest it is intended to go to its parent class. I already add https://github.com/apache/tvm/blob/main/include/tvm/tir/stmt_functor.h#L530-L531 to its parent class, not sure why the warning still occurs.
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.
I don't think adding more overloads to the parent class changes the issue. Here's how I understand it (but I may be missing something...)
Suppose we have code like this:
#include <iostream>
using namespace std;
class BaseClass {
public:
virtual void foo(int x) {
cout << "BaseClass::foo(int): x = " << x << endl;
}
};
class DerivedClass : public BaseClass {
public:
virtual void foo(float x) {
cout << "DerivedClass::foo(float): x = " << x << endl;
}
};
int main() {
DerivedClass d;
d.foo(42);
}
Many people would expect this to print BaseClass::foo(int): x = 42
because 42
is an int.
But what actually gets printed is DerivedClass::foo(float): x = 42
. This is unintuitive for a lot of C++ programmers, which I think is why this warning was created.
IIUC, adding the using ...
statements that @Lunderberg proposed would make this code behave more like you intended originally.
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.
I expect it to only override virtual methods already available in DataTypeLegalizer
or StmtExprMutator
, instead of adding new overloads, maybe I'm missing something
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.
Sorry, let me try making my point better with a slightly different example:
#include <iostream>
#include <string>
using namespace std;
class BaseClass {
public:
virtual void foo(int x) {
cout << "BaseClass::foo(int): x = " << x << endl;
}
virtual void foo(string x) {
cout << "BaseClass::foo(string): x = " << x << endl;
}
};
class DerivedClass : public BaseClass {
public:
#ifdef OVERLOAD_FOO
virtual void foo(int x) {
cout << "DerivedClass::foo(int): x = " << x << endl;
}
#endif
};
int main() {
DerivedClass d;
d.foo("Hello, TVM!");
}
If I compile this with simply clang++ x.cpp
, the compilation succeeds. And when I run the resulting executable, it prints BaseClass::foo(string): x = Hello, TVM!
.
But if I try to compile this with clang++ -DOVERLOAD_FOO x.cpp
, I get this error:
x.cpp:27:11: error: cannot initialize a parameter of type 'int' with an lvalue of type 'const char[12]'
d.foo("Hello, TVM!");
^~~~~~~~~~~~~
x.cpp:19:26: note: passing argument to parameter 'x' here
virtual void foo(int x) {
^
1 error generated.
The issue, as I understand it, is that because DerviedClass
provides even one override of foo
, C++ will no longer look at any of the BaseClass::foo(...)
overloads when it sees a call such as d.foo("Hello, TVM!")
in the example above.
(However, those base-class functions aren't completely hidden. For example, if we use d.BaseClass::foo("Hello, TVM!")
instead, the code compiles just fine.)
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.
Thanks for the explanation. I think it's common in the codebase to only override visitors for some IR nodes, for example https://github.com/apache/tvm/blob/main/src/tir/transforms/storage_rewrite.cc#L63. Any idea how it works?
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.
Sorry it took several examples to make my point :)
I think it's common in the codebase to only override visitors for some IR nodes, for example https://github.com/apache/tvm/blob/main/src/tir/transforms/storage_rewrite.cc#L63. Any idea how it works?
I think we'd need to look more closely at code that calls one of those methods to see what's going on. Two possibilities that come to mind are:
(a) We're doing something equivalent to this:
StmtExprVisitor * p = new LinearAccessPatternFinder(...);
p->VisitStmt_(...)
Which at compile time will search the VisitStmt_
overloads provided by StmtExprVisitor
. (Although runtime dispatch will still use the vtable, and thus resolve to a suitable `LinearAccessPatternFinder method if it exists.)
If only code in one of the ancestor classes directly calls VisitStmt_
, then maybe we could address this by making VisitStmt_
be protected
rather than public
? That might at least reduce the opportunities for this to bite people, although @Lunderberg 's using ...
suggestion is even more robust AFAICT.
(b) We're unwittingly invoking the wrong overload provided by LinearAccessPatternFinder
because C++ can automatically cast the argument to one of the overloads provided by LinearAccessPatternFinder
. And TVM's testing just never noticed the mistake. (So, similar to what happens in that first example I gave, above: #13267 (comment))
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.
(A little bit late to the discussion, but I hope this helps.)
I looked a bit into the warning, and it looks like part of it is because the DataTypeLegalizer
defines the VisitStmt_
as public, whereas the StmtExprMutator
defines them as protected. So the other instances of this pattern are overriding a protected method, which doesn't trigger the warning.
As example code. the warning is trying to avoid cases like the third one below, where the static type causes an unexpected overload set when calling a method on the derived type.
class Base {
public:
virtual func(int x) {}
virtual func(double x) {}
};
class Derived {
public:
virtual func(double x) {}
};
int main() {
// Static type is base, uses Base's vtable.
std::unique_ptr<Base> base = std::make_unique<Base>();
base->func(5); // Calls Base::func(int)
// Static type is base, uses Derived's vtable.
std::unique_ptr<Base> derived = std::make_unique<Dervied>();
derived->func(5); // Calls Base::func(int)
// Static type is Derived, uses Derived's vtable. Overload
// resolution selects `Derived::func(double)` because the overload
// resolution set is based on the static type, and doesn't include
// `Base::func(int)`.
std::unique_ptr<Derived> derived = std::make_unique<Dervied>();
derived->func(5); // Calls Derived::func(double)
}
6b3e9c8
to
8f94ef4
Compare
I've reworked this based on our discussion:
@Lunderberg @vinx13 : Ready for review. |
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.
LGTM! Can we apply a similar change in the DataTypeLegalizer
? (Either as part of this PR or another.) It has the same issue of the VisitStmt_
methods being exposed, when external users should go through StmtExprMutator::operator()
instead.
Thanks for the idea! It's not too much scope creep, so I'll add that to this PR. |
- Address a (valid) warning from clang-15.0.3 regarding the `tvm::tir::DataTypeRewriter` class. - Make some class methods `protected` rather than `public` to better reflect authors' intent.
8f94ef4
to
76a2b71
Compare
- Address a (valid) warning from clang-15.0.3 regarding the `tvm::tir::DataTypeRewriter` class. - Make some class methods `protected` rather than `public` to better reflect authors' intent.
- Address a (valid) warning from clang-15.0.3 regarding the `tvm::tir::DataTypeRewriter` class. - Make some class methods `protected` rather than `public` to better reflect authors' intent.
Suppress a spurious
-Woverloaded-virtual
clang warning for thetvm::tir::DataTypeRewriter
class.I think we're safe to ignore clang version for this pragma, because it's been supported for a long time now.