This is the mail archive of the gcc-patches@gcc.gnu.org mailing list for the GCC project.


Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]
Other format: [Raw text]

Re: C++ PATCH for constexpr


Jason Merrill <jason@redhat.com> writes:

| On 11/26/2009 08:39 PM, Gabriel Dos Reis wrote:
| > I do not know exactly what to do with __builtin_xxx functions when
| > testing whether an expression is a potential constant expressions or
| > not.   When and how GCC fold those expressions depend on commandlines...
| 
| I'd allow them if GCC ever folds them to a constant.  If a particular
| call isn't folded to a constant, we can give an error at that point.

OK.  See updated patch with morally_constexpr_builtin_function_p.
The previous patch already allowed for folding builtins; however at the
semantics phase of input source code I was rejecting them.

| 
| > +/* True if the expression tree NODE represents an object that can
| > +   be taken apart at compile time.  This is not to be confused with
| > +   link-time constants or load-time constants.  A compiler constant
| > +   may still be an expression that the middle end may be able to
| > +   reduce further.  */
| > +#define COMPILE_TIME_CONSTANT_P(NODE) \
| > +  (TREE_LANG_FLAG_7 (NODE))
| > +
| > +/* Same as COMPILE_TIME_CONSTANT_P, except that it includes literal
| > +   values too, such as INTEGER_CST, PTRMEM_CST, or address of
| > +   variables with static storage.  */
| > +#define VALID_FOR_STATIC_INITIALIZATION_P(NODE) \
| > +  (CONSTANT_CLASS_P (NODE) || COMPILE_TIME_CONSTANT_P (NODE))
| 
| Your first comment seems a bit off. The address of a variable with
| static storage duration is a load-time constant; at compile time we
| don't know the numeric address, so it's a symbolic reference.  

yes; that is considered compile-time (symbolic) constants.

| What link-time or load-time constants do you mean to exclude?

What I meant was that there are expressions that may be found link-time or
load-time constants by that we cannot legitimately consider compile time
constant from the languge point of view.  For example, I had in mind
this scenario

     constexpr int n = 8;
     int m = n * 8;
     int main() {
        return m;
     }

'm' may be considered a load-time constant, but we should not accept it.

| 
| Also, it seems that COMPILE_TIME_CONSTANT_P is only getting set on
| CONSTRUCTOR nodes (not ADDR_EXPR of TREE_STATIC decls);

That was a mistake on my part.  It is now set for (ADDR_EXPR var)
where var is a ststic, and also for appropriate POINTER_PlUS_EXPR.

| if you make it
| specific to CONSTRUCTORs we don't need a new TREE_LANG_FLAG.  Maybe
| LITERAL_CONSTRUCTOR_P?
| 
| Or, better, can we just make VALID_FOR_STATIC_INITIALIZATION_P a
| function that knows to descend into CONSTRUCTORs so we don't need a
| flag at all?  It seems like potential_constant_expression might
| already be that function if you add a flag to control the special parm
| handling.

I chosed a flag based on the perspective that people would start using
more and more constants of class types (and combinations with other
symbolic references), and for efficiency reason we
should just "remember" that a particular expression tree we already
processed denotes a compile time constant.
The other reason was that, I thought it is a good thing to build in a
non-circular sanity check during compile time evaluation:  Basically,
during type checking we decide that a particular expression denotes a
compile time constant in a given context.  Then we go off evaluating it.
If during evaluation we fail to reduce a expression to a constant
and we call again the same routine that told us that that expression is
a constant, it would not be obvious where a potential bug was.  

| > +    case AGGR_INIT_EXPR:
| > +      if (AGGR_INIT_VIA_CTOR_P (t) && !CLASSTYPE_LITERAL_P (TREE_TYPE (t)))
| > +        {
| > +          error ("object of non-literal type is not potential constant");
| > +          return false;
| > +        }
| 
| I don't think we need any special code for AGGR_INIT_EXPR.  If the
| function is a constructor for a non-literal class, the constructor
| won't be constexpr, so we'll complain later.

OK, thanks.

| > +            if (i == 0 && DECL_NONSTATIC_MEMBER_P (fun)
| > +                && (TREE_CODE (t) != AGGR_INIT_EXPR
| > +                    || !AGGR_INIT_VIA_CTOR_P (t)))
| 
| Maybe
| 
| if (i == 0 && DECL_NONSTATIC_MEMBER_P (fun)
|     && !DECL_CONSTRUCTOR_P (fun))
| 
| ?

yes, that is much better.

| > +  for (b = call->bindings; b != NULL; b = TREE_CHAIN (b))
| > +    if (TREE_PURPOSE (b) == t)
| > +      return TREE_VALUE (b);
| 
| Weren't you going to use purpose_value here?

yes, definitely it was supposed to be purpose_member.  It is silly that
change did not make it into the patch.

I integrated your comments from the other message.  Please check that I
did not leave anything out.

-- Gaby

gcc/ChangeLog
2009-11-29  Gabriel Dos Reis  <gdr@cse.tamu.edu>

	* tree.h (VAR_DECL_P): New predicate macro.
	(FUNCTION_DECL_P): Likewise.
	(tree_base::lang_flag_7): New language flag.
	(tree_base::spare): Decrease precision by one.
	(TREE_LANG_FLAG_7): New.

gcc/cp/ChangeLog
2009-11-29  Gabriel Dos Reis  <gdr@cse.tamu.edu>

	* parser.c (cp_parser_ctor_initializer_opt_and_function_body):
	Check body of constexpr constructors.
	* cp-tree.h (COMPILE_TIME_CONSTANT_P): New.
	(VALID_FOR_STATIC_INITIALIZATION_P): Likewise.
	(TYPE_ARRAY_P): Likewise.
	(hash_constexpr_args): Declare.
	(register_constexpr_fundef): Likewise.
	(cxx_constant_value): Likewise.
	(generalized_constant_expression_allowed): New.
	* decl.c (validate_constexpr_redeclaration): New.
	(duplicate_decls): Use it.
	(cp_finish_decl): Validate constexpr bit.
	(grokdeclarator): Check uses of constexpr specifier.
	(maybe_save_function_definition): New.
	(finish_function): Use it.
	* class.c (check_bases): Accumulate literal type property from
	base classes.
	(check_field_decls): Same for non-static data members.
	(finalize_literal_type_property): New.
	(check_bases_and_members): Use it.
	(finish_struct_1): Assume the class being processed is literal.
	* typeck2.c (store_init_value): Fold initializers of 
	constexpr variables.
	* pt.c (hash_constexpr_args): Define.
	* semantics.c (ensure_literal_type_for_constexpr_object): Tidy.
	(constexpr_fundef): New datatype.
	(constexpr_fundef_table): New global table.
	(constexpr_fundef_equal): New.
	(constexpr_fundef_hash): Likewise.
	(retrieve_constexpr_fundef): Likewise.
	(validate_constexpr_fundecl): Tidy.  Allow constexpr function
	declarations that are not definitions.
	(build_constexpr_constructor_member_initializers): New.
	(register_constexpr_fundef): Define.
	(constexpr_call): New datatype.
	(constexpr_call_table): New global table.
	(constexpr_call_hash): New.
	(constexpr_call_equal): Likewise.
	(maybe_initialize_constexpr_call_table): Likewise.
	(is_this_parameter): Likewise.
	(get_function_named_in_call): Likewise.
	(get_nth_callarg): Likewise.
	(lookup_parameter_binding): Likewise.
	(cxx_eval_builtin_function_call): Likewise.
	(cxx_bind_parameters_in_call): Likewise.
	(cxx_eval_call_expression): Likewise.
	(cxx_eval_unary_expression): Likewise.
	(cxx_eval_binary_expression): Likewise.
	(cxx_eval_conditional_expression): Likewise.
	(cxx_eval_array_reference): Likewise.
	(cxx_eval_component_reference): Likewise.
	(cxx_eval_logical_expression): Likewise.
	(cxx_eval_object_construction): Likewise.
	(cxx_eval_constant_expression): Likewise.
	(cxx_constant_value): Define.
	(has_automatic_or_tls): New.
	(morally_constexpr_builtin_function_p): Likewise.
	(potential_constant_expression): Likewise.

=== gcc/tree.h
==================================================================
--- gcc/tree.h	(revision 154736)
+++ gcc/tree.h	(patch const level 1)
@@ -105,6 +105,16 @@
 #define DECL_P(CODE)\
         (TREE_CODE_CLASS (TREE_CODE (CODE)) == tcc_declaration)
 
+/* Nonzero if NODE represents a VAR_DECL.  */
+
+#define VAR_DECL_P(NODE) \
+  (TREE_CODE (NODE) == VAR_DECL)
+
+/* Nonzero if NODE represents a FUNCTION_DECL.  */
+
+#define FUNCTION_DECL_P(NODE) \
+  (TREE_CODE (NODE) == FUNCTION_DECL)
+
 /* Nonzero if DECL represents a VAR_DECL or FUNCTION_DECL.  */
 
 #define VAR_OR_FUNCTION_DECL_P(DECL)\
@@ -386,12 +396,13 @@
   unsigned lang_flag_4 : 1;
   unsigned lang_flag_5 : 1;
   unsigned lang_flag_6 : 1;
+  unsigned lang_flag_7 : 1;
 
   unsigned visited : 1;
   unsigned packed_flag : 1;
   unsigned user_align : 1;
 
-  unsigned spare : 13;
+  unsigned spare : 12;
 
   /* This field is only used with type nodes; the only reason it is present
      in tree_base instead of tree_type is to save space.  The size of the
@@ -1358,6 +1369,7 @@
 #define TREE_LANG_FLAG_4(NODE) ((NODE)->base.lang_flag_4)
 #define TREE_LANG_FLAG_5(NODE) ((NODE)->base.lang_flag_5)
 #define TREE_LANG_FLAG_6(NODE) ((NODE)->base.lang_flag_6)
+#define TREE_LANG_FLAG_7(NODE) ((NODE)->base.lang_flag_7)
 
 /* Define additional fields and accessors for nodes representing constants.  */
 
=== gcc/cp/class.c
==================================================================
--- gcc/cp/class.c	(revision 154736)
+++ gcc/cp/class.c	(patch const level 1)
@@ -1264,6 +1264,11 @@
 
       gcc_assert (COMPLETE_TYPE_P (basetype));
 
+      /* If any of the base class is non-literal, the whole class
+         becomes non-literal.  */
+      if (!CLASSTYPE_LITERAL_P (basetype))
+        CLASSTYPE_LITERAL_P (t) = false;
+
       /* Effective C++ rule 14.  We only need to check TYPE_POLYMORPHIC_P
 	 here because the case of virtual functions but non-virtual
 	 dtor is handled in finish_struct_1.  */
@@ -3004,6 +3009,11 @@
       if (TREE_PRIVATE (x) || TREE_PROTECTED (x))
 	CLASSTYPE_NON_AGGREGATE (t) = 1;
 
+      /* If at least one non-static data member is non-literal, the whole
+         class becomes non-literal.  */
+      if (!literal_type_p (type))
+        CLASSTYPE_LITERAL_P (t) = false;
+
       /* A standard-layout class is a class that:
 	 ...
 	 has the same access control (Clause 11) for all non-static data members,
@@ -4317,6 +4327,45 @@
   return has_two_argument_delete_p;
 }
 
+
+/* Finish computing the `literal type' property of class type T.
+
+   At this point, we have already processed base classes and
+   non-static data members.  We need to check whether the copy
+   constructor is trivial, the destructor is trivial, and there
+   is a trivial default constructor or at least one constexpr
+   constructor other than the copy constructor.  */
+
+static void
+finalize_literal_type_property (tree t)
+{
+  if (TYPE_HAS_NONTRIVIAL_DESTRUCTOR (t))
+    CLASSTYPE_LITERAL_P (t) = false;
+  if (!TYPE_HAS_TRIVIAL_INIT_REF (t))
+    CLASSTYPE_LITERAL_P (t) = false;
+  if (CLASSTYPE_LITERAL_P (t) && !TYPE_HAS_TRIVIAL_DFLT (t)
+      && CLASSTYPE_METHOD_VEC (t) != NULL)
+    {
+      tree ctors = CLASSTYPE_CONSTRUCTORS (t);
+      bool found_one = false;
+      for (; !found_one && ctors != NULL; ctors = OVL_NEXT (ctors))
+        {
+          tree ctor = OVL_CURRENT (ctors);
+          /* If this class a constexpr constructor template, then the class
+             is literal if at least one instantiation is 'constexpr'.
+             If no such instantiation exists, there is no way to use
+             the literalness of the class.  Consequently, we can accept
+             constexpr constructor template.  */
+          if (DECL_COPY_CONSTRUCTOR_P (ctor)
+              || DECL_CLONED_FUNCTION_P (ctor))
+            continue;
+          if (DECL_DECLARED_CONSTEXPR_P (STRIP_TEMPLATE (ctor)))
+            found_one = true;
+        }
+      CLASSTYPE_LITERAL_P (t) = found_one;
+    }
+}
+
 /* Check the validity of the bases and members declared in T.  Add any
    implicitly-generated functions (like copy-constructors and
    assignment operators).  Compute various flag bits (like
@@ -4472,6 +4521,10 @@
       CLASSTYPE_NON_AGGREGATE (t) = 1;
     }
 
+  /* Compute the `literal type' property before we get to
+     do anything with non-static member functions.  */
+  finalize_literal_type_property (t);
+
   /* Create the in-charge and not-in-charge variants of constructors
      and destructors.  */
   clone_constructors_and_destructors (t);
@@ -5291,6 +5344,7 @@
   CLASSTYPE_EMPTY_P (t) = 1;
   CLASSTYPE_NEARLY_EMPTY_P (t) = 1;
   CLASSTYPE_CONTAINS_EMPTY_CLASS_P (t) = 0;
+  CLASSTYPE_LITERAL_P (t) = true;
 
   /* Do end-of-class semantic processing: checking the validity of the
      bases and members and add implicitly generated methods.  */
=== gcc/cp/decl.c
==================================================================
--- gcc/cp/decl.c	(revision 154736)
+++ gcc/cp/decl.c	(patch const level 1)
@@ -1099,6 +1099,25 @@
     }
 }
 
+/* Return true if both OLD_DECL and NEW_DECL agrees on constexprnes.
+   Otherwise issue diagnostics.  */
+
+static bool
+validate_constexpr_redeclaration (tree old_decl, tree new_decl)
+{
+  old_decl = STRIP_TEMPLATE (old_decl);
+  new_decl = STRIP_TEMPLATE (new_decl);
+  if (!VAR_OR_FUNCTION_DECL_P (old_decl)
+      || !VAR_OR_FUNCTION_DECL_P (new_decl))
+    return true;
+  if (DECL_DECLARED_CONSTEXPR_P (old_decl)
+      == DECL_DECLARED_CONSTEXPR_P (new_decl))
+    return true;
+  error ("redeclaration %qD differs in %<constexpr%>", new_decl);
+  error ("from previous declaration %q+D", old_decl);
+  return false;
+}
+
 #define GNU_INLINE_P(fn) (DECL_DECLARED_INLINE_P (fn)			\
 			  && lookup_attribute ("gnu_inline",		\
 					       DECL_ATTRIBUTES (fn)))
@@ -1576,6 +1595,9 @@
      warn about it.  */
   warn_extern_redeclared_static (newdecl, olddecl);
 
+  if (!validate_constexpr_redeclaration (olddecl, newdecl))
+    return error_mark_node;
+
   /* We have committed to returning 1 at this point.  */
   if (TREE_CODE (newdecl) == FUNCTION_DECL)
     {
@@ -5606,6 +5628,12 @@
 	}
     }
 
+  if (!processing_template_decl
+      && FUNCTION_DECL_P (decl)
+      && !DECL_CLONED_FUNCTION_P (decl)
+      && DECL_DECLARED_CONSTEXPR_P (decl))
+     validate_constexpr_fundecl (decl);
+
   if (init && TREE_CODE (decl) == FUNCTION_DECL)
     {
       tree clone;
@@ -5648,7 +5676,9 @@
 	  DECL_INITIAL (decl) = NULL_TREE;
 	}
 
-      if (init && init_const_expr_p && TREE_CODE (decl) == VAR_DECL)
+      if (init
+          && (init_const_expr_p || DECL_DECLARED_CONSTEXPR_P (decl))
+          && VAR_DECL_P (decl))
 	{
 	  DECL_INITIALIZED_BY_CONSTANT_EXPRESSION_P (decl) = 1;
 	  if (DECL_INTEGRAL_CONSTANT_VAR_P (decl))
@@ -5770,7 +5800,7 @@
 	  if (init)
 	    {
 	      DECL_NONTRIVIALLY_INITIALIZED_P (decl) = 1;
-	      if (init_const_expr_p)
+	      if (init_const_expr_p || DECL_DECLARED_CONSTEXPR_P (decl))
 		{
 		  DECL_INITIALIZED_BY_CONSTANT_EXPRESSION_P (decl) = 1;
 		  if (DECL_INTEGRAL_CONSTANT_VAR_P (decl))
@@ -7906,6 +7936,12 @@
   if (name == NULL)
     name = decl_context == PARM ? "parameter" : "type name";
 
+  if (constexpr_p && declspecs->specs[(int)ds_typedef])
+    {
+      error ("%<constexpr%> cannot appear in a typedef declaration");
+      return error_mark_node;
+    }
+
   /* If there were multiple types specified in the decl-specifier-seq,
      issue an error message.  */
   if (declspecs->multiple_types_p)
@@ -9216,6 +9252,10 @@
 	    int publicp = 0;
 	    tree function_context;
 
+            if (constexpr_p && !staticp && !friendp
+                && sfk != sfk_constructor && sfk != sfk_destructor)
+              memfn_quals |= TYPE_QUAL_CONST;
+            
 	    if (friendp == 0)
 	      {
 		if (ctype == NULL_TREE)
@@ -9271,7 +9311,10 @@
 		    return error_mark_node;
 		  }
                 if (constexpr_p)
-                  error ("a destructor cannot be %<constexpr%>");
+                  {
+                    error ("a destructor cannot be %<constexpr%>");
+                    return error_mark_node;
+                  }
 	      }
 	    else if (sfk == sfk_constructor && friendp)
 	      {
@@ -11594,10 +11637,6 @@
   /* In a function definition, arg types must be complete.  */
   require_complete_types_for_parms (current_function_parms);
 
-  /* constexpr functions must have literal argument types and
-     literal return type.  */
-  validate_constexpr_fundecl (decl);
-
   if (dependent_type_p (return_type))
     return;
   if (!COMPLETE_OR_VOID_TYPE_P (return_type)
@@ -12365,6 +12404,30 @@
   return block;
 }
 
+/* Subroutine of finish_function.
+   Save the body of constexpr functions for possible
+   future compile time evaluation.  */
+
+static void
+maybe_save_function_definition (tree fun)
+{
+  if (!processing_template_decl
+      && DECL_DECLARED_CONSTEXPR_P (fun)
+      && !DECL_CLONED_FUNCTION_P (fun))
+    {
+      if (DECL_NONSTATIC_MEMBER_FUNCTION_P (fun)
+          && !DECL_CONSTRUCTOR_P (fun)
+          && !literal_type_p (DECL_CONTEXT (fun)))
+        {
+          error ("containing class of %qD is not a literal type",
+                 DECL_CONTEXT (fun));
+          DECL_DECLARED_CONSTEXPR_P (fun) = false;
+          return;
+        }
+      register_constexpr_fundef (fun, DECL_SAVED_TREE (fun));
+    }
+}
+
 /* Finish up a function declaration and compile that function
    all the way to assembler language output.  The free the storage
    for the function definition.
@@ -12485,6 +12548,10 @@
      of curly braces for a function.  */
   gcc_assert (stmts_are_full_exprs_p ());
 
+  /* Save constexpr function body before it gets munged by
+     the NRV transformation.   */
+  maybe_save_function_definition (fndecl);
+
   /* Set up the named return value optimization, if we can.  Candidate
      variables are selected in check_return_expr.  */
   if (current_function_return_value)
=== gcc/cp/cp-tree.h
==================================================================
--- gcc/cp/cp-tree.h	(revision 154736)
+++ gcc/cp/cp-tree.h	(patch const level 1)
@@ -113,6 +113,7 @@
    6: IDENTIFIER_REPO_CHOSEN (in IDENTIFIER_NODE)
       DECL_CONSTRUCTION_VTABLE_P (in VAR_DECL)
       TYPE_MARKED_P (in _TYPE)
+   7: COMPILE_TIME_CONSTANT_P (in _EXPR or _REF)
 
    Usage of TYPE_LANG_FLAG_?:
    0: TYPE_DEPENDENT_P
@@ -2141,6 +2142,21 @@
    && INTEGRAL_OR_ENUMERATION_TYPE_P (TREE_TYPE (NODE))	\
    && DECL_INITIALIZED_BY_CONSTANT_EXPRESSION_P (NODE))
 
+/* True if the expression tree NODE represents an object that can
+   be taken apart by the front end.  This is not to be confused with
+   link-time constants or load-time constants.  A compiler constant
+   may still be an expression that the middle end may be able to
+   reduce further.  */
+#define COMPILE_TIME_CONSTANT_P(NODE) \
+  (TREE_LANG_FLAG_7 (NODE))
+
+/* Same as COMPILE_TIME_CONSTANT_P, except that it includes literal
+   values too, such as INTEGER_CST, PTRMEM_CST, or address of
+   variables with static storage or combination thereof.  */
+#define VALID_FOR_STATIC_INITIALIZATION_P(NODE) \
+  (CONSTANT_CLASS_P (NODE) || COMPILE_TIME_CONSTANT_P (NODE))
+
+
 /* Nonzero if the DECL was initialized in the class definition itself,
    rather than outside the class.  This is used for both static member
    VAR_DECLS, and FUNCTION_DECLS that are defined in the class.  */
@@ -3123,6 +3139,10 @@
 #define TYPE_PTR_P(NODE)			\
   (TREE_CODE (NODE) == POINTER_TYPE)
 
+/* Return true if NODE is an array type.  */
+#define TYPE_ARRAY_P(NODE)                      \
+  (TREE_CODE (NODE) == ARRAY_TYPE)
+
 /* Returns true if NODE is an object type:
 
      [basic.types]
@@ -4929,6 +4949,8 @@
 extern tree get_function_template_decl		(const_tree);
 extern tree resolve_nondeduced_context		(tree);
 
+extern hashval_t hash_constexpr_args (tree, hashval_t);
+
 /* in repo.c */
 extern void init_repo				(void);
 extern int repo_emit_p				(tree);
@@ -5054,8 +5076,14 @@
 extern void finish_cleanup			(tree, tree);
 extern bool literal_type_p (tree);
 extern tree validate_constexpr_fundecl (tree);
+extern tree register_constexpr_fundef (tree, tree);
 extern tree ensure_literal_type_for_constexpr_object (tree);
+extern tree cxx_constant_value (tree);
 
+/* True if C++0x-style conctant expresions are allowed.  */
+#define generalized_constant_expression_allowed() \
+  ((cxx_dialect != cxx98) || in_system_header)
+
 enum {
   BCS_NO_SCOPE = 1,
   BCS_TRY_BLOCK = 2,
=== gcc/cp/typeck2.c
==================================================================
--- gcc/cp/typeck2.c	(revision 154736)
+++ gcc/cp/typeck2.c	(patch const level 1)
@@ -632,6 +632,11 @@
 
   /* Digest the specified initializer into an expression.  */
   value = digest_init_flags (type, init, flags);
+
+  /* constexpr variables need to have their initializers reduced.  */
+  if (DECL_DECLARED_CONSTEXPR_P (decl) && value != error_mark_node)
+    value = cxx_constant_value (value);
+
   /* If the initializer is not a constant, fill in DECL_INITIAL with
      the bits that are constant, and then return an expression that
      will perform the dynamic initialization.  */
=== gcc/cp/pt.c
==================================================================
--- gcc/cp/pt.c	(revision 154736)
+++ gcc/cp/pt.c	(patch const level 1)
@@ -1576,6 +1576,15 @@
   return 0;
 }
 
+/* Return a hash value for arguments ARGS in a call to a constexpr
+   function.  INIT is an initial hash value to combine with.  */
+
+hashval_t
+hash_constexpr_args (tree arg, hashval_t init)
+{
+   return iterative_hash_template_arg (arg, init);
+}
+
 /* Unregister the specialization SPEC as a specialization of TMPL.
    Replace it with NEW_SPEC, if NEW_SPEC is non-NULL.  Returns true
    if the SPEC was listed as a specialization of TMPL.
=== gcc/cp/semantics.c
==================================================================
--- gcc/cp/semantics.c	(revision 154736)
+++ gcc/cp/semantics.c	(patch const level 1)
@@ -5275,6 +5275,7 @@
   return 0;
 }
 
+
 /* Return true if T is a literal type.   */
 
 bool
@@ -5297,7 +5298,7 @@
 ensure_literal_type_for_constexpr_object (tree decl)
 {
   tree type = TREE_TYPE (decl);
-  if (TREE_CODE (decl) == VAR_DECL && DECL_DECLARED_CONSTEXPR_P (decl)
+  if (VAR_DECL_P (decl) && DECL_DECLARED_CONSTEXPR_P (decl)
       && !processing_template_decl && !literal_type_p (type))
     {
       error ("the type %qT of constexpr variable %qD is not literal",
@@ -5307,6 +5308,57 @@
   return decl;
 }
 
+/* Representationof entries in the constexpr function definition table.  */
+
+typedef struct GTY(()) constexpr_fundef {
+  tree decl;
+  tree parms;
+  tree body;
+} constexpr_fundef;
+
+/* This table holds all constexpr function definitions seen in
+   the current translation unit.  */
+
+static GTY ((param_is (constexpr_fundef))) htab_t constexpr_fundef_table;
+
+static bool potential_constant_expression (tree, tsubst_flags_t);
+
+/* Utility function used for managing the constexpr function table.
+   Return true if the entries pointed to by P and Q are for the
+   same constexpr function.  */
+
+static inline int
+constexpr_fundef_equal (const void *p, const void *q)
+{
+  const constexpr_fundef *lhs = (const constexpr_fundef *) p;
+  const constexpr_fundef *rhs = (const constexpr_fundef *) q;
+  return lhs->decl == rhs->decl;
+}
+
+
+/* Utility function used for managing the constexpr function table.
+   Return a hash value for the entry pointed to by Q.  */
+
+static inline hashval_t
+constexpr_fundef_hash (const void *p)
+{
+  const constexpr_fundef *fundef = (const constexpr_fundef *) p;
+  return DECL_UID (fundef->decl);
+}
+
+/* Return a previously saved definition of function FUN.   */
+
+static constexpr_fundef *
+retrieve_constexpr_fundef (tree fun)
+{
+  constexpr_fundef fundef = { NULL, NULL, NULL };
+  if (constexpr_fundef_table == NULL)
+    return NULL;
+  
+  fundef.decl = fun;
+  return (constexpr_fundef *) htab_find (constexpr_fundef_table, &fundef);
+}
+
 /* Return non-null if FUN certainly designates a valid constexpr function
    declaration.  Otherwise return NULL.  Issue appropriate diagnostics
    if necessary.  Note that we only check the declaration, not the body
@@ -5317,45 +5369,1079 @@
 {
   tree rettype = NULL;
   tree parm = NULL;
+  constexpr_fundef entry;
+  constexpr_fundef **slot;
 
-  /* Don't bother if FUN is not marked constexpr.  */
-  if (!DECL_DECLARED_CONSTEXPR_P (fun))
-    return NULL;
-
-  /* For a function template, we have absolutely no guarantee that all
-     instantiations will be constexpr.  */
-  if (TREE_CODE (fun) == TEMPLATE_DECL)
-    return NULL;
-  
   parm = FUNCTION_FIRST_USER_PARM (fun);
   for (; parm != NULL; parm = TREE_CHAIN (parm))
+    if (!literal_type_p (TREE_TYPE (parm)))
+      {
+        error ("parameter %q#D is not of literal type", parm);
+        DECL_DECLARED_CONSTEXPR_P (fun) = false;
+        return NULL;
+      }
+
+  if (!DECL_CONSTRUCTOR_P (fun))
     {
-      tree type = TREE_TYPE (parm);
-      if (dependent_type_p (type))
-        return NULL;
-      if (!literal_type_p (type))
+      rettype = TREE_TYPE (TREE_TYPE (fun));
+      if (!literal_type_p (rettype))
         {
-           error ("parameter %q#D is not of literal type", parm);
+          error ("return type %qT of function %qD is not a literal type",
+                 rettype, fun);
+          DECL_DECLARED_CONSTEXPR_P (fun) = false;
           return NULL;
         }
     }
 
+  /* Create the constexpr function table if necessary.  */
+  if (constexpr_fundef_table == NULL)
+    constexpr_fundef_table = htab_create_ggc (101,
+                                              constexpr_fundef_hash,
+                                              constexpr_fundef_equal,
+                                              ggc_free);
+  entry.decl = fun;
+  /* We don't store parameters at this point.  The parameters that
+     matter are the ones we see in the definition.
+     register_constexpr_fundef will store them.   */
+  entry.parms = NULL;
+  entry.body = NULL;
+  slot = (constexpr_fundef **)
+    htab_find_slot (constexpr_fundef_table, &entry, INSERT);
+  if (*slot == NULL)
+    {
+      *slot = GGC_NEW (constexpr_fundef);
+      **slot = entry;
+    }
+  return fun;
+}
+
+/* Build compile-time evalable representations of member-initializer list
+   for a constexpr constructor.  */
+
+static tree
+build_constexpr_constructor_member_initializers (tree type, tree body)
+{
+  tree_stmt_iterator i;
+  tree inits = NULL;
+  if (TREE_CODE (body) == BIND_EXPR)
+    body = BIND_EXPR_BODY (body);
+  gcc_assert (TREE_CODE (body) == STATEMENT_LIST);
+  for (i = tsi_start (body); !tsi_end_p (i); tsi_next (&i))
+    {
+      tree x = tsi_stmt (i);
+      tree member;
+      gcc_assert (TREE_CODE (x) == CLEANUP_POINT_EXPR);
+      x = TREE_OPERAND (x, 0);
+      gcc_assert (TREE_CODE (x) == EXPR_STMT);
+      x = TREE_OPERAND (x, 0);
+      gcc_assert (TREE_CODE (x) == CONVERT_EXPR);
+      x = TREE_OPERAND (x, 0);
+      gcc_assert (TREE_CODE (x) == INIT_EXPR);
+      member = TREE_OPERAND (x, 0);
+      if (TREE_CODE (member) == COMPONENT_REF)
+        member = TREE_OPERAND (member, 1);
+      inits = tree_cons (member, unshare_expr (TREE_OPERAND (x, 1)), inits);
+    }
+  return build1 (CTOR_INITIALIZER, type, nreverse (inits));
+}
+
+/* We are processing the definition of the constexpr function FUN.
+   Check that its BODY fulfills the propriate requirements and
+   enter it in the constexpr function definition table.
+   For constructor BODY is actually the TREE_LIST of the
+   member-initializer list.  */
+
+tree
+register_constexpr_fundef (tree fun, tree body)
+{
+  constexpr_fundef *fundef = retrieve_constexpr_fundef (fun);
+  gcc_assert (fundef != NULL && fundef->body == NULL); 
+
   if (DECL_CONSTRUCTOR_P (fun))
-    return fun;
+    body = build_constexpr_constructor_member_initializers
+      (DECL_CONTEXT (fun), body);
+  else
+    {
+      if (TREE_CODE (body) == EH_SPEC_BLOCK)
+        body = EH_SPEC_STMTS (body);
+      if (TREE_CODE (body) == CLEANUP_POINT_EXPR)
+        body = TREE_OPERAND (body, 0);
+      if (TREE_CODE (body) != RETURN_EXPR)
+        {
+          error ("body of constexpr function %qD not a return-statement", fun);
+          DECL_DECLARED_CONSTEXPR_P (fun) = false;
+          return NULL;
+        }
+      body = unshare_expr (TREE_OPERAND (body, 0));
+    }
 
-  rettype = TREE_TYPE (TREE_TYPE (fun));
-  if (dependent_type_p (rettype))
-    return NULL;
-  if (!literal_type_p (rettype))
+  if (!potential_constant_expression (body, tf_error))
     {
-      error ("return type %qT of function %qD is not a literal type",
-             TREE_TYPE (TREE_TYPE (fun)), fun);
+      DECL_DECLARED_CONSTEXPR_P (fun) = false;
       return NULL;
     }
+  fundef->parms = DECL_ARGUMENTS (fun);
+  fundef->body = body;
   return fun;
 }
 
+/* Objects of this type represent calls to constexpr functions
+   along with the bindings of parameters to their arguments, for
+   the purpose of compile time evaluation.  */
 
+typedef struct GTY(()) constexpr_call {
+  /* Description of the constexpr function definition.  */
+  constexpr_fundef *fundef;
+  /* Parameter bindings enironment.  A TREE_LIST where each TREE_PURPOSE
+     is a parameter _DECL and the TREE_VALUE is the value of the parameter.
+     Note: This arrangement is made to accomodate the use of
+     iterative_hash_template_args (see pt.c).  If you change this
+     representation, also change the implementation of the function
+     hash_constexpr_args.  */
+  tree bindings;
+  /* Result of the call.
+       NULL means the call is being evaluated.
+       error_mark_node means that the evaluation was erroneous
+       otherwise, the actuall value of the call.  */
+  tree result;
+} constexpr_call;
+
+/* A table of all constexpr calls that have been evaluated by the
+   compiler in this translation unit.  */
+
+static GTY ((param_is (constexpr_call))) htab_t constexpr_call_table;
+
+static tree cxx_eval_constant_expression (const constexpr_call *, tree);
+
+/* Compute a hash value for a constexpr call representation.  */
+
+static hashval_t
+constexpr_call_hash (const void *p)
+{
+  const constexpr_call *info = (const constexpr_call *) p;
+  return hash_constexpr_args (info->bindings,
+                              constexpr_fundef_hash (info->fundef));
+}
+
+/* Return 1 if the objects pointed to by P and Q represent the same
+   call to a constexpr function with same set of argument list.
+   Otherwise, return 0.  */
+
+static int
+constexpr_call_equal (const void *p, const void *q)
+{
+  const constexpr_call *lhs = (const constexpr_call *) p;
+  const constexpr_call *rhs = (const constexpr_call *) q;
+  tree lhs_bindings;
+  tree rhs_bindings;
+  if (lhs == rhs)
+    return 1;
+  if (!constexpr_fundef_equal (lhs->fundef, rhs->fundef))
+    return 0;
+  lhs_bindings = lhs->bindings;
+  rhs_bindings = rhs->bindings;
+  while (lhs_bindings != NULL && rhs_bindings != NULL)
+    {
+      tree lhs_arg = TREE_VALUE (lhs_bindings);
+      tree rhs_arg = TREE_VALUE (rhs_bindings);
+      gcc_assert (TREE_TYPE (lhs_arg) == TREE_TYPE (rhs_arg));
+      if (!cp_tree_equal (lhs_arg, rhs_arg))
+        return 0;
+      lhs_bindings = TREE_CHAIN (lhs_bindings);
+      rhs_bindings = TREE_CHAIN (rhs_bindings);
+    }
+  return lhs_bindings == rhs_bindings;
+}
+
+/* Initialized the constexpr call table, if needed.  */
+
+static void
+maybe_initialize_constexpr_call_table (void)
+{
+  if (constexpr_call_table == NULL)
+    constexpr_call_table = htab_create_ggc (101,
+                                            constexpr_call_hash,
+                                            constexpr_call_equal,
+                                            ggc_free);
+}
+
+/* Return true if T designate the implied `this' parameter.  */
+
+static inline bool
+is_this_parameter (tree t)
+{
+  return DECL_P (t) && DECL_NAME (t) == this_identifier;
+}
+
+/* We have an expression tree T that represents a call, either CALL_EXPR
+   or AGGR_INIT_EXPR.  If the call is lexically to a named function,
+   retrun the _DECL for that function.  */
+
+static tree
+get_function_named_in_call (tree t)
+{
+  tree fun = NULL;
+  switch (TREE_CODE (t))
+    {
+    case CALL_EXPR:
+      fun = CALL_EXPR_FN (t);
+      break;
+
+    case AGGR_INIT_EXPR:
+      fun = AGGR_INIT_EXPR_FN (t);
+      break;
+
+    default:
+      gcc_unreachable();
+      break;
+    }
+  if (TREE_CODE (fun) == ADDR_EXPR
+      && FUNCTION_DECL_P (TREE_OPERAND (fun, 0)))
+    fun = TREE_OPERAND (fun, 0);
+  return fun;
+}
+
+/* We have an expression tree T that represents a call, either CALL_EXPR
+   or AGGR_INIT_EXPR.  Return the Nth argument.  */
+
+static inline tree
+get_nth_callarg (tree t, int n)
+{
+  switch (TREE_CODE (t))
+    {
+    case CALL_EXPR:
+      return CALL_EXPR_ARG (t, n);
+
+    case AGGR_INIT_EXPR:
+      return AGGR_INIT_EXPR_ARG (t, n);
+
+    default:
+      gcc_unreachable();
+      return NULL;
+    }
+}
+
+
+/* Look up the binding of the function parameter T in a constexpr
+   function call context CALL.  */
+
+static tree
+lookup_parameter_binding (const constexpr_call *call, tree t)
+{
+  tree b = purpose_member (t, call->bindings);
+  gcc_assert(b != NULL);
+  return b;
+}
+
+/* Attempt to evaluate T which represents a call to a builtin function.
+   We assume here that all builtin functions evaluate to scalar types
+   represented by _CST nodes.  */
+
+static tree
+cxx_eval_builtin_function_call (const constexpr_call *call, tree t)
+{
+  const int nargs = call_expr_nargs (t);
+  tree *args = (tree *) alloca (nargs * sizeof (tree));
+  tree new_call;
+  tree v;
+  int i;
+  for (i = 0; i < nargs; ++i)
+    {
+      args[i] = cxx_eval_constant_expression (call, CALL_EXPR_ARG (t, i));
+      if (args[i] == error_mark_node)
+        return args[i];
+    }
+  new_call = build_call_array_loc (EXPR_LOCATION (t), TREE_TYPE (t),
+                                   CALL_EXPR_FN (t), nargs, args);
+  v = fold (new_call);
+  if (new_call == v || !CONSTANT_CLASS_P (v))
+    return error_mark_node;
+  return v;
+}
+
+/* Subroutine of cxx_eval_call_expression.
+   We are processing a call expression (either CALL_EXPR or
+   AGGR_INIT_EXPR) in the call context of OLD_CALL.  Evaluate
+   all arguments and bind their values to correspondings
+   parameters, making up the NEW_CALL context.  */
+
+static bool
+cxx_bind_parameters_in_call (const constexpr_call *old_call, tree t,
+                             constexpr_call *new_call)
+{
+  const int nargs = call_expr_nargs (t);
+  tree parms = new_call->fundef->parms;
+  tree fun = new_call->fundef->decl;
+  int i;
+  for (i = 0; i < nargs; ++i, parms = TREE_CHAIN (parms))
+    {
+      tree arg;
+      /* For member function, the first argument is a pointer to the implied
+         object.  And for an object contruction, don't bind `this' before
+         it is fully constructed.  */
+      if (i == 0 && DECL_CONSTRUCTOR_P (fun))
+        continue;
+      else if (i == 0 && DECL_NONSTATIC_MEMBER_P (fun))
+        {
+          tree x = get_nth_callarg (t, i);
+          if (is_this_parameter (x))
+            arg = lookup_parameter_binding (old_call, x);
+          else
+            {
+              if (TREE_CODE (x) == ADDR_EXPR)
+                x = TREE_OPERAND (x, 0);
+              arg = cxx_eval_constant_expression (old_call, x);
+            }
+        }
+      else
+        arg = cxx_eval_constant_expression (old_call, get_nth_callarg (t, i));
+      if (arg == error_mark_node)
+        return false;
+      new_call->bindings = tree_cons (parms, arg, new_call->bindings);
+    }
+  return true;
+}
+
+/* Subroutine of cxx_eval_constant_expression.
+   Evaluate the call expression tree T in the context of OLD_CALL expression
+   evaluation.  */
+
+static tree
+cxx_eval_call_expression (const constexpr_call *old_call, tree t)
+{
+  tree fun = get_function_named_in_call (t);
+  constexpr_call new_call = { NULL, NULL, NULL };
+  constexpr_call **slot;
+  /* The call must be to a constexpr function.
+     FIXME:  check the standard.  */
+  if (!DECL_P (fun))
+    {
+      error ("expression %qE does not designate a constexpr function", fun);
+      return error_mark_node;
+    }
+  if (DECL_CLONED_FUNCTION_P (fun))
+    fun = DECL_CLONED_FUNCTION (fun);
+  if (is_builtin_fn (fun))
+    return cxx_eval_builtin_function_call (old_call, t);
+  if (!DECL_DECLARED_CONSTEXPR_P (fun))
+    {
+      error ("%qD is not a constexpr function", fun);
+      return error_mark_node;
+    }
+  
+  /* If in direct recursive call, optimize definition search.  */
+  if (old_call != NULL && old_call->fundef->decl == fun)
+    new_call.fundef = old_call->fundef;
+  else
+    {
+      new_call.fundef = retrieve_constexpr_fundef (fun);
+      if (new_call.fundef == NULL || new_call.fundef->body == NULL)
+        {
+          error ("constexpr %qD used before its definition", fun);
+          return error_mark_node;
+        }
+    }
+  if (!cxx_bind_parameters_in_call (old_call, t, &new_call))
+    return error_mark_node;
+    
+  
+  /* If we have seen this call before, we are done.  */
+  maybe_initialize_constexpr_call_table ();
+  slot = (constexpr_call **)
+    htab_find_slot (constexpr_call_table, &new_call, INSERT);
+  if (*slot != NULL)
+    {
+      /* Calls which are in progress have their result set to NULL
+         so that we can detect circular dependencies.  */
+      if ((*slot)->result == NULL)
+        {
+          error ("call to %qE has circular dependency", fun);
+          (*slot)->result = error_mark_node;
+        }
+      return (*slot)->result;
+    }
+  new_call.result =
+    cxx_eval_constant_expression (&new_call, new_call.fundef->body);
+  *slot = GGC_NEW (constexpr_call);
+  **slot = new_call;
+  return new_call.result;
+}
+
+/* Subroutine of cxx_eval_constant_expression.
+   Attempt to reduce the unary expression tree T to a compile time value.
+   If successful, return the value.  Otherwise issue a diagnostic
+   and return error_mark_node.  */
+
+static tree
+cxx_eval_unary_expression (const constexpr_call *call, tree t)
+{
+  tree arg = cxx_eval_constant_expression (call, TREE_OPERAND (t, 0));
+  if (arg == error_mark_node)
+    return arg;
+  arg = fold_if_not_in_template (build1 (TREE_CODE (t), TREE_TYPE (t), arg));
+  if (VALID_FOR_STATIC_INITIALIZATION_P (arg))
+    return arg;
+  sorry ("could not evaluate %qE to a value", arg);
+  return error_mark_node;
+}
+
+/* Subroutine of cxx_eval_constant_expression.
+   Like cxx_eval_unary_expression, except for binary expressions.  */
+
+static tree
+cxx_eval_binary_expression (const constexpr_call *call, tree t)
+{
+  tree lhs = cxx_eval_constant_expression (call, TREE_OPERAND (t, 0));
+  tree rhs = cxx_eval_constant_expression (call, TREE_OPERAND (t, 1));
+  if (lhs == error_mark_node || rhs == error_mark_node)
+    return error_mark_node;
+  t = fold_if_not_in_template
+    (build2 (TREE_CODE (t), TREE_TYPE (t), lhs, rhs));
+  if (VALID_FOR_STATIC_INITIALIZATION_P (t))
+    return t;
+  sorry ("could not evaluate %qE to a value", t);
+  return error_mark_node;
+}
+
+/* Subroutine of cxx_eval_constant_expression.
+   Attempt to evaluate condition expressions.  Dead branches are not
+   looked into.  */
+
+static tree
+cxx_eval_conditional_expression (const constexpr_call *call, tree t)
+{
+  tree val = cxx_eval_constant_expression (call, TREE_OPERAND (t, 0));
+  if (val == error_mark_node)
+    return val;
+  if (val == boolean_true_node)
+    return cxx_eval_constant_expression (call, TREE_OPERAND (t, 1));
+  gcc_assert (val == boolean_false_node);
+  return cxx_eval_constant_expression (call, TREE_OPERAND (t, 2));
+}
+
+/* Subroutine of cxx_eval_constant_expression.
+   Attempt to reduce a reference to an array slot.  */
+
+static tree
+cxx_eval_array_reference (const constexpr_call *call, tree t)
+{
+  tree ary = cxx_eval_constant_expression (call, TREE_OPERAND (t, 0));
+  tree index;
+  if (ary == error_mark_node)
+    return ary;
+  gcc_assert (TREE_CODE (ary) == CONSTRUCTOR);
+  index = cxx_eval_constant_expression (call, TREE_OPERAND (t, 1));
+  if (index == error_mark_node)
+    return index;
+  /* FIXME: For the time being, refuse to index into a too big arrary.  */
+  if (!host_integerp (index, 0))
+    {
+      error ("array subscript too big");
+      return error_mark_node;
+    }
+  if (tree_low_cst (index, 0) >= CONSTRUCTOR_NELTS (ary))
+    {
+      error ("array subscript out of bound");
+      return error_mark_node;
+    }
+  return VEC_index (constructor_elt, CONSTRUCTOR_ELTS (ary),
+                    tree_low_cst (index, 0))->value;
+}
+
+/* Subroutine of cxx_eval_constant_expression.
+   Attempt to reduce a field access of a value of class type.  */
+
+static tree
+cxx_eval_component_reference (const constexpr_call *call, tree t)
+{
+  tree whole = cxx_eval_constant_expression (call, TREE_OPERAND (t, 0));
+  tree part = TREE_OPERAND (t, 1);
+  unsigned HOST_WIDE_INT i;
+  tree field;
+  tree value;
+  if (whole == error_mark_node)
+    return whole;
+  gcc_assert (TREE_CODE (whole) == CONSTRUCTOR);
+  FOR_EACH_CONSTRUCTOR_ELT (CONSTRUCTOR_ELTS (whole), i, field, value)
+    {
+      if (field == part)
+        return value;
+    }
+  gcc_unreachable();
+  return error_mark_node;
+}
+
+/* Subroutine of cxx_eval_constant_expression.
+   Evaluate a short-circuited logical expression T in the context
+   of a given constexpr CALL.  BAILOUT_VALUE is the value for
+   early return.  CONTINUE_VALUE is used here purely for
+   sanity check purposes.  */
+
+static tree
+cxx_eval_logical_expression (const constexpr_call *call, tree t,
+                             tree bailout_value, tree continue_value)
+{
+  tree lhs = cxx_eval_constant_expression (call, TREE_OPERAND (t, 0));
+  if (lhs == error_mark_node || lhs == bailout_value)
+    return lhs;
+  gcc_assert (lhs == continue_value);
+  return cxx_eval_constant_expression (call, TREE_OPERAND (t, 1));
+}
+
+/* Subroutine of cxx_eval_constant_expression.
+  Evaluate an object construction (CTOR_INITIALIZER) denoted by T,
+  in the context of contexpr CALL.  */
+
+static tree
+cxx_eval_object_construction (const constexpr_call *call, tree t)
+{
+  tree subobjects = NULL;
+  tree inits = TREE_OPERAND (t, 0);
+  for (; inits != NULL; inits = TREE_CHAIN (inits))
+    {
+      tree v = cxx_eval_constant_expression (call, TREE_VALUE (inits));
+      if (v == error_mark_node)
+        return v;
+      subobjects = tree_cons (TREE_PURPOSE (inits), v, subobjects);
+    }
+  t = build_constructor_from_list (TREE_TYPE (t), nreverse (subobjects));
+  COMPILE_TIME_CONSTANT_P (t) = true;
+  return t;
+}
+
+
+/* Attempt to reduced the expression tree T to a compile time value.
+   On failure, issue diagnostic and return error_mark_node.  */
+
+static tree
+cxx_eval_constant_expression (const constexpr_call *call, tree t)
+{
+  if (t == error_mark_node || VALID_FOR_STATIC_INITIALIZATION_P (t))
+    return t;
+
+  STRIP_NOPS (t);
+  switch (TREE_CODE (t))
+    {
+    case VAR_DECL:
+      return cxx_eval_constant_expression (call, DECL_INITIAL (t));
+
+    case PARM_DECL:
+      return lookup_parameter_binding (call, t);
+
+    case CALL_EXPR:
+    case AGGR_INIT_EXPR:
+      return cxx_eval_call_expression (call, t);
+
+    case INIT_EXPR:
+    case TARGET_EXPR:
+      return cxx_eval_constant_expression (call, TREE_OPERAND (t, 1));
+
+    case RETURN_EXPR:
+    case NON_LVALUE_EXPR:
+      return cxx_eval_constant_expression (call, TREE_OPERAND (t, 0));
+
+    case ADDR_EXPR:
+      if (TREE_STATIC (TREE_OPERAND (t, 0)))
+        {
+          COMPILE_TIME_CONSTANT_P (t) = true;
+          return t;
+        }
+      /* Fall through.  */
+    case REALPART_EXPR:
+    case IMAGPART_EXPR:
+    case CONJ_EXPR:
+    case SAVE_EXPR:
+    case FIX_TRUNC_EXPR:
+    case FLOAT_EXPR:
+    case NEGATE_EXPR:
+    case ABS_EXPR:
+    case BIT_NOT_EXPR:
+    case TRUTH_NOT_EXPR:
+    case PAREN_EXPR:
+    case FIXED_CONVERT_EXPR:
+      return cxx_eval_unary_expression (call, t);
+
+    case POINTER_PLUS_EXPR:
+      if (VALID_FOR_STATIC_INITIALIZATION_P (TREE_OPERAND (t, 0))
+          && VALID_FOR_STATIC_INITIALIZATION_P (TREE_OPERAND (t, 1)))
+        {
+          COMPILE_TIME_CONSTANT_P (t) = true;
+          return t;
+        }
+      /* Fall through.  */
+    case COMPOUND_EXPR:
+    case PLUS_EXPR:
+    case MULT_EXPR:
+    case TRUNC_DIV_EXPR:
+    case CEIL_DIV_EXPR:
+    case FLOOR_DIV_EXPR:
+    case ROUND_DIV_EXPR:
+    case TRUNC_MOD_EXPR:
+    case CEIL_MOD_EXPR:
+    case ROUND_MOD_EXPR:
+    case RDIV_EXPR:
+    case EXACT_DIV_EXPR:
+    case MIN_EXPR:
+    case MAX_EXPR:
+    case LSHIFT_EXPR:
+    case RSHIFT_EXPR:
+    case LROTATE_EXPR:
+    case RROTATE_EXPR:
+    case BIT_IOR_EXPR:
+    case BIT_XOR_EXPR:
+    case BIT_AND_EXPR:
+    case TRUTH_XOR_EXPR:
+    case LT_EXPR:
+    case LE_EXPR:
+    case GT_EXPR:
+    case GE_EXPR:
+    case EQ_EXPR:
+    case NE_EXPR:
+    case UNLT_EXPR:
+    case UNLE_EXPR:
+    case UNGT_EXPR:
+    case UNGE_EXPR:
+    case UNEQ_EXPR:
+    case RANGE_EXPR:
+    case COMPLEX_EXPR:
+      return cxx_eval_binary_expression (call, t);
+
+    case TRUTH_ANDIF_EXPR:
+      return cxx_eval_logical_expression (call, t, boolean_false_node,
+                                          boolean_true_node);
+
+    case TRUTH_ORIF_EXPR:
+      return cxx_eval_logical_expression (call, t, boolean_true_node,
+                                          boolean_false_node);
+
+    case ARRAY_REF:
+      return cxx_eval_array_reference (call, t);
+
+    case COMPONENT_REF:
+      return cxx_eval_component_reference (call, t);
+
+    case COND_EXPR:
+    case VEC_COND_EXPR:
+      return cxx_eval_conditional_expression (call, t);
+
+    case INDIRECT_REF:
+      {
+        tree x = TREE_OPERAND (t, 0);
+        gcc_assert (TREE_CODE (x) == NOP_EXPR);
+        STRIP_NOPS (x);
+        if (is_this_parameter (x))
+          return lookup_parameter_binding (call, x);
+        return cxx_eval_constant_expression (call, x);
+      }
+
+    case CTOR_INITIALIZER:
+      return cxx_eval_object_construction (call, t);
+
+    default:
+      internal_error ("unexpected expression %qE of kind %s", t,
+                      tree_code_name[TREE_CODE (t)]);
+      return error_mark_node;
+    }
+}
+
+
+/* If T represents a constant expression returns its reduced value.
+   Otherwise return error_mark_node.  If T is dependent, then
+   return NULL.  */
+
+tree
+cxx_constant_value (tree t)
+{
+  return potential_constant_expression (t, tf_error)
+    ? cxx_eval_constant_expression (NULL, t)
+    : error_mark_node;
+}
+
+/* Return true if DECL has automatic or thread local storage.   */
+
+static bool
+has_automatic_or_tls (tree decl)
+{
+  switch (TREE_CODE (decl))
+    {
+    case PARM_DECL:
+      return true;
+
+    case VAR_DECL:
+      return DECL_THREAD_LOCAL_P (decl)
+         || (DECL_FUNCTION_SCOPE_P (decl) && !TREE_STATIC (decl));
+
+    default:
+      return false;
+    }
+}
+
+
+/* Return true if the DECL designates a builtin function that is
+   morally constexpr in the sense that, its parameter types and
+   return type are literal types, and the compiler is allowed to
+   fold its invocations.  */
+static bool
+morally_constexpr_builtin_function_p (tree decl)
+{
+  tree funtype = TREE_TYPE (decl);
+  tree t;
+
+  if (!is_builtin_fn (decl))
+    return false;
+  if (!literal_type_p (TREE_TYPE (funtype)))
+    return false;
+  for (t = TYPE_ARG_TYPES (funtype); t != NULL ; t = TREE_CHAIN (t))
+    {
+      if (t == void_list_node)
+        return true;
+      if (!literal_type_p (TREE_VALUE (t)))
+        return false;
+    }
+  /* We don't want to mess with varargs functions, yet.  */
+  return t != NULL;
+}
+
+
+/* Return true if T denotes a potential constant expressions.
+   Issue diagnostic as appropriate under control of flags.  Variables
+   with static storage duration initialized by constant expressions
+   are guaranteed to be statically initialized.
+
+   C++0x [expr.const]
+
+   6 An expression is a potential constant expression if it is
+     a constant expression where all occurences of function
+     parameters are replaced by arbitrary constant expressions
+     of the appropriate type. 
+
+   2  A conditional expression is a constant expression unless it
+      involves one of the following as a potentially evaluated
+      subexpression (3.2), but subexpressions of logical AND (5.14),
+      logical OR (5.15), and conditional (5.16) operations that are
+      not evaluated are not considered.   */
+
+static bool
+potential_constant_expression (tree t, tsubst_flags_t flags)
+{
+  if (t == error_mark_node)
+    return false;
+  if (TREE_THIS_VOLATILE (t))
+    {
+      if (flags & tf_error)
+        error ("expression %qE has side-effects", t);
+      return false;
+    }
+  if (VALID_FOR_STATIC_INITIALIZATION_P (t))
+    return true;
+  
+  switch (TREE_CODE (t))
+    {
+    case PARM_DECL:
+      /* -- this (5.1) unless it appears as the postfix-expression in a
+            class member access expression, including the result of the
+            implicit transformation in the body of the non-static
+            member function (9.3.1);  */
+      if (is_this_parameter (t))
+        {
+          if (flags & tf_error)
+            error ("%qE is not a potential constant expression", t);
+          return false;
+        }
+      return true;
+
+    case AGGR_INIT_EXPR:
+    case CALL_EXPR:
+      /* -- an invocation of a function other than a constexpr function
+            or a constexpr constructor.  */
+      {
+        tree fun = get_function_named_in_call (t);
+        const int nargs = call_expr_nargs (t);
+        int i;
+        if (!DECL_P (fun))
+          {
+            if (flags & tf_error)
+              error ("%qE is not a function name", fun);
+            return false;
+          }
+        if (DECL_CLONED_FUNCTION_P (fun))
+          fun = DECL_CLONED_FUNCTION (fun);
+        if (builtin_valid_in_constant_expr_p (fun))
+          return true;
+        if (!DECL_DECLARED_CONSTEXPR_P (fun)
+            && !morally_constexpr_builtin_function_p (fun))
+          {
+            if (flags & tf_error)
+              error ("%qD is not %<constexpr%>", fun);
+            return false;
+          }
+        for (i = 0; i < nargs; ++i)
+          {
+            tree x = get_nth_callarg (t, i);
+            /* A call to a non-static member function takes the
+               address of the implied object as first argument.
+               If this is an rvalue object, don't look into its storage.  */
+            if (i == 0 && DECL_NONSTATIC_MEMBER_P (fun)
+                && !DECL_CONSTRUCTOR_P (fun))
+              {
+                gcc_assert (TREE_CODE (x) == ADDR_EXPR);
+                if (!potential_constant_expression (x, flags))
+                  return false;
+              }
+            else if (!potential_constant_expression (x, flags))
+              {
+                if (flags & tf_error)
+                  error ("argument in position %qd is not a "
+                         "potential constant expression", i);
+                return false;
+              }
+          }
+        return true;
+      }
+
+    case NOP_EXPR:
+    case NON_LVALUE_EXPR:
+      /* -- an lvalue-to-rvalue conversion (4.1) unless it is applied to
+            -- an lvalue of integral type that refers to a non-volatile
+               const variable or static data member initialized with
+               constant expressions, or
+
+            -- an lvalue of literal type that refers to non-volatile
+               object defined with constexpr, or that refers to a
+               sub-object of such an object;  */
+      return potential_constant_expression (TREE_OPERAND (t, 0), flags);
+
+    case VAR_DECL:
+      if (!DECL_INTEGRAL_CONSTANT_VAR_P (t)
+          && !DECL_DECLARED_CONSTEXPR_P (t))
+        {
+          if (flags & tf_error)
+            error ("variable %qD is not declared constexpr", t);
+          return false;
+        }
+      return true;
+
+    case CONVERT_EXPR:
+    case VIEW_CONVERT_EXPR:
+      /* -- an array-to-pointer conversion that is applied to an lvalue
+            that designates an object with thread or automatic storage
+            duration;
+         -- a type conversion from a pointer or pointer-to-member type
+            to a literal type.  */
+      {
+        tree from = TREE_OPERAND (t, 0);
+        tree source = TREE_TYPE (from);
+        tree target = TREE_TYPE (t);
+        if (TYPE_ARRAY_P (source) && TYPE_PTR_P (target)
+            && has_automatic_or_tls (from))
+          {
+            if (flags & tf_error)
+              error ("array-to-pointer conversion of %qE with automatic "
+                     "or thread local storage cannot yield a constant "
+                     "expression", from);
+            return false;
+          }
+        if (TYPE_PTR_P (source) || TYPE_PTRMEM_P (source))
+          {
+            if (flags & tf_error)
+              error ("conversion of expression %qE of pointer or "
+                     "pointer-to-member type cannot yield a constant "
+                     "expression", from);
+            return false;
+          }
+        return potential_constant_expression (from, flags);
+      }
+      
+    case ADDR_EXPR:
+      /* -- a unary operator & that is applied to an lvalue that
+            designates an object with thread or automatic storage
+            duration;  */
+      t = TREE_OPERAND (t, 0);
+      if (VAR_DECL_P (t) && TREE_STATIC (t))
+        return true;
+      if (has_automatic_or_tls (t))
+        {
+          if (flags & tf_error)
+            error ("address-of a object %qE with thread local or "
+                   "automatic storage is not a constant expression", t);
+          return false;
+        }
+      return potential_constant_expression (t, flags);
+
+    case COMPONENT_REF:
+    case BIT_FIELD_REF:
+      /* -- a class member access unless its postfix-expression is
+            of literal type or of pointer to literal type.  */
+      return potential_constant_expression (TREE_OPERAND (t, 0), flags);
+
+    case INDIRECT_REF:
+      {
+        tree x = TREE_OPERAND (t, 0);
+        STRIP_NOPS (x);
+        if (!is_this_parameter (x))
+          return potential_constant_expression (x, flags);
+        return true;
+      }
+      
+    case LAMBDA_EXPR:
+    case DYNAMIC_CAST_EXPR:
+    case PSEUDO_DTOR_EXPR:
+    case PREINCREMENT_EXPR:
+    case POSTINCREMENT_EXPR:
+    case PREDECREMENT_EXPR:
+    case POSTDECREMENT_EXPR:
+    case NEW_EXPR:
+    case VEC_NEW_EXPR:
+    case DELETE_EXPR:
+    case VEC_DELETE_EXPR:
+    case THROW_EXPR:
+    case MODIFY_EXPR:
+    case MODOP_EXPR:
+      /* GCC internal stuff.  */
+    case VA_ARG_EXPR:
+    case OBJ_TYPE_REF:
+    case WITH_CLEANUP_EXPR:
+    case CLEANUP_POINT_EXPR:
+      if (flags & tf_error)
+        error ("expression %qE is not a constant-expression", t);
+      return false;
+
+    case TYPEID_EXPR:
+      /* -- a typeid expression whose operand is of polymorphic
+            class type;  */
+      {
+        tree e = TREE_OPERAND (t, 0);
+        if (!TYPE_P (e) && TYPE_POLYMORPHIC_P (TREE_TYPE (e)))
+          {
+            if (flags & tf_error)
+              error ("typeid-expression is not a constant expression "
+                     "because %qE is of polymorphic type", e);
+            return false;
+          }
+        return true;
+      }
+
+    case MINUS_EXPR:
+      /* -- a subtraction where both operands are pointers.   */
+      if (TYPE_PTR_P (TREE_OPERAND (t, 0))
+          && TYPE_PTR_P (TREE_OPERAND (t, 1)))
+        {
+          if (flags & tf_error)
+            error ("difference of two pointer expressions is not "
+                   "a constant expression");
+          return false;
+        }
+      return potential_constant_expression (TREE_OPERAND (t, 0), flags)
+        && potential_constant_expression (TREE_OPERAND (t, 1), flags);
+
+    case LT_EXPR:
+    case LE_EXPR:
+    case GT_EXPR:
+    case GE_EXPR:
+    case EQ_EXPR:
+    case NE_EXPR:
+      /* -- a relational or equality operator where at least
+            one of the operands is a pointer.  */
+      if (TYPE_PTR_P (TREE_OPERAND (t, 0))
+          || TYPE_PTR_P (TREE_OPERAND (t, 1)))
+        {
+          if (flags & tf_error)
+            error ("pointer comparison expression is not a "
+                   "constant expression");
+          return false;
+        }
+      return potential_constant_expression (TREE_OPERAND (t, 0), flags)
+        && potential_constant_expression (TREE_OPERAND (t, 1), flags);
+
+    case REALPART_EXPR:
+    case IMAGPART_EXPR:
+    case CONJ_EXPR:
+    case SAVE_EXPR:
+    case FIX_TRUNC_EXPR:
+    case FLOAT_EXPR:
+    case NEGATE_EXPR:
+    case ABS_EXPR:
+    case BIT_NOT_EXPR:
+    case TRUTH_NOT_EXPR:
+    case PAREN_EXPR:
+    case FIXED_CONVERT_EXPR:
+    case CONST_CAST_EXPR:
+      /* For convenience.  */
+    case RETURN_EXPR:
+      return potential_constant_expression (TREE_OPERAND (t, 0), flags);
+
+    case INIT_EXPR:
+    case TARGET_EXPR:
+      return potential_constant_expression (TREE_OPERAND (t, 1), flags);
+
+    case CONSTRUCTOR:
+      {
+        VEC(constructor_elt, gc) *v = CONSTRUCTOR_ELTS (t);
+        constructor_elt *ce;
+        HOST_WIDE_INT i;
+        for (i = 0; VEC_iterate(constructor_elt, v, i, ce); ++i)
+          if (!potential_constant_expression (ce->value, flags))
+            return false;
+        return true;
+      }
+
+    case ARRAY_REF:
+    case ARRAY_RANGE_REF:
+    case COMPOUND_EXPR:
+    case PLUS_EXPR:
+    case MULT_EXPR:
+    case POINTER_PLUS_EXPR:
+    case TRUNC_DIV_EXPR:
+    case CEIL_DIV_EXPR:
+    case FLOOR_DIV_EXPR:
+    case ROUND_DIV_EXPR:
+    case TRUNC_MOD_EXPR:
+    case CEIL_MOD_EXPR:
+    case ROUND_MOD_EXPR:
+    case RDIV_EXPR:
+    case EXACT_DIV_EXPR:
+    case MIN_EXPR:
+    case MAX_EXPR:
+    case LSHIFT_EXPR:
+    case RSHIFT_EXPR:
+    case LROTATE_EXPR:
+    case RROTATE_EXPR:
+    case BIT_IOR_EXPR:
+    case BIT_XOR_EXPR:
+    case BIT_AND_EXPR:
+    case TRUTH_ANDIF_EXPR:
+    case TRUTH_ORIF_EXPR:
+    case TRUTH_XOR_EXPR:
+    case UNLT_EXPR:
+    case UNLE_EXPR:
+    case UNGT_EXPR:
+    case UNGE_EXPR:
+    case UNEQ_EXPR:
+    case RANGE_EXPR:
+    case COMPLEX_EXPR:
+      return potential_constant_expression (TREE_OPERAND (t, 0), flags)
+        && potential_constant_expression (TREE_OPERAND (t, 1), flags);
+
+    case COND_EXPR:
+    case VEC_COND_EXPR:
+      return potential_constant_expression (TREE_OPERAND (t, 0), flags)
+        && potential_constant_expression (TREE_OPERAND (t, 1), flags)
+        && potential_constant_expression (TREE_OPERAND (t, 2), flags);
+
+    case CTOR_INITIALIZER:
+      for (t = TREE_OPERAND (t, 0); t != NULL; t = TREE_CHAIN (t))
+        if (!potential_constant_expression (TREE_VALUE (t), flags))
+          return false;
+      return true;
+
+    default:
+      sorry ("unexpected ast of kind %s", tree_code_name[TREE_CODE (t)]);
+      gcc_unreachable();
+      return false;
+    }
+}
+
+
 /* Constructor for a lambda expression.  */
 
 tree
=== gcc/cp/parser.c
==================================================================
--- gcc/cp/parser.c	(revision 154736)
+++ gcc/cp/parser.c	(patch const level 1)
@@ -15388,13 +15388,33 @@
 {
   tree body;
   bool ctor_initializer_p;
+  const bool check_body_p =
+     DECL_CONSTRUCTOR_P (current_function_decl)
+     && DECL_DECLARED_CONSTEXPR_P (current_function_decl);
+  tree last = NULL;
 
   /* Begin the function body.  */
   body = begin_function_body ();
   /* Parse the optional ctor-initializer.  */
   ctor_initializer_p = cp_parser_ctor_initializer_opt (parser);
+
+  /* If we're parsing a constexpr constructor definition, we need
+     to check that the constructor body is indeed empty.  However,
+     before we get to cp_parser_function_body lot of junk has been
+     generated, so we can't just check that we have an empty block.
+     Rather we take a snapshot of the outermost block, and check whether
+     cp_parser_function_body changed its state.  */
+  if (check_body_p && TREE_CODE (body) == STATEMENT_LIST)
+    last = STATEMENT_LIST_TAIL (body)->stmt;
   /* Parse the function-body.  */
   cp_parser_function_body (parser);
+  if (check_body_p
+      && (TREE_CODE (body) != STATEMENT_LIST
+          || last != STATEMENT_LIST_TAIL (body)->stmt))
+    {
+      error ("constexpr constructor does not have empty body");
+      DECL_DECLARED_CONSTEXPR_P (current_function_decl) = false;
+    }
   /* Finish the function body.  */
   finish_function_body (body);
 


Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]