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]

C++ PATCH for constexpr


Hi Jason,

  Below is a revision of the constexpr patch.  Please have a look
the the codes that involves AGGR_INIT_EXPR.  I incorporated your earlier
comments, but you might want to double check in case I forgot a point.
The modification to the library will be submitted in a different patch,
once this is in and Benjamin clarifies how he wants to handle the
'constexpr' specifier bit (it does not change the ABI).

Summary:

This version implements the core of compile-time evaluation, incorporating
DR resolutions as discussed on the reflectors, and other
clarifications. 

Now, the general plan:

  (1) I maintain a table that maps constexpr functions to their bodies. 
  (2) since constexpr functions are pure, I maintain a compile-time
      memoization table, and in the process we can detect circular
      recursions. 

This patch handles, I believe, almost all examples and all uses
that affect the standard library.  Exceptions are templates, and the
request to accept reference types.  I would prefer to handle those in a
separate patch once the basic evaluation machinery in accepted into
mainline. 

The general idea is that compile time evaluation of expressions usually
produces values, e.g. _CST nodes or CONSTRUCTOR nodes (for arrays and
object of class types.).  However, occasionally, we also have symbolic
values, e.g. (ADDR_EXPR var) where var has a static storage class.
We don't attempt to fold those.  And we don't attempt to 
fold further (POINTER_PLUS (ADDR_EXPR var) 1).  Yet, we still maintain
that those expressions are `constant'.  Consequently, we cannot just use
TREE_CONSTANT.  So I introduced a flag taken from one of the spare bits
in tree_common to mark non-_CST that should not be folded further.
I thought the flag solution is less disturbing to existing fold
machinery than introducing a separate tree code.  Also, the C front-end
c_fully_fold is inadequate.  The other thing I needed to maintain is
that of type preservation.  If we have an expression of type T, its
compile-time evaluation should also yield a value of type T.
In particular I consider CONST_DECL to be fully evaluated; I don't look
into their DECL_INITIAL (which might have different type).  On the other 
hand I do look into constexpr VAR_DECL's DECL_INITIAL.

Finally, as for the evaluation proper, I use very small environment that
consists in bindings function parameters to the values they receive in a
call.  I do not maintain a call stack, as I'm not sure we really need
one for diagnostic purposes.

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...

Best,

-- Gaby



gcc/ChangeLog
2009-11-26  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-26  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.
	(potential_constant_expression): Likewise.

=== gcc/tree.h
==================================================================
--- gcc/tree.h	(revision 154697)
+++ 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 154697)
+++ 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 154697)
+++ 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 154697)
+++ 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 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))
+
+
 /* 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 154697)
+++ 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 154697)
+++ 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 154697)
+++ gcc/cp/semantics.c	(patch const level 1)
@@ -5248,6 +5248,7 @@
   return 0;
 }
 
+
 /* Return true if T is a literal type.   */
 
 bool
@@ -5270,7 +5271,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",
@@ -5280,6 +5281,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
@@ -5290,45 +5342,1049 @@
 {
   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);
+      if (!same_type_p (TREE_TYPE (lhs_arg), TREE_TYPE (rhs_arg)))
+        return 0;
+      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;
+  for (b = call->bindings; b != NULL; b = TREE_CHAIN (b))
+    if (TREE_PURPOSE (b) == t)
+      return TREE_VALUE (b);
+  
+  gcc_unreachable();
+  return error_mark_node;
+}
+
+/* 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 && TREE_CODE (t) == AGGR_INIT_EXPR)
+        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 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 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 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:
+      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;
+        }
+      /* fall through.  */
+    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))
+          {
+            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)
+                && (TREE_CODE (t) != AGGR_INIT_EXPR
+                    || !AGGR_INIT_VIA_CTOR_P (t)))
+              {
+                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 154697)
+++ gcc/cp/parser.c	(patch const level 1)
@@ -15388,12 +15388,32 @@
 {
   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]