Skip to content
Open
Show file tree
Hide file tree
Changes from all 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
2 changes: 2 additions & 0 deletions clang/include/clang/Basic/DiagnosticParseKinds.td
Original file line number Diff line number Diff line change
Expand Up @@ -399,6 +399,8 @@ def err_requires_clause_on_declarator_not_declaring_a_function : Error<
"trailing requires clause can only be used when declaring a function">;
def err_requires_clause_inside_parens : Error<
"trailing requires clause should be placed outside parentheses">;
def err_auto_type_specifier : Error<
"'auto' cannot be combined with a type specifier">;
def ext_auto_storage_class : ExtWarn<
"'auto' storage class specifier is not permitted in C++11, and will not "
Comment on lines 404 to 405
Copy link
Member

Choose a reason for hiding this comment

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

This pr makes ext_auto_storage_class unused, so we should remove it

"be supported in future releases">, InGroup<DiagGroup<"auto-storage-class">>;
Expand Down
22 changes: 17 additions & 5 deletions clang/lib/Parse/ParseDecl.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -4095,11 +4095,23 @@ void Parser::ParseDeclarationSpecifiers(
case tok::kw_auto:
if (getLangOpts().CPlusPlus11 || getLangOpts().C23) {
if (isKnownToBeTypeSpecifier(GetLookAheadToken(1))) {
isInvalid = DS.SetStorageClassSpec(Actions, DeclSpec::SCS_auto, Loc,
PrevSpec, DiagID, Policy);
if (!isInvalid && !getLangOpts().C23)
Diag(Tok, diag::ext_auto_storage_class)
<< FixItHint::CreateRemoval(DS.getStorageClassSpecLoc());
// In C++ (not C23), 'auto' cannot be combined with a type specifier.
// OpenCL is excluded here because Sema emits a more specific error
// message for OpenCL (e.g., "does not support the 'auto' storage
// class specifier").
if (!getLangOpts().C23 && !getLangOpts().OpenCLCPlusPlus) {
// In C++11+, 'auto' cannot be combined with a type specifier.
// Don't set the storage class specifier to avoid Sema emitting a
// redundant error (GCC only emits one error for this case: "two or
// more data types in declaration").
isInvalid = true;
PrevSpec = "auto";
Copy link
Collaborator

Choose a reason for hiding this comment

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

Suggested change
PrevSpec = "auto";
PrevSpec = Tok.getIdentifierInfo()->getNameStart();

DiagID = diag::err_auto_type_specifier;
} else {
// C23 allows 'auto' as storage class with type specifier.
isInvalid = DS.SetStorageClassSpec(Actions, DeclSpec::SCS_auto, Loc,
PrevSpec, DiagID, Policy);
}
} else
isInvalid = DS.SetTypeSpecType(DeclSpec::TST_auto, Loc, PrevSpec,
DiagID, Policy);
Expand Down
36 changes: 23 additions & 13 deletions clang/test/CXX/dcl.dcl/dcl.spec/dcl.stc/p2.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -5,14 +5,18 @@
// The auto or register specifiers can be applied only to names of objects
// declared in a block (6.3) or to function parameters (8.4).

auto int ao; // expected-error {{illegal storage class on file-scoped variable}}
auto int ao;
#if __cplusplus >= 201103L // C++11 or later
// expected-warning@-2 {{'auto' storage class specifier is not permitted in C++11, and will not be supported in future releases}}
// expected-error@-2 {{'auto' cannot be combined with a type specifier}}
#else
// expected-error@-4 {{illegal storage class on file-scoped variable}}
Comment on lines +10 to +12
Copy link
Collaborator

Choose a reason for hiding this comment

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

It'd be slightly easier to review this file if we used -verify= and different prefixes instead of preprocessor conditionals, but I don't insist on a change for this PR either unless others have strong feelings.

#endif

auto void af(); // expected-error {{illegal storage class on function}}
auto void af();
#if __cplusplus >= 201103L // C++11 or later
// expected-warning@-2 {{'auto' storage class specifier is not permitted in C++11, and will not be supported in future releases}}
// expected-error@-2 {{'auto' cannot be combined with a type specifier}}
#else
// expected-error@-4 {{illegal storage class on function}}
#endif

register int ro; // expected-error {{illegal storage class on file-scoped variable}}
Expand All @@ -25,13 +29,17 @@ register int ro; // expected-error {{illegal storage class on file-scoped variab
register void rf(); // expected-error {{illegal storage class on function}}

struct S {
auto int ao; // expected-error {{storage class specified for a member declaration}}
auto int ao;
#if __cplusplus >= 201103L // C++11 or later
// expected-warning@-2 {{'auto' storage class specifier is not permitted in C++11, and will not be supported in future releases}}
// expected-error@-2 {{'auto' cannot be combined with a type specifier}}
#else
// expected-error@-4 {{storage class specified for a member declaration}}
#endif
auto void af(); // expected-error {{storage class specified for a member declaration}}
auto void af();
#if __cplusplus >= 201103L // C++11 or later
// expected-warning@-2 {{'auto' storage class specifier is not permitted in C++11, and will not be supported in future releases}}
// expected-error@-2 {{'auto' cannot be combined with a type specifier}}
#else
// expected-error@-4 {{storage class specified for a member declaration}}
#endif

register int ro; // expected-error {{storage class specified for a member declaration}}
Expand All @@ -40,19 +48,21 @@ struct S {

void foo(auto int ap, register int rp) {
#if __cplusplus >= 201703L
// expected-warning@-2 {{'auto' storage class specifier is not permitted in C++11, and will not be supported in future releases}}
// expected-error@-2 {{'auto' cannot be combined with a type specifier}}
// expected-error@-3 {{ISO C++17 does not allow 'register' storage class specifier}}
#elif __cplusplus >= 201103L
// expected-warning@-5 {{'auto' storage class specifier is not permitted in C++11, and will not be supported in future releases}}
// expected-error@-5 {{'auto' cannot be combined with a type specifier}}
// expected-warning@-6 {{'register' storage class specifier is deprecated}}
#endif
auto int abo;
#if __cplusplus >= 201103L // C++11 or later
// expected-warning@-2 {{'auto' storage class specifier is not permitted in C++11, and will not be supported in future releases}}
// expected-error@-2 {{'auto' cannot be combined with a type specifier}}
#endif
auto void abf(); // expected-error {{illegal storage class on function}}
auto void abf();
#if __cplusplus >= 201103L // C++11 or later
// expected-warning@-2 {{'auto' storage class specifier is not permitted in C++11, and will not be supported in future releases}}
// expected-error@-2 {{'auto' cannot be combined with a type specifier}}
#else
// expected-error@-4 {{illegal storage class on function}}
#endif

register int rbo;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -56,7 +56,7 @@ namespace p3_example {
auto x = 5;
const auto *v = &x, u = 6;
static auto y = 0.0;
auto int r; // expected-warning {{storage class}} expected-error {{file-scope}}
auto int r; // expected-error {{'auto' cannot be combined with a type specifier}}

static_assert(is_same<decltype(x), int>(), "");
static_assert(is_same<decltype(v), const int*>(), "");
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -42,7 +42,12 @@ void p3example() {
static auto y = 0.0;
Copy link
Collaborator

Choose a reason for hiding this comment

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

This line should also be diagnosed in C++98 mode... this seems to be a preexisting bug: https://godbolt.org/z/3cza618cx (we have a similar bug with register: https://godbolt.org/z/zs5918YY4)

GitHub is too useless to let me put this comment on the correct line, but line 40 has a similar C++98 bug: https://godbolt.org/z/xEozMhe6z because there's no type specifier there, and line 41 does as well for the same reason.

Hmmm, it seems we're treating type deduction as an extension in C++98 mode, but we don't list it in the language extensions page as such and we don't issue pedantic diagnostics for it. @zygoloid do you recall if this was an intentional extension or not? Regardless, because this is existing behavior, nothing needs to change as part of this PR.

Copy link
Collaborator

Choose a reason for hiding this comment

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

Hmmm, it seems we're treating type deduction as an extension in C++98 mode, but we don't list it in the language extensions page as such and we don't issue pedantic diagnostics for it. @zygoloid do you recall if this was an intentional extension or not?

I see a diagnostic for it appearing in all of your test cases:

<source>:2:10: warning: 'auto' type specifier is a C++11 extension [-Wc++11-extensions]
    2 |   static auto y = 0.0;
      |     

... and -pedantic-errors does promote that to an error. So yeah, this is an intentional extension, from the general category of feature from a later language mode accepted in earlier language modes, but I guess the table in our documentation is incomplete -- it only seems to include the C++ features with feature test macros (plus one that I guess postdates the table).

If we want that table to be complete, it's probably worth going through the diagnostics in the -Wc++XY-extensions groups and making sure they're all listed. All the relevant extensions should have diagnostics already.

Copy link
Collaborator

Choose a reason for hiding this comment

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

I see a diagnostic for it appearing in all of your test cases:

Ugh, yeah, I am seeing that now, I think I was looking at the wrong output before. :-D

Yeah, I think the table just needs to be updated, that doesn't need to be a part of this PR though. Thanks!

// In C++98: 'auto' storage class specifier is redundant and incompatible with C++0x
// In C++0x: 'auto' storage class specifier is not permitted in C++0x, and will not be supported in future releases
auto int r; // expected-warning {{'auto' storage class specifier}}
auto int r;
#if __cplusplus >= 201103L
// expected-error@-2 {{'auto' cannot be combined with a type specifier}}
#else
// expected-warning@-4 {{'auto' storage class specifier}}
#endif

same<__typeof(x), int> xHasTypeInt;
same<__typeof(v), const int*> vHasTypeConstIntPtr;
Expand Down
8 changes: 5 additions & 3 deletions clang/test/CXX/drs/cwg3xx.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1732,11 +1732,13 @@ namespace cwg395 { // cwg395: 3.0
namespace cwg396 { // cwg396: 3.0
void f() {
auto int a();
// since-cxx11-error@-1 {{'auto' storage class specifier is not permitted in C++11, and will not be supported in future releases}}
// expected-error@-2 {{illegal storage class on function}}
// cxx98-error@-1 {{illegal storage class on function}}
// since-cxx11-error@-2 {{'auto' cannot be combined with a type specifier}}
// since-cxx11-warning@-3 {{empty parentheses interpreted as a function declaration}}
// since-cxx11-note@-4 {{replace parentheses with an initializer to declare a variable}}
int (i); // #cwg396-i
auto int (i);
// since-cxx11-error@-1 {{'auto' storage class specifier is not permitted in C++11, and will not be supported in future releases}}
// since-cxx11-error@-1 {{'auto' cannot be combined with a type specifier}}
// expected-error@-2 {{redefinition of 'i'}}
// expected-note@#cwg396-i {{previous definition is here}}
}
Expand Down
22 changes: 22 additions & 0 deletions clang/test/Parser/cxx-auto-type-specifier.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
// RUN: %clang_cc1 -fsyntax-only -verify -std=c++11 %s
// RUN: %clang_cc1 -fsyntax-only -verify -std=c++14 %s
// RUN: %clang_cc1 -fsyntax-only -verify -std=c++17 %s
// RUN: %clang_cc1 -fsyntax-only -verify -std=c++20 %s
// RUN: %clang_cc1 -fsyntax-only -verify -std=c++23 %s

// Test that 'auto' cannot be combined with a type specifier in C++.
void f() {
auto int x = 1; // expected-error {{'auto' cannot be combined with a type specifier}}
Comment on lines +8 to +9
Copy link
Collaborator

Choose a reason for hiding this comment

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

One more test to add:

template <typename Ty>
void g() {
  auto Ty x;
}

void test() {
  g<float>();
}

auto char c = 'a'; // expected-error {{'auto' cannot be combined with a type specifier}}
auto float f = 1.0f; // expected-error {{'auto' cannot be combined with a type specifier}}
auto double d = 1.0; // expected-error {{'auto' cannot be combined with a type specifier}}
auto long l = 1L; // expected-error {{'auto' cannot be combined with a type specifier}}
}

// Test that regular 'auto' (type deduction) still works in C++.
void h() {
auto x = 1;
auto y = 2.0;
auto z = 'c';
}

2 changes: 1 addition & 1 deletion clang/test/SemaCXX/auto-cxx0x.cpp
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
// RUN: %clang_cc1 -fsyntax-only -verify %s -std=c++11
// RUN: %clang_cc1 -fsyntax-only -verify %s -std=c++1y
void f() {
auto int a; // expected-warning {{'auto' storage class specifier is not permitted in C++11, and will not be supported in future releases}}
auto int a; // expected-error {{'auto' cannot be combined with a type specifier}}
int auto b; // expected-error{{cannot combine with previous 'int' declaration specifier}}
}

Expand Down
7 changes: 4 additions & 3 deletions clang/test/SemaCXX/class.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -2,11 +2,12 @@
// RUN: %clang_cc1 -fsyntax-only -verify=expected,cxx98 -Wc++11-compat %s -std=c++98
class C {
public:
auto int errx; // expected-error {{storage class specified for a member declaration}}
auto int errx;
#if __cplusplus <= 199711L
// expected-warning@-2 {{'auto' storage class specifier is redundant}}
// expected-error@-2 {{storage class specified for a member declaration}}
// expected-warning@-3 {{'auto' storage class specifier is redundant and incompatible with C++11}}
#else
// expected-warning@-4 {{'auto' storage class specifier is not permitted in C++11, and will not be supported in future releases}}
// expected-error@-5 {{'auto' cannot be combined with a type specifier}}
#endif
register int erry; // expected-error {{storage class specified for a member declaration}}
extern int errz; // expected-error {{storage class specified for a member declaration}}
Expand Down
7 changes: 6 additions & 1 deletion clang/test/SemaCXX/static-data-member.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,12 @@ double ABC::a = 1.0;
extern double ABC::b = 1.0; // expected-error {{static data member definition cannot specify a storage class}}
static double ABC::c = 1.0; // expected-error {{'static' can only be specified inside the class definition}}
__private_extern__ double ABC::d = 1.0; // expected-error {{static data member definition cannot specify a storage class}}
auto double ABC::e = 1.0; // expected-error {{static data member definition cannot specify a storage class}}
auto double ABC::e = 1.0;
#if __cplusplus >= 201103L
// expected-error@-2 {{'auto' cannot be combined with a type specifier}}
#else
// expected-error@-4 {{static data member definition cannot specify a storage class}}
#endif
#if __cplusplus < 201703L
register double ABC::f = 1.0; // expected-error {{static data member definition cannot specify a storage class}}
#endif