mirror of
https://github.com/capstone-engine/llvm-capstone.git
synced 2024-12-14 03:29:57 +00:00
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:
parent
e9c4e84f8e
commit
58c7433709
@ -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">;
|
||||
|
@ -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;
|
||||
|
@ -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();
|
||||
|
@ -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.
|
||||
|
@ -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}}
|
||||
|
@ -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;
|
||||
}
|
||||
|
@ -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};
|
||||
|
@ -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 {
|
||||
|
@ -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;
|
||||
}
|
||||
|
@ -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
|
||||
|
7
clang/test/SemaCXX/PR10458.cpp
Normal file
7
clang/test/SemaCXX/PR10458.cpp
Normal 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}}
|
||||
}
|
||||
}
|
@ -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}}
|
||||
}
|
||||
|
@ -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}}
|
||||
}
|
||||
|
@ -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}}
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user