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

<div><div class="h5"><br>
>> @@ -5796,11 +5824,26 @@<br>
>> //   A member-declarator can contain a constant-initializer only<br>
>> //   if it declares a static member (9.4) of const integral or<br>
>> //   const enumeration type, see 9.4.2.<br>
>> +    //<br>
>> +    // C++0x [class.static.data]p3:<br>
>> +    //   If a non-volatile const static data member is of integral or<br>
>> +    //   enumeration type, its declaration in the class definition can<br>
>> +    //   specify a brace-or-equal-initializer in which every<br>
>> initalizer-clause +    //   that is an assignment-expression is a constant<br>
>> expression. A static +    //   data member of literal type can be declared in<br>
>> the class definition +    //   with the constexpr specifier; if so, its<br>
>> declaration shall specify a +    //   brace-or-equal-initializer in which<br>
>> every initializer-clause that is +    //   an assignment-expression is a<br>
>> constant expression. QualType T = VDecl->getType();<br>
>><br>
>><br>
>> // Do nothing on dependent types.<br>
>> if (T->isDependentType()) {<br>
>><br>
>> +    // Allow any 'static constexpr' members, whether or not they are of<br>
>> literal +    // type. We separately check that the initializer is a constant<br>
>> expression, +    // which implicitly requires the member to be of literal<br>
>> type. +    } else if (VDecl->isConstexpr()) {<br>
>> +<br>
>> // Require constness.<br>
>> } else if (!T.isConstQualified()) {<br>
>> Diag(VDecl->getLocation(), diag::err_in_class_initializer_non_const)<br>
>> @@ -5809,6 +5852,9 @@<br>
>><br>
>><br>
>> // We allow integer constant expressions in all cases.<br>
>> } else if (T->isIntegralOrEnumerationType()) {<br>
>> +      // FIXME: In C++0x, a non-constexpr const static data member with an<br>
>> +      // in-class initializer cannot be volatile.<br>
>> +<br>
>> // Check whether the expression is a constant expression.<br>
>> SourceLocation Loc;<br>
>> if (Init->isValueDependent()) @@ -5828,31 +5874,28 @@<br>
>> VDecl->setInvalidDecl();<br>
>> }<br>
>><br>
>><br>
>> -    // We allow floating-point constants as an extension in C++03, and<br>
>> -    // C++0x has far more complicated rules that we don't really<br>
>> -    // implement fully.<br>
>> -    } else {<br>
>> -      bool Allowed = false;<br>
>> -      if (getLangOptions().CPlusPlus0x) {<br>
>> -        Allowed = T->isLiteralType();<br>
>> -      } else if (T->isFloatingType()) { // also permits complex, which is<br>
>> ok -        Diag(VDecl->getLocation(),<br>
>> diag::ext_in_class_initializer_float_type)<br>
>> -          << T << Init->getSourceRange();<br>
>> -        Allowed = true;<br>
>> -      }<br>
>> +    // Suggest adding 'constexpr' in C++0x for literal types.<br>
>> +    } else if (getLangOptions().CPlusPlus0x && T->isLiteralType()) {<br>
>> +      Diag(VDecl->getLocation(),<br>
>> diag::ext_in_class_initializer_literal_type)<br>
>> +        << T << Init->getSourceRange()<br>
>> +        << FixItHint::CreateInsertion(VDecl->getLocStart(), "constexpr ");<br>
>><br>
>><br>
><br>
> This FixItHint needs to be on a note, rather than the ext-warn; we don't<br>
> recover here by parsing this *as* a constexpr (nor would that be entirely<br>
> appropriate I suspect)...<br>
<br>
</div></div>I've moved this from an ExtWarn to an Error (with the same fixit and error<br>
recovery) in r140820. The GNU extension allowing in-class initializers for<br>
static const members of floating point types is kept as-is -- such values<br>
aren't implicitly marked constexpr and thus can't be used in constant<br>
expressions.<br>
<div class="HOEnZb"><div class="h5"><br>
>> +      VDecl->setConstexpr(true);<br>
>> +<br>
>> +    // We allow floating-point constants as an extension.<br>
>> +    } else if (T->isFloatingType()) { // also permits complex, which is ok<br>
>> +      Diag(VDecl->getLocation(),<br>
>> diag::ext_in_class_initializer_float_type)<br>
>> +        << T << Init->getSourceRange();<br>
>><br>
>><br>
>> -      if (!Allowed) {<br>
>> -        Diag(VDecl->getLocation(),<br>
>> diag::err_in_class_initializer_bad_type)<br>
>> -          << T << Init->getSourceRange();<br>
>> -        VDecl->setInvalidDecl();<br>
>> -<br>
>> -      // TODO: there are probably expressions that pass here that<br>
>> shouldn't. -      } else if (!Init->isValueDependent() &&<br>
>> -                 !Init->isConstantInitializer(Context, false)) {<br>
>> +      if (!Init->isValueDependent() &&<br>
>> +          !Init->isConstantInitializer(Context, false)) {<br>
>> Diag(Init->getExprLoc(),<br>
>> diag::err_in_class_initializer_non_constant)<br>
>> << Init->getSourceRange();<br>
>> VDecl->setInvalidDecl();<br>
>> }<br>
>> +    } else {<br>
>> +      Diag(VDecl->getLocation(), diag::err_in_class_initializer_bad_type)<br>
>> +        << T << Init->getSourceRange();<br>
>> +      VDecl->setInvalidDecl();<br>
>> }<br>
>> } else if (VDecl->isFileVarDecl()) {<br>
>> if (VDecl->getStorageClassAsWritten() == SC_Extern && @@ -5893,6 +5936,17 @@<br>
>><br>
>><br>
>> if (!VDecl->isInvalidDecl()) checkUnsafeAssigns(VDecl->getLocation(),<br>
>> VDecl->getType(), Init);<br>
>> +<br>
>> +  if (VDecl->isConstexpr() && !VDecl->isInvalidDecl() &&<br>
>> +      !VDecl->getType()->isDependentType() &&<br>
>> +      !Init->isTypeDependent() && !Init->isValueDependent() &&<br>
>> +      !Init->isConstantInitializer(Context,<br>
>> +                                   VDecl->getType()->isReferenceType())) {<br>
>> +    // FIXME: Improve this diagnostic to explain why the initializer is<br>
>> not +    // a constant expression.<br>
>> +    Diag(VDecl->getLocation(),<br>
>> diag::err_constexpr_var_requires_const_init)<br>
>> +      << VDecl << Init->getSourceRange();<br>
>> +  }<br>
>><br>
>><br>
>> Init = MaybeCreateExprWithCleanups(Init);<br>
>> // Attach the initializer to the decl.<br>
>> @@ -5958,6 +6012,24 @@<br>
>> return; }<br>
>><br>
>><br>
>> +    // C++0x [dcl.constexpr]p9: An object or reference declared constexpr<br>
>> must +    // have an initializer.<br>
>> +    // C++0x [class.static.data]p3: A static data member can be declared<br>
>> with +    // the constexpr specifier; if so, its declaration shall specify<br>
>> +    // a brace-or-equal-initializer.<br>
>> +    if (Var->isConstexpr()) {<br>
>> +      // FIXME: Provide fix-its to convert the constexpr to const.<br>
>> +      if (Var->isStaticDataMember() && Var->getAnyInitializer()) {<br>
>> +        Diag(Var->getLocation(),<br>
>> diag::err_constexpr_initialized_static_member)<br>
>> +          << Var->getDeclName();<br>
>> +      } else {<br>
>> +        Diag(Var->getLocation(), diag::err_constexpr_var_requires_init)<br>
>> +          << Var->getDeclName();<br>
>> +      }<br>
>> +      Var->setInvalidDecl();<br>
>> +      return;<br>
>> +    }<br>
>> +<br>
>> switch (Var->isThisDeclarationADefinition()) { case VarDecl::Definition: if<br>
>> (!Var->isStaticDataMember() || !Var->getAnyInitializer())<br>
<br>
<br>
</div></div></blockquote></div><br>