public inbox for gcc-patches@gcc.gnu.org
 help / color / mirror / Atom feed
* C++ PATCH for constexpr
@ 2009-11-27  1:42 Gabriel Dos Reis
  2009-11-29 10:35 ` Jason Merrill
  2009-11-29 16:24 ` C++ PATCH for constexpr Jason Merrill
  0 siblings, 2 replies; 34+ messages in thread
From: Gabriel Dos Reis @ 2009-11-27  1:42 UTC (permalink / raw)
  To: jason; +Cc: bkoz, gcc-patches


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)
 \f
 /* 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;
 }
 
+\f
 /* 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;
+    }
+}
+
+\f
 /* 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);

^ permalink raw reply	[flat|nested] 34+ messages in thread

* Re: C++ PATCH for constexpr
  2009-11-27  1:42 C++ PATCH for constexpr Gabriel Dos Reis
@ 2009-11-29 10:35 ` Jason Merrill
  2009-11-29 19:11   ` Gabriel Dos Reis
  2009-11-29 16:24 ` C++ PATCH for constexpr Jason Merrill
  1 sibling, 1 reply; 34+ messages in thread
From: Jason Merrill @ 2009-11-29 10:35 UTC (permalink / raw)
  To: Gabriel Dos Reis; +Cc: bkoz, gcc-patches

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.

> +/* 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.  What 
link-time or load-time constants do you mean to exclude?

Also, it seems that COMPILE_TIME_CONSTANT_P is only getting set on 
CONSTRUCTOR nodes (not ADDR_EXPR of TREE_STATIC decls); 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.

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

> +            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))

?

> +  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?

Jason

^ permalink raw reply	[flat|nested] 34+ messages in thread

* Re: C++ PATCH for constexpr
  2009-11-27  1:42 C++ PATCH for constexpr Gabriel Dos Reis
  2009-11-29 10:35 ` Jason Merrill
@ 2009-11-29 16:24 ` Jason Merrill
  2009-11-29 17:32   ` Gabriel Dos Reis
  1 sibling, 1 reply; 34+ messages in thread
From: Jason Merrill @ 2009-11-29 16:24 UTC (permalink / raw)
  To: Gabriel Dos Reis; +Cc: bkoz, gcc-patches

On 11/26/2009 08:39 PM, Gabriel Dos Reis wrote:
> +      if (!same_type_p (TREE_TYPE (lhs_arg), TREE_TYPE (rhs_arg)))
> +        return 0;

You were going to turn this into an assert?

> +      /* 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;

Here you're still assuming that all AGGR_INIT_EXPR are constructor 
calls.  Again, check DECL_CONSTRUCTOR_P (fun) instead.

> +constexpr_call_equal(const void *p, const void *q)
> +    cxx_eval_constant_expression(&new_call, new_call.fundef->body);
> +  return VEC_index(constructor_elt, CONSTRUCTOR_ELTS (ary),

Missing space before (.

> +    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))

The array-to-pointer conversion is expressed with ADDR_EXPR; see 
decay_conversion.

Jason

^ permalink raw reply	[flat|nested] 34+ messages in thread

* Re: C++ PATCH for constexpr
  2009-11-29 16:24 ` C++ PATCH for constexpr Jason Merrill
@ 2009-11-29 17:32   ` Gabriel Dos Reis
  0 siblings, 0 replies; 34+ messages in thread
From: Gabriel Dos Reis @ 2009-11-29 17:32 UTC (permalink / raw)
  To: Jason Merrill; +Cc: bkoz, gcc-patches

Jason Merrill <jason@redhat.com> writes:

| On 11/26/2009 08:39 PM, Gabriel Dos Reis wrote:
| > +      if (!same_type_p (TREE_TYPE (lhs_arg), TREE_TYPE (rhs_arg)))
| > +        return 0;
| 
| You were going to turn this into an assert?

Oops :-(

| 
| > +      /* 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;
| 
| Here you're still assuming that all AGGR_INIT_EXPR are constructor
| calls.  Again, check DECL_CONSTRUCTOR_P (fun) instead.

Thanks, fixed.

| > +constexpr_call_equal(const void *p, const void *q)
| > +    cxx_eval_constant_expression(&new_call, new_call.fundef->body);
| > +  return VEC_index(constructor_elt, CONSTRUCTOR_ELTS (ary),
| 
| Missing space before (.

Fixed.

| > +    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))
| 
| The array-to-pointer conversion is expressed with ADDR_EXPR; see
| decay_conversion.

OK, in that case the conversion will be handled by the ADDR_EXPR case which
subsumes this specific test then.

This goes back a question I had some time ago.  It is not clear to me
exactly which language constructs are mapped to these conversion nodes
(including NOP_EXPR).  I looked at the doc several times, but it does
not appear to me that there is a systematic semantics mapping in this
conversion part of the compiler.
Did I overlook something?

I'm regtesting a revised patch that includes your previous comments.

-- Gaby

^ permalink raw reply	[flat|nested] 34+ messages in thread

* Re: C++ PATCH for constexpr
  2009-11-29 10:35 ` Jason Merrill
@ 2009-11-29 19:11   ` Gabriel Dos Reis
  2009-11-30  6:37     ` Jason Merrill
  0 siblings, 1 reply; 34+ messages in thread
From: Gabriel Dos Reis @ 2009-11-29 19:11 UTC (permalink / raw)
  To: Jason Merrill; +Cc: bkoz, gcc-patches

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)
 \f
 /* 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;
 }
 
+\f
 /* 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;
+    }
+}
+
+\f
 /* 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);
 

^ permalink raw reply	[flat|nested] 34+ messages in thread

* Re: C++ PATCH for constexpr
  2009-11-29 19:11   ` Gabriel Dos Reis
@ 2009-11-30  6:37     ` Jason Merrill
  2009-11-30  8:18       ` Gabriel Dos Reis
  0 siblings, 1 reply; 34+ messages in thread
From: Jason Merrill @ 2009-11-30  6:37 UTC (permalink / raw)
  To: Gabriel Dos Reis; +Cc: bkoz, gcc-patches

On 11/29/2009 02:08 PM, Gabriel Dos Reis wrote:
> Jason Merrill<jason@redhat.com>  writes:

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

m isn't any sort of constant, it's just a statically initialized 
variable.  Anything else?

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

I'm dubious that this checking would even show up in a callgraph 
profile; I don't expect a literal class to have many members, so walking 
through the elements of a constructor shouldn't take significant time.

But feel free to use a TREE_LANG_FLAG for CONSTRUCTORs; I only object to 
claiming a flag for all expressions.

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

How would that be different from the function setting a flag?  We're 
getting the same value either way.

Jason

^ permalink raw reply	[flat|nested] 34+ messages in thread

* Re: C++ PATCH for constexpr
  2009-11-30  6:37     ` Jason Merrill
@ 2009-11-30  8:18       ` Gabriel Dos Reis
  2009-11-30 20:21         ` Jason Merrill
  0 siblings, 1 reply; 34+ messages in thread
From: Gabriel Dos Reis @ 2009-11-30  8:18 UTC (permalink / raw)
  To: Jason Merrill; +Cc: bkoz, gcc-patches

Jason Merrill <jason@redhat.com> writes:

| On 11/29/2009 02:08 PM, Gabriel Dos Reis wrote:
| > Jason Merrill<jason@redhat.com>  writes:
| 
| > | 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.
| 
| m isn't any sort of constant, it's just a statically initialized
| variable.  Anything else?

It surely isn't constant in the C++ front-end sense.  The issue is
whether a link-time optimization would decide it is constant -- which it
is.  I was just making that distinction.  I don't feel wedded to it.

| > | 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 chose 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.
| 
| I'm dubious that this checking would even show up in a callgraph
| profile; I don't expect a literal class to have many members, so
| walking through the elements of a constructor shouldn't take
| significant time.

A literal class can have base many classes, and arbitrary inheritance
depth. So, even though I would expect a literal class to have on average
2-3 members, the nesting structure can be non-trivial.

| 
| But feel free to use a TREE_LANG_FLAG for CONSTRUCTORs; I only object
| to claiming a flag for all expressions.

there are three classes of expressions that currently use the flag:
symbolic address references, symbolic pointers, and CONSTRUCTORs.
Are you suggesting each of those three should each a separate flag,
instead of using one from the spare bit?


| 
| > 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.
| 
| How would that be different from the function setting a flag?  We're
| getting the same value either way.

yes, but not by the same process.
there are two separate things involved in the approach: 
  (1) semantics checking that an expression is compile time constant
  (2) evaluation of an expression that passes (1).

The C++ front-end has control over (1), but has much less control over (2)

What else need change?
(I'm about to head for a hectic travel in about 48 hours, so anything
that can be done by then is good, otherwise, it would be after the 20th.)

-- Gaby

^ permalink raw reply	[flat|nested] 34+ messages in thread

* Re: C++ PATCH for constexpr
  2009-11-30  8:18       ` Gabriel Dos Reis
@ 2009-11-30 20:21         ` Jason Merrill
  2009-12-01  0:24           ` Gabriel Dos Reis
  2009-12-01  0:32           ` Gabriel Dos Reis
  0 siblings, 2 replies; 34+ messages in thread
From: Jason Merrill @ 2009-11-30 20:21 UTC (permalink / raw)
  To: Gabriel Dos Reis; +Cc: bkoz, gcc-patches

On 11/30/2009 03:03 AM, Gabriel Dos Reis wrote:
> Jason Merrill<jason@redhat.com>  writes:
>
> | On 11/29/2009 02:08 PM, Gabriel Dos Reis wrote:
> |>  Jason Merrill<jason@redhat.com>   writes:
> |
> |>  | 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.
> |
> | m isn't any sort of constant, it's just a statically initialized
> | variable.  Anything else?
>
> It surely isn't constant in the C++ front-end sense.  The issue is
> whether a link-time optimization would decide it is constant -- which it
> is.  I was just making that distinction.  I don't feel wedded to it.

But that distinction doesn't seem related to compile-time vs link-time; 
it's a distinction between language-level constants and 
optimization-level constants.  The same thing would apply if 'm' were a 
local variable in main(); it always has the value 16, but it isn't 
usable in a constant expression.

> | But feel free to use a TREE_LANG_FLAG for CONSTRUCTORs; I only object
> | to claiming a flag for all expressions.
>
> there are three classes of expressions that currently use the flag:
> symbolic address references, symbolic pointers, and CONSTRUCTORs.
> Are you suggesting each of those three should each a separate flag,
> instead of using one from the spare bit?

I was thinking that you would walk the tree to check the others.

 > +lookup_parameter_binding (const constexpr_call *call, tree t)
 > +{
 > +  tree b = purpose_member (t, call->bindings);
 > +  gcc_assert(b != NULL);
 > +  return b;
 > +}

Don't you still need TREE_VALUE?  Also, space before the ( in the assert 
line.

Jason

^ permalink raw reply	[flat|nested] 34+ messages in thread

* Re: C++ PATCH for constexpr
  2009-11-30 20:21         ` Jason Merrill
@ 2009-12-01  0:24           ` Gabriel Dos Reis
  2009-12-01  0:32           ` Gabriel Dos Reis
  1 sibling, 0 replies; 34+ messages in thread
From: Gabriel Dos Reis @ 2009-12-01  0:24 UTC (permalink / raw)
  To: Jason Merrill; +Cc: bkoz, gcc-patches

Jason Merrill <jason@redhat.com> writes:

| On 11/30/2009 03:03 AM, Gabriel Dos Reis wrote:
| > Jason Merrill<jason@redhat.com>  writes:
| >
| > | On 11/29/2009 02:08 PM, Gabriel Dos Reis wrote:
| > |>  Jason Merrill<jason@redhat.com>   writes:
| > |
| > |>  | 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.
| > |
| > | m isn't any sort of constant, it's just a statically initialized
| > | variable.  Anything else?
| >
| > It surely isn't constant in the C++ front-end sense.  The issue is
| > whether a link-time optimization would decide it is constant -- which it
| > is.  I was just making that distinction.  I don't feel wedded to it.
| 
| But that distinction doesn't seem related to compile-time vs
| link-time; it's a distinction between language-level constants and
| optimization-level constants.  The same thing would apply if 'm' were
| a local variable in main(); it always has the value 16, but it isn't
| usable in a constant expression.

OK.

| 
| > | But feel free to use a TREE_LANG_FLAG for CONSTRUCTORs; I only object
| > | to claiming a flag for all expressions.
| >
| > there are three classes of expressions that currently use the flag:
| > symbolic address references, symbolic pointers, and CONSTRUCTORs.
| > Are you suggesting each of those three should each a separate flag,
| > instead of using one from the spare bit?
| 
| I was thinking that you would walk the tree to check the others.
| 
| > +lookup_parameter_binding (const constexpr_call *call, tree t)
| > +{
| > +  tree b = purpose_member (t, call->bindings);
| > +  gcc_assert(b != NULL);
| > +  return b;
| > +}
| 
| Don't you still need TREE_VALUE?  Also, space before the ( in the
| assert line.
| 
| Jason

-- 
Dr. Gabriel Dos Reis (gdr@cs.tamu.edu), Assistant Professor
	      http://www.cs.tamu.edu/people/faculty/gdr
	  Department of Computer Science & Engineering; TAMU
	301, Bright Building -- College Station, TX 77843-3112

^ permalink raw reply	[flat|nested] 34+ messages in thread

* Re: C++ PATCH for constexpr
  2009-11-30 20:21         ` Jason Merrill
  2009-12-01  0:24           ` Gabriel Dos Reis
@ 2009-12-01  0:32           ` Gabriel Dos Reis
  2009-12-02 23:10             ` Jason Merrill
  1 sibling, 1 reply; 34+ messages in thread
From: Gabriel Dos Reis @ 2009-12-01  0:32 UTC (permalink / raw)
  To: Jason Merrill; +Cc: bkoz, gcc-patches

Jason Merrill <jason@redhat.com> writes:

| On 11/30/2009 03:03 AM, Gabriel Dos Reis wrote:
| > Jason Merrill<jason@redhat.com>  writes:
| >
| > | On 11/29/2009 02:08 PM, Gabriel Dos Reis wrote:
| > |>  Jason Merrill<jason@redhat.com>   writes:
| > |
| > |>  | 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.
| > |
| > | m isn't any sort of constant, it's just a statically initialized
| > | variable.  Anything else?
| >
| > It surely isn't constant in the C++ front-end sense.  The issue is
| > whether a link-time optimization would decide it is constant -- which it
| > is.  I was just making that distinction.  I don't feel wedded to it.
| 
| But that distinction doesn't seem related to compile-time vs
| link-time; it's a distinction between language-level constants and
| optimization-level constants.  The same thing would apply if 'm' were
| a local variable in main(); it always has the value 16, but it isn't
| usable in a constant expression.

OK, I see what you mean.

| > | But feel free to use a TREE_LANG_FLAG for CONSTRUCTORs; I only object
| > | to claiming a flag for all expressions.
| >
| > there are three classes of expressions that currently use the flag:
| > symbolic address references, symbolic pointers, and CONSTRUCTORs.
| > Are you suggesting each of those three should each a separate flag,
| > instead of using one from the spare bit?
| 
| I was thinking that you would walk the tree to check the others.

yeah, I'm (was) operating under the assumption that there is no point in
computing the same information repeatedly; but I can live with
traversing the tree all the time.

| > +lookup_parameter_binding (const constexpr_call *call, tree t)
| > +{
| > +  tree b = purpose_member (t, call->bindings);
| > +  gcc_assert(b != NULL);
| > +  return b;
| > +}
| 
| Don't you still need TREE_VALUE?  Also, space before the ( in the
| assert line.

Right on both accounts.

-- Gaby

^ permalink raw reply	[flat|nested] 34+ messages in thread

* Re: C++ PATCH for constexpr
  2009-12-01  0:32           ` Gabriel Dos Reis
@ 2009-12-02 23:10             ` Jason Merrill
  2009-12-02 23:11               ` Gabriel Dos Reis
  0 siblings, 1 reply; 34+ messages in thread
From: Jason Merrill @ 2009-12-02 23:10 UTC (permalink / raw)
  To: Gabriel Dos Reis; +Cc: bkoz, gcc-patches

The patch is also missing testcases.  I assume you have some?

I guess it's too late to catch you before you go off on your trip, so I 
suppose I'll finish it up myself...but if you have a moment to send me 
your testcases, that would help a lot.

Jason

^ permalink raw reply	[flat|nested] 34+ messages in thread

* Re: C++ PATCH for constexpr
  2009-12-02 23:10             ` Jason Merrill
@ 2009-12-02 23:11               ` Gabriel Dos Reis
  2009-12-04  1:31                 ` [C++] constexpr testsuite Benjamin Kosnik
                                   ` (2 more replies)
  0 siblings, 3 replies; 34+ messages in thread
From: Gabriel Dos Reis @ 2009-12-02 23:11 UTC (permalink / raw)
  To: Jason Merrill; +Cc: Gabriel Dos Reis, bkoz, gcc-patches

On Wed, Dec 2, 2009 at 5:05 PM, Jason Merrill <jason@redhat.com> wrote:
> The patch is also missing testcases.  I assume you have some?

Yes.

>
> I guess it's too late to catch you before you go off on your trip, so I
> suppose I'll finish it up myself...but if you have a moment to send me your
> testcases, that would help a lot.

I'll send you a revision of the patch plus the testcases, in the evening.
Then after that, I expect to have connections but not as comfortable
as I would like and I won't before the 20th.

-- Gaby

^ permalink raw reply	[flat|nested] 34+ messages in thread

* [C++] constexpr testsuite
  2009-12-02 23:11               ` Gabriel Dos Reis
@ 2009-12-04  1:31                 ` Benjamin Kosnik
  2009-12-13 19:56                   ` Gabriel Dos Reis
  2009-12-07 16:21                 ` C++ PATCH for constexpr Jason Merrill
  2010-01-06 16:17                 ` Jason Merrill
  2 siblings, 1 reply; 34+ messages in thread
From: Benjamin Kosnik @ 2009-12-04  1:31 UTC (permalink / raw)
  To: gdr; +Cc: dosreis, Jason Merrill, Gabriel Dos Reis, gcc-patches

[-- Attachment #1: Type: text/plain, Size: 768 bytes --]


> > The patch is also missing testcases.  I assume you have some?
> 
> Yes.

I thought I'd start in on this part, starting with the code examples in
N2235. Then I started to add things that looked like it might be legal,
illegal, or should warn.

In particular, I wanted to make sure that all template use
could stand up to specialization, instantiation, etc. At least at the
parsing phase.

Gaby, not trying to step on your toes here but thought instead that
you'd appreciate the extra hands. 

Results wise, I am using the latest Nov 29 patch, which passes
bootstrap and regression testing testing for me on x86_linux. These new
tests are not especially marked up for dg-error, because I ran into
other issues before this.

best,
benjamin


[-- Warning: decoded text below may be mangled, UTF-8 assumed --]
[-- Attachment #2: 20091203-1.patch --]
[-- Type: text/x-patch, Size: 10881 bytes --]

2009-12-03  Benjamin Kosnik  <bkoz@redhat.com>
	    Gabriel Dos Reis  <gdr@cs.tamu.edu>

	* constexpr-data1.C: New.
	* constexpr-data2.C: New.
	* constexpr-ex1.C: New.
	* constexpr-ex2.C: New.
	* constexpr-function1.C: New.
	* constexpr-function2.C: New.
	* constexpr-function3.C: New.
	* constexpr-object1.C: New.
	* constexpr-object2.C: New.

Index: g++.dg/cpp0x/constexpr-object1.C
===================================================================
--- g++.dg/cpp0x/constexpr-object1.C	(revision 0)
+++ g++.dg/cpp0x/constexpr-object1.C	(revision 0)
@@ -0,0 +1,31 @@
+// { dg-do "compile" }
+// { dg-options "-std=gnu++0x" }
+
+// From N2235
+
+// 4.5.2 semantics
+
+// p 1 constexpr specifier
+// objects, static const data
+struct A1 { };
+
+constexpr int i1 = 1024;
+constexpr A1 a1 = A1();
+
+// error: not a definition
+extern constexpr int i2; // { dg-error "invalid" }
+
+// error: missing initializer
+constexpr A1 a2; // { dg-error "missing initializer for constexpr" }
+
+// error: duplicate cv
+const constexpr A1 a3 = A1(); // { dg-error "both ‘const’ and ‘constexpr’ cannot" }
+
+volatile constexpr A1 a4 = A1(); // { dg-error "both ‘volatile’ and ‘constexpr’ cannot" }
+
+// error: on type declaration
+constexpr struct pixel // { dg-error "cannot be used for type declarations" }
+{
+  int x;
+  int y;
+};
Index: g++.dg/cpp0x/constexpr-data1.C
===================================================================
--- g++.dg/cpp0x/constexpr-data1.C	(revision 0)
+++ g++.dg/cpp0x/constexpr-data1.C	(revision 0)
@@ -0,0 +1,43 @@
+// { dg-do "compile" }
+// { dg-options "-std=gnu++0x" }
+
+// From N2235
+
+// 1
+struct A2
+{
+  static const int eights = 888;
+  static constexpr int nines = 999;
+};
+
+A2 a;
+
+// 2
+struct pixel
+{
+  int x, y;
+};
+constexpr pixel ur = { 1294, 1024 }; // OK
+
+// p4
+struct Length
+{
+   explicit constexpr Length(int i = 0) : val(i) { }
+private:
+   int val;
+};
+
+constexpr int abs(int x)
+{ return x < 0 ? -x : x; }    // OK
+
+Length l(abs(-97)); // OK
+
+// p6
+class debug_flag
+{
+public:
+   explicit debug_flag(bool);
+   constexpr bool is_on(); // error: debug_flag not literal type
+private:
+   bool flag;
+};
Index: g++.dg/cpp0x/constexpr-ex1.C
===================================================================
--- g++.dg/cpp0x/constexpr-ex1.C	(revision 0)
+++ g++.dg/cpp0x/constexpr-ex1.C	(revision 0)
@@ -0,0 +1,90 @@
+// { dg-do "compile" }
+// { dg-options "-std=gnu++0x" }
+
+// From N2235
+
+// 4.1 constant-expression functions
+// 1 examples
+
+
+
+
+
+// 2 defined before first use
+struct S {
+    constexpr int twice();
+    constexpr int t();
+private:
+    static constexpr int val;  // constexpr variable
+};
+constexpr int S::val = 7;
+constexpr int S::twice() { return val + val; }
+constexpr S s = { };
+int x1 = s.twice();     // ok
+int x2 = s.t();         // error: S::t() not defined
+constexpr int ff();     // ok
+constexpr int gg();     // ok
+int x3 = ff();          // error: ff() not defined
+constexpr int ff() { return 1; }        // too late
+constexpr int gg() { return 2; }
+int x4 = gg();  // ok
+
+
+// 4.2 const-expression data
+
+// 2
+// storage  not allocated untill address taken
+constexpr double x = 9484.748;
+const double* p = &x;          // the &x forces x into memory
+
+// 4.3 constant-expression constructors
+
+// 1
+struct complex {
+   constexpr complex(double r, double i) : re(r), im(i) { }
+   constexpr double real() { return re; }
+   constexpr double imag() { return im; }
+private:
+   double re;
+   double im;
+};
+constexpr complex I(0, 1);  // OK -- literal complex
+
+
+// 2 invoked with non-const args
+double x = 1.0;
+constexpr complex unit(x, 0); // error: x non-constant
+const complex one(x, 0);   // OK, ‘‘ordinary const’’ -- dynamic
+                           //   initialization
+constexpr double xx = I.real(); // OK
+complex z(2, 4);           // OK -- ordinary variable
+
+// 3
+constexpr complex v[] = {
+     complex(0, 0), complex(1, 1), complex(2, 2)
+};
+constexpr double x = v[2].real(); // OK
+
+// 4 
+  constexpr int i = 98;
+  const int p = (int) &i;           // ERROR
+
+// 4.3.2 copy-constructor
+constexpr complex operator+(complex z, complex w)
+{
+  return complex(z.real() + w.real(), z.imag() + w.imag()); // fine
+}
+constexpr complex I2 = I + I;                 // OK
+struct resource {
+  int id;
+  constexpr resource(int i) : id(i) { }       // fine
+  resource(const resource& r) : id(r.id)
+  {
+    cout << id << " copied" << endl;
+  }
+};
+constexpr resource f(resource d)
+{ return d; }                  // error: copy-constructor not trivial
+constexpr resource d = f(9);
+
+// 4.4 floating-point constant expressions
Index: g++.dg/cpp0x/constexpr-object2.C
===================================================================
--- g++.dg/cpp0x/constexpr-object2.C	(revision 0)
+++ g++.dg/cpp0x/constexpr-object2.C	(revision 0)
@@ -0,0 +1,14 @@
+// { dg-do "compile" }
+// { dg-options "-std=gnu++0x" }
+
+constexpr int verysquare(int x) { return x * x; }
+
+const double mass = 9.8;
+constexpr double energy = mass * verysquare(56.6); // OK
+
+float array[verysquare(9)];         // OK -- not C99 VLA
+
+extern const int medium;
+const int high = verysquare(medium); // OK -- dynamic initialization
+
+enum { Max = verysquare(7) };      // OK
Index: g++.dg/cpp0x/constexpr-data2.C
===================================================================
--- g++.dg/cpp0x/constexpr-data2.C	(revision 0)
+++ g++.dg/cpp0x/constexpr-data2.C	(revision 0)
@@ -0,0 +1,47 @@
+// { dg-do "compile" }
+// { dg-options "-std=gnu++0x" }
+
+template<typename _Tp, _Tp v>
+  struct A3
+  {
+    typedef _Tp value_type;
+    typedef A3<value_type,v> type;
+
+    static constexpr value_type value = v;
+
+    constexpr operator value_type() { return value; }
+  };
+
+// Partial specialization.
+template<typename _Tp, _Tp v>
+  struct A3<_Tp*, v>
+  {
+    typedef _Tp* value_type;
+    typedef A3<value_type,v> type;
+
+    static constexpr value_type value = v;
+
+    constexpr operator value_type() { return value; }
+  };
+
+// Explicit specialization.
+template<>
+  struct A3<unsigned short, 0>
+  {
+    typedef unsigned short value_type;
+    typedef A3<value_type, 0> type;
+
+    static constexpr value_type value = 0;
+
+    constexpr operator value_type() { return value; }
+  };
+
+// Explicitly instantiate.
+template struct A3<int, 415>;
+
+// Extern explicitly instantiate.
+extern template struct A3<int, 510>;
+
+// Use.
+A3<int, 1111> a31;
+A3<char, 9999> a32; // Truncate? Overflow?
Index: g++.dg/cpp0x/constexpr-ex2.C
===================================================================
--- g++.dg/cpp0x/constexpr-ex2.C	(revision 0)
+++ g++.dg/cpp0x/constexpr-ex2.C	(revision 0)
@@ -0,0 +1,35 @@
+// { dg-do "compile" }
+// { dg-options "-std=gnu++0x" }
+
+// From N2235
+
+// 4.5.3 constant expressions
+
+// p 4
+struct A {
+  constexpr A(int i) : val(i) { }
+  constexpr operator int() { return val; }
+  constexpr operator long() { return 43; }
+private:
+  int val;
+};
+
+template<int> struct X { };
+constexpr A a = 42;
+
+X<a> x;            // OK: unique conversion to int
+int ary[a];        // error: ambiguous conversion
+
+// p 5
+struct Z {
+  operator int() const { return 42; }
+  operator unsigned char() const { return 43; }
+};
+const Z z = { };
+const int n = z; // OK: n is initialized with 42
+const long m = z; // error: ambiguous conversion
+enum E { v1 = 2, v2 = 10 };
+E operator+(E, E);
+float array[v1 + v2];   // error: v1+v2 not constant
+
+
Index: g++.dg/cpp0x/constexpr-function1.C
===================================================================
--- g++.dg/cpp0x/constexpr-function1.C	(revision 0)
+++ g++.dg/cpp0x/constexpr-function1.C	(revision 0)
@@ -0,0 +1,10 @@
+// { dg-do "compile" }
+// { dg-options "-std=gnu++0x" }
+
+// From N2235
+
+constexpr int veryabs(int x) { return x < 0 ? -x : x; }
+
+constexpr long long_max() { return 2147483647; }
+
+constexpr int verysquare(int x) { return x * x; }
Index: g++.dg/cpp0x/constexpr-function2.C
===================================================================
--- g++.dg/cpp0x/constexpr-function2.C	(revision 0)
+++ g++.dg/cpp0x/constexpr-function2.C	(revision 0)
@@ -0,0 +1,51 @@
+// { dg-do "compile" }
+// { dg-options "-std=gnu++0x" }
+
+// From N2235
+
+// Mess with the builtin by redeclaring.
+constexpr int abs(int x) { return x < 0 ? -x : x; }
+
+extern "C"
+{
+  constexpr float
+  squaref(float x) { return x * x; }
+}
+
+// implicitly inline, already: warn?
+inline constexpr double
+squared(double x) { return x * x; }
+
+constexpr int squarei(int x) { return x * x; }
+extern const int side;
+constexpr int area = squarei(side); // error: squarei(side) is not a
+				    //   constant expression
+
+int next(constexpr int x) // error: argument
+{ return x + 1; }
+
+constexpr void f(int x)       // error: return type is void
+{ /* ... */ }
+
+constexpr int prev(int x)
+{ return --x; }               // error: use of decrement
+
+constexpr int g(int x, int n) // error: body not just ‘‘return expr’’
+{
+   int r = 1;
+   while (--n > 0) r *= x;
+   return r;
+}
+
+constexpr int
+bar(int x, int y) { return x + y + x * y; }
+
+int bar(int x, int y)      // error: redefinition of bar
+{ return x * 2 + 3 * y; }
+
+constexpr int twice(int x);
+enum { bufsz = twice(256) };    // error: twice() isn’t (yet) defined
+
+constexpr int fac(int x)
+{ return x > 2 ? x * fac(x - 1) : 1; } // error: fac() not defined
+					// before use
Index: g++.dg/cpp0x/constexpr-function3.C
===================================================================
--- g++.dg/cpp0x/constexpr-function3.C	(revision 0)
+++ g++.dg/cpp0x/constexpr-function3.C	(revision 0)
@@ -0,0 +1,30 @@
+// { dg-do "compile" }
+// { dg-options "-std=gnu++0x" }
+
+// From N2235
+
+// function template 1
+template<typename T>
+  constexpr int bytesize(T t)
+  { return sizeof (t); }        // OK
+
+char buf[bytesize(0)];          // OK -- not C99 VLA
+
+
+// function template 2
+template<typename _Tp>
+  constexpr _Tp
+  square(_Tp x) { return x; }
+
+// Explicit specialization
+template<>
+  constexpr unsigned long
+  square(unsigned long x) { return x * x; }
+
+// Explicit instantiation
+template int square(int);
+
+class A { };
+template A square(A);
+
+template constexpr long square(long); // { dg-error "specifier cannot be used in a function declaration that is not a definition" }

^ permalink raw reply	[flat|nested] 34+ messages in thread

* Re: C++ PATCH for constexpr
  2009-12-02 23:11               ` Gabriel Dos Reis
  2009-12-04  1:31                 ` [C++] constexpr testsuite Benjamin Kosnik
@ 2009-12-07 16:21                 ` Jason Merrill
  2010-01-06 16:17                 ` Jason Merrill
  2 siblings, 0 replies; 34+ messages in thread
From: Jason Merrill @ 2009-12-07 16:21 UTC (permalink / raw)
  To: gdr; +Cc: Gabriel Dos Reis, Gabriel Dos Reis, bkoz, gcc-patches

On 12/02/2009 06:10 PM, Gabriel Dos Reis wrote:
> I'll send you a revision of the patch plus the testcases, in the evening.

I never saw this.

Jason

^ permalink raw reply	[flat|nested] 34+ messages in thread

* Re: [C++] constexpr testsuite
  2009-12-04  1:31                 ` [C++] constexpr testsuite Benjamin Kosnik
@ 2009-12-13 19:56                   ` Gabriel Dos Reis
  2009-12-13 22:25                     ` Dave Korn
  2009-12-14  7:29                     ` Benjamin Kosnik
  0 siblings, 2 replies; 34+ messages in thread
From: Gabriel Dos Reis @ 2009-12-13 19:56 UTC (permalink / raw)
  To: Benjamin Kosnik; +Cc: dosreis, Jason Merrill, gcc-patches

Benjamin Kosnik <bkoz@redhat.com> writes:

| > > The patch is also missing testcases.  I assume you have some?
| > 
| > Yes.
| 
| I thought I'd start in on this part, starting with the code examples in
| N2235. Then I started to add things that looked like it might be legal,
| illegal, or should warn.
| 
| In particular, I wanted to make sure that all template use
| could stand up to specialization, instantiation, etc. At least at the
| parsing phase.
| 
| Gaby, not trying to step on your toes here but thought instead that
| you'd appreciate the extra hands. 
| 
| Results wise, I am using the latest Nov 29 patch, which passes
| bootstrap and regression testing testing for me on x86_linux. These new
| tests are not especially marked up for dg-error, because I ran into
| other issues before this.

Hi Benjamin,

  I very much appreciate your helping hand, and I suspect I owe you
a bottle of Pomerol.  I did not have time to update the patch as I
planned before leaving.  I hope to get that done today or tomorrow.
Though I'm having trouble connecting to gcc.gnu.org -- is here any issue
there? 
I'm currently in Japan and I know I cannot access some sites (such as
www.nytimes.com or www.mingw.org).  I have no clue whether this is just the
hotel trying to protect me or whether it is something more general.
I don't know whether gcc.gnu.org is supposed to be blocked too.  
If that is the case, then it is going to be more painful than I anticipated.

-- Gaby

^ permalink raw reply	[flat|nested] 34+ messages in thread

* Re: [C++] constexpr testsuite
  2009-12-13 19:56                   ` Gabriel Dos Reis
@ 2009-12-13 22:25                     ` Dave Korn
  2009-12-14 10:27                       ` Gabriel Dos Reis
  2009-12-14  7:29                     ` Benjamin Kosnik
  1 sibling, 1 reply; 34+ messages in thread
From: Dave Korn @ 2009-12-13 22:25 UTC (permalink / raw)
  To: Gabriel Dos Reis; +Cc: Benjamin Kosnik, dosreis, Jason Merrill, gcc-patches

Gabriel Dos Reis wrote:

> Though I'm having trouble connecting to gcc.gnu.org -- is here any issue
> there? 

  You must have forgotten about the planned outage this weekend :)  Server got
relocated.  The move is mostly complete now and the server is back up.

> I'm currently in Japan and I know I cannot access some sites (such as
> www.nytimes.com or www.mingw.org).  I have no clue whether this is just the
> hotel trying to protect me or whether it is something more general.
> I don't know whether gcc.gnu.org is supposed to be blocked too.  
> If that is the case, then it is going to be more painful than I anticipated.

  Last I checked there was some hiccup getting the new DNS set up.  If you're
still having problems, a workaround is 'echo "209.132.180.131 gcc.gnu.org" >>
/etc/hosts'.  If it's not DNS, try a proxy.

    cheers,
      DaveK

^ permalink raw reply	[flat|nested] 34+ messages in thread

* Re: [C++] constexpr testsuite
  2009-12-13 19:56                   ` Gabriel Dos Reis
  2009-12-13 22:25                     ` Dave Korn
@ 2009-12-14  7:29                     ` Benjamin Kosnik
  1 sibling, 0 replies; 34+ messages in thread
From: Benjamin Kosnik @ 2009-12-14  7:29 UTC (permalink / raw)
  To: Gabriel Dos Reis; +Cc: dosreis, Jason Merrill, gcc-patches


>   I very much appreciate your helping hand, and I suspect I owe you
> a bottle of Pomerol.  I did not have time to update the patch as I
> planned before leaving.  I hope to get that done today or tomorrow.

No worries. This is just a first effort, glad to be of any help.

> Though I'm having trouble connecting to gcc.gnu.org -- is here any
> issue there? 

It was a bit touch an go there early in the weekend but it looks to be
up and running now. Let me know if you are still having problems?

-benjamin

^ permalink raw reply	[flat|nested] 34+ messages in thread

* Re: [C++] constexpr testsuite
  2009-12-13 22:25                     ` Dave Korn
@ 2009-12-14 10:27                       ` Gabriel Dos Reis
  0 siblings, 0 replies; 34+ messages in thread
From: Gabriel Dos Reis @ 2009-12-14 10:27 UTC (permalink / raw)
  To: Dave Korn; +Cc: Gabriel Dos Reis, Benjamin Kosnik, Jason Merrill, gcc-patches

On Sun, Dec 13, 2009 at 3:22 PM, Dave Korn
<dave.korn.cygwin@googlemail.com> wrote:
> Gabriel Dos Reis wrote:
>
>> Though I'm having trouble connecting to gcc.gnu.org -- is here any issue
>> there?
>
>  You must have forgotten about the planned outage this weekend :)  Server got
> relocated.  The move is mostly complete now and the server is back up.

Thanks; I "forgot" it because I did not get to know about it.  Thanks!.

>
>> I'm currently in Japan and I know I cannot access some sites (such as
>> www.nytimes.com or www.mingw.org).  I have no clue whether this is just the
>> hotel trying to protect me or whether it is something more general.
>> I don't know whether gcc.gnu.org is supposed to be blocked too.
>> If that is the case, then it is going to be more painful than I anticipated.
>
>  Last I checked there was some hiccup getting the new DNS set up.  If you're
> still having problems, a workaround is 'echo "209.132.180.131 gcc.gnu.org" >>
> /etc/hosts'.  If it's not DNS, try a proxy.

Thanks!

-- Gaby

^ permalink raw reply	[flat|nested] 34+ messages in thread

* Re: C++ PATCH for constexpr
  2009-12-02 23:11               ` Gabriel Dos Reis
  2009-12-04  1:31                 ` [C++] constexpr testsuite Benjamin Kosnik
  2009-12-07 16:21                 ` C++ PATCH for constexpr Jason Merrill
@ 2010-01-06 16:17                 ` Jason Merrill
  2010-01-12  2:18                   ` Benjamin Kosnik
  2010-02-02 18:25                   ` Jason Merrill
  2 siblings, 2 replies; 34+ messages in thread
From: Jason Merrill @ 2010-01-06 16:17 UTC (permalink / raw)
  To: gdr; +Cc: Gabriel Dos Reis, Gabriel Dos Reis, bkoz, gcc-patches

On 12/02/2009 06:10 PM, Gabriel Dos Reis wrote:
> I'll send you a revision of the patch plus the testcases, in the evening.
> Then after that, I expect to have connections but not as comfortable
> as I would like and I won't before the 20th.

Any news on that revision?

Jason

^ permalink raw reply	[flat|nested] 34+ messages in thread

* Re: C++ PATCH for constexpr
  2010-01-06 16:17                 ` Jason Merrill
@ 2010-01-12  2:18                   ` Benjamin Kosnik
  2010-02-02 18:25                   ` Jason Merrill
  1 sibling, 0 replies; 34+ messages in thread
From: Benjamin Kosnik @ 2010-01-12  2:18 UTC (permalink / raw)
  To: Jason Merrill; +Cc: gdr, Gabriel Dos Reis, Gabriel Dos Reis, gcc-patches


> Any news on that revision?

I am also interested. Gaby, any chance we can get a status update?

best,
benjamin

^ permalink raw reply	[flat|nested] 34+ messages in thread

* Re: C++ PATCH for constexpr
  2010-01-06 16:17                 ` Jason Merrill
  2010-01-12  2:18                   ` Benjamin Kosnik
@ 2010-02-02 18:25                   ` Jason Merrill
  2010-02-02 18:29                     ` Gabriel Dos Reis
  1 sibling, 1 reply; 34+ messages in thread
From: Jason Merrill @ 2010-02-02 18:25 UTC (permalink / raw)
  To: gdr; +Cc: Gabriel Dos Reis, Gabriel Dos Reis, bkoz, gcc-patches

On 01/06/2010 11:17 AM, Jason Merrill wrote:
> On 12/02/2009 06:10 PM, Gabriel Dos Reis wrote:
>> I'll send you a revision of the patch plus the testcases, in the evening.
>> Then after that, I expect to have connections but not as comfortable
>> as I would like and I won't before the 20th.
>
> Any news on that revision?

Ping?

Jason

^ permalink raw reply	[flat|nested] 34+ messages in thread

* Re: C++ PATCH for constexpr
  2010-02-02 18:25                   ` Jason Merrill
@ 2010-02-02 18:29                     ` Gabriel Dos Reis
  2010-02-02 18:33                       ` Paolo Carlini
  2010-02-02 18:56                       ` Jason Merrill
  0 siblings, 2 replies; 34+ messages in thread
From: Gabriel Dos Reis @ 2010-02-02 18:29 UTC (permalink / raw)
  To: Jason Merrill; +Cc: Gabriel Dos Reis, bkoz, gcc-patches

Jason Merrill <jason@redhat.com> writes:

| On 01/06/2010 11:17 AM, Jason Merrill wrote:
| > On 12/02/2009 06:10 PM, Gabriel Dos Reis wrote:
| >> I'll send you a revision of the patch plus the testcases, in the evening.
| >> Then after that, I expect to have connections but not as comfortable
| >> as I would like and I won't before the 20th.
| >
| > Any news on that revision?
| 
| Ping?

Yup, I'll get back to you tomorrow.  I hope things are still OK for gcc-3.5.0.

Thanks!

-- Gaby

^ permalink raw reply	[flat|nested] 34+ messages in thread

* Re: C++ PATCH for constexpr
  2010-02-02 18:29                     ` Gabriel Dos Reis
@ 2010-02-02 18:33                       ` Paolo Carlini
  2010-02-02 18:37                         ` Gabriel Dos Reis
  2010-02-03  3:48                         ` Dave Korn
  2010-02-02 18:56                       ` Jason Merrill
  1 sibling, 2 replies; 34+ messages in thread
From: Paolo Carlini @ 2010-02-02 18:33 UTC (permalink / raw)
  To: Gabriel Dos Reis; +Cc: Jason Merrill, Gabriel Dos Reis, bkoz, gcc-patches

On 02/02/2010 07:29 PM, Gabriel Dos Reis wrote:
> Yup, I'll get back to you tomorrow.  I hope things are still OK for gcc-3.5.0.
>   
Indeed, but make sure to provide also a time machine ;)

Paolo.

^ permalink raw reply	[flat|nested] 34+ messages in thread

* Re: C++ PATCH for constexpr
  2010-02-02 18:33                       ` Paolo Carlini
@ 2010-02-02 18:37                         ` Gabriel Dos Reis
  2010-02-03  3:48                         ` Dave Korn
  1 sibling, 0 replies; 34+ messages in thread
From: Gabriel Dos Reis @ 2010-02-02 18:37 UTC (permalink / raw)
  To: Paolo Carlini; +Cc: Jason Merrill, Gabriel Dos Reis, bkoz, gcc-patches

Paolo Carlini <paolo.carlini@oracle.com> writes:

| On 02/02/2010 07:29 PM, Gabriel Dos Reis wrote:
| > Yup, I'll get back to you tomorrow.  I hope things are still OK for gcc-3.5.0.
| >   
| Indeed, but make sure to provide also a time machine ;)

as you probably guessed, I'm behind lot of things (including emails, I
don't how LWG manages to produce over 2K messages in such a short
time) and I'm sure I can find a use for a time travel machine :-)

-- Gaby

^ permalink raw reply	[flat|nested] 34+ messages in thread

* Re: C++ PATCH for constexpr
  2010-02-02 18:29                     ` Gabriel Dos Reis
  2010-02-02 18:33                       ` Paolo Carlini
@ 2010-02-02 18:56                       ` Jason Merrill
  2010-02-02 19:24                         ` Gabriel Dos Reis
  1 sibling, 1 reply; 34+ messages in thread
From: Jason Merrill @ 2010-02-02 18:56 UTC (permalink / raw)
  To: Gabriel Dos Reis; +Cc: Gabriel Dos Reis, bkoz, gcc-patches

On 02/02/2010 01:29 PM, Gabriel Dos Reis wrote:
> Yup, I'll get back to you tomorrow.  I hope things are still OK for gcc-3.5.0.

Sorry, that window closed a couple of months ago.  I'd still like to 
finalize it ASAP so that we have something for the Pittsburgh meeting, 
particularly for nailing down the const ref semantics.

Jason

^ permalink raw reply	[flat|nested] 34+ messages in thread

* Re: C++ PATCH for constexpr
  2010-02-02 18:56                       ` Jason Merrill
@ 2010-02-02 19:24                         ` Gabriel Dos Reis
  2010-05-07  2:14                           ` git repository for constexpr (was Re: C++ PATCH for constexpr) Jason Merrill
  0 siblings, 1 reply; 34+ messages in thread
From: Gabriel Dos Reis @ 2010-02-02 19:24 UTC (permalink / raw)
  To: Jason Merrill; +Cc: Gabriel Dos Reis, bkoz, gcc-patches

Jason Merrill <jason@redhat.com> writes:

| On 02/02/2010 01:29 PM, Gabriel Dos Reis wrote:
| > Yup, I'll get back to you tomorrow.  I hope things are still OK for gcc-3.5.0.
| 
| Sorry, that window closed a couple of months ago.  I'd still like to

OK.

| finalize it ASAP so that we have something for the Pittsburgh meeting,
| particularly for nailing down the const ref semantics.

That makes sense.

-- Gaby

^ permalink raw reply	[flat|nested] 34+ messages in thread

* Re: C++ PATCH for constexpr
  2010-02-02 18:33                       ` Paolo Carlini
  2010-02-02 18:37                         ` Gabriel Dos Reis
@ 2010-02-03  3:48                         ` Dave Korn
  1 sibling, 0 replies; 34+ messages in thread
From: Dave Korn @ 2010-02-03  3:48 UTC (permalink / raw)
  To: Paolo Carlini
  Cc: Gabriel Dos Reis, Jason Merrill, Gabriel Dos Reis, bkoz, gcc-patches

On 02/02/2010 18:31, Paolo Carlini wrote:
> On 02/02/2010 07:29 PM, Gabriel Dos Reis wrote:
>> Yup, I'll get back to you tomorrow.  I hope things are still OK for
>> gcc-3.5.0.
>> 
> Indeed, but make sure to provide also a time machine ;)
> 
> Paolo.

  Well, I got it, anyway :)

    cheers,
      DaveK

^ permalink raw reply	[flat|nested] 34+ messages in thread

* git repository for constexpr (was Re: C++ PATCH for constexpr)
  2010-02-02 19:24                         ` Gabriel Dos Reis
@ 2010-05-07  2:14                           ` Jason Merrill
  2010-05-12 13:42                             ` git repository for constexpr Gabriel Dos Reis
  2010-07-14 17:36                             ` git repository for constexpr (was Re: C++ PATCH for constexpr) Jason Merrill
  0 siblings, 2 replies; 34+ messages in thread
From: Jason Merrill @ 2010-05-07  2:14 UTC (permalink / raw)
  To: Gabriel Dos Reis; +Cc: Gabriel Dos Reis, bkoz, gcc-patches

I've set up a git repository for constexpr work: the web interface is at

   http://repo.or.cz/w/official-gcc/constexpr.git

There are currently two branches there: master and jason.  The former 
contains a revision history based on the various patches you sent me, 
rebased onto recent trunk.  I figure that will track any reasonably 
complete changes.

jason is currently equivalent, but is intended to track my local 
constexpr working tree and might have changes that break things.

Starting from a git working tree as described in
  http://gcc.gnu.org/wiki/GitMirror
you can set up to use the constexpr repository as follows:

# git remote add cx git://repo.or.cz/official-gcc/constexpr.git
# git remote set-url --push cx 
ssh://repo.or.cz/srv/git/official-gcc/constexpr.git
# git config remote.cx.push constexpr:$MYNAME
# git checkout -b constexpr cx/master

Of course, to push you'll need to create a repo.or.cz account and add 
yourself to the list of users.

To update from changes in the master branch, just 'git pull'.  To bring 
in changes from my branch as well, use 'git pull cx jason'.  To publish 
your changes to the $MYNAME branch, use 'git push'.  To update the 
master branch, use 'git push cx HEAD:master' (or some other refspec 
instead of HEAD).

Does this seem useful?  Do you have any local changes since the last 
patch you sent me?

Jason

^ permalink raw reply	[flat|nested] 34+ messages in thread

* Re: git repository for constexpr
  2010-05-07  2:14                           ` git repository for constexpr (was Re: C++ PATCH for constexpr) Jason Merrill
@ 2010-05-12 13:42                             ` Gabriel Dos Reis
  2010-05-12 15:27                               ` Jason Merrill
  2010-07-14 17:36                             ` git repository for constexpr (was Re: C++ PATCH for constexpr) Jason Merrill
  1 sibling, 1 reply; 34+ messages in thread
From: Gabriel Dos Reis @ 2010-05-12 13:42 UTC (permalink / raw)
  To: Jason Merrill; +Cc: Gabriel Dos Reis, bkoz, gcc-patches

Jason Merrill <jason@redhat.com> writes:

| I've set up a git repository for constexpr work: the web interface is at
| 
|   http://repo.or.cz/w/official-gcc/constexpr.git
| 
| There are currently two branches there: master and jason.  The former
| contains a revision history based on the various patches you sent me,
| rebased onto recent trunk.  I figure that will track any reasonably
| complete changes.

Thanks for setting the repo to track this.

| jason is currently equivalent, but is intended to track my local
| constexpr working tree and might have changes that break things.
| 
| Starting from a git working tree as described in
|  http://gcc.gnu.org/wiki/GitMirror
| you can set up to use the constexpr repository as follows:
| 
| # git remote add cx git://repo.or.cz/official-gcc/constexpr.git
| # git remote set-url --push cx
| ssh://repo.or.cz/srv/git/official-gcc/constexpr.git
| # git config remote.cx.push constexpr:$MYNAME
| # git checkout -b constexpr cx/master
| 
| Of course, to push you'll need to create a repo.or.cz account and add
| yourself to the list of users.

OK.

| 
| To update from changes in the master branch, just 'git pull'.  To
| bring in changes from my branch as well, use 'git pull cx jason'.  To
| publish your changes to the $MYNAME branch, use 'git push'.  To update
| the master branch, use 'git push cx HEAD:master' (or some other
| refspec instead of HEAD).
| 
| Does this seem useful?

Yes, it does.  Many thanks.

| Do you have any local changes since the last patch you sent me?

Yes, I'll send them to the list as well as pushing into the repo.
Does that sound right, or is that unnecessary noise -- as a general
question about how we handle changes to the repo?

Again, thanks!

-- Gaby

^ permalink raw reply	[flat|nested] 34+ messages in thread

* Re: git repository for constexpr
  2010-05-12 13:42                             ` git repository for constexpr Gabriel Dos Reis
@ 2010-05-12 15:27                               ` Jason Merrill
  2010-06-02 20:30                                 ` Jason Merrill
  0 siblings, 1 reply; 34+ messages in thread
From: Jason Merrill @ 2010-05-12 15:27 UTC (permalink / raw)
  To: Gabriel Dos Reis; +Cc: Gabriel Dos Reis, bkoz, gcc-patches

On 05/12/2010 09:40 AM, Gabriel Dos Reis wrote:
> Jason Merrill<jason@redhat.com>  writes:
>

> | # git remote add cx git://repo.or.cz/official-gcc/constexpr.git
> | # git remote set-url --push cx
> | ssh://repo.or.cz/srv/git/official-gcc/constexpr.git
> | # git config remote.cx.push constexpr:$MYNAME

Forgot:

# git fetch cx

> | # git checkout -b constexpr cx/master

> | Do you have any local changes since the last patch you sent me?
>
> Yes, I'll send them to the list as well as pushing into the repo.
> Does that sound right, or is that unnecessary noise -- as a general
> question about how we handle changes to the repo?

I'd say push and just send mail with some information about the push, no 
need to send the patch itself.  When I look at the changes in git, 
they're color-coded for me.  :)

Jason

^ permalink raw reply	[flat|nested] 34+ messages in thread

* Re: git repository for constexpr
  2010-05-12 15:27                               ` Jason Merrill
@ 2010-06-02 20:30                                 ` Jason Merrill
  0 siblings, 0 replies; 34+ messages in thread
From: Jason Merrill @ 2010-06-02 20:30 UTC (permalink / raw)
  To: Gabriel Dos Reis; +Cc: Gabriel Dos Reis, bkoz, gcc-patches

On 05/12/2010 11:27 AM, Jason Merrill wrote:
> On 05/12/2010 09:40 AM, Gabriel Dos Reis wrote:
>> | Do you have any local changes since the last patch you sent me?
>>
>> Yes, I'll send them to the list as well as pushing into the repo.
>> Does that sound right, or is that unnecessary noise -- as a general
>> question about how we handle changes to the repo?
>
> I'd say push and just send mail with some information about the push, no
> need to send the patch itself. When I look at the changes in git,
> they're color-coded for me. :)

Ping.  If you'd rather just send the patch to me that's fine too; I'd 
like to start working on this, but don't want to duplicate effort.

Jason

^ permalink raw reply	[flat|nested] 34+ messages in thread

* Re: git repository for constexpr (was Re: C++ PATCH for constexpr)
  2010-05-07  2:14                           ` git repository for constexpr (was Re: C++ PATCH for constexpr) Jason Merrill
  2010-05-12 13:42                             ` git repository for constexpr Gabriel Dos Reis
@ 2010-07-14 17:36                             ` Jason Merrill
  2010-07-15  1:02                               ` constexpr for zurich! let's make it happen Benjamin Kosnik
  2010-07-16 14:03                               ` git repository for constexpr (was Re: C++ PATCH for constexpr) Jason Merrill
  1 sibling, 2 replies; 34+ messages in thread
From: Jason Merrill @ 2010-07-14 17:36 UTC (permalink / raw)
  To: Gabriel Dos Reis; +Cc: Gabriel Dos Reis, bkoz, gcc-patches

On 05/06/2010 10:14 PM, Jason Merrill wrote:
> I've set up a git repository for constexpr work: the web interface is at
>
> http://repo.or.cz/w/official-gcc/constexpr.git

It occurred to me that it wasn't really necessary to use a third-party 
site; I have now added a "constexpr" branch to the official git mirror 
(http://gcc.gnu.org/wiki/GitMirror).

Jason

^ permalink raw reply	[flat|nested] 34+ messages in thread

* constexpr for zurich! let's make it happen
  2010-07-14 17:36                             ` git repository for constexpr (was Re: C++ PATCH for constexpr) Jason Merrill
@ 2010-07-15  1:02                               ` Benjamin Kosnik
  2010-07-16 14:03                               ` git repository for constexpr (was Re: C++ PATCH for constexpr) Jason Merrill
  1 sibling, 0 replies; 34+ messages in thread
From: Benjamin Kosnik @ 2010-07-15  1:02 UTC (permalink / raw)
  To: Jason Merrill; +Cc: Gabriel Dos Reis, Gabriel Dos Reis, gcc-patches

 
> It occurred to me that it wasn't really necessary to use a
> third-party site; I have now added a "constexpr" branch to the
> official git mirror (http://gcc.gnu.org/wiki/GitMirror).

awesome. I tried the other this week but no joy, will try the official
mirror today.

-benjamin

^ permalink raw reply	[flat|nested] 34+ messages in thread

* Re: git repository for constexpr (was Re: C++ PATCH for constexpr)
  2010-07-14 17:36                             ` git repository for constexpr (was Re: C++ PATCH for constexpr) Jason Merrill
  2010-07-15  1:02                               ` constexpr for zurich! let's make it happen Benjamin Kosnik
@ 2010-07-16 14:03                               ` Jason Merrill
  1 sibling, 0 replies; 34+ messages in thread
From: Jason Merrill @ 2010-07-16 14:03 UTC (permalink / raw)
  To: Gabriel Dos Reis; +Cc: Gabriel Dos Reis, bkoz, gcc-patches

[-- Attachment #1: Type: text/plain, Size: 553 bytes --]

On 07/14/2010 01:36 PM, Jason Merrill wrote:
> On 05/06/2010 10:14 PM, Jason Merrill wrote:
>> I've set up a git repository for constexpr work: the web interface is at
>>
>> http://repo.or.cz/w/official-gcc/constexpr.git
>
> It occurred to me that it wasn't really necessary to use a third-party
> site; I have now added a "constexpr" branch to the official git mirror
> (http://gcc.gnu.org/wiki/GitMirror).

I've now updated this branch to current trunk, with no regressions.  I 
needed to apply this patch to avoid some regressions on initlist tests.

[-- Attachment #2: constexpr-initlist.patch --]
[-- Type: text/x-patch, Size: 1603 bytes --]

commit af4de5b1df1cb3ffb8148fcb7b8f0258ee5e717f
Author: Jason Merrill <jason@redhat.com>
Date:   Fri Jul 16 00:47:54 2010 -0400

    fix initlist tests

diff --git a/gcc/cp/semantics.c b/gcc/cp/semantics.c
index 5d64075..c6140dc 100644
--- a/gcc/cp/semantics.c
+++ b/gcc/cp/semantics.c
@@ -5930,7 +5930,9 @@ implicit_dereference_p (tree t)
 static bool
 implicit_address_p (tree t)
 {
-  if (TREE_CODE (t) == NOP_EXPR)
+  if (TREE_CODE (t) != NOP_EXPR
+      || TREE_CODE (TREE_TYPE (t)) != REFERENCE_TYPE)
+    return false;
     switch (TREE_CODE (TREE_OPERAND (t, 0)))
       {
       case ADDR_EXPR:
@@ -5947,7 +5949,6 @@ implicit_address_p (tree t)
       default:
         return false;
       }
-  return false;
 }
 
 
@@ -5984,7 +5985,8 @@ cxx_eval_constant_expression (const constexpr_call *call, tree t)
       return cxx_eval_constant_expression (call, TREE_OPERAND (t, 0));
 
     case ADDR_EXPR:
-      if (TREE_STATIC (TREE_OPERAND (t, 0)))
+      if (TREE_STATIC (TREE_OPERAND (t, 0))
+	  || DECL_EXTERNAL (TREE_OPERAND (t, 0)))
         return t;
       error ("address of object %qE with non-static storage is "
              " not a constant expression", t);
@@ -6097,10 +6099,9 @@ cxx_eval_constant_expression (const constexpr_call *call, tree t)
               }
             return cxx_eval_constant_expression (call, t);
           }
-        t =  cp_convert
+        return cp_convert
           (TREE_TYPE (t),
            cxx_eval_constant_expression (call, TREE_OPERAND (t, 0)));
-        return cxx_eval_constant_expression (call, t);
       }
       
     case CONVERT_EXPR:

^ permalink raw reply	[flat|nested] 34+ messages in thread

end of thread, other threads:[~2010-07-16 14:03 UTC | newest]

Thread overview: 34+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2009-11-27  1:42 C++ PATCH for constexpr Gabriel Dos Reis
2009-11-29 10:35 ` Jason Merrill
2009-11-29 19:11   ` Gabriel Dos Reis
2009-11-30  6:37     ` Jason Merrill
2009-11-30  8:18       ` Gabriel Dos Reis
2009-11-30 20:21         ` Jason Merrill
2009-12-01  0:24           ` Gabriel Dos Reis
2009-12-01  0:32           ` Gabriel Dos Reis
2009-12-02 23:10             ` Jason Merrill
2009-12-02 23:11               ` Gabriel Dos Reis
2009-12-04  1:31                 ` [C++] constexpr testsuite Benjamin Kosnik
2009-12-13 19:56                   ` Gabriel Dos Reis
2009-12-13 22:25                     ` Dave Korn
2009-12-14 10:27                       ` Gabriel Dos Reis
2009-12-14  7:29                     ` Benjamin Kosnik
2009-12-07 16:21                 ` C++ PATCH for constexpr Jason Merrill
2010-01-06 16:17                 ` Jason Merrill
2010-01-12  2:18                   ` Benjamin Kosnik
2010-02-02 18:25                   ` Jason Merrill
2010-02-02 18:29                     ` Gabriel Dos Reis
2010-02-02 18:33                       ` Paolo Carlini
2010-02-02 18:37                         ` Gabriel Dos Reis
2010-02-03  3:48                         ` Dave Korn
2010-02-02 18:56                       ` Jason Merrill
2010-02-02 19:24                         ` Gabriel Dos Reis
2010-05-07  2:14                           ` git repository for constexpr (was Re: C++ PATCH for constexpr) Jason Merrill
2010-05-12 13:42                             ` git repository for constexpr Gabriel Dos Reis
2010-05-12 15:27                               ` Jason Merrill
2010-06-02 20:30                                 ` Jason Merrill
2010-07-14 17:36                             ` git repository for constexpr (was Re: C++ PATCH for constexpr) Jason Merrill
2010-07-15  1:02                               ` constexpr for zurich! let's make it happen Benjamin Kosnik
2010-07-16 14:03                               ` git repository for constexpr (was Re: C++ PATCH for constexpr) Jason Merrill
2009-11-29 16:24 ` C++ PATCH for constexpr Jason Merrill
2009-11-29 17:32   ` Gabriel Dos Reis

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for read-only IMAP folder(s) and NNTP newsgroup(s).