def err_not_integral_type_anon_bitfield : Error<
"anonymous bit-field has non-integral type %0">;
def err_member_initialization : Error<
- "%0 can only be initialized if it is a static const integral data member">;
+ "fields can only be initialized in constructors">;
def err_member_function_initialization : Error<
"initializer on function does not look like a pure-specifier">;
def err_non_virtual_pure : Error<
def err_not_direct_base_or_virtual : Error<
"type %0 is not a direct or virtual base of %1">;
-def err_in_class_initializer_non_integral_type : Error<
- "in-class initializer has non-integral, non-enumeration type %0">;
+def err_in_class_initializer_non_const : Error<
+ "non-const static data member must be initialized out of line">;
+def err_in_class_initializer_bad_type : Error<
+ "static data member of type %0 must be initialized out of line">;
+def ext_in_class_initializer_float_type : ExtWarn<
+ "in-class initializer for static data member of type %0 "
+ "is a C++0x extension">;
def err_in_class_initializer_non_constant : Error<
- "in-class initializer is not an integral constant expression">;
+ "in-class initializer is not a constant expression">;
// C++ anonymous unions and GNU anonymous structs/unions
def ext_anonymous_union : Extension<
if (getLangOptions().CPlusPlus &&
RealDecl->getLexicalDeclContext()->isRecord() &&
isa<NamedDecl>(RealDecl))
- Diag(RealDecl->getLocation(), diag::err_member_initialization)
- << cast<NamedDecl>(RealDecl)->getDeclName();
+ Diag(RealDecl->getLocation(), diag::err_member_initialization);
else
Diag(RealDecl->getLocation(), diag::err_illegal_initializer);
RealDecl->setInvalidDecl();
// static const int value = 17;
// };
- // Attach the initializer
- VDecl->setInit(Init);
+ // Try to perform the initialization regardless.
+ if (!VDecl->isInvalidDecl()) {
+ InitializationSequence InitSeq(*this, Entity, Kind, &Init, 1);
+ ExprResult Result = InitSeq.Perform(*this, Entity, Kind,
+ MultiExprArg(*this, &Init, 1),
+ &DclT);
+ if (Result.isInvalid()) {
+ VDecl->setInvalidDecl();
+ return;
+ }
+
+ Init = Result.takeAs<Expr>();
+ }
// C++ [class.mem]p4:
// A member-declarator can contain a constant-initializer only
// if it declares a static member (9.4) of const integral or
// const enumeration type, see 9.4.2.
QualType T = VDecl->getType();
- if (!T->isDependentType() &&
- (!Context.getCanonicalType(T).isConstQualified() ||
- !T->isIntegralOrEnumerationType())) {
- Diag(VDecl->getLocation(), diag::err_member_initialization)
- << VDecl->getDeclName() << Init->getSourceRange();
+
+ // Do nothing on dependent types.
+ if (T->isDependentType()) {
+
+ // Require constness.
+ } else if (!T.isConstQualified()) {
+ Diag(VDecl->getLocation(), diag::err_in_class_initializer_non_const)
+ << Init->getSourceRange();
VDecl->setInvalidDecl();
- } else {
- // C++ [class.static.data]p4:
- // If a static data member is of const integral or const
- // enumeration type, its declaration in the class definition
- // can specify a constant-initializer which shall be an
- // integral constant expression (5.19).
- if (!Init->isTypeDependent() &&
- !Init->getType()->isIntegralOrEnumerationType()) {
- // We have a non-dependent, non-integral or enumeration type.
- Diag(Init->getSourceRange().getBegin(),
- diag::err_in_class_initializer_non_integral_type)
- << Init->getType() << Init->getSourceRange();
- VDecl->setInvalidDecl();
- } else if (!Init->isTypeDependent() && !Init->isValueDependent()) {
+
+ // We allow integer constant expressions in all cases.
+ } else if (T->isIntegralOrEnumerationType()) {
+ if (!Init->isValueDependent()) {
// Check whether the expression is a constant expression.
llvm::APSInt Value;
SourceLocation Loc;
Diag(Loc, diag::err_in_class_initializer_non_constant)
<< Init->getSourceRange();
VDecl->setInvalidDecl();
- } else if (!VDecl->getType()->isDependentType())
- ImpCastExprToType(Init, VDecl->getType(), CK_IntegralCast);
+ }
+ }
+
+ // We allow floating-point constants as an extension in C++03, and
+ // C++0x has far more complicated rules that we don't really
+ // implement fully.
+ } else {
+ bool Allowed = false;
+ if (getLangOptions().CPlusPlus0x) {
+ Allowed = T->isLiteralType();
+ } else if (T->isFloatingType()) { // also permits complex, which is ok
+ Diag(VDecl->getLocation(), diag::ext_in_class_initializer_float_type)
+ << T << Init->getSourceRange();
+ Allowed = true;
+ }
+
+ if (!Allowed) {
+ Diag(VDecl->getLocation(), diag::err_in_class_initializer_bad_type)
+ << T << Init->getSourceRange();
+ VDecl->setInvalidDecl();
+
+ // TODO: there are probably expressions that pass here that shouldn't.
+ } else if (!Init->isValueDependent() &&
+ !Init->isConstantInitializer(Context, false)) {
+ Diag(Init->getExprLoc(), diag::err_in_class_initializer_non_constant)
+ << Init->getSourceRange();
+ VDecl->setInvalidDecl();
}
}
} else if (VDecl->isFileVarDecl()) {
}
class NestedC {
+ public:
+ NestedC(int);
void m() {
sx = 0;
- x = 0; // expected-error {{error: invalid use of nonstatic data member 'x'}}
+ x = 0; // expected-error {{invalid use of nonstatic data member 'x'}}
}
};
int b : 1, w : 2;
int : 1, : 2;
typedef int E : 1; // expected-error {{typedef member 'E' cannot be a bit-field}}
- static int sb : 1; // expected-error {{error: static member 'sb' cannot be a bit-field}}
+ static int sb : 1; // expected-error {{static member 'sb' cannot be a bit-field}}
static int vs;
typedef int func();
enum E1 { en1, en2 };
- int i = 0; // expected-error {{error: 'i' can only be initialized if it is a static const integral data member}}
- static int si = 0; // expected-error {{error: 'si' can only be initialized if it is a static const integral data member}}
- static const NestedC ci = 0; // expected-error {{error: 'ci' can only be initialized if it is a static const integral data member}}
- static const int nci = vs; // expected-error {{in-class initializer is not an integral constant expression}}
+ int i = 0; // expected-error {{fields can only be initialized in constructors}}
+ static int si = 0; // expected-error {{non-const static data member must be initialized out of line}}
+ static const NestedC ci = 0; // expected-error {{static data member of type 'const C::NestedC' must be initialized out of line}}
+ static const int nci = vs; // expected-error {{in-class initializer is not a constant expression}}
static const int vi = 0;
static const E evi = 0;
C() {}
} // expected-error{{expected ';' after class}}
}
+
+namespace rdar8367341 {
+ float foo();
+
+ struct A {
+ static const float x = 5.0f; // expected-warning {{in-class initializer for static data member of type 'const float' is a C++0x extension}}
+ static const float y = foo(); // expected-warning {{in-class initializer for static data member of type 'const float' is a C++0x extension}} expected-error {{in-class initializer is not a constant expression}}
+ };
+}