mirror of
https://github.com/capstone-engine/llvm-capstone.git
synced 2025-03-04 16:41:43 +00:00

(This relands 59337263ab45d7657e and makes sure comma operator diagnostics are suppressed in a SFINAE context.) While at it, add the diagnosis message "left operand of comma operator has no effect" (used by GCC) for comma operator. This also makes Clang diagnose in the constant evaluation context which aligns with GCC/MSVC behavior. (https://godbolt.org/z/7zxb8Tx96) Reviewed By: aaron.ballman Differential Revision: https://reviews.llvm.org/D103938
171 lines
4.5 KiB
C++
171 lines
4.5 KiB
C++
// RUN: %clang_cc1 -fsyntax-only -verify -Wunused-value %s
|
|
// RUN: %clang_cc1 -fsyntax-only -verify -Wunused-value -std=c++98 %s
|
|
// RUN: %clang_cc1 -fsyntax-only -verify -Wunused-value -std=c++11 %s
|
|
// RUN: %clang_cc1 -fsyntax-only -verify -Wunused-value -std=c++17 %s
|
|
|
|
// PR4806
|
|
namespace test0 {
|
|
class Box {
|
|
public:
|
|
int i;
|
|
volatile int j;
|
|
};
|
|
|
|
void doit() {
|
|
// pointer to volatile has side effect (thus no warning)
|
|
Box* box = new Box;
|
|
box->i; // expected-warning {{expression result unused}}
|
|
box->j;
|
|
#if __cplusplus <= 199711L
|
|
// expected-warning@-2 {{expression result unused}}
|
|
#endif
|
|
}
|
|
}
|
|
|
|
namespace test1 {
|
|
struct Foo {
|
|
int i;
|
|
bool operator==(const Foo& rhs) {
|
|
return i == rhs.i;
|
|
}
|
|
};
|
|
|
|
#define NOP(x) (x)
|
|
void b(Foo f1, Foo f2) {
|
|
NOP(f1 == f2); // expected-warning {{expression result unused}}
|
|
}
|
|
#undef NOP
|
|
}
|
|
|
|
namespace test2 {
|
|
extern "C++" {
|
|
namespace std {
|
|
template<typename T> struct basic_string {
|
|
struct X {};
|
|
void method() const {
|
|
X* x;
|
|
&x[0]; // expected-warning {{expression result unused}}
|
|
}
|
|
};
|
|
typedef basic_string<char> string;
|
|
void func(const std::string& str) {
|
|
str.method(); // expected-note {{in instantiation of member function}}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
namespace test3 {
|
|
struct Used {
|
|
Used();
|
|
Used(int);
|
|
Used(int, int);
|
|
~Used() {}
|
|
};
|
|
struct __attribute__((warn_unused)) Unused {
|
|
Unused();
|
|
Unused(int);
|
|
Unused(int, int);
|
|
~Unused() {}
|
|
};
|
|
void f() {
|
|
Used();
|
|
Used(1);
|
|
Used(1, 1);
|
|
Unused(); // expected-warning {{expression result unused}}
|
|
Unused(1); // expected-warning {{expression result unused}}
|
|
Unused(1, 1); // expected-warning {{expression result unused}}
|
|
#if __cplusplus >= 201103L // C++11 or later
|
|
Used({});
|
|
Unused({}); // expected-warning {{expression result unused}}
|
|
#endif
|
|
}
|
|
}
|
|
|
|
namespace std {
|
|
struct type_info {};
|
|
}
|
|
|
|
namespace test4 {
|
|
struct Good { Good &f(); };
|
|
struct Bad { virtual Bad& f(); };
|
|
|
|
void f() {
|
|
int i = 0;
|
|
(void)typeid(++i); // expected-warning {{expression with side effects has no effect in an unevaluated context}}
|
|
|
|
Good g;
|
|
(void)typeid(g.f()); // Ok; not a polymorphic use of a glvalue.
|
|
|
|
// This is a polymorphic use of a glvalue, which results in the typeid being
|
|
// evaluated instead of unevaluated.
|
|
Bad b;
|
|
(void)typeid(b.f()); // expected-warning {{expression with side effects will be evaluated despite being used as an operand to 'typeid'}}
|
|
|
|
// A dereference of a volatile pointer is a side effecting operation, however
|
|
// since it is idiomatic code, and the alternatives induce higher maintenance
|
|
// costs, it is allowed.
|
|
int * volatile x;
|
|
(void)sizeof(*x); // Ok
|
|
}
|
|
}
|
|
|
|
static volatile char var1 = 'a';
|
|
volatile char var2 = 'a';
|
|
static volatile char arr1[] = "hello";
|
|
volatile char arr2[] = "hello";
|
|
void volatile_array() {
|
|
static volatile char var3 = 'a';
|
|
volatile char var4 = 'a';
|
|
static volatile char arr3[] = "hello";
|
|
volatile char arr4[] = "hello";
|
|
|
|
// These all result in volatile loads in C and C++11. In C++98, they don't,
|
|
// but we suppress the warning in the case where '(void)var;' might be
|
|
// idiomatically suppressing an 'unused variable' warning.
|
|
(void)var1;
|
|
(void)var2;
|
|
#if __cplusplus < 201103L
|
|
// expected-warning@-2 {{expression result unused; assign into a variable to force a volatile load}}
|
|
#endif
|
|
(void)var3;
|
|
(void)var4;
|
|
|
|
// None of these result in volatile loads in any language mode, and it's not
|
|
// really reasonable to assume that they would, since volatile array loads
|
|
// don't really exist anywhere.
|
|
(void)arr1;
|
|
(void)arr2;
|
|
(void)arr3;
|
|
(void)arr4;
|
|
}
|
|
|
|
#if __cplusplus >= 201103L // C++11 or later
|
|
namespace test5 {
|
|
int v[(5, 6)]; // expected-warning {{left operand of comma operator has no effect}}
|
|
void foo() {
|
|
new double[false ? (1, 2) : 3]
|
|
// FIXME: We shouldn't diagnose the unreachable constant expression
|
|
// here.
|
|
[false ? (1, 2) : 3]; // expected-warning {{left operand of comma operator has no effect}}
|
|
}
|
|
} // namespace test5
|
|
|
|
// comma operator diagnostics should be suppressed in a SFINAE context.
|
|
template <typename T, int = (T{},0)> int c(int) { return 0; }
|
|
template <typename T, int> int c(double) { return 1; }
|
|
int foo() { return c<int>(0); }
|
|
|
|
#endif
|
|
|
|
#if __cplusplus >= 201703L // C++17 or later
|
|
namespace test6 {
|
|
auto b() {
|
|
if constexpr (false)
|
|
return (1,0);
|
|
else
|
|
return (1.0,0.0); // expected-warning {{left operand of comma operator has no effect}}
|
|
}
|
|
} // namespace test6
|
|
#endif
|