diff --git a/clang/include/clang/Basic/DiagnosticParseKinds.td b/clang/include/clang/Basic/DiagnosticParseKinds.td index b6039f8e297d..96252654dd27 100644 --- a/clang/include/clang/Basic/DiagnosticParseKinds.td +++ b/clang/include/clang/Basic/DiagnosticParseKinds.td @@ -28,10 +28,6 @@ def ext_extra_struct_semi : Extension< def ext_extra_ivar_semi : Extension< "extra ';' inside instance variable list">; -def auto_storage_class : ExtWarn< - "'auto' storage class specifier is redundant and will be " - "removed in future releases">; - def ext_duplicate_declspec : Extension<"duplicate '%0' declaration specifier">; def ext_plain_complex : ExtWarn< "plain '_Complex' requires a type specifier; assuming '_Complex double'">; @@ -198,6 +194,16 @@ def err_generalized_initializer_lists : Error< def ext_generalized_initializer_lists : ExtWarn< "generalized initializer lists are a C++0x extension unsupported in Clang">, InGroup; +def ext_auto_type_specifier : ExtWarn< + "'auto' type specifier is a C++0x extension">, InGroup; +def warn_auto_storage_class : Warning< + "'auto' storage class specifier is redundant and incompatible with C++0x">, + InGroup; +def ext_auto_storage_class : ExtWarn< + "'auto' storage class specifier is not permitted in C++0x, and will not " + "be supported in future releases">; +def ext_for_range : ExtWarn< + "range-based for loop is a C++0x extension">, InGroup; def err_argument_required_after_attribute : Error< "argument required after attribute">; def err_missing_param : Error<"expected parameter declarator">; diff --git a/clang/lib/Parse/ParseDecl.cpp b/clang/lib/Parse/ParseDecl.cpp index 8329757b6312..ad649a3c2250 100644 --- a/clang/lib/Parse/ParseDecl.cpp +++ b/clang/lib/Parse/ParseDecl.cpp @@ -1769,16 +1769,14 @@ void Parser::ParseDeclarationSpecifiers(DeclSpec &DS, if (getLang().CPlusPlus0x) { if (isKnownToBeTypeSpecifier(GetLookAheadToken(1))) { isInvalid = DS.SetStorageClassSpec(DeclSpec::SCS_auto, Loc, PrevSpec, - DiagID, getLang()); + DiagID, getLang()); if (!isInvalid) - Diag(Tok, diag::auto_storage_class) + Diag(Tok, diag::ext_auto_storage_class) << FixItHint::CreateRemoval(DS.getStorageClassSpecLoc()); - } - else + } else isInvalid = DS.SetTypeSpecType(DeclSpec::TST_auto, Loc, PrevSpec, DiagID); - } - else + } else isInvalid = DS.SetStorageClassSpec(DeclSpec::SCS_auto, Loc, PrevSpec, DiagID, getLang()); break; diff --git a/clang/lib/Parse/ParseStmt.cpp b/clang/lib/Parse/ParseStmt.cpp index 7ad48a1f5d9b..e400ed1391d2 100644 --- a/clang/lib/Parse/ParseStmt.cpp +++ b/clang/lib/Parse/ParseStmt.cpp @@ -1313,6 +1313,9 @@ StmtResult Parser::ParseForStatement(ParsedAttributes &attrs) { FirstPart = Actions.ActOnDeclStmt(DG, DeclStart, Tok.getLocation()); if (ForRangeInit.ParsedForRangeDecl()) { + if (!getLang().CPlusPlus0x) + Diag(ForRangeInit.ColonLoc, diag::ext_for_range); + ForRange = true; } else if (Tok.is(tok::semi)) { // for (int x = 4; ConsumeToken(); diff --git a/clang/lib/Sema/DeclSpec.cpp b/clang/lib/Sema/DeclSpec.cpp index c87f2cff5489..c388192bfef7 100644 --- a/clang/lib/Sema/DeclSpec.cpp +++ b/clang/lib/Sema/DeclSpec.cpp @@ -425,10 +425,23 @@ bool DeclSpec::SetStorageClassSpec(SCS S, SourceLocation Loc, } if (StorageClassSpec != SCS_unspecified) { + // Maybe this is an attempt to use C++0x 'auto' outside of C++0x mode. + bool isInvalid = true; + if (TypeSpecType == TST_unspecified && Lang.CPlusPlus) { + if (S == SCS_auto) + return SetTypeSpecType(TST_auto, Loc, PrevSpec, DiagID); + if (StorageClassSpec == SCS_auto) { + isInvalid = SetTypeSpecType(TST_auto, StorageClassSpecLoc, + PrevSpec, DiagID); + assert(!isInvalid && "auto SCS -> TST recovery failed"); + } + } + // Changing storage class is allowed only if the previous one // was the 'extern' that is part of a linkage specification and // the new storage class is 'typedef'. - if (!(SCS_extern_in_linkage_spec && + if (isInvalid && + !(SCS_extern_in_linkage_spec && StorageClassSpec == SCS_extern && S == SCS_typedef)) return BadSpecifier(S, (SCS)StorageClassSpec, PrevSpec, DiagID); @@ -836,6 +849,27 @@ void DeclSpec::Finish(Diagnostic &D, Preprocessor &PP) { } } + // If no type specifier was provided and we're parsing a language where + // the type specifier is not optional, but we got 'auto' as a storage + // class specifier, then assume this is an attempt to use C++0x's 'auto' + // type specifier. + // FIXME: Does Microsoft really support implicit int in C++? + if (PP.getLangOptions().CPlusPlus && !PP.getLangOptions().Microsoft && + TypeSpecType == TST_unspecified && StorageClassSpec == SCS_auto) { + TypeSpecType = TST_auto; + StorageClassSpec = StorageClassSpecAsWritten = SCS_unspecified; + TSTLoc = TSTNameLoc = StorageClassSpecLoc; + StorageClassSpecLoc = SourceLocation(); + } + // Diagnose if we've recovered from an ill-formed 'auto' storage class + // specifier in a pre-C++0x dialect of C++. + if (!PP.getLangOptions().CPlusPlus0x && TypeSpecType == TST_auto) + Diag(D, TSTLoc, diag::ext_auto_type_specifier); + if (PP.getLangOptions().CPlusPlus && !PP.getLangOptions().CPlusPlus0x && + StorageClassSpec == SCS_auto) + Diag(D, StorageClassSpecLoc, diag::warn_auto_storage_class) + << FixItHint::CreateRemoval(StorageClassSpecLoc); + // C++ [class.friend]p6: // No storage-class-specifier shall appear in the decl-specifier-seq // of a friend declaration. diff --git a/clang/test/CXX/class/class.friend/p6.cpp b/clang/test/CXX/class/class.friend/p6.cpp index bd4630e2aa9d..0b173b5b3f70 100644 --- a/clang/test/CXX/class/class.friend/p6.cpp +++ b/clang/test/CXX/class/class.friend/p6.cpp @@ -3,7 +3,7 @@ class A { friend static class B; // expected-error {{'static' is invalid in friend declarations}} friend extern class C; // expected-error {{'extern' is invalid in friend declarations}} - friend auto class D; // expected-error {{'auto' is invalid in friend declarations}} + friend auto class D; // expected-warning {{incompatible with C++0x}} expected-error {{'auto' is invalid in friend declarations}} friend register class E; // expected-error {{'register' is invalid in friend declarations}} friend mutable class F; // expected-error {{'mutable' is invalid in friend declarations}} friend typedef class G; // expected-error {{'typedef' is invalid in friend declarations}} diff --git a/clang/test/CXX/dcl.dcl/dcl.spec/dcl.type/dcl.spec.auto/p3.cpp b/clang/test/CXX/dcl.dcl/dcl.spec/dcl.type/dcl.spec.auto/p3.cpp index b675fb8013e3..fdca88591cec 100644 --- a/clang/test/CXX/dcl.dcl/dcl.spec/dcl.type/dcl.spec.auto/p3.cpp +++ b/clang/test/CXX/dcl.dcl/dcl.spec/dcl.type/dcl.spec.auto/p3.cpp @@ -1,4 +1,5 @@ // RUN: %clang_cc1 -fsyntax-only -verify %s -std=c++0x +// RUN: %clang_cc1 -fsyntax-only -verify %s -std=c++98 -Wno-c++0x-extensions void f() { auto a = a; // expected-error{{variable 'a' declared with 'auto' type cannot appear in its own initializer}} auto *b = b; // expected-error{{variable 'b' declared with 'auto' type cannot appear in its own initializer}} @@ -39,10 +40,12 @@ void p3example() { auto x = 5; const auto *v = &x, u = 6; static auto y = 0.0; - auto int r; // expected-warning {{'auto' storage class specifier is redundant and will be removed in future releases}} + // 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}} - same xHasTypeInt; - same vHasTypeConstIntPtr; - same uHasTypeConstInt; - same yHasTypeDouble; + same<__typeof(x), int> xHasTypeInt; + same<__typeof(v), const int*> vHasTypeConstIntPtr; + same<__typeof(u), const int> uHasTypeConstInt; + same<__typeof(y), double> yHasTypeDouble; } diff --git a/clang/test/CXX/dcl.dcl/dcl.spec/dcl.type/dcl.spec.auto/p4.cpp b/clang/test/CXX/dcl.dcl/dcl.spec/dcl.type/dcl.spec.auto/p4.cpp index 8a68e4bcd795..856c707a7fa4 100644 --- a/clang/test/CXX/dcl.dcl/dcl.spec/dcl.type/dcl.spec.auto/p4.cpp +++ b/clang/test/CXX/dcl.dcl/dcl.spec/dcl.type/dcl.spec.auto/p4.cpp @@ -1,4 +1,5 @@ // RUN: %clang_cc1 -fsyntax-only -verify %s -std=c++0x +// RUN: %clang_cc1 -fsyntax-only -verify %s -std=c++98 -Wno-c++0x-extensions template struct only { @@ -19,7 +20,10 @@ void f() { for (; auto a = false; ) { } + // FIXME: support 'auto' error recovery here in pre-C++0x mode. +#if __has_feature(cxx_auto_type) new const auto (0); +#endif new (auto) (0.0); int arr[] = {1, 2, 3}; diff --git a/clang/test/CXX/dcl.dcl/dcl.spec/dcl.type/dcl.spec.auto/p6.cpp b/clang/test/CXX/dcl.dcl/dcl.spec/dcl.type/dcl.spec.auto/p6.cpp index 8b4b70398471..25ce99fc10ef 100644 --- a/clang/test/CXX/dcl.dcl/dcl.spec/dcl.type/dcl.spec.auto/p6.cpp +++ b/clang/test/CXX/dcl.dcl/dcl.spec/dcl.type/dcl.spec.auto/p6.cpp @@ -1,4 +1,5 @@ // RUN: %clang_cc1 -fsyntax-only -verify %s -std=c++0x +// RUN: %clang_cc1 -fsyntax-only -verify %s -std=c++98 -Wno-c++0x-extensions template struct only { diff --git a/clang/test/CXX/dcl.dcl/dcl.spec/dcl.type/dcl.spec.auto/p7.cpp b/clang/test/CXX/dcl.dcl/dcl.spec/dcl.type/dcl.spec.auto/p7.cpp index de87a93a2bc1..9a3689f1c428 100644 --- a/clang/test/CXX/dcl.dcl/dcl.spec/dcl.type/dcl.spec.auto/p7.cpp +++ b/clang/test/CXX/dcl.dcl/dcl.spec/dcl.type/dcl.spec.auto/p7.cpp @@ -1,4 +1,5 @@ // RUN: %clang_cc1 -fsyntax-only -verify %s -std=c++0x +// RUN: %clang_cc1 -fsyntax-only -verify %s -std=c++98 -Wno-c++0x-extensions void f() { auto a = 0, b = 0, c = 0; auto d = 0, e = 0.0; // expected-error {{'int' in declaration of 'd' and deduced as 'double' in declaration of 'e'}} @@ -18,6 +19,14 @@ void f() { } void g() { - auto a = 0, (*b)() -> void, c = 0; - auto d = 0, (*e)() -> void, f = 0.0; // expected-error {{'auto' deduced as 'int' in declaration of 'd' and deduced as 'double' in declaration of 'f'}} + auto a = 0, +#if __has_feature(cxx_trailing_return) + (*b)() -> void, +#endif + c = 0; + auto d = 0, // expected-error {{'auto' deduced as 'int' in declaration of 'd' and deduced as 'double' in declaration of 'f'}} +#if __has_feature(cxx_trailing_return) + (*e)() -> void, +#endif + f = 0.0; } diff --git a/clang/test/Misc/warning-flags.c b/clang/test/Misc/warning-flags.c index d24b02b27c02..50abbff6b5f5 100644 --- a/clang/test/Misc/warning-flags.c +++ b/clang/test/Misc/warning-flags.c @@ -18,12 +18,12 @@ This test serves two purposes: The list of warnings below should NEVER grow. It should gradually shrink to 0. CHECK: Warnings without flags (311): -CHECK-NEXT: auto_storage_class CHECK-NEXT: backslash_newline_space CHECK-NEXT: charize_microsoft_ext CHECK-NEXT: ext_anon_param_requires_type_specifier CHECK-NEXT: ext_anonymous_struct_union_qualified CHECK-NEXT: ext_array_init_copy +CHECK-NEXT: ext_auto_storage_class CHECK-NEXT: ext_binary_literal CHECK-NEXT: ext_c1x_generic_selection CHECK-NEXT: ext_c1x_static_assert diff --git a/clang/test/SemaCXX/PR10458.cpp b/clang/test/SemaCXX/PR10458.cpp new file mode 100644 index 000000000000..e1f077aa2639 --- /dev/null +++ b/clang/test/SemaCXX/PR10458.cpp @@ -0,0 +1,7 @@ +// RUN: %clang_cc1 -fsyntax-only -verify %s -std=c++98 + +void f() { + int arr[] = { 1, 2, 3 }; + for (auto &i : arr) { // expected-warning {{'auto' type specifier is a C++0x extension}} expected-warning {{range-based for loop is a C++0x extension}} + } +} diff --git a/clang/test/SemaCXX/auto-cxx0x.cpp b/clang/test/SemaCXX/auto-cxx0x.cpp index f9246beff92a..a7bb3e64e4ae 100644 --- a/clang/test/SemaCXX/auto-cxx0x.cpp +++ b/clang/test/SemaCXX/auto-cxx0x.cpp @@ -1,5 +1,5 @@ // RUN: %clang_cc1 -fsyntax-only -verify %s -std=c++0x void f() { - auto int a; // expected-warning {{'auto' storage class specifier is redundant and will be removed in future releases}} + auto int a; // expected-warning {{'auto' storage class specifier is not permitted in C++0x, and will not be supported in future releases}} int auto b; // expected-error{{cannot combine with previous 'int' declaration specifier}} } diff --git a/clang/test/SemaCXX/auto-cxx98.cpp b/clang/test/SemaCXX/auto-cxx98.cpp index fe028114880a..8d22469825c0 100644 --- a/clang/test/SemaCXX/auto-cxx98.cpp +++ b/clang/test/SemaCXX/auto-cxx98.cpp @@ -1,5 +1,8 @@ // RUN: %clang_cc1 -fsyntax-only -verify %s -std=c++98 void f() { - auto int a; - int auto b; + auto int a; // expected-warning {{'auto' storage class specifier is redundant and incompatible with C++0x}} + int auto b; // expected-warning {{'auto' storage class specifier is redundant and incompatible with C++0x}} + auto c; // expected-warning {{C++0x extension}} expected-error {{requires an initializer}} + static auto d = 0; // expected-warning {{C++0x extension}} + auto static e = 0; // expected-warning {{C++0x extension}} } diff --git a/clang/test/SemaCXX/class.cpp b/clang/test/SemaCXX/class.cpp index 44fa0ce7ec9f..fd2d0b388a75 100644 --- a/clang/test/SemaCXX/class.cpp +++ b/clang/test/SemaCXX/class.cpp @@ -1,7 +1,7 @@ // RUN: %clang_cc1 -fsyntax-only -verify %s class C { public: - auto int errx; // expected-error {{error: storage class specified for a member declaration}} + auto int errx; // expected-error {{error: storage class specified for a member declaration}} expected-warning {{'auto' storage class specifier is redundant}} register int erry; // expected-error {{error: storage class specified for a member declaration}} extern int errz; // expected-error {{error: storage class specified for a member declaration}}