Old GCC used to aggressively fold VLAs to constant-bound arrays at block scope in GNU mode. That's non-conforming, and more modern versions of GCC only do this at file scope. Update Clang to do the same. Also promote the warning for this from off-by-default to on-by-default in all cases; more recent versions of GCC likewise warn on this by default. This is still slightly more permissive than GCC, as pointed out in PR44406, as we still fold VLAs to constant arrays in structs, but that seems justifiable given that we don't support VLA-in-struct (and don't intend to ever support it), but GCC does. Differential Revision: https://reviews.llvm.org/D89523
186 lines
7.3 KiB
C++
186 lines
7.3 KiB
C++
// RUN: %clang_cc1 -fsyntax-only -verify %s
|
|
// RUN: %clang_cc1 -fsyntax-only -verify -std=c++98 %s
|
|
// RUN: %clang_cc1 -fsyntax-only -verify -std=c++11 %s
|
|
// RUN: %clang_cc1 -fsyntax-only -verify -std=c++2a %s
|
|
|
|
struct S {
|
|
S();
|
|
#if __cplusplus <= 199711L
|
|
// expected-note@-2 {{because type 'S' has a user-provided default constructor}}
|
|
#endif
|
|
};
|
|
|
|
struct { // expected-error {{anonymous structs and classes must be class members}} expected-warning {{does not declare anything}}
|
|
};
|
|
|
|
struct E {
|
|
struct {
|
|
S x;
|
|
#if __cplusplus <= 199711L
|
|
// expected-error@-2 {{anonymous struct member 'x' has a non-trivial default constructor}}
|
|
#endif
|
|
};
|
|
static struct { // expected-warning {{does not declare anything}}
|
|
};
|
|
class {
|
|
int anon_priv_field; // expected-error {{anonymous struct cannot contain a private data member}}
|
|
};
|
|
};
|
|
|
|
template <class T> void foo(T);
|
|
typedef struct { // expected-error {{anonymous non-C-compatible type given name for linkage purposes by typedef declaration after its linkage was computed; add a tag name here to establish linkage prior to definition}}
|
|
#if __cplusplus <= 199711L
|
|
// expected-note@-2 {{declared here}}
|
|
#endif
|
|
|
|
void test() { // expected-note {{type is not C-compatible due to this member declaration}}
|
|
foo(this);
|
|
#if __cplusplus <= 199711L
|
|
// expected-warning@-2 {{template argument uses unnamed type}}
|
|
#endif
|
|
}
|
|
} A; // expected-note {{type is given name 'A' for linkage purposes by this typedef declaration}}
|
|
|
|
typedef struct { // expected-warning {{anonymous non-C-compatible type given name for linkage purposes by typedef declaration; add a tag name here}}
|
|
int x = 0; // expected-note {{type is not C-compatible due to this default member initializer}} expected-warning 0-1{{extension}}
|
|
} B; // expected-note {{type is given name 'B' for linkage purposes by this typedef declaration}}
|
|
|
|
typedef struct // expected-warning {{anonymous non-C-compatible type given name for linkage purposes by typedef declaration; add a tag name here}}
|
|
: B { // expected-note {{type is not C-compatible due to this base class}}
|
|
} C; // expected-note {{type is given name 'C' for linkage purposes by this typedef declaration}}
|
|
|
|
#if __cplusplus > 201703L
|
|
typedef struct { // expected-warning {{anonymous non-C-compatible type given name for linkage purposes by typedef declaration; add a tag name here}}
|
|
static_assert([]{ return true; }()); // expected-note {{type is not C-compatible due to this lambda expression}}
|
|
} Lambda1; // expected-note {{type is given name 'Lambda1' for linkage purposes by this typedef declaration}}
|
|
|
|
template<int> struct X {};
|
|
typedef struct { // expected-warning {{anonymous non-C-compatible type given name for linkage purposes by typedef declaration; add a tag name here}}
|
|
X<[]{ return 0; }()> x; // expected-note {{type is not C-compatible due to this lambda expression}}
|
|
// FIXME: expected-error@-1 {{lambda expression cannot appear}}
|
|
} Lambda2; // expected-note {{type is given name 'Lambda2' for linkage purposes by this typedef declaration}}
|
|
|
|
typedef struct { // expected-warning {{anonymous non-C-compatible type given name for linkage purposes by typedef declaration; add a tag name here}}
|
|
enum E {
|
|
a = []{ return 1; }() // expected-note {{type is not C-compatible due to this lambda expression}}
|
|
};
|
|
} Lambda3; // expected-note {{type is given name 'Lambda3' for linkage purposes by this typedef declaration}}
|
|
#endif
|
|
|
|
typedef struct { // expected-warning {{anonymous non-C-compatible type given name for linkage purposes by typedef declaration; add a tag name here}}
|
|
template<int> void f() {} // expected-note {{type is not C-compatible due to this member declaration}}
|
|
} Template; // expected-note {{type is given name 'Template' for linkage purposes by this typedef declaration}}
|
|
|
|
typedef struct { // expected-warning {{anonymous non-C-compatible type given name for linkage purposes by typedef declaration; add a tag name here}}
|
|
struct U {
|
|
void f(); // expected-note {{type is not C-compatible due to this member declaration}}
|
|
};
|
|
} Nested; // expected-note {{type is given name 'Nested' for linkage purposes by this typedef declaration}}
|
|
|
|
typedef struct { // expected-warning {{anonymous non-C-compatible type given name for linkage purposes by typedef declaration; add a tag name here}}
|
|
friend void f() {} // expected-note {{type is not C-compatible due to this friend declaration}}
|
|
} Friend; // expected-note {{type is given name 'Friend' for linkage purposes by this typedef declaration}}
|
|
|
|
typedef struct { // expected-warning {{anonymous non-C-compatible type given name for linkage purposes by typedef declaration; add a tag name here}}
|
|
template<typename T> friend void f() {} // expected-note {{type is not C-compatible due to this friend declaration}}
|
|
} FriendTemplate; // expected-note {{type is given name 'FriendTemplate' for linkage purposes by this typedef declaration}}
|
|
|
|
// Check that we don't diagnose the permitted cases:
|
|
typedef struct {
|
|
// (non-members)
|
|
_Static_assert(true, "");
|
|
int : 0;
|
|
/*empty-declaration*/;
|
|
|
|
// non-static data members
|
|
int a;
|
|
// member enumerations
|
|
enum E { x, y, z };
|
|
// member classes
|
|
struct S {};
|
|
|
|
// recursively
|
|
struct T { int a; };
|
|
} OK;
|
|
|
|
// There are still some known permitted cases that require an early linkage
|
|
// computation. Ensure we diagnose those too.
|
|
namespace ValidButUnsupported {
|
|
#if __cplusplus >= 201402L
|
|
template<typename T> auto compute_linkage() {
|
|
static int n;
|
|
return &n;
|
|
}
|
|
|
|
typedef struct { // expected-error {{unsupported: anonymous type given name for linkage purposes by typedef declaration after its linkage was computed; add a tag name here to establish linkage}}
|
|
struct X {};
|
|
decltype(compute_linkage<X>()) a;
|
|
} A; // expected-note {{by this typedef declaration}}
|
|
#endif
|
|
|
|
// This fails in some language modes but not others.
|
|
template<typename T> struct Y {
|
|
static const int value = 10;
|
|
};
|
|
typedef struct { // expected-error 0-1{{unsupported}}
|
|
enum X {};
|
|
int arr[Y<X>::value];
|
|
} B; // expected-note 0-1{{by this typedef}}
|
|
|
|
template<typename T> void f() {}
|
|
typedef struct { // expected-error {{unsupported}}
|
|
enum X {};
|
|
int arr[&f<X> ? 1 : 2];
|
|
#if __cplusplus < 201103L
|
|
// expected-warning@-2 {{folded to constant}}
|
|
#endif
|
|
} C; // expected-note {{by this typedef}}
|
|
}
|
|
|
|
namespace ImplicitDecls {
|
|
struct Destructor {
|
|
~Destructor() {}
|
|
};
|
|
typedef struct {
|
|
} Empty;
|
|
|
|
typedef struct {
|
|
Destructor x;
|
|
} A;
|
|
|
|
typedef struct {
|
|
Empty E;
|
|
} B;
|
|
|
|
typedef struct {
|
|
const Empty E;
|
|
} C;
|
|
} // namespace ImplicitDecls
|
|
|
|
struct {
|
|
static int x; // expected-error {{static data member 'x' not allowed in anonymous struct}}
|
|
} static_member_1;
|
|
|
|
class {
|
|
struct A {
|
|
static int x; // expected-error {{static data member 'x' not allowed in anonymous class}}
|
|
} x;
|
|
} static_member_2;
|
|
|
|
union {
|
|
struct A {
|
|
struct B {
|
|
static int x; // expected-error {{static data member 'x' not allowed in anonymous union}}
|
|
} x;
|
|
} x;
|
|
} static_member_3;
|
|
|
|
// Ensure we don't compute the linkage of a member function just because it
|
|
// happens to have the same name as a builtin.
|
|
namespace BuiltinName {
|
|
// Note that this is not an error: we didn't trigger linkage computation in this example.
|
|
typedef struct { // expected-warning {{anonymous non-C-compatible type}}
|
|
void memcpy(); // expected-note {{due to this member}}
|
|
} A; // expected-note {{given name 'A' for linkage purposes by this typedef}}
|
|
}
|