1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180
|
// 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'}}
extern Bad * pb;
// This typeid can throw but that is not a side-effect that we care about
// warning for since this is idiomatic code
(void)typeid(*pb);
(void)sizeof(typeid(*pb));
(void)typeid(*++pb); // expected-warning {{expression with side effects will be evaluated despite being used as an operand to 'typeid'}}
(void)sizeof(typeid(*++pb)); // expected-warning {{expression with side effects has no effect in an unevaluated context}}
// FIXME: we should not warn about this in an unevaluated context
// expected-warning@-2 {{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
|