C++0x: Generalized constant expression / User-defined literal: Difference between revisions

From wiki.dwarfstd.org
Jump to navigation Jump to search
>Kendrick.wong
No edit summary
>Kendrick.wong
No edit summary
 
Line 8: Line 8:
== Overview ==
== Overview ==


The new keyword <tt>constexpr</tt> allows the user to guarantee that a data, function or object constructor is a compile-time constant.  Standard allows floating-point constant expression as well. The <tt>constexpr</tt> is a new declaration specifier (not a new type) and it does not affect overloading rules.  A variable or data member declared with <tt>constexpr</tt> behaves as if it was declared with <tt>const</tt>. Constant expression function must be defined before it is used, thus disallowing recursive function calls. Function parameter cannot be declared <tt>constexpr</tt>. A function declared with <tt>constexpr</tt> is not a constant expression unless all parameters are constant expression as well. A function or a constructor declared with <tt>constexpr</tt> is implicitly <tt>inline</tt>.
The new keyword <tt>constexpr</tt> allows the user to guarantee that a data, function or object constructor is a compile-time constant.  Standard allows floating-point constant expression as well. The <tt>constexpr</tt> is a new declaration specifier (not a new type) and it does not affect overloading rules.  A variable or data member declared with <tt>constexpr</tt> behaves as if it was declared with <tt>const</tt>. Constant expression function must be defined before it is used, thus disallowing recursive function calls. Function parameter cannot be declared <tt>constexpr</tt>. A constant-expression function may be called with non-constant expressions, in that case there is no requirement that the resulting value be evaluated at compile-time. A function or a constructor declared with <tt>constexpr</tt> is implicitly <tt>inline</tt>. A constant-expression constructor may be invoked with non-constant expression arguments, the resulting initialization may then be dynamic.


<pre>
<pre>
Line 44: Line 44:




'''3.3.1: General Subroutine and Entry Point Information'''
'''3.3.8.1: Abstract Instances'''


A subroutine entry may contain a <tt>DW_AT_const_expr</tt> attribute whose value is a flag which indicates that the subroutine, under appropriate conditions, can be evaluated as a compile-time constant. Such entries may have a <tt>DW_AT_const_value</tt> attribute, whose value may be a string or any of the constant data or data block forms, as appropriate for the representation of the subroutine's return value. The value of this attribute is the actual return value of the subroutine, represented as it would be on the target architecture.
''In C++, a function or a constructor declared with <tt>constexpr</tt> is implicitly <tt>inline</tt>. This abstract inline instance is represented by a debugging information entry with the tag <tt>DW_TAG_subprogram</tt>. Such entry has a <tt>DW_AT_inline</tt> attribute whose value is <tt>DW_INL_inlined</tt>.''


{| style="color:green;background-color:#ffffcc;" border="1"
|Note:
Since these constant expression subroutines will likely be inlined by the compiler, and therefore, they may not be callable within a debug session. If the return expression is simple enough, it may make sense to extend the <tt>DW_AT_const_value</tt> attribute to accept DWARF expressions to describe the semantic of the subroutine. However, I don't want to over design this in the first try, so I will delay this discussion until a later time.


For example:
'''3.3.8.2: Concrete Inlined Instances'''
<pre>
 
constexpr int square(int x) { return x * x; }
Each inline subroutine entry may contain a <tt>DW_AT_const_expr</tt> attribute whose value is a flag which indicates that the subroutine can be evaluated as a compile-time constant. Such entries may have a <tt>DW_AT_const_value</tt> attribute, whose value may be a string or any of the constant data or data block forms, as appropriate for the representation of the subroutine's return value. The value of this attribute is the actual return value of the subroutine, represented as it would be on the target architecture.
</pre>
can be described as:
# Push all parameters to the stack
# duplicate the entry on top of stack (so two x's are on top of stack)
# pop 2 values off the stack and multiply (effectively x*x)


<pre>
''In C++, if a function or a constructor declared with <tt>constexpr</tt> is called with constant-expressions, then this concrete inlined instance has a <tt>DW_AT_const_expr</tt> attribute, as well as a <tt>DW_AT_const_value</tt> attribute, whose value represent the actual return value of the concrete inline instance. Such entry also have <tt>DW_AT_call_file</tt>, <tt>DW_AT_call_line</tt> and <tt>DW_AT_call_col</tt>, indicating where the subroutine is called.''
<1>< yyy>     DW_TAG_subprogram
                DW_AT_type                  <xxx>
                DW_AT_const_expr            yes
                DW_AT_const_value           DW_OP_dup DW_op_mul
</pre>
|}




Line 74: Line 60:
An entry describing a variable may have a <tt>DW_AT_const_expr</tt> attribute, whose value is a flag which indicate that the variable can be evaluated as a compile-time constant.
An entry describing a variable may have a <tt>DW_AT_const_expr</tt> attribute, whose value is a flag which indicate that the variable can be evaluated as a compile-time constant.


''In C++, a variable declared with <tt>constexpr</tt> is implicitly <tt>const</tt>. Such variable has a <tt>DW_AT_type</tt> attribute, whose value is a reference to a debugging information entry describing a const qualified type.''


== Example ==
== Example ==


<pre>
<pre>
constexpr int GetFive() {return 5;}
constexpr double mass = 9.8;
 
<1><  xxx>      DW_TAG_base_type
                DW_AT_name                  double
                DW_AT_encoding              DW_ATE_float
<1><  yyy>      DW_TAG_const_type
                DW_AT_type                  <xxx>
<1><  yyy>      DW_TAG_variable
                DW_AT_name                  mass
                DW_AT_type                  <yyy>
                DW_AT_const_expr            yes
                DW_AT_const_value          9.8
</pre>
 
<pre>
constexpr int square (int x) { return x * x; }
 
float array[square(9)];          // square() called at line 3, column 12
extern const in medium;
const int high = square(medium);  // high is NOT a constant expression


<1><  xxx>      DW_TAG_base_type
<1><  xxx>      DW_TAG_base_type
                 DW_AT_name                  int
                 DW_AT_name                  int
                 DW_AT_encoding              DW_ATE_signed
                 DW_AT_encoding              DW_ATE_signed
! abstract instance
<1><  yyy>      DW_TAG_subprogram
<1><  yyy>      DW_TAG_subprogram
                DW_AT_name                  square
                 DW_AT_type                  <xxx>
                 DW_AT_type                  <xxx>
                DW_AT_inline                DW_INL_inlined
<2><  zzz>      DW_TAG_formal_parameter
                DW_AT_name                  x
                DW_AT_type                  <xxx>
! concrete instance for square(9)
<1><  ...>      DW_TAG_inlined_subroutine
                DW_AT_abstract_origin      <yyy>
                 DW_AT_const_expr            yes
                 DW_AT_const_expr            yes
                 DW_AT_const_value          5
                 DW_AT_const_value          81
                DW_AT_call_file            1
                DW_AT_call_line            3
                DW_AT_call_column          12
<2><  ...>      DW_TAG_formal_parameter
                DW_AT_abstract_origin      <zzz>
                DW_AT_const_value          9
 
! concrete instance for non constant-expression version of square()
<1><  ...>      DW_TAG_inlined_subroutine
                DW_AT_abstract_origin      <yyy>
                DW_AT_low_pc                ...
                DW_AT_high_pc              ...
<2><  ...>      DW_TAG_formal_parameter
                DW_AT_abstract_origin      <zzz>
                DW_AT_location              ...
</pre>
</pre>

Latest revision as of 16:45, 24 February 2009

For detail description of the feature, please refer to:

http://www.research.att.com/~bs/C++0xFAQ.html#constexpr

http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2007/n2235.pdf


Overview

The new keyword constexpr allows the user to guarantee that a data, function or object constructor is a compile-time constant. Standard allows floating-point constant expression as well. The constexpr is a new declaration specifier (not a new type) and it does not affect overloading rules. A variable or data member declared with constexpr behaves as if it was declared with const. Constant expression function must be defined before it is used, thus disallowing recursive function calls. Function parameter cannot be declared constexpr. A constant-expression function may be called with non-constant expressions, in that case there is no requirement that the resulting value be evaluated at compile-time. A function or a constructor declared with constexpr is implicitly inline. A constant-expression constructor may be invoked with non-constant expression arguments, the resulting initialization may then be dynamic.

constexpr int Five = 5;                  // constant-expression data
constexpr int GetFive() {return 5;}      // constant-expression function
struct integer {
  constexpr integer (int a) : v(a) { }
  constexpr int val() { return v; }
private:
  int v;
};
constexpr integer numFive(5);            // constant-expression constructor
                                         // or user-defined literal

//create an array of 15 integers.
int some_value[Five+GetFive()+numFive.val()];

Proposed change to DWARF

Purpose:

  • To identify if a variable, function or object constructor can be evaluated as compile-time constants.
  • (Optional) To capture the value of the constant-expression.


New DWARF attribute:

DW_AT_const_expr 0x69 flag A compile-time constant expression


3.3.8.1: Abstract Instances

In C++, a function or a constructor declared with constexpr is implicitly inline. This abstract inline instance is represented by a debugging information entry with the tag DW_TAG_subprogram. Such entry has a DW_AT_inline attribute whose value is DW_INL_inlined.


3.3.8.2: Concrete Inlined Instances

Each inline subroutine entry may contain a DW_AT_const_expr attribute whose value is a flag which indicates that the subroutine can be evaluated as a compile-time constant. Such entries may have a DW_AT_const_value attribute, whose value may be a string or any of the constant data or data block forms, as appropriate for the representation of the subroutine's return value. The value of this attribute is the actual return value of the subroutine, represented as it would be on the target architecture.

In C++, if a function or a constructor declared with constexpr is called with constant-expressions, then this concrete inlined instance has a DW_AT_const_expr attribute, as well as a DW_AT_const_value attribute, whose value represent the actual return value of the concrete inline instance. Such entry also have DW_AT_call_file, DW_AT_call_line and DW_AT_call_col, indicating where the subroutine is called.


4.1: Data Object Entries

An entry describing a variable may have a DW_AT_const_expr attribute, whose value is a flag which indicate that the variable can be evaluated as a compile-time constant.

In C++, a variable declared with constexpr is implicitly const. Such variable has a DW_AT_type attribute, whose value is a reference to a debugging information entry describing a const qualified type.

Example

constexpr double mass = 9.8;

<1><  xxx>      DW_TAG_base_type
                DW_AT_name                  double
                DW_AT_encoding              DW_ATE_float
<1><  yyy>      DW_TAG_const_type
                DW_AT_type                  <xxx>
<1><  yyy>      DW_TAG_variable
                DW_AT_name                  mass
                DW_AT_type                  <yyy>
                DW_AT_const_expr            yes
                DW_AT_const_value           9.8
constexpr int square (int x) { return x * x; }

float array[square(9)];           // square() called at line 3, column 12
extern const in medium;
const int high = square(medium);  // high is NOT a constant expression

<1><  xxx>      DW_TAG_base_type
                DW_AT_name                  int
                DW_AT_encoding              DW_ATE_signed
! abstract instance
<1><  yyy>      DW_TAG_subprogram
                DW_AT_name                  square
                DW_AT_type                  <xxx>
                DW_AT_inline                DW_INL_inlined
<2><  zzz>      DW_TAG_formal_parameter
                DW_AT_name                  x
                DW_AT_type                  <xxx>

! concrete instance for square(9)
<1><  ...>      DW_TAG_inlined_subroutine
                DW_AT_abstract_origin       <yyy>
                DW_AT_const_expr            yes
                DW_AT_const_value           81
                DW_AT_call_file             1
                DW_AT_call_line             3
                DW_AT_call_column           12
<2><  ...>      DW_TAG_formal_parameter
                DW_AT_abstract_origin       <zzz>
                DW_AT_const_value           9

! concrete instance for non constant-expression version of square()
<1><  ...>      DW_TAG_inlined_subroutine
                DW_AT_abstract_origin       <yyy>
                DW_AT_low_pc                ...
                DW_AT_high_pc               ...
<2><  ...>      DW_TAG_formal_parameter
                DW_AT_abstract_origin       <zzz>
                DW_AT_location              ...