Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Turn -Wdeprecated-literal-operator on by default #111027

Merged
merged 4 commits into from
Oct 11, 2024
Merged
Show file tree
Hide file tree
Changes from 3 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
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 @@ -216,6 +230,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

- Clang now emits a diagnostic note at the class declaration when the method definition does not match any declaration (#GH110638).

- 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)) {
Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It isn't clear to me that this check was necessary at all? So I've removed it. Both diags happen now without the check, and unconditionally on each-other. They also share the FixItHint, which was done in a frightening-ish way.

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I don't think we need it any longer because I believe we suppress diagnostics in system headers via the diagnostics engine itself; you can test it out by using GNU line markers to pretend some code is a system header: https://godbolt.org/z/PsaM19Pe8

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
Loading