Skip to content

Commit

Permalink
Turn -Wdeprecated-literal-operator on by default (llvm#111027)
Browse files Browse the repository at this point in the history
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]>
  • Loading branch information
2 people authored and bricknerb committed Oct 17, 2024
1 parent b5b679b commit 28599aa
Show file tree
Hide file tree
Showing 32 changed files with 236 additions and 197 deletions.
22 changes: 22 additions & 0 deletions clang/docs/ReleaseNotes.rst
Original file line number Diff line number Diff line change
Expand Up @@ -99,6 +99,20 @@ C++ Specific Potentially Breaking Changes
// Was error, now evaluates to false.
constexpr bool b = f() == g();
- The warning ``-Wdeprecated-literal-operator`` is now on by default, as this is
something that WG21 has shown interest in removing from the language. The
result is that anyone who is compiling with ``-Werror`` should see this
diagnostic. To fix this diagnostic, simply removing the space character from
between the ``operator""`` and the user defined literal name will make the
source no longer deprecated. This is consistent with `CWG2521 <https://cplusplus.github.io/CWG/issues/2521.html>_`.

.. code-block:: c++

// Now diagnoses by default.
unsigned operator"" _udl_name(unsigned long long);
// Fixed version:
unsigned operator""_udl_name(unsigned long long);

ABI Changes in This Version
---------------------------

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

- Clang now diagnoses a space in the first production of a ``literal-operator-id``
by default.
(`CWG2521: User-defined literals and reserved identifiers <https://cplusplus.github.io/CWG/issues/2521.html>`_).

C Language Changes
------------------

Expand Down Expand Up @@ -378,6 +396,10 @@ Improvements to Clang's diagnostics
- The warning for an unsupported type for a named register variable is now phrased ``unsupported type for named register variable``,
instead of ``bad type for named register variable``. This makes it clear that the type is not supported at all, rather than being
suboptimal in some way the error fails to mention (#GH111550).

- Clang now emits a ``-Wdepredcated-literal-operator`` diagnostic, even if the
name was a reserved name, which we improperly allowed to suppress the
diagnostic.

Improvements to Clang's time-trace
----------------------------------
Expand Down
2 changes: 1 addition & 1 deletion clang/include/clang/Basic/DiagnosticSemaKinds.td
Original file line number Diff line number Diff line change
Expand Up @@ -439,7 +439,7 @@ def warn_reserved_extern_symbol: Warning<
InGroup<ReservedIdentifier>, DefaultIgnore;
def warn_deprecated_literal_operator_id: Warning<
"identifier %0 preceded by whitespace in a literal operator declaration "
"is deprecated">, InGroup<DeprecatedLiteralOperator>, DefaultIgnore;
"is deprecated">, InGroup<DeprecatedLiteralOperator>;
def warn_reserved_module_name : Warning<
"%0 is a reserved name for a module">, InGroup<ReservedModuleIdentifier>;
def warn_import_implementation_partition_unit_in_interface_unit : Warning<
Expand Down
3 changes: 3 additions & 0 deletions clang/lib/Basic/IdentifierTable.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -406,6 +406,9 @@ ReservedLiteralSuffixIdStatus
IdentifierInfo::isReservedLiteralSuffixId() const {
StringRef Name = getName();

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

Expand Down
28 changes: 17 additions & 11 deletions clang/lib/Sema/SemaExprCXX.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -503,17 +503,23 @@ bool Sema::checkLiteralOperatorId(const CXXScopeSpec &SS,
const IdentifierInfo *II = Name.Identifier;
ReservedIdentifierStatus Status = II->isReserved(PP.getLangOpts());
SourceLocation Loc = Name.getEndLoc();
if (!PP.getSourceManager().isInSystemHeader(Loc)) {
if (auto Hint = FixItHint::CreateReplacement(
Name.getSourceRange(),
(StringRef("operator\"\"") + II->getName()).str());
isReservedInAllContexts(Status)) {
Diag(Loc, diag::warn_reserved_extern_symbol)
<< II << static_cast<int>(Status) << Hint;
} else {
Diag(Loc, diag::warn_deprecated_literal_operator_id) << II << Hint;
}
}

auto Hint = FixItHint::CreateReplacement(
Name.getSourceRange(),
(StringRef("operator\"\"") + II->getName()).str());

// Only emit this diagnostic if we start with an underscore, else the
// diagnostic for C++11 requiring a space between the quotes and the
// identifier conflicts with this and gets confusing. The diagnostic stating
// this is a reserved name should force the underscore, which gets this
// back.
if (II->isReservedLiteralSuffixId() !=
ReservedLiteralSuffixIdStatus::NotStartsWithUnderscore)
Diag(Loc, diag::warn_deprecated_literal_operator_id) << II << Hint;

if (isReservedInAllContexts(Status))
Diag(Loc, diag::warn_reserved_extern_symbol)
<< II << static_cast<int>(Status) << Hint;
}

if (!SS.isValid())
Expand Down
2 changes: 1 addition & 1 deletion clang/test/CXX/drs/cwg14xx.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -627,7 +627,7 @@ int i = N::f();

namespace cwg1479 { // cwg1479: 3.1
#if __cplusplus >= 201103L
int operator"" _a(const char*, std::size_t = 0);
int operator""_a(const char*, std::size_t = 0);
// since-cxx11-error@-1 {{literal operator cannot have a default argument}}
#endif
}
Expand Down
3 changes: 3 additions & 0 deletions clang/test/CXX/drs/cwg25xx.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -88,6 +88,9 @@ operator"" _div();
using ::cwg2521::operator"" _\u03C0___;
using ::cwg2521::operator""_div;
// since-cxx11-warning@-2 {{identifier '_π___' preceded by whitespace in a literal operator declaration is deprecated}}

long double operator"" _RESERVED(long double);
// since-cxx11-warning@-1 {{identifier '_RESERVED' preceded by whitespace in a literal operator declaration is deprecated}}
#pragma clang diagnostic pop
#endif
} // namespace cwg2521
Expand Down
2 changes: 1 addition & 1 deletion clang/test/CXX/lex/lex.literal/lex.ext/p1.cpp
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
// RUN: %clang_cc1 -fsyntax-only -std=c++11 -verify %s
// RUN: %clang_cc1 -fsyntax-only -std=c++11 -Wno-deprecated-literal-operator -verify %s

void operator "" p31(long double); // expected-warning{{user-defined literal suffixes not starting with '_' are reserved}}
void operator "" _p31(long double);
Expand Down
2 changes: 1 addition & 1 deletion clang/test/CXX/lex/lex.literal/lex.ext/p10.cpp
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
// RUN: %clang_cc1 -std=c++11 -verify %s
// RUN: %clang_cc1 -std=c++11 -Wno-deprecated-literal-operator -verify %s

using size_t = decltype(sizeof(int));
void operator "" wibble(const char *); // expected-warning {{user-defined literal suffixes not starting with '_' are reserved; no literal will invoke this operator}}
Expand Down
6 changes: 3 additions & 3 deletions clang/test/CXX/lex/lex.literal/lex.ext/p11.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -6,16 +6,16 @@ template<typename T, typename U> struct same_type;
template<typename T> struct same_type<T, T> {};
template<typename T> using X = T;
template<typename CharT, X<CharT>...>
int operator "" _x(); // expected-warning {{string literal operator templates are a GNU extension}}
int operator ""_x(); // expected-warning {{string literal operator templates are a GNU extension}}
template<char...>
double operator "" _x();
double operator ""_x();

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

char operator "" _x(const char *begin, size_t size);
char operator ""_x(const char *begin, size_t size);
auto c="string"_x;
auto d=L"string"_x;
same_type<decltype(c), char> test_c;
Expand Down
10 changes: 5 additions & 5 deletions clang/test/CXX/lex/lex.literal/lex.ext/p3.cpp
Original file line number Diff line number Diff line change
@@ -1,18 +1,18 @@
// RUN: %clang_cc1 -fsyntax-only -std=c++11 -verify %s

int &operator "" _x1 (unsigned long long);
int &operator ""_x1 (unsigned long long);
int &i1 = 0x123_x1;

double &operator "" _x1 (const char *);
double &operator ""_x1 (const char *);
int &i2 = 45_x1;

template<char...> char &operator "" _x1 ();
template<char...> char &operator ""_x1 ();
int &i3 = 0377_x1;

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

double &operator "" _x2 (const char *);
double &operator ""_x2 (const char *);
double &i5 = 123123123123123123123123123123123123123123123_x2;

template<char...Cs> constexpr int operator "" _x3() { return sizeof...(Cs); }
template<char...Cs> constexpr int operator ""_x3() { return sizeof...(Cs); }
static_assert(123456789012345678901234567890123456789012345678901234567890_x3 == 60, "");
10 changes: 5 additions & 5 deletions clang/test/CXX/lex/lex.literal/lex.ext/p4.cpp
Original file line number Diff line number Diff line change
@@ -1,18 +1,18 @@
// RUN: %clang_cc1 -fsyntax-only -std=c++11 -verify %s

int &operator "" _x1 (long double);
int &operator ""_x1 (long double);
int &i1 = 0.123_x1;

double &operator "" _x1 (const char *);
double &operator ""_x1 (const char *);
int &i2 = 45._x1;

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

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

double &operator "" _x2 (const char *);
double &operator ""_x2 (const char *);
double &i5 = 1e1000000_x2;

template<char...Cs> constexpr int operator "" _x3() { return sizeof...(Cs); }
template<char...Cs> constexpr int operator ""_x3() { return sizeof...(Cs); }
static_assert(1e1000000_x3 == 9, "");
8 changes: 4 additions & 4 deletions clang/test/CXX/lex/lex.literal/lex.ext/p5.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -3,19 +3,19 @@

using size_t = decltype(sizeof(int));

int &operator "" _x1 (const char *);
double &operator "" _x1 (const char *, size_t);
int &operator ""_x1 (const char *);
double &operator ""_x1 (const char *, size_t);
double &i1 = "foo"_x1;
#if __cplusplus >= 202002L
using char8 = float;
float &operator "" _x1 (const char8_t *, size_t);
float &operator ""_x1 (const char8_t *, size_t);
#else
using char8 = double;
#endif
char8 &i2 = u8"foo"_x1;
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'}}

char &operator "" _x1(const wchar_t *, size_t);
char &operator ""_x1(const wchar_t *, size_t);
char &i4 = L"foo"_x1; // ok
double &i5 = R"(foo)"_x1; // ok
char8 &i6 = u\
Expand Down
8 changes: 4 additions & 4 deletions clang/test/CXX/lex/lex.literal/lex.ext/p6.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -2,13 +2,13 @@

using size_t = decltype(sizeof(int));

int &operator "" _x1 (const char *);
int &operator ""_x1 (const char *);
double &i1 = 'a'_x1; // expected-error {{no matching literal operator}}
double &operator "" _x1 (wchar_t);
double &operator ""_x1 (wchar_t);
double &i2 = L'a'_x1;
double &i3 = 'a'_x1; // expected-error {{no matching literal operator}}
double &i4 = operator"" _x1('a'); // ok
double &i4 = operator""_x1('a'); // ok

char &operator "" _x1(char16_t);
char &operator ""_x1(char16_t);
char &i5 = u'a'_x1; // ok
double &i6 = L'a'_x1; // ok
6 changes: 3 additions & 3 deletions clang/test/CXX/lex/lex.literal/lex.ext/p7.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -10,9 +10,9 @@ template<typename T> struct same_type<T, T> {};

namespace std_example {

long double operator "" _w(long double);
std::string operator "" _w(const char16_t*, size_t);
unsigned operator "" _w(const char*);
long double operator ""_w(long double);
std::string operator ""_w(const char16_t*, size_t);
unsigned operator ""_w(const char*);
int main() {
auto v1 = 1.2_w; // calls operator""_w(1.2L)
auto v2 = u"one"_w; // calls operator""_w(u"one", 3)
Expand Down
6 changes: 3 additions & 3 deletions clang/test/CXX/lex/lex.literal/lex.ext/p8.cpp
Original file line number Diff line number Diff line change
@@ -1,16 +1,16 @@
// RUN: %clang_cc1 -std=c++11 -verify %s

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

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

constexpr const char *operator "" _trim(const char *p, size_t n) {
return *p == ' ' ? operator "" _trim(p + 1, n - 1) : p;
constexpr const char *operator ""_trim(const char *p, size_t n) {
return *p == ' ' ? operator ""_trim(p + 1, n - 1) : p;
}
constexpr const char *t = " " " "_trim " foo";
static_assert(streq(t, "foo"), "");
Expand Down
2 changes: 1 addition & 1 deletion clang/test/CXX/lex/lex.literal/lex.ext/p9.cpp
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
// RUN: %clang_cc1 -std=c++11 -fsyntax-only -verify %s

using size_t = decltype(sizeof(int));
void operator "" _x(const wchar_t *, size_t);
void operator ""_x(const wchar_t *, size_t);

namespace std_example {

Expand Down
28 changes: 14 additions & 14 deletions clang/test/CXX/over/over.oper/over.literal/p2.cpp
Original file line number Diff line number Diff line change
@@ -1,43 +1,43 @@
// RUN: %clang_cc1 -std=c++11 %s -verify

void operator "" _a(const char *);
void operator ""_a(const char *);

namespace N {
using ::operator "" _a;
using ::operator ""_a;

void operator "" _b(const char *);
void operator ""_b(const char *);
}

using N::operator "" _b;
using N::operator ""_b;

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

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

friend void operator "" _d(const char *);
friend void operator ""_d(const char *);
};

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

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

extern "C++" {
void operator "" _g(const char *);
void operator ""_g(const char *);
}

template<char...> void operator "" _h() {}
template<char...> void operator ""_h() {}

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

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

namespace rdar13605348 {

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

Expand Down
Loading

0 comments on commit 28599aa

Please sign in to comment.