Skip to content

Commit c8554e1

Browse files
erichkeaneEndilll
andauthored
Turn -Wdeprecated-literal-operator on by default (#111027)
It would be nice to see what our users think about this change, as this is something that WG21/EWG quite wants to fix a handful of questionable issues with UB. Depending on the outcome of this after being committed, we might instead suggest EWG undeprecate this, and require a bit of 'magic' from the lexer. Additionally, this patch makes it so we emit this diagnostic ALSO in cases where the literal name is reserved. It doesn't make sense to limit that. --------- Co-authored-by: Vlad Serebrennikov <[email protected]>
1 parent 870d37d commit c8554e1

32 files changed

+236
-197
lines changed

clang/docs/ReleaseNotes.rst

+22
Original file line numberDiff line numberDiff line change
@@ -99,6 +99,20 @@ C++ Specific Potentially Breaking Changes
9999
// Was error, now evaluates to false.
100100
constexpr bool b = f() == g();
101101
102+
- The warning ``-Wdeprecated-literal-operator`` is now on by default, as this is
103+
something that WG21 has shown interest in removing from the language. The
104+
result is that anyone who is compiling with ``-Werror`` should see this
105+
diagnostic. To fix this diagnostic, simply removing the space character from
106+
between the ``operator""`` and the user defined literal name will make the
107+
source no longer deprecated. This is consistent with `CWG2521 <https://cplusplus.github.io/CWG/issues/2521.html>_`.
108+
109+
.. code-block:: c++
110+
111+
// Now diagnoses by default.
112+
unsigned operator"" _udl_name(unsigned long long);
113+
// Fixed version:
114+
unsigned operator""_udl_name(unsigned long long);
115+
102116
ABI Changes in This Version
103117
---------------------------
104118

@@ -215,6 +229,10 @@ Resolutions to C++ Defect Reports
215229
- Clang now allows trailing requires clause on explicit deduction guides.
216230
(`CWG2707: Deduction guides cannot have a trailing requires-clause <https://cplusplus.github.io/CWG/issues/2707.html>`_).
217231

232+
- Clang now diagnoses a space in the first production of a ``literal-operator-id``
233+
by default.
234+
(`CWG2521: User-defined literals and reserved identifiers <https://cplusplus.github.io/CWG/issues/2521.html>`_).
235+
218236
C Language Changes
219237
------------------
220238

@@ -378,6 +396,10 @@ Improvements to Clang's diagnostics
378396
- The warning for an unsupported type for a named register variable is now phrased ``unsupported type for named register variable``,
379397
instead of ``bad type for named register variable``. This makes it clear that the type is not supported at all, rather than being
380398
suboptimal in some way the error fails to mention (#GH111550).
399+
400+
- Clang now emits a ``-Wdepredcated-literal-operator`` diagnostic, even if the
401+
name was a reserved name, which we improperly allowed to suppress the
402+
diagnostic.
381403

382404
Improvements to Clang's time-trace
383405
----------------------------------

clang/include/clang/Basic/DiagnosticSemaKinds.td

+1-1
Original file line numberDiff line numberDiff line change
@@ -439,7 +439,7 @@ def warn_reserved_extern_symbol: Warning<
439439
InGroup<ReservedIdentifier>, DefaultIgnore;
440440
def warn_deprecated_literal_operator_id: Warning<
441441
"identifier %0 preceded by whitespace in a literal operator declaration "
442-
"is deprecated">, InGroup<DeprecatedLiteralOperator>, DefaultIgnore;
442+
"is deprecated">, InGroup<DeprecatedLiteralOperator>;
443443
def warn_reserved_module_name : Warning<
444444
"%0 is a reserved name for a module">, InGroup<ReservedModuleIdentifier>;
445445
def warn_import_implementation_partition_unit_in_interface_unit : Warning<

clang/lib/Basic/IdentifierTable.cpp

+3
Original file line numberDiff line numberDiff line change
@@ -406,6 +406,9 @@ ReservedLiteralSuffixIdStatus
406406
IdentifierInfo::isReservedLiteralSuffixId() const {
407407
StringRef Name = getName();
408408

409+
// Note: the diag::warn_deprecated_literal_operator_id diagnostic depends on
410+
// this being the first check we do, so if this order changes, we have to fix
411+
// that as well.
409412
if (Name[0] != '_')
410413
return ReservedLiteralSuffixIdStatus::NotStartsWithUnderscore;
411414

clang/lib/Sema/SemaExprCXX.cpp

+17-11
Original file line numberDiff line numberDiff line change
@@ -503,17 +503,23 @@ bool Sema::checkLiteralOperatorId(const CXXScopeSpec &SS,
503503
const IdentifierInfo *II = Name.Identifier;
504504
ReservedIdentifierStatus Status = II->isReserved(PP.getLangOpts());
505505
SourceLocation Loc = Name.getEndLoc();
506-
if (!PP.getSourceManager().isInSystemHeader(Loc)) {
507-
if (auto Hint = FixItHint::CreateReplacement(
508-
Name.getSourceRange(),
509-
(StringRef("operator\"\"") + II->getName()).str());
510-
isReservedInAllContexts(Status)) {
511-
Diag(Loc, diag::warn_reserved_extern_symbol)
512-
<< II << static_cast<int>(Status) << Hint;
513-
} else {
514-
Diag(Loc, diag::warn_deprecated_literal_operator_id) << II << Hint;
515-
}
516-
}
506+
507+
auto Hint = FixItHint::CreateReplacement(
508+
Name.getSourceRange(),
509+
(StringRef("operator\"\"") + II->getName()).str());
510+
511+
// Only emit this diagnostic if we start with an underscore, else the
512+
// diagnostic for C++11 requiring a space between the quotes and the
513+
// identifier conflicts with this and gets confusing. The diagnostic stating
514+
// this is a reserved name should force the underscore, which gets this
515+
// back.
516+
if (II->isReservedLiteralSuffixId() !=
517+
ReservedLiteralSuffixIdStatus::NotStartsWithUnderscore)
518+
Diag(Loc, diag::warn_deprecated_literal_operator_id) << II << Hint;
519+
520+
if (isReservedInAllContexts(Status))
521+
Diag(Loc, diag::warn_reserved_extern_symbol)
522+
<< II << static_cast<int>(Status) << Hint;
517523
}
518524

519525
if (!SS.isValid())

clang/test/CXX/drs/cwg14xx.cpp

+1-1
Original file line numberDiff line numberDiff line change
@@ -627,7 +627,7 @@ int i = N::f();
627627

628628
namespace cwg1479 { // cwg1479: 3.1
629629
#if __cplusplus >= 201103L
630-
int operator"" _a(const char*, std::size_t = 0);
630+
int operator""_a(const char*, std::size_t = 0);
631631
// since-cxx11-error@-1 {{literal operator cannot have a default argument}}
632632
#endif
633633
}

clang/test/CXX/drs/cwg25xx.cpp

+3
Original file line numberDiff line numberDiff line change
@@ -88,6 +88,9 @@ operator"" _div();
8888
using ::cwg2521::operator"" _\u03C0___;
8989
using ::cwg2521::operator""_div;
9090
// since-cxx11-warning@-2 {{identifier '_π___' preceded by whitespace in a literal operator declaration is deprecated}}
91+
92+
long double operator"" _RESERVED(long double);
93+
// since-cxx11-warning@-1 {{identifier '_RESERVED' preceded by whitespace in a literal operator declaration is deprecated}}
9194
#pragma clang diagnostic pop
9295
#endif
9396
} // namespace cwg2521

clang/test/CXX/lex/lex.literal/lex.ext/p1.cpp

+1-1
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
// RUN: %clang_cc1 -fsyntax-only -std=c++11 -verify %s
1+
// RUN: %clang_cc1 -fsyntax-only -std=c++11 -Wno-deprecated-literal-operator -verify %s
22

33
void operator "" p31(long double); // expected-warning{{user-defined literal suffixes not starting with '_' are reserved}}
44
void operator "" _p31(long double);

clang/test/CXX/lex/lex.literal/lex.ext/p10.cpp

+1-1
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
// RUN: %clang_cc1 -std=c++11 -verify %s
1+
// RUN: %clang_cc1 -std=c++11 -Wno-deprecated-literal-operator -verify %s
22

33
using size_t = decltype(sizeof(int));
44
void operator "" wibble(const char *); // expected-warning {{user-defined literal suffixes not starting with '_' are reserved; no literal will invoke this operator}}

clang/test/CXX/lex/lex.literal/lex.ext/p11.cpp

+3-3
Original file line numberDiff line numberDiff line change
@@ -6,16 +6,16 @@ template<typename T, typename U> struct same_type;
66
template<typename T> struct same_type<T, T> {};
77
template<typename T> using X = T;
88
template<typename CharT, X<CharT>...>
9-
int operator "" _x(); // expected-warning {{string literal operator templates are a GNU extension}}
9+
int operator ""_x(); // expected-warning {{string literal operator templates are a GNU extension}}
1010
template<char...>
11-
double operator "" _x();
11+
double operator ""_x();
1212

1313
auto a="string"_x;
1414
auto b=42_x;
1515
same_type<decltype(a), int> test_a;
1616
same_type<decltype(b), double> test_b;
1717

18-
char operator "" _x(const char *begin, size_t size);
18+
char operator ""_x(const char *begin, size_t size);
1919
auto c="string"_x;
2020
auto d=L"string"_x;
2121
same_type<decltype(c), char> test_c;
Original file line numberDiff line numberDiff line change
@@ -1,18 +1,18 @@
11
// RUN: %clang_cc1 -fsyntax-only -std=c++11 -verify %s
22

3-
int &operator "" _x1 (unsigned long long);
3+
int &operator ""_x1 (unsigned long long);
44
int &i1 = 0x123_x1;
55

6-
double &operator "" _x1 (const char *);
6+
double &operator ""_x1 (const char *);
77
int &i2 = 45_x1;
88

9-
template<char...> char &operator "" _x1 ();
9+
template<char...> char &operator ""_x1 ();
1010
int &i3 = 0377_x1;
1111

1212
int &i4 = 90000000000000000000000000000000000000000000000_x1; // expected-error {{integer literal is too large to be represented in any integer type}}
1313

14-
double &operator "" _x2 (const char *);
14+
double &operator ""_x2 (const char *);
1515
double &i5 = 123123123123123123123123123123123123123123123_x2;
1616

17-
template<char...Cs> constexpr int operator "" _x3() { return sizeof...(Cs); }
17+
template<char...Cs> constexpr int operator ""_x3() { return sizeof...(Cs); }
1818
static_assert(123456789012345678901234567890123456789012345678901234567890_x3 == 60, "");
Original file line numberDiff line numberDiff line change
@@ -1,18 +1,18 @@
11
// RUN: %clang_cc1 -fsyntax-only -std=c++11 -verify %s
22

3-
int &operator "" _x1 (long double);
3+
int &operator ""_x1 (long double);
44
int &i1 = 0.123_x1;
55

6-
double &operator "" _x1 (const char *);
6+
double &operator ""_x1 (const char *);
77
int &i2 = 45._x1;
88

9-
template<char...> char &operator "" _x1 ();
9+
template<char...> char &operator ""_x1 ();
1010
int &i3 = 0377e-1_x1;
1111

1212
int &i4 = 1e1000000_x1; // expected-warning {{too large for type 'long double'}}
1313

14-
double &operator "" _x2 (const char *);
14+
double &operator ""_x2 (const char *);
1515
double &i5 = 1e1000000_x2;
1616

17-
template<char...Cs> constexpr int operator "" _x3() { return sizeof...(Cs); }
17+
template<char...Cs> constexpr int operator ""_x3() { return sizeof...(Cs); }
1818
static_assert(1e1000000_x3 == 9, "");

clang/test/CXX/lex/lex.literal/lex.ext/p5.cpp

+4-4
Original file line numberDiff line numberDiff line change
@@ -3,19 +3,19 @@
33

44
using size_t = decltype(sizeof(int));
55

6-
int &operator "" _x1 (const char *);
7-
double &operator "" _x1 (const char *, size_t);
6+
int &operator ""_x1 (const char *);
7+
double &operator ""_x1 (const char *, size_t);
88
double &i1 = "foo"_x1;
99
#if __cplusplus >= 202002L
1010
using char8 = float;
11-
float &operator "" _x1 (const char8_t *, size_t);
11+
float &operator ""_x1 (const char8_t *, size_t);
1212
#else
1313
using char8 = double;
1414
#endif
1515
char8 &i2 = u8"foo"_x1;
1616
double &i3 = L"foo"_x1; // expected-error {{no matching literal operator for call to 'operator""_x1' with arguments of types 'const wchar_t *' and 'unsigned long'}}
1717

18-
char &operator "" _x1(const wchar_t *, size_t);
18+
char &operator ""_x1(const wchar_t *, size_t);
1919
char &i4 = L"foo"_x1; // ok
2020
double &i5 = R"(foo)"_x1; // ok
2121
char8 &i6 = u\

clang/test/CXX/lex/lex.literal/lex.ext/p6.cpp

+4-4
Original file line numberDiff line numberDiff line change
@@ -2,13 +2,13 @@
22

33
using size_t = decltype(sizeof(int));
44

5-
int &operator "" _x1 (const char *);
5+
int &operator ""_x1 (const char *);
66
double &i1 = 'a'_x1; // expected-error {{no matching literal operator}}
7-
double &operator "" _x1 (wchar_t);
7+
double &operator ""_x1 (wchar_t);
88
double &i2 = L'a'_x1;
99
double &i3 = 'a'_x1; // expected-error {{no matching literal operator}}
10-
double &i4 = operator"" _x1('a'); // ok
10+
double &i4 = operator""_x1('a'); // ok
1111

12-
char &operator "" _x1(char16_t);
12+
char &operator ""_x1(char16_t);
1313
char &i5 = u'a'_x1; // ok
1414
double &i6 = L'a'_x1; // ok

clang/test/CXX/lex/lex.literal/lex.ext/p7.cpp

+3-3
Original file line numberDiff line numberDiff line change
@@ -10,9 +10,9 @@ template<typename T> struct same_type<T, T> {};
1010

1111
namespace std_example {
1212

13-
long double operator "" _w(long double);
14-
std::string operator "" _w(const char16_t*, size_t);
15-
unsigned operator "" _w(const char*);
13+
long double operator ""_w(long double);
14+
std::string operator ""_w(const char16_t*, size_t);
15+
unsigned operator ""_w(const char*);
1616
int main() {
1717
auto v1 = 1.2_w; // calls operator""_w(1.2L)
1818
auto v2 = u"one"_w; // calls operator""_w(u"one", 3)

clang/test/CXX/lex/lex.literal/lex.ext/p8.cpp

+3-3
Original file line numberDiff line numberDiff line change
@@ -1,16 +1,16 @@
11
// RUN: %clang_cc1 -std=c++11 -verify %s
22

33
using size_t = decltype(sizeof(int));
4-
constexpr const char *operator "" _id(const char *p, size_t) { return p; }
4+
constexpr const char *operator ""_id(const char *p, size_t) { return p; }
55
constexpr const char *s = "foo"_id "bar" "baz"_id "quux";
66

77
constexpr bool streq(const char *p, const char *q) {
88
return *p == *q && (!*p || streq(p+1, q+1));
99
}
1010
static_assert(streq(s, "foobarbazquux"), "");
1111

12-
constexpr const char *operator "" _trim(const char *p, size_t n) {
13-
return *p == ' ' ? operator "" _trim(p + 1, n - 1) : p;
12+
constexpr const char *operator ""_trim(const char *p, size_t n) {
13+
return *p == ' ' ? operator ""_trim(p + 1, n - 1) : p;
1414
}
1515
constexpr const char *t = " " " "_trim " foo";
1616
static_assert(streq(t, "foo"), "");

clang/test/CXX/lex/lex.literal/lex.ext/p9.cpp

+1-1
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
// RUN: %clang_cc1 -std=c++11 -fsyntax-only -verify %s
22

33
using size_t = decltype(sizeof(int));
4-
void operator "" _x(const wchar_t *, size_t);
4+
void operator ""_x(const wchar_t *, size_t);
55

66
namespace std_example {
77

clang/test/CXX/over/over.oper/over.literal/p2.cpp

+14-14
Original file line numberDiff line numberDiff line change
@@ -1,43 +1,43 @@
11
// RUN: %clang_cc1 -std=c++11 %s -verify
22

3-
void operator "" _a(const char *);
3+
void operator ""_a(const char *);
44

55
namespace N {
6-
using ::operator "" _a;
6+
using ::operator ""_a;
77

8-
void operator "" _b(const char *);
8+
void operator ""_b(const char *);
99
}
1010

11-
using N::operator "" _b;
11+
using N::operator ""_b;
1212

1313
class C {
14-
void operator "" _c(const char *); // expected-error {{must be in a namespace or global scope}}
14+
void operator ""_c(const char *); // expected-error {{must be in a namespace or global scope}}
1515

16-
static void operator "" _c(unsigned long long); // expected-error {{must be in a namespace or global scope}}
16+
static void operator ""_c(unsigned long long); // expected-error {{must be in a namespace or global scope}}
1717

18-
friend void operator "" _d(const char *);
18+
friend void operator ""_d(const char *);
1919
};
2020

21-
int operator "" _e; // expected-error {{cannot be the name of a variable}}
21+
int operator ""_e; // expected-error {{cannot be the name of a variable}}
2222

2323
void f() {
24-
int operator "" _f; // expected-error {{cannot be the name of a variable}}
24+
int operator ""_f; // expected-error {{cannot be the name of a variable}}
2525
}
2626

2727
extern "C++" {
28-
void operator "" _g(const char *);
28+
void operator ""_g(const char *);
2929
}
3030

31-
template<char...> void operator "" _h() {}
31+
template<char...> void operator ""_h() {}
3232

33-
template<> void operator "" _h<'a', 'b', 'c'>() {}
33+
template<> void operator ""_h<'a', 'b', 'c'>() {}
3434

35-
template void operator "" _h<'a', 'b', 'c', 'd'>();
35+
template void operator ""_h<'a', 'b', 'c', 'd'>();
3636

3737
namespace rdar13605348 {
3838

3939
class C {
40-
double operator"" _x(long double value) { return double(value); } // expected-error{{literal operator 'operator""_x' must be in a namespace or global scope}}
40+
double operator""_x(long double value) { return double(value); } // expected-error{{literal operator 'operator""_x' must be in a namespace or global scope}}
4141
double value() { return 3.2_x; } // expected-error{{no matching literal operator for call to}}
4242
};
4343

0 commit comments

Comments
 (0)