[Sema] Extend -Wself-assign and -Wself-assign-field to warn on overloaded self-assignment (classes)
Summary:
This has just bit me, so i though it would be nice to avoid that next time :)
Motivational case:
https://godbolt.org/g/cq9UNk
Basically, it's likely to happen if you don't like shadowing issues,
and use `-Wshadow` and friends. And it won't be diagnosed by clang.
The reason is, these self-assign diagnostics only work for builtin assignment
operators. Which makes sense, one could have a very special operator=,
that does something unusual in case of self-assignment,
so it may make sense to not warn on that.
But while it may be intentional in some cases, it may be a bug in other cases,
so it would be really great to have some diagnostic about it...
Reviewers: aaron.ballman, rsmith, rtrieu, nikola, rjmccall, dblaikie
Reviewed By: rjmccall
Subscribers: EricWF, lebedev.ri, thakis, Quuxplusone, cfe-commits
Differential Revision: https://reviews.llvm.org/D44883
llvm-svn: 329493
2018-04-07 18:39:21 +08:00
|
|
|
// RUN: %clang_cc1 -fsyntax-only -Wself-assign -DDUMMY -verify %s
|
|
|
|
// RUN: %clang_cc1 -fsyntax-only -Wself-assign -DV0 -verify %s
|
|
|
|
// RUN: %clang_cc1 -fsyntax-only -Wself-assign -DV1 -verify %s
|
|
|
|
// RUN: %clang_cc1 -fsyntax-only -Wself-assign -DV2 -verify %s
|
|
|
|
// RUN: %clang_cc1 -fsyntax-only -Wself-assign -DV3 -verify %s
|
|
|
|
// RUN: %clang_cc1 -fsyntax-only -Wself-assign -DV4 -verify %s
|
[Sema] Add -Wno-self-assign-overloaded
Summary:
It seems there isn't much enthusiasm for `-wtest` D45685.
This is more conservative version, which i had in the very first
revision of D44883, but that 'erroneously' got removed because of the review.
**Based on some [irc] discussions, it must really be documented that
we want all the new diagnostics to have their own flags, to ease
rollouts, transitions, etc.**
Please do note that i'm only adding `-Wno-self-assign-overloaded`,
but not `-Wno-self-assign-field-overloaded`, because i'm honestly
not aware of any false-positives from the `-field` variant,
but i can just as easily add it if wanted.
https://reviews.llvm.org/D44883#1068561
Reviewers: dblaikie, aaron.ballman, thakis, rjmccall, rsmith
Reviewed By: dblaikie
Subscribers: Quuxplusone, chandlerc, cfe-commits
Differential Revision: https://reviews.llvm.org/D45766
llvm-svn: 330651
2018-04-24 05:35:21 +08:00
|
|
|
// RUN: %clang_cc1 -fsyntax-only -Wno-self-assign -Wself-assign-overloaded -DDUMMY -verify %s
|
|
|
|
// RUN: %clang_cc1 -fsyntax-only -Wno-self-assign -Wself-assign-overloaded -DV0 -verify %s
|
|
|
|
// RUN: %clang_cc1 -fsyntax-only -Wno-self-assign -Wself-assign-overloaded -DV1 -verify %s
|
|
|
|
// RUN: %clang_cc1 -fsyntax-only -Wno-self-assign -Wself-assign-overloaded -DV2 -verify %s
|
|
|
|
// RUN: %clang_cc1 -fsyntax-only -Wno-self-assign -Wself-assign-overloaded -DV3 -verify %s
|
|
|
|
// RUN: %clang_cc1 -fsyntax-only -Wno-self-assign -Wself-assign-overloaded -DV4 -verify %s
|
[Sema] Extend -Wself-assign and -Wself-assign-field to warn on overloaded self-assignment (classes)
Summary:
This has just bit me, so i though it would be nice to avoid that next time :)
Motivational case:
https://godbolt.org/g/cq9UNk
Basically, it's likely to happen if you don't like shadowing issues,
and use `-Wshadow` and friends. And it won't be diagnosed by clang.
The reason is, these self-assign diagnostics only work for builtin assignment
operators. Which makes sense, one could have a very special operator=,
that does something unusual in case of self-assignment,
so it may make sense to not warn on that.
But while it may be intentional in some cases, it may be a bug in other cases,
so it would be really great to have some diagnostic about it...
Reviewers: aaron.ballman, rsmith, rtrieu, nikola, rjmccall, dblaikie
Reviewed By: rjmccall
Subscribers: EricWF, lebedev.ri, thakis, Quuxplusone, cfe-commits
Differential Revision: https://reviews.llvm.org/D44883
llvm-svn: 329493
2018-04-07 18:39:21 +08:00
|
|
|
|
|
|
|
#ifdef DUMMY
|
|
|
|
struct S {};
|
|
|
|
#else
|
|
|
|
struct S {
|
|
|
|
#if defined(V0)
|
|
|
|
S() = default;
|
|
|
|
#elif defined(V1)
|
|
|
|
S &operator=(const S &) = default;
|
|
|
|
#elif defined(V2)
|
|
|
|
S &operator=(S &) = default;
|
|
|
|
#elif defined(V3)
|
|
|
|
S &operator=(const S &);
|
|
|
|
#elif defined(V4)
|
|
|
|
S &operator=(S &);
|
|
|
|
#else
|
|
|
|
#error Define something!
|
|
|
|
#endif
|
|
|
|
S &operator*=(const S &);
|
|
|
|
S &operator/=(const S &);
|
|
|
|
S &operator%=(const S &);
|
|
|
|
S &operator+=(const S &);
|
|
|
|
S &operator-=(const S &);
|
|
|
|
S &operator<<=(const S &);
|
|
|
|
S &operator>>=(const S &);
|
|
|
|
S &operator&=(const S &);
|
|
|
|
S &operator|=(const S &);
|
|
|
|
S &operator^=(const S &);
|
|
|
|
S &operator=(const volatile S &) volatile;
|
|
|
|
};
|
|
|
|
#endif
|
|
|
|
|
|
|
|
void f() {
|
|
|
|
S a, b;
|
|
|
|
a = a; // expected-warning{{explicitly assigning}}
|
|
|
|
b = b; // expected-warning{{explicitly assigning}}
|
|
|
|
a = b;
|
|
|
|
b = a = b;
|
|
|
|
a = a = a; // expected-warning{{explicitly assigning}}
|
|
|
|
a = b = b = a;
|
|
|
|
|
|
|
|
#ifndef DUMMY
|
|
|
|
a *= a;
|
|
|
|
a /= a; // expected-warning {{explicitly assigning}}
|
|
|
|
a %= a; // expected-warning {{explicitly assigning}}
|
|
|
|
a += a;
|
|
|
|
a -= a; // expected-warning {{explicitly assigning}}
|
|
|
|
a <<= a;
|
|
|
|
a >>= a;
|
|
|
|
a &= a; // expected-warning {{explicitly assigning}}
|
|
|
|
a |= a; // expected-warning {{explicitly assigning}}
|
|
|
|
a ^= a; // expected-warning {{explicitly assigning}}
|
|
|
|
#endif
|
|
|
|
}
|
|
|
|
|
|
|
|
void false_positives() {
|
|
|
|
#define OP =
|
|
|
|
#define LHS a
|
|
|
|
#define RHS a
|
|
|
|
S a;
|
|
|
|
// These shouldn't warn due to the use of the preprocessor.
|
|
|
|
a OP a;
|
|
|
|
LHS = a;
|
|
|
|
a = RHS;
|
|
|
|
LHS OP RHS;
|
|
|
|
#undef OP
|
|
|
|
#undef LHS
|
|
|
|
#undef RHS
|
|
|
|
|
|
|
|
// Ways to silence the warning.
|
|
|
|
a = *&a;
|
|
|
|
a = (S &)a;
|
|
|
|
a = static_cast<decltype(a) &>(a);
|
|
|
|
|
|
|
|
#ifndef DUMMY
|
|
|
|
// Volatile stores aren't side-effect free.
|
|
|
|
volatile S vol_a;
|
|
|
|
vol_a = vol_a;
|
|
|
|
volatile S &vol_a_ref = vol_a;
|
|
|
|
vol_a_ref = vol_a_ref;
|
|
|
|
#endif
|
|
|
|
}
|
|
|
|
|
|
|
|
// Do not diagnose self-assigment in an unevaluated context
|
|
|
|
struct SNoExcept {
|
|
|
|
SNoExcept() = default;
|
|
|
|
SNoExcept &operator=(const SNoExcept &) noexcept;
|
|
|
|
};
|
|
|
|
void false_positives_unevaluated_ctx(SNoExcept a) noexcept(noexcept(a = a)) {
|
|
|
|
decltype(a = a) b = a;
|
|
|
|
static_assert(noexcept(a = a), "");
|
|
|
|
static_assert(sizeof(a = a), "");
|
|
|
|
}
|
|
|
|
|
|
|
|
template <typename T>
|
|
|
|
void g() {
|
|
|
|
T a;
|
|
|
|
a = a; // expected-warning{{explicitly assigning}}
|
|
|
|
}
|
|
|
|
void instantiate() {
|
|
|
|
g<int>();
|
|
|
|
g<S>();
|
|
|
|
}
|