Title
Value-dependent integral null pointer constants
Status
cd3
Section
17.7.2.3 [temp.dep.constexpr]
Submitter
Doug Gregor

Created on 2009-05-22.00:00:00, last changed 2014-03-03.00:00:00.

Messages

Date: 2013-04-15.00:00:00

[Moved to DR status at the April, 2013 meeting.]

Date: 2013-01-15.00:00:00

Additional note (January, 2013):

Concerns were raised at the Portland (October, 2012) meeting that the value false has been used in existing code as a null pointer constant, and such code would be broken by this change. This issue has been returned to "review" status to allow discussion of whether to accommodate such code or not.

Date: 2012-10-15.00:00:00

Proposed resolution (October, 2012):

  1. Change 7.11 [conv.ptr] paragraph 1 as follows:

  2. A null pointer constant is an integral constant expression (8.20 [expr.const]) prvalue of integer type that evaluates to integer literal (5.13.2 [lex.icon]) with value zero or a prvalue of type std::nullptr_t. A null pointer constant can be converted...
  3. Change 8.20 [expr.const] paragraph 3 as follows:

  4. ...[Note: Such expressions may be used as array bounds (11.3.4 [dcl.array], 8.3.4 [expr.new]), as bit-field lengths (12.2.4 [class.bit]), as enumerator initializers if the underlying type is not fixed (10.2 [dcl.enum]), as null pointer constants (7.11 [conv.ptr]), and as alignments (10.6.2 [dcl.align]). —end note]...
  5. Change 11.6 [dcl.init] paragraph 5 as follows:

  6. To zero-initialize an object or reference of type T means:

    • if T is a scalar type (6.9 [basic.types]), the object is set to the value 0 (zero), taken as an integral constant expression, converted initialized to the value obtained by converting integer literal 0 (zero) to T; [Footnote: As specified in 7.11 [conv.ptr], converting an integral constant expression integer literal whose value is 0 to a pointer type results in a null pointer value. —end footnote]

    • ...

  7. Change 17.3.2 [temp.arg.nontype] paragraph 5 as follows:

    • ...

    • for a non-type template-parameter of type pointer to object, qualification conversions (7.5 [conv.qual]) and the array-to-pointer conversion (7.2 [conv.array]) are applied; if the template-argument is of type std::nullptr_t, the null pointer conversion (7.11 [conv.ptr]) is applied. [Note: In particular, neither the null pointer conversion for a zero-valued integral constant expression integer literal (7.11 [conv.ptr]) nor the derived-to-base conversion (7.11 [conv.ptr]) are applied. Although 0 is...

    • ...

  8. Change 18.3 [except.handle] paragraph 3 as follows:

  9. ...[Note: A throw-expression whose operand is an integral constant expression of integer type that evaluates to integer literal with value zero does not match a handler of pointer or pointer to member type. —end note]. [Example: ...
  10. Add a new section to C.2 [diff.cpp03] as follows:

  11. C.2.x Clause 4: standard conversions [diff.cpp03.conv]

    7.11 [conv.ptr]
    Change: Only literals are integer null pointer constants
    Rationale: Removing surprising interactions with templates and constant expressions
    Effect on original feature: Valid C++ 2003 code may fail to compile or produce different results in this International Standard, as the following example illustrates:

      void f(void *);  // #1
      void f(...);     // #2
      template<int N> void g() {
          f(0*N);      // calls #2; used to call #1
      }
    

Date: 2009-07-15.00:00:00

Notes from the July, 2009 meeting:

There was a strong consensus among the CWG that only the literal 0 should be considered a null pointer constant, not any arbitrary zero-valued constant expression as is currently specified.

Date: 2009-05-22.00:00:00

Consider the following example:

    void f(int*);
    void f(...);

    template <int N> void g() {
      f(N);
    }

    int main() {
      g<0>();
      g<1>();
    }

The call to f in g is not type-dependent, so the overload resolution must be done at definition time rather than at instantiation time. As a result, both of the calls to g will result in calls to f(...), i.e., N will not be a null pointer constant, even if the value of N is 0.

It would be most consistent to adopt a rule that a value-dependent expression can never be a null pointer constant, even in cases like

    template <int N> void g() {
      int* p = N;
    }

This would always be ill-formed, even when N is 0.

John Spicer: It's clear that this treatment is required for overload resolution, but it seems too expansive given that there are other cases in which the value of a template parameter can affect the validity of the program, and an implementation is forbidden to issue a diagnostic on a template definition unless there are no possible valid specializations.

History
Date User Action Args
2014-03-03 00:00:00adminsetstatus: drwp -> cd3
2013-10-14 00:00:00adminsetstatus: dr -> drwp
2013-05-03 00:00:00adminsetmessages: + msg4428
2013-05-03 00:00:00adminsetstatus: review -> dr
2013-01-14 00:00:00adminsetstatus: ready -> review
2012-11-03 00:00:00adminsetstatus: review -> ready
2012-09-24 00:00:00adminsetmessages: + msg3894
2012-09-24 00:00:00adminsetstatus: ready -> review
2012-02-27 00:00:00adminsetstatus: tentatively ready -> ready
2012-01-17 00:00:00adminsetstatus: review -> tentatively ready
2011-09-06 00:00:00adminsetmessages: + msg3508
2011-09-06 00:00:00adminsetstatus: open -> review
2009-08-03 00:00:00adminsetmessages: + msg2222
2009-05-22 00:00:00admincreate