PR10458: Finesse behaviour of C++0x features when in pre-0x mode. Accept for-range and auto with an ExtWarn, and produce a -Wc++0x-compat warning in C++98 mode when auto is used as a storage class.

llvm-svn: 139102
This commit is contained in:
Richard Smith 2011-09-04 19:54:14 +00:00
parent e9c4e84f8e
commit 58c7433709
14 changed files with 92 additions and 24 deletions

View File

@ -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<CXX0x>;
def ext_auto_type_specifier : ExtWarn<
"'auto' type specifier is a C++0x extension">, InGroup<CXX0x>;
def warn_auto_storage_class : Warning<
"'auto' storage class specifier is redundant and incompatible with C++0x">,
InGroup<CXX0xCompat>;
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<CXX0x>;
def err_argument_required_after_attribute : Error<
"argument required after attribute">;
def err_missing_param : Error<"expected parameter declarator">;

View File

@ -1771,14 +1771,12 @@ void Parser::ParseDeclarationSpecifiers(DeclSpec &DS,
isInvalid = DS.SetStorageClassSpec(DeclSpec::SCS_auto, Loc, PrevSpec,
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;

View File

@ -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();

View File

@ -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.

View File

@ -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}}

View File

@ -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<decltype(x), int> xHasTypeInt;
same<decltype(v), const int*> vHasTypeConstIntPtr;
same<decltype(u), const int> uHasTypeConstInt;
same<decltype(y), double> yHasTypeDouble;
same<__typeof(x), int> xHasTypeInt;
same<__typeof(v), const int*> vHasTypeConstIntPtr;
same<__typeof(u), const int> uHasTypeConstInt;
same<__typeof(y), double> yHasTypeDouble;
}

View File

@ -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<typename T>
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};

View File

@ -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<typename T>
struct only {

View File

@ -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;
}

View File

@ -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

View File

@ -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}}
}
}

View File

@ -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}}
}

View File

@ -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}}
}

View File

@ -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}}