[cfe-commits] r140801 - in /cfe/trunk: include/clang/Basic/DiagnosticGroups.td include/clang/Basic/DiagnosticSemaKinds.td lib/Sema/SemaDecl.cpp lib/Sema/SemaDeclCXX.cpp test/CXX/class/class.static/class.static.data/p3.cpp test/CXX/dcl.dcl/dcl.spe

Richard Smith richard at metafoo.co.uk
Thu Sep 29 16:22:07 PDT 2011


On Thu, September 29, 2011 21:35, Chandler Carruth wrote:
> On Thu, Sep 29, 2011 at 12:11 PM, Richard Smith
> <richard-llvm at metafoo.co.uk>wrote:
>> Author: rsmith
>> Date: Thu Sep 29 14:11:37 2011
>> New Revision: 140801
>>
>>
>> URL: http://llvm.org/viewvc/llvm-project?rev=140801&view=rev
>> Log:
>> constexpr: semantic checking for constexpr variables.
>>
>>
>> We had an extension which allowed const static class members of
>> floating-point type to have in-class initializers, 'as a C++0x extension'.
>> However, C++0x does not allow this. The extension has been kept, and
>> extended to all literal types in C++0x mode (with a fixit to add the
>> 'constexpr' specifier).
>>
>>
>> Added:
>> cfe/trunk/test/CXX/class/class.static/class.static.data/p3.cpp
>> cfe/trunk/test/CXX/dcl.dcl/dcl.spec/dcl.constexpr/p9.cpp Modified:
>> cfe/trunk/include/clang/Basic/DiagnosticGroups.td
>> cfe/trunk/include/clang/Basic/DiagnosticSemaKinds.td
>> cfe/trunk/lib/Sema/SemaDecl.cpp cfe/trunk/lib/Sema/SemaDeclCXX.cpp
>> cfe/trunk/test/CXX/dcl.dcl/dcl.spec/dcl.constexpr/p1.cpp
>> cfe/trunk/test/CXX/stmt.stmt/stmt.iter/stmt.ranged/p1.cpp
>> cfe/trunk/test/FixIt/fixit-cxx0x.cpp cfe/trunk/test/SemaCXX/class.cpp
>> cfe/trunk/test/SemaTemplate/instantiate-static-var.cpp
>>
>> Modified: cfe/trunk/include/clang/Basic/DiagnosticGroups.td
>> URL:
>> http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/Basic/Diagnostic
>> Groups.td?rev=140801&r1=140800&r2=140801&view=diff
>>
>>
>> ===========================================================================
>> ===
>> --- cfe/trunk/include/clang/Basic/DiagnosticGroups.td (original)
>> +++ cfe/trunk/include/clang/Basic/DiagnosticGroups.td Thu Sep 29 14:11:37
>> 2011
>> @@ -303,9 +303,7 @@
>>
>>
>> // A warning group for warnings about using C++0x features as extensions
>> in // earlier C++ versions.
>> -def CXX0xStaticNonIntegralInitializer :
>> -  DiagGroup<"c++0x-static-nonintegral-init">;
>> -def CXX0x : DiagGroup<"c++0x-extensions",
>> [CXX0xStaticNonIntegralInitializer]>;
>> +def CXX0x : DiagGroup<"c++0x-extensions">;
>
> This could really use a better name than 'CXX0x'...

CXX0xExt? And similarly for C1X, GNU and Microsoft?

>> @@ -5796,11 +5824,26 @@
>> //   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.
>> +    //
>> +    // C++0x [class.static.data]p3:
>> +    //   If a non-volatile const static data member is of integral or
>> +    //   enumeration type, its declaration in the class definition can
>> +    //   specify a brace-or-equal-initializer in which every
>> initalizer-clause +    //   that is an assignment-expression is a constant
>> expression. A static +    //   data member of literal type can be declared in
>> the class definition +    //   with the constexpr specifier; if so, its
>> declaration shall specify a +    //   brace-or-equal-initializer in which
>> every initializer-clause that is +    //   an assignment-expression is a
>> constant expression. QualType T = VDecl->getType();
>>
>>
>> // Do nothing on dependent types.
>> if (T->isDependentType()) {
>>
>> +    // Allow any 'static constexpr' members, whether or not they are of
>> literal +    // type. We separately check that the initializer is a constant
>> expression, +    // which implicitly requires the member to be of literal
>> type. +    } else if (VDecl->isConstexpr()) {
>> +
>> // Require constness.
>> } else if (!T.isConstQualified()) {
>> Diag(VDecl->getLocation(), diag::err_in_class_initializer_non_const)
>> @@ -5809,6 +5852,9 @@
>>
>>
>> // We allow integer constant expressions in all cases.
>> } else if (T->isIntegralOrEnumerationType()) {
>> +      // FIXME: In C++0x, a non-constexpr const static data member with an
>> +      // in-class initializer cannot be volatile.
>> +
>> // Check whether the expression is a constant expression.
>> SourceLocation Loc;
>> if (Init->isValueDependent()) @@ -5828,31 +5874,28 @@
>> VDecl->setInvalidDecl();
>> }
>>
>>
>> -    // 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;
>> -      }
>> +    // Suggest adding 'constexpr' in C++0x for literal types.
>> +    } else if (getLangOptions().CPlusPlus0x && T->isLiteralType()) {
>> +      Diag(VDecl->getLocation(),
>> diag::ext_in_class_initializer_literal_type)
>> +        << T << Init->getSourceRange()
>> +        << FixItHint::CreateInsertion(VDecl->getLocStart(), "constexpr ");
>>
>>
>
> This FixItHint needs to be on a note, rather than the ext-warn; we don't
> recover here by parsing this *as* a constexpr (nor would that be entirely
> appropriate I suspect)...

I've moved this from an ExtWarn to an Error (with the same fixit and error
recovery) in r140820. The GNU extension allowing in-class initializers for
static const members of floating point types is kept as-is -- such values
aren't implicitly marked constexpr and thus can't be used in constant
expressions.

>> +      VDecl->setConstexpr(true);
>> +
>> +    // We allow floating-point constants as an extension.
>> +    } else if (T->isFloatingType()) { // also permits complex, which is ok
>> +      Diag(VDecl->getLocation(),
>> diag::ext_in_class_initializer_float_type)
>> +        << T << Init->getSourceRange();
>>
>>
>> -      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)) {
>> +      if (!Init->isValueDependent() &&
>> +          !Init->isConstantInitializer(Context, false)) {
>> Diag(Init->getExprLoc(),
>> diag::err_in_class_initializer_non_constant)
>> << Init->getSourceRange();
>> VDecl->setInvalidDecl();
>> }
>> +    } else {
>> +      Diag(VDecl->getLocation(), diag::err_in_class_initializer_bad_type)
>> +        << T << Init->getSourceRange();
>> +      VDecl->setInvalidDecl();
>> }
>> } else if (VDecl->isFileVarDecl()) {
>> if (VDecl->getStorageClassAsWritten() == SC_Extern && @@ -5893,6 +5936,17 @@
>>
>>
>> if (!VDecl->isInvalidDecl()) checkUnsafeAssigns(VDecl->getLocation(),
>> VDecl->getType(), Init);
>> +
>> +  if (VDecl->isConstexpr() && !VDecl->isInvalidDecl() &&
>> +      !VDecl->getType()->isDependentType() &&
>> +      !Init->isTypeDependent() && !Init->isValueDependent() &&
>> +      !Init->isConstantInitializer(Context,
>> +                                   VDecl->getType()->isReferenceType())) {
>> +    // FIXME: Improve this diagnostic to explain why the initializer is
>> not +    // a constant expression.
>> +    Diag(VDecl->getLocation(),
>> diag::err_constexpr_var_requires_const_init)
>> +      << VDecl << Init->getSourceRange();
>> +  }
>>
>>
>> Init = MaybeCreateExprWithCleanups(Init);
>> // Attach the initializer to the decl.
>> @@ -5958,6 +6012,24 @@
>> return; }
>>
>>
>> +    // C++0x [dcl.constexpr]p9: An object or reference declared constexpr
>> must +    // have an initializer.
>> +    // C++0x [class.static.data]p3: A static data member can be declared
>> with +    // the constexpr specifier; if so, its declaration shall specify
>> +    // a brace-or-equal-initializer.
>> +    if (Var->isConstexpr()) {
>> +      // FIXME: Provide fix-its to convert the constexpr to const.
>> +      if (Var->isStaticDataMember() && Var->getAnyInitializer()) {
>> +        Diag(Var->getLocation(),
>> diag::err_constexpr_initialized_static_member)
>> +          << Var->getDeclName();
>> +      } else {
>> +        Diag(Var->getLocation(), diag::err_constexpr_var_requires_init)
>> +          << Var->getDeclName();
>> +      }
>> +      Var->setInvalidDecl();
>> +      return;
>> +    }
>> +
>> switch (Var->isThisDeclarationADefinition()) { case VarDecl::Definition: if
>> (!Var->isStaticDataMember() || !Var->getAnyInitializer())





More information about the cfe-commits mailing list