c-common.c (builtin_define_float_constants): Define __<TYPE>_HAS_INFINITY__ and __<TYPE>_HAS_QUIET_NAN__.

* c-common.c (builtin_define_float_constants): Define
	__<TYPE>_HAS_INFINITY__ and __<TYPE>_HAS_QUIET_NAN__.

	* call.c (build_field_call): Use build_new_op, not build_opfncall.
	(prep_operand): New function.
	(build_new_op): Use it.  Remove dead code.
	* class.c (pushclass): Change "modify" parameter type from int to
	bool.
	(currently_open_class): Use same_type_p, not pointer equality.
	(push_nested_class): Adjust calls to pushclass, remove modify
	parameter.
	* cp-tree.h (INTEGRAL_OR_ENUMERATION_TYPE_P): New macro.
	(pushclass): Change prototype.
	(push_nested_class): Likewise.
	(grokoptypename): Remove.
	(build_opfncall): Remove.
	(value_dependent_expression_p): Declare.
	(resolve_typename_type): Likewise.
	(resolve_typename_type_in_current_instantiation): Likewise.
	(enter_scope_of): Remove.
	(tsubst): Remove.
	(tsubst_expr): Likewise.
	(tsubst_copy): Likewise.
	(tsubst_copy_and_build): Likewise.
	* decl.c (warn_about_implicit_typename_lookup): Remove.
	(finish_case_label): Return error_mark_node for erroneous labels.
	(start_decl): Adjust calls to push_nested_class.
	(grokfndecl): Call push_scope/pop_scope around call to
	duplicate_decls.
	(grokdeclarator): Do not call tsubst.
	(start_function): Adjust calls to push_nested_class.
	* decl2.c (grok_array_decl): Use build_new_op, not build_opfncall.
	(check_classfn): Use push_scope/pop_scope around type comparisions.
	(grokoptypename): Remove.
	(push_sscope): Adjust call to push_nested_class.
	* error.c (dump_type): Show cv-qualification of typename types.
	* init.c (build_member_call): Use build_new_op, not
	build_opfncall.
	* method.c (build_opfncall): Remove.
	* parser.c (cp_parser): Add allow_non_constant_expression_p and
	non_constant_expression_p.
	(cp_parser_constant_expression): Adjust prototype.
	(cp_parser_resolve_typename_type): Remove.
	(cp_parser_non_constant_expression): New function.
	(cp_parser_non_constant_id_expression): Likewise.
	(cp_parser_new): Set allow_non_constant_expression_p and
	non_constant_expression_p.
	(cp_parser_primary_expression): Reject `this' and `va_arg' in
	constant-expressions.  Note that dependent names aren't really
	constant.
	(cp_parser_postfix_expression): Reject conversions to non-integral
	types in constant-expressions.  Neither are increments or
	decrements.
	(cp_parser_unary_expression): Reject increments and decrements in
	constant-expressions.
	(cp_parser_direct_new_declarator): Adjust call to
	cp_parser_constant_expression.
	(cp_parser_cast_expression): Reject conversions to non-integral
	types in constant-expressions.
	(cp_parser_assignment_expression): Rejects assignments in
	constant-expressions.
	(cp_parser_expression): Reject commas in constant-expressions.
	(cp_parser_labeled_statement): Adjust call to
	cp_parser_constant_expression.
	(cp_parser_direct_declarator): Simplify array bounds, even in
	templates, when they are non-dependent.  Use
	resolve_typename_type, not cp_parser_resolve_typename_type.
	(cp_parser_class_head): Use resolve_typename_type, not
	cp_parser_resolve_typename_type.
	(cp_parser_member_declaration): Adjust call to
	cp_parser_constant_expression.
	(cp_parser_constant_initializer): Likewise.
	(cp_parser_constructor_declarator): Use resolve_typename_type, not
	cp_parser_resolve_typename_type.
	(cp_parser_late_parsing_default_args): Adjust call to
	push_nested_class.
	* pt.c (tsubst): Give it internal linkage.
	(tsubst_expr): Likewise.
	(tsubst_copy): Likewise.
	(tsubst_copy_and_build): Likewise.
	(push_access_scope_real): Likewise.
	(tsubst_friend_class): Likewise.
	(instantiate_class_template): Adjust call to pushclass.
	(value_dependent_expression_p): Give it external linkage.
	Robustify.
	(resolve_typename_type): New function.
	* semantics.c (finish_call_expr): Use build_new_op, not
	build_opfncall.
	(begin_constructor_declarator): Remove.
	(begin_class_definition): Adjust call to pushclass.
	(enter_scope_of): Remove.
	* typeck.c (comptypes): Resolve typename types as appropriate.
	(build_x_indirect_ref): Use build_new_op, not build_opfncall.
	(build_x_compound_expr): Likewise.
	(build_modify_expr): Likewise.
	(build_x_modify_expr): Likewise.
	* typeck2.c (build_x_arrow): Likewise.

	* g++.dg/parser/constant1.C: New test.

	* include/std/std_limits.h (numeric_limits<float>::has_infinity):
	Use __FLT_HAS_INIFINITY__ to initialize.
	(numeric_limits<float>::has_quiet_NaN): Likewise.
	(numeric_limits<double>::has_infinity): Use __DBL_HAS_INIFINITY__
	to initialize.
	(numeric_limits<double>::has_quiet_NaN): Likewise.
	(numeric_limits<long double>::has_infinity): Use
	__LDBL_HAS_INIFINITY__ to initialize.
	(numeric_limits<long_double>::has_quiet_NaN): Likewise.

From-SVN: r62130
This commit is contained in:
Mark Mitchell 2003-01-30 07:24:02 +00:00 committed by Mark Mitchell
parent 825db093df
commit 14d22dd667
20 changed files with 795 additions and 359 deletions

View file

@ -1,3 +1,8 @@
2003-01-29 Mark Mitchell <mark@codesourcery.com>
* c-common.c (builtin_define_float_constants): Define
__<TYPE>_HAS_INFINITY__ and __<TYPE>_HAS_QUIET_NAN__.
2003-01-30 Kazu Hirata <kazu@cs.umass.edu>
* config/sh/lib1funcs.asm: Fix comment typos.

View file

@ -4896,6 +4896,18 @@ builtin_define_float_constants (name_prefix, fp_suffix, type)
sprintf (buf, "0.0%s", fp_suffix);
builtin_define_with_value (name, buf, 0);
}
/* For C++ std::numeric_limits<T>::has_infinity. */
sprintf (name, "__%s_HAS_INFINITY__", name_prefix);
builtin_define_with_int_value (name,
MODE_HAS_INFINITIES (TYPE_MODE (type)));
/* For C++ std::numeric_limits<T>::has_quiet_NaN. We do not have a
predicate to distinguish a target that has both quiet and
signalling NaNs from a target that has only quiet NaNs or only
signalling NaNs, so we assume that a target that has any kind of
NaN has quiet NaNs. */
sprintf (name, "__%s_HAS_QUIET_NAN__", name_prefix);
builtin_define_with_int_value (name, MODE_HAS_NANS (TYPE_MODE (type)));
}
/* Hook that registers front end and target-specific built-ins. */

View file

@ -1,3 +1,100 @@
2003-01-29 Mark Mitchell <mark@codesourcery.com>
* call.c (build_field_call): Use build_new_op, not build_opfncall.
(prep_operand): New function.
(build_new_op): Use it. Remove dead code.
* class.c (pushclass): Change "modify" parameter type from int to
bool.
(currently_open_class): Use same_type_p, not pointer equality.
(push_nested_class): Adjust calls to pushclass, remove modify
parameter.
* cp-tree.h (INTEGRAL_OR_ENUMERATION_TYPE_P): New macro.
(pushclass): Change prototype.
(push_nested_class): Likewise.
(grokoptypename): Remove.
(build_opfncall): Remove.
(value_dependent_expression_p): Declare.
(resolve_typename_type): Likewise.
(resolve_typename_type_in_current_instantiation): Likewise.
(enter_scope_of): Remove.
(tsubst): Remove.
(tsubst_expr): Likewise.
(tsubst_copy): Likewise.
(tsubst_copy_and_build): Likewise.
* decl.c (warn_about_implicit_typename_lookup): Remove.
(finish_case_label): Return error_mark_node for erroneous labels.
(start_decl): Adjust calls to push_nested_class.
(grokfndecl): Call push_scope/pop_scope around call to
duplicate_decls.
(grokdeclarator): Do not call tsubst.
(start_function): Adjust calls to push_nested_class.
* decl2.c (grok_array_decl): Use build_new_op, not build_opfncall.
(check_classfn): Use push_scope/pop_scope around type comparisions.
(grokoptypename): Remove.
(push_sscope): Adjust call to push_nested_class.
* error.c (dump_type): Show cv-qualification of typename types.
* init.c (build_member_call): Use build_new_op, not
build_opfncall.
* method.c (build_opfncall): Remove.
* parser.c (cp_parser): Add allow_non_constant_expression_p and
non_constant_expression_p.
(cp_parser_constant_expression): Adjust prototype.
(cp_parser_resolve_typename_type): Remove.
(cp_parser_non_constant_expression): New function.
(cp_parser_non_constant_id_expression): Likewise.
(cp_parser_new): Set allow_non_constant_expression_p and
non_constant_expression_p.
(cp_parser_primary_expression): Reject `this' and `va_arg' in
constant-expressions. Note that dependent names aren't really
constant.
(cp_parser_postfix_expression): Reject conversions to non-integral
types in constant-expressions. Neither are increments or
decrements.
(cp_parser_unary_expression): Reject increments and decrements in
constant-expressions.
(cp_parser_direct_new_declarator): Adjust call to
cp_parser_constant_expression.
(cp_parser_cast_expression): Reject conversions to non-integral
types in constant-expressions.
(cp_parser_assignment_expression): Rejects assignments in
constant-expressions.
(cp_parser_expression): Reject commas in constant-expressions.
(cp_parser_labeled_statement): Adjust call to
cp_parser_constant_expression.
(cp_parser_direct_declarator): Simplify array bounds, even in
templates, when they are non-dependent. Use
resolve_typename_type, not cp_parser_resolve_typename_type.
(cp_parser_class_head): Use resolve_typename_type, not
cp_parser_resolve_typename_type.
(cp_parser_member_declaration): Adjust call to
cp_parser_constant_expression.
(cp_parser_constant_initializer): Likewise.
(cp_parser_constructor_declarator): Use resolve_typename_type, not
cp_parser_resolve_typename_type.
(cp_parser_late_parsing_default_args): Adjust call to
push_nested_class.
* pt.c (tsubst): Give it internal linkage.
(tsubst_expr): Likewise.
(tsubst_copy): Likewise.
(tsubst_copy_and_build): Likewise.
(push_access_scope_real): Likewise.
(tsubst_friend_class): Likewise.
(instantiate_class_template): Adjust call to pushclass.
(value_dependent_expression_p): Give it external linkage.
Robustify.
(resolve_typename_type): New function.
* semantics.c (finish_call_expr): Use build_new_op, not
build_opfncall.
(begin_constructor_declarator): Remove.
(begin_class_definition): Adjust call to pushclass.
(enter_scope_of): Remove.
* typeck.c (comptypes): Resolve typename types as appropriate.
(build_x_indirect_ref): Use build_new_op, not build_opfncall.
(build_x_compound_expr): Likewise.
(build_modify_expr): Likewise.
(build_x_modify_expr): Likewise.
* typeck2.c (build_x_arrow): Likewise.
2003-01-29 Fariborz Jahanian <fjahanian@apple.com>
* pt.c (last_pending_template) Declare GTY().

View file

@ -103,6 +103,7 @@ static bool promoted_arithmetic_type_p (tree);
static tree conditional_conversion (tree, tree);
static char *name_as_c_string (tree, tree, bool *);
static tree call_builtin_trap (void);
static tree prep_operand (tree);
tree
build_vfield_ref (tree datum, tree type)
@ -145,8 +146,8 @@ build_field_call (tree instance_ptr, tree decl, tree parms)
return error_mark_node;
if (IS_AGGR_TYPE (TREE_TYPE (instance)))
return build_opfncall (CALL_EXPR, LOOKUP_NORMAL,
instance, parms, NULL_TREE);
return build_new_op (CALL_EXPR, LOOKUP_NORMAL,
instance, parms, NULL_TREE);
else if (TREE_CODE (TREE_TYPE (instance)) == FUNCTION_TYPE
|| (TREE_CODE (TREE_TYPE (instance)) == POINTER_TYPE
&& (TREE_CODE (TREE_TYPE (TREE_TYPE (instance)))
@ -3295,6 +3296,27 @@ build_conditional_expr (tree arg1, tree arg2, tree arg3)
return result;
}
/* OPERAND is an operand to an expression. Perform necessary steps
required before using it. If OPERAND is NULL_TREE, NULL_TREE is
returned. */
static tree
prep_operand (tree operand)
{
if (operand)
{
if (TREE_CODE (operand) == OFFSET_REF)
operand = resolve_offset_ref (operand);
operand = convert_from_reference (operand);
if (CLASS_TYPE_P (TREE_TYPE (operand))
&& CLASSTYPE_TEMPLATE_INSTANTIATION (TREE_TYPE (operand)))
/* Make sure the template type is instantiated now. */
instantiate_class_template (TYPE_MAIN_VARIANT (TREE_TYPE (operand)));
}
return operand;
}
tree
build_new_op (enum tree_code code, int flags, tree arg1, tree arg2, tree arg3)
{
@ -3310,14 +3332,6 @@ build_new_op (enum tree_code code, int flags, tree arg1, tree arg2, tree arg3)
|| error_operand_p (arg3))
return error_mark_node;
/* This can happen if a template takes all non-type parameters, e.g.
undeclared_template<1, 5, 72>a; */
if (code == LT_EXPR && TREE_CODE (arg1) == TEMPLATE_DECL)
{
error ("`%D' must be declared before use", arg1);
return error_mark_node;
}
if (code == MODIFY_EXPR)
{
code2 = TREE_CODE (arg3);
@ -3327,13 +3341,7 @@ build_new_op (enum tree_code code, int flags, tree arg1, tree arg2, tree arg3)
else
fnname = ansi_opname (code);
if (TREE_CODE (arg1) == OFFSET_REF)
arg1 = resolve_offset_ref (arg1);
arg1 = convert_from_reference (arg1);
if (CLASS_TYPE_P (TREE_TYPE (arg1))
&& CLASSTYPE_TEMPLATE_INSTANTIATION (TREE_TYPE (arg1)))
/* Make sure the template type is instantiated now. */
instantiate_class_template (TYPE_MAIN_VARIANT (TREE_TYPE (arg1)));
arg1 = prep_operand (arg1);
switch (code)
{
@ -3351,24 +3359,8 @@ build_new_op (enum tree_code code, int flags, tree arg1, tree arg2, tree arg3)
break;
}
if (arg2)
{
if (TREE_CODE (arg2) == OFFSET_REF)
arg2 = resolve_offset_ref (arg2);
arg2 = convert_from_reference (arg2);
if (CLASS_TYPE_P (TREE_TYPE (arg2))
&& CLASSTYPE_TEMPLATE_INSTANTIATION (TREE_TYPE (arg2)))
instantiate_class_template (TYPE_MAIN_VARIANT (TREE_TYPE (arg2)));
}
if (arg3)
{
if (TREE_CODE (arg3) == OFFSET_REF)
arg3 = resolve_offset_ref (arg3);
arg3 = convert_from_reference (arg3);
if (CLASS_TYPE_P (TREE_TYPE (arg3))
&& CLASSTYPE_TEMPLATE_INSTANTIATION (TREE_TYPE (arg3)))
instantiate_class_template (TYPE_MAIN_VARIANT (TREE_TYPE (arg3)));
}
arg2 = prep_operand (arg2);
arg3 = prep_operand (arg3);
if (code == COND_EXPR)
{
@ -3553,7 +3545,6 @@ build_new_op (enum tree_code code, int flags, tree arg1, tree arg2, tree arg3)
if (TREE_CODE (cand->fn) == FUNCTION_DECL)
{
extern int warn_synth;
if (warn_synth
&& fnname == ansi_assopname (NOP_EXPR)
&& DECL_ARTIFICIAL (cand->fn)

View file

@ -5758,7 +5758,7 @@ init_class_processing (void)
that name becomes `error_mark_node'. */
void
pushclass (tree type, int modify)
pushclass (tree type, bool modify)
{
type = TYPE_MAIN_VARIANT (type);
@ -5880,10 +5880,11 @@ int
currently_open_class (tree t)
{
int i;
if (t == current_class_type)
if (current_class_type && same_type_p (t, current_class_type))
return 1;
for (i = 1; i < current_class_depth; ++i)
if (current_class_stack [i].type == t)
if (current_class_stack[i].type
&& same_type_p (current_class_stack [i].type, t))
return 1;
return 0;
}
@ -5912,14 +5913,13 @@ currently_open_derived_class (tree t)
}
/* When entering a class scope, all enclosing class scopes' names with
static meaning (static variables, static functions, types and enumerators)
have to be visible. This recursive function calls pushclass for all
enclosing class contexts until global or a local scope is reached.
TYPE is the enclosed class and MODIFY is equivalent with the pushclass
formal of the same name. */
static meaning (static variables, static functions, types and
enumerators) have to be visible. This recursive function calls
pushclass for all enclosing class contexts until global or a local
scope is reached. TYPE is the enclosed class. */
void
push_nested_class (tree type, int modify)
push_nested_class (tree type)
{
tree context;
@ -5935,8 +5935,8 @@ push_nested_class (tree type, int modify)
context = DECL_CONTEXT (TYPE_MAIN_DECL (type));
if (context && CLASS_TYPE_P (context))
push_nested_class (context, 2);
pushclass (type, modify);
push_nested_class (context);
pushclass (type, true);
}
/* Undoes a push_nested_class call. */

View file

@ -2477,6 +2477,10 @@ struct lang_decl GTY(())
(TREE_CODE (TYPE) == BOOLEAN_TYPE \
|| TREE_CODE (TYPE) == INTEGER_TYPE)
/* Returns true if TYPE is an integral or enumeration name. */
#define INTEGRAL_OR_ENUMERATION_TYPE_P(TYPE) \
(CP_INTEGRAL_TYPE_P (TYPE) || TREE_CODE (TYPE) == ENUMERAL_TYPE)
/* [basic.fundamental]
Integral and floating types are collectively called arithmetic
@ -3642,9 +3646,9 @@ extern void finish_struct_1 (tree);
extern int resolves_to_fixed_type_p (tree, int *);
extern void init_class_processing (void);
extern int is_empty_class (tree);
extern void pushclass (tree, int);
extern void pushclass (tree, bool);
extern void popclass (void);
extern void push_nested_class (tree, int);
extern void push_nested_class (tree);
extern void pop_nested_class (void);
extern int current_lang_depth (void);
extern void push_lang_context (tree);
@ -3854,7 +3858,6 @@ extern void check_member_template (tree);
extern tree grokfield (tree, tree, tree, tree, tree);
extern tree grokbitfield (tree, tree, tree);
extern tree groktypefield (tree, tree);
extern tree grokoptypename (tree, tree, tree);
extern void cplus_decl_attributes (tree *, tree, int);
extern tree constructor_name_full (tree);
extern tree constructor_name (tree);
@ -4009,7 +4012,6 @@ extern void cxx_init_options (void);
/* in method.c */
extern void init_method (void);
extern void set_mangled_name_for_decl (tree);
extern tree build_opfncall (enum tree_code, int, tree, tree, tree);
extern tree hack_identifier (tree, tree);
extern tree make_thunk (tree, bool, tree, tree);
extern void finish_thunk (tree);
@ -4026,10 +4028,6 @@ extern bool maybe_clone_body (tree);
/* in pt.c */
extern void check_template_shadow (tree);
extern tree get_innermost_template_args (tree, int);
extern tree tsubst (tree, tree, tsubst_flags_t, tree);
extern tree tsubst_expr (tree, tree, tsubst_flags_t, tree);
extern tree tsubst_copy (tree, tree, tsubst_flags_t, tree);
extern tree tsubst_copy_and_build (tree, tree, tsubst_flags_t, tree);
extern void maybe_begin_member_template_processing (tree);
extern void maybe_end_member_template_processing (void);
extern tree finish_member_template_decl (tree);
@ -4086,6 +4084,9 @@ extern bool dependent_type_p (tree);
extern bool dependent_template_arg_p (tree);
extern bool dependent_template_p (tree);
extern bool type_dependent_expression_p (tree);
extern bool value_dependent_expression_p (tree);
extern tree resolve_typename_type (tree, bool);
extern tree resolve_typename_type_in_current_instantiation (tree);
/* in repo.c */
extern void repo_template_used (tree);
@ -4226,7 +4227,6 @@ extern tree finish_unary_op_expr (enum tree_code, tree);
extern tree finish_compound_literal (tree, tree);
extern tree finish_fname (tree);
extern int begin_function_definition (tree, tree, tree);
extern tree begin_constructor_declarator (tree, tree);
extern tree finish_declarator (tree, tree, tree, tree, int);
extern void finish_translation_unit (void);
extern tree finish_template_type_parm (tree, tree);
@ -4238,7 +4238,6 @@ extern void finish_default_args (void);
extern tree finish_member_class_template (tree);
extern void finish_template_decl (tree);
extern tree finish_template_type (tree, tree, int);
extern void enter_scope_of (tree);
extern tree finish_base_specifier (tree, tree);
extern void finish_member_declaration (tree);
extern void check_multiple_declarators (void);

View file

@ -105,7 +105,6 @@ static tree record_builtin_java_type (const char *, int);
static const char *tag_name (enum tag_types code);
static void find_class_binding_level (void);
static struct cp_binding_level *innermost_nonclass_level (void);
static void warn_about_implicit_typename_lookup (tree, tree);
static int walk_namespaces_r (tree, walk_namespaces_fn, void *);
static int walk_globals_r (tree, void*);
static int walk_vtables_r (tree, void*);
@ -5072,8 +5071,6 @@ finish_case_label (tree low_value, tree high_value)
cond = TREE_VALUE (cond);
r = c_add_case_label (switch_stack->cases, cond, low_value, high_value);
if (r == error_mark_node)
r = NULL_TREE;
check_switch_goto (switch_stack->level);
@ -5785,30 +5782,6 @@ qualify_lookup (tree val, int flags)
return val;
}
/* Any other BINDING overrides an implicit TYPENAME. Warn about
that. */
static void
warn_about_implicit_typename_lookup (tree typename, tree binding)
{
tree subtype = TREE_TYPE (TREE_TYPE (typename));
tree name = DECL_NAME (typename);
if (! (TREE_CODE (binding) == TEMPLATE_DECL
&& CLASSTYPE_TEMPLATE_INFO (subtype)
&& CLASSTYPE_TI_TEMPLATE (subtype) == binding)
&& ! (TREE_CODE (binding) == TYPE_DECL
&& same_type_p (TREE_TYPE (binding), subtype)))
{
warning ("lookup of `%D' finds `%#D'",
name, binding);
warning (" instead of `%D' from dependent base class",
typename);
warning (" (use `typename %T::%D' if that's what you meant)",
constructor_name (current_class_type), name);
}
}
/* Look up NAME (an IDENTIFIER_NODE) in SCOPE (either a NAMESPACE_DECL
or a class TYPE). If IS_TYPE_P is TRUE, then ignore non-type
bindings.
@ -7078,7 +7051,7 @@ start_decl (tree declarator,
if (context && COMPLETE_TYPE_P (complete_type (context)))
{
push_nested_class (context, 2);
push_nested_class (context);
if (TREE_CODE (decl) == VAR_DECL)
{
@ -9086,9 +9059,11 @@ grokfndecl (tree ctype,
/* Attempt to merge the declarations. This can fail, in
the case of some invalid specialization declarations. */
push_scope (ctype);
if (!duplicate_decls (decl, old_decl))
error ("no `%#D' member function declared in class `%T'",
decl, ctype);
pop_scope (ctype);
return old_decl;
}
}
@ -11055,35 +11030,6 @@ grokdeclarator (tree declarator,
attrlist = &returned_attrs;
}
/* Resolve any TYPENAME_TYPEs from the decl-specifier-seq that refer
to ctype. They couldn't be resolved earlier because we hadn't
pushed into the class yet.
For example, consider:
template <typename T>
struct S {
typedef T X;
X f();
};
template <typename T>
typename S<T>::X f() {}
When parsing the decl-specifier-seq for the definition of `f',
we construct a TYPENAME_TYPE for `S<T>::X'. By substituting
here, we resolve it to the correct type. */
if (scope && CLASS_TYPE_P (scope)
&& current_template_parms
&& uses_template_parms (scope))
{
tree args = current_template_args ();
push_scope (scope);
type = tsubst (type, args, tf_error | tf_warning,
NULL_TREE);
pop_scope (scope);
}
/* Now TYPE has the actual type. */
/* Did array size calculations overflow? */
@ -13470,9 +13416,9 @@ start_function (tree declspecs, tree declarator, tree attrs, int flags)
/* Set up current_class_type, and enter the scope of the class, if
appropriate. */
if (ctype)
push_nested_class (ctype, 1);
push_nested_class (ctype);
else if (DECL_STATIC_FUNCTION_P (decl1))
push_nested_class (DECL_CONTEXT (decl1), 2);
push_nested_class (DECL_CONTEXT (decl1));
/* Now that we have entered the scope of the class, we must restore
the bindings for any template parameters surrounding DECL1, if it

View file

@ -423,8 +423,8 @@ grok_array_decl (tree array_expr, tree index_exp)
/* If they have an `operator[]', use that. */
if (IS_AGGR_TYPE (type) || IS_AGGR_TYPE (TREE_TYPE (index_exp)))
return build_opfncall (ARRAY_REF, LOOKUP_NORMAL,
array_expr, index_exp, NULL_TREE);
return build_new_op (ARRAY_REF, LOOKUP_NORMAL,
array_expr, index_exp, NULL_TREE);
/* Otherwise, create an ARRAY_REF for a pointer or array type. It
is a little-known fact that, if `a' is an array and `i' is an
@ -685,6 +685,7 @@ check_classfn (tree ctype, tree function)
bool is_conv_op;
const char *format = NULL;
push_scope (ctype);
for (fndecls = TREE_VEC_ELT (methods, ix);
fndecls; fndecls = OVL_NEXT (fndecls))
{
@ -713,8 +714,11 @@ check_classfn (tree ctype, tree function)
&& (!DECL_TEMPLATE_SPECIALIZATION (function)
|| (DECL_TI_TEMPLATE (function)
== DECL_TI_TEMPLATE (fndecl))))
return fndecl;
break;
}
pop_scope (ctype);
if (fndecls)
return OVL_CURRENT (fndecls);
error ("prototype for `%#D' does not match any in class `%T'",
function, ctype);
is_conv_op = DECL_CONV_FN_P (fndecl);
@ -1071,30 +1075,6 @@ grokbitfield (tree declarator, tree declspecs, tree width)
return value;
}
/* Convert a conversion operator name to an identifier. SCOPE is the
scope of the conversion operator, if explicit. */
tree
grokoptypename (tree declspecs, tree declarator, tree scope)
{
tree t = grokdeclarator (declarator, declspecs, TYPENAME, 0, NULL);
/* Resolve any TYPENAME_TYPEs that refer to SCOPE, before mangling
the name, so that we mangle the right thing. */
if (scope && current_template_parms
&& uses_template_parms (t)
&& uses_template_parms (scope))
{
tree args = current_template_args ();
push_scope (scope);
t = tsubst (t, args, tf_error | tf_warning, NULL_TREE);
pop_scope (scope);
}
return mangle_conv_op_name_for_type (t);
}
/* When a function is declared with an initializer,
do the right thing. Currently, there are two possibilities:
@ -3749,7 +3729,7 @@ push_scope (tree t)
if (TREE_CODE (t) == NAMESPACE_DECL)
push_decl_namespace (t);
else if CLASS_TYPE_P (t)
push_nested_class (t, 2);
push_nested_class (t);
}
/* Leave scope pushed by push_scope. */

View file

@ -454,6 +454,7 @@ dump_type (t, flags)
break;
}
case TYPENAME_TYPE:
dump_qualifiers (t, after);
output_add_string (scratch_buffer, "typename ");
dump_typename (t, flags);
break;

View file

@ -1511,8 +1511,8 @@ build_member_call (type, name, parmlist)
return error_mark_node;
}
if (TYPE_LANG_SPECIFIC (TREE_TYPE (decl)))
return build_opfncall (CALL_EXPR, LOOKUP_NORMAL, decl,
parmlist, NULL_TREE);
return build_new_op (CALL_EXPR, LOOKUP_NORMAL, decl,
parmlist, NULL_TREE);
return build_function_call (decl, parmlist);
}
else

View file

@ -84,36 +84,6 @@ set_mangled_name_for_decl (tree decl)
mangle_decl (decl);
}
/* Given a tree_code CODE, and some arguments (at least one),
attempt to use an overloaded operator on the arguments.
For unary operators, only the first argument need be checked.
For binary operators, both arguments may need to be checked.
Member functions can convert class references to class pointers,
for one-level deep indirection. More than that is not supported.
Operators [](), ()(), and ->() must be member functions.
We call function call building calls with LOOKUP_COMPLAIN if they
are our only hope. This is true when we see a vanilla operator
applied to something of aggregate type. If this fails, we are free
to return `error_mark_node', because we will have reported the
error.
Operators NEW and DELETE overload in funny ways: operator new takes
a single `size' parameter, and operator delete takes a pointer to the
storage being deleted. When overloading these operators, success is
assumed. If there is a failure, report an error message and return
`error_mark_node'. */
/* NOSTRICT */
tree
build_opfncall (enum tree_code code, int flags,
tree xarg1, tree xarg2, tree arg3)
{
return build_new_op (code, flags, xarg1, xarg2, arg3);
}
/* This function takes an identifier, ID, and attempts to figure out what
it means. There are a number of possible scenarios, presented in increasing

View file

@ -1275,9 +1275,18 @@ typedef struct cp_parser GTY(())
/* TRUE if we are parsing an integral constant-expression. See
[expr.const] for a precise definition. */
/* FIXME: Need to implement code that checks this flag. */
bool constant_expression_p;
/* TRUE if we are parsing an integral constant-expression -- but a
non-constant expression should be permitted as well. This flag
is used when parsing an array bound so that GNU variable-length
arrays are tolerated. */
bool allow_non_constant_expression_p;
/* TRUE if ALLOW_NON_CONSTANT_EXPRESSION_P is TRUE and something has
been seen that makes the expression non-constant. */
bool non_constant_expression_p;
/* TRUE if local variable names and `this' are forbidden in the
current context. */
bool local_variables_forbidden_p;
@ -1422,7 +1431,7 @@ static enum tree_code cp_parser_assignment_operator_opt
static tree cp_parser_expression
(cp_parser *);
static tree cp_parser_constant_expression
(cp_parser *);
(cp_parser *, bool, bool *);
/* Statements [gram.stmt.stmt] */
@ -1658,8 +1667,6 @@ static tree cp_parser_lookup_name
(cp_parser *, tree, bool, bool, bool, bool);
static tree cp_parser_lookup_name_simple
(cp_parser *, tree);
static tree cp_parser_resolve_typename_type
(cp_parser *, tree);
static tree cp_parser_maybe_treat_template_as_class
(tree, bool);
static bool cp_parser_check_declarator_template_parameters
@ -1728,6 +1735,10 @@ static bool cp_parser_simulate_error
(cp_parser *);
static void cp_parser_check_type_definition
(cp_parser *);
static tree cp_parser_non_constant_expression
(const char *);
static tree cp_parser_non_constant_id_expression
(tree);
static bool cp_parser_diagnose_invalid_type_name
(cp_parser *);
static bool cp_parser_skip_to_closing_parenthesis
@ -1875,6 +1886,26 @@ cp_parser_check_type_definition (cp_parser* parser)
error ("%s", parser->type_definition_forbidden_message);
}
/* Issue an eror message about the fact that THING appeared in a
constant-expression. Returns ERROR_MARK_NODE. */
static tree
cp_parser_non_constant_expression (const char *thing)
{
error ("%s cannot appear in a constant-expression", thing);
return error_mark_node;
}
/* Issue an eror message about the fact that DECL appeared in a
constant-expression. Returns ERROR_MARK_NODE. */
static tree
cp_parser_non_constant_id_expression (tree decl)
{
error ("`%D' cannot appear in a constant-expression", decl);
return error_mark_node;
}
/* Check for a common situation where a type-name should be present,
but is not, and issue a sensible error message. Returns true if an
invalid type-name was detected. */
@ -2182,6 +2213,8 @@ cp_parser_new (void)
/* We are not parsing a constant-expression. */
parser->constant_expression_p = false;
parser->allow_non_constant_expression_p = false;
parser->non_constant_expression_p = false;
/* Local variable names are not forbidden. */
parser->local_variables_forbidden_p = false;
@ -2395,6 +2428,13 @@ cp_parser_primary_expression (cp_parser *parser,
error ("`this' may not be used in this context");
return error_mark_node;
}
/* Pointers cannot appear in constant-expressions. */
if (parser->constant_expression_p)
{
if (!parser->allow_non_constant_expression_p)
return cp_parser_non_constant_expression ("`this'");
parser->non_constant_expression_p = true;
}
return finish_this_expr ();
/* The `operator' keyword can be the beginning of an
@ -2434,7 +2474,14 @@ cp_parser_primary_expression (cp_parser *parser,
type = cp_parser_type_id (parser);
/* Look for the closing `)'. */
cp_parser_require (parser, CPP_CLOSE_PAREN, "`)'");
/* Using `va_arg' in a constant-expression is not
allowed. */
if (parser->constant_expression_p)
{
if (!parser->allow_non_constant_expression_p)
return cp_parser_non_constant_expression ("`va_arg'");
parser->non_constant_expression_p = true;
}
return build_x_va_arg (expression, type);
}
@ -2481,6 +2528,11 @@ cp_parser_primary_expression (cp_parser *parser,
{
if (TYPE_P (TREE_OPERAND (decl, 0)))
*qualifying_class = TREE_OPERAND (decl, 0);
/* Since this name was dependent, the expression isn't
constant -- yet. No error is issued because it
might be constant when things are instantiated. */
if (parser->constant_expression_p)
parser->non_constant_expression_p = true;
return decl;
}
/* Check to see if DECL is a local variable in a context
@ -2704,6 +2756,11 @@ cp_parser_primary_expression (cp_parser *parser,
{
if (TYPE_P (parser->scope))
*qualifying_class = parser->scope;
/* Since this name was dependent, the expression isn't
constant -- yet. No error is issued because it
might be constant when things are instantiated. */
if (parser->constant_expression_p)
parser->non_constant_expression_p = true;
return build_nt (SCOPE_REF,
parser->scope,
id_expression);
@ -2712,10 +2769,36 @@ cp_parser_primary_expression (cp_parser *parser,
we need. */
if (TREE_CODE (id_expression) == TEMPLATE_ID_EXPR)
return id_expression;
/* Since this name was dependent, the expression isn't
constant -- yet. No error is issued because it
might be constant when things are instantiated. */
if (parser->constant_expression_p)
parser->non_constant_expression_p = true;
/* Create a LOOKUP_EXPR for other unqualified names. */
return build_min_nt (LOOKUP_EXPR, id_expression);
}
/* Only certain kinds of names are allowed in constant
expression. Enumerators have already been handled
above. */
if (parser->constant_expression_p
/* Non-type template parameters of integral or
enumeration type. */
&& !(TREE_CODE (decl) == TEMPLATE_PARM_INDEX
&& INTEGRAL_OR_ENUMERATION_TYPE_P (TREE_TYPE (decl)))
/* Const variables or static data members of integral
or enumeration types initialized with constant
expressions. */
&& !(TREE_CODE (decl) == VAR_DECL
&& INTEGRAL_OR_ENUMERATION_TYPE_P (TREE_TYPE (decl))
&& DECL_INITIAL (decl)
&& TREE_CONSTANT (DECL_INITIAL (decl))))
{
if (!parser->allow_non_constant_expression_p)
return cp_parser_non_constant_id_expression (decl);
parser->non_constant_expression_p = true;
}
if (parser->scope)
{
decl = (adjust_result_of_qualified_name_lookup
@ -3520,6 +3603,19 @@ cp_parser_postfix_expression (cp_parser *parser, bool address_p)
expression = cp_parser_expression (parser);
cp_parser_require (parser, CPP_CLOSE_PAREN, "`)'");
/* Only type conversions to integral or enumeration types
can be used in constant-expressions. */
if (parser->constant_expression_p
&& !dependent_type_p (type)
&& !INTEGRAL_OR_ENUMERATION_TYPE_P (type))
{
if (!parser->allow_non_constant_expression_p)
return (cp_parser_non_constant_expression
("a cast to a type other than an integral or "
"enumeration type"));
parser->non_constant_expression_p = true;
}
switch (keyword)
{
case RID_DYNCAST:
@ -3645,32 +3741,32 @@ cp_parser_postfix_expression (cp_parser *parser, bool address_p)
/* If the functional-cast didn't work out, try a
compound-literal. */
if (cp_parser_allow_gnu_extensions_p (parser))
if (cp_parser_allow_gnu_extensions_p (parser)
&& cp_lexer_next_token_is (parser->lexer, CPP_OPEN_PAREN))
{
tree initializer_list = NULL_TREE;
cp_parser_parse_tentatively (parser);
/* Look for the `('. */
if (cp_parser_require (parser, CPP_OPEN_PAREN, "`('"))
/* Consume the `('. */
cp_lexer_consume_token (parser->lexer);
/* Parse the type. */
type = cp_parser_type_id (parser);
/* Look for the `)'. */
cp_parser_require (parser, CPP_CLOSE_PAREN, "`)'");
/* Look for the `{'. */
cp_parser_require (parser, CPP_OPEN_BRACE, "`{'");
/* If things aren't going well, there's no need to
keep going. */
if (!cp_parser_error_occurred (parser))
{
type = cp_parser_type_id (parser);
/* Look for the `)'. */
cp_parser_require (parser, CPP_CLOSE_PAREN, "`)'");
/* Look for the `{'. */
cp_parser_require (parser, CPP_OPEN_BRACE, "`{'");
/* If things aren't going well, there's no need to
keep going. */
if (!cp_parser_error_occurred (parser))
{
/* Parse the initializer-list. */
initializer_list
= cp_parser_initializer_list (parser);
/* Allow a trailing `,'. */
if (cp_lexer_next_token_is (parser->lexer, CPP_COMMA))
cp_lexer_consume_token (parser->lexer);
/* Look for the final `}'. */
cp_parser_require (parser, CPP_CLOSE_BRACE, "`}'");
}
/* Parse the initializer-list. */
initializer_list
= cp_parser_initializer_list (parser);
/* Allow a trailing `,'. */
if (cp_lexer_next_token_is (parser->lexer, CPP_COMMA))
cp_lexer_consume_token (parser->lexer);
/* Look for the final `}'. */
cp_parser_require (parser, CPP_CLOSE_BRACE, "`}'");
}
/* If that worked, we're definitely looking at a
compound-literal expression. */
@ -3806,6 +3902,14 @@ cp_parser_postfix_expression (cp_parser *parser, bool address_p)
args = NULL_TREE;
/* Look for the closing `)'. */
cp_parser_require (parser, CPP_CLOSE_PAREN, "`)'");
/* Function calls are not permitted in
constant-expressions. */
if (parser->constant_expression_p)
{
if (!parser->allow_non_constant_expression_p)
return cp_parser_non_constant_expression ("a function call");
parser->non_constant_expression_p = true;
}
if (idk == CP_PARSER_ID_KIND_UNQUALIFIED
&& (is_overloaded_fn (postfix_expression)
@ -4029,6 +4133,13 @@ cp_parser_postfix_expression (cp_parser *parser, bool address_p)
/* postfix-expression ++ */
/* Consume the `++' token. */
cp_lexer_consume_token (parser->lexer);
/* Increments may not appear in constant-expressions. */
if (parser->constant_expression_p)
{
if (!parser->allow_non_constant_expression_p)
return cp_parser_non_constant_expression ("an increment");
parser->non_constant_expression_p = true;
}
/* Generate a reprsentation for the complete expression. */
postfix_expression
= finish_increment_expr (postfix_expression,
@ -4040,6 +4151,13 @@ cp_parser_postfix_expression (cp_parser *parser, bool address_p)
/* postfix-expression -- */
/* Consume the `--' token. */
cp_lexer_consume_token (parser->lexer);
/* Decrements may not appear in constant-expressions. */
if (parser->constant_expression_p)
{
if (!parser->allow_non_constant_expression_p)
return cp_parser_non_constant_expression ("a decrement");
parser->non_constant_expression_p = true;
}
/* Generate a reprsentation for the complete expression. */
postfix_expression
= finish_increment_expr (postfix_expression,
@ -4341,11 +4459,20 @@ cp_parser_unary_expression (cp_parser *parser, bool address_p)
case ADDR_EXPR:
return build_x_unary_op (ADDR_EXPR, cast_expression);
case PREINCREMENT_EXPR:
case PREDECREMENT_EXPR:
if (parser->constant_expression_p)
{
if (!parser->allow_non_constant_expression_p)
return cp_parser_non_constant_expression (PREINCREMENT_EXPR
? "an increment"
: "a decrement");
parser->non_constant_expression_p = true;
}
/* Fall through. */
case CONVERT_EXPR:
case NEGATE_EXPR:
case TRUTH_NOT_EXPR:
case PREINCREMENT_EXPR:
case PREDECREMENT_EXPR:
return finish_unary_op_expr (unary_operator, cast_expression);
case BIT_NOT_EXPR:
@ -4597,7 +4724,10 @@ cp_parser_direct_new_declarator (cp_parser* parser)
}
/* But all the other expressions must be. */
else
expression = cp_parser_constant_expression (parser);
expression
= cp_parser_constant_expression (parser,
/*allow_non_constant=*/false,
NULL);
/* Look for the closing `]'. */
cp_parser_require (parser, CPP_CLOSE_SQUARE, "`]'");
@ -4766,7 +4896,19 @@ cp_parser_cast_expression (cp_parser *parser, bool address_p)
&& !VOID_TYPE_P (type)
&& current_lang_name != lang_name_c)
warning ("use of old-style cast");
/* Only type conversions to integral or enumeration types
can be used in constant-expressions. */
if (parser->constant_expression_p
&& !dependent_type_p (type)
&& !INTEGRAL_OR_ENUMERATION_TYPE_P (type))
{
if (!parser->allow_non_constant_expression_p)
return (cp_parser_non_constant_expression
("a casts to a type other than an integral or "
"enumeration type"));
parser->non_constant_expression_p = true;
}
/* Perform the cast. */
expr = build_c_cast (type, expr);
return expr;
@ -5176,6 +5318,14 @@ cp_parser_assignment_expression (cp_parser* parser)
/* Parse the right-hand side of the assignment. */
rhs = cp_parser_assignment_expression (parser);
/* An assignment may not appear in a
constant-expression. */
if (parser->constant_expression_p)
{
if (!parser->allow_non_constant_expression_p)
return cp_parser_non_constant_expression ("an assignment");
parser->non_constant_expression_p = true;
}
/* Build the asignment expression. */
expr = build_x_modify_expr (expr,
assignment_operator,
@ -5334,7 +5484,16 @@ cp_parser_expression (cp_parser* parser)
necessary. We built up the list in reverse order, so we must
straighten it out here. */
if (saw_comma_p)
expression = build_x_compound_expr (nreverse (expression));
{
/* A comma operator cannot appear in a constant-expression. */
if (parser->constant_expression_p)
{
if (!parser->allow_non_constant_expression_p)
return cp_parser_non_constant_expression ("a comma operator");
parser->non_constant_expression_p = true;
}
expression = build_x_compound_expr (nreverse (expression));
}
return expression;
}
@ -5342,12 +5501,20 @@ cp_parser_expression (cp_parser* parser)
/* Parse a constant-expression.
constant-expression:
conditional-expression */
conditional-expression
If ALLOW_NON_CONSTANT_P a non-constant expression is silently
accepted. In that case *NON_CONSTANT_P is set to TRUE. If
ALLOW_NON_CONSTANT_P is false, NON_CONSTANT_P should be NULL. */
static tree
cp_parser_constant_expression (cp_parser* parser)
cp_parser_constant_expression (cp_parser* parser,
bool allow_non_constant_p,
bool *non_constant_p)
{
bool saved_constant_expression_p;
bool saved_allow_non_constant_expression_p;
bool saved_non_constant_expression_p;
tree expression;
/* It might seem that we could simply parse the
@ -5367,14 +5534,24 @@ cp_parser_constant_expression (cp_parser* parser)
constant-expression. However, GCC's constant-folding machinery
will fold this operation to an INTEGER_CST for `3'. */
/* Save the old setting of CONSTANT_EXPRESSION_P. */
/* Save the old settings. */
saved_constant_expression_p = parser->constant_expression_p;
saved_allow_non_constant_expression_p
= parser->allow_non_constant_expression_p;
saved_non_constant_expression_p = parser->non_constant_expression_p;
/* We are now parsing a constant-expression. */
parser->constant_expression_p = true;
parser->allow_non_constant_expression_p = allow_non_constant_p;
parser->non_constant_expression_p = false;
/* Parse the conditional-expression. */
expression = cp_parser_conditional_expression (parser);
/* Restore the old setting of CONSTANT_EXPRESSION_P. */
/* Restore the old settings. */
parser->constant_expression_p = saved_constant_expression_p;
parser->allow_non_constant_expression_p
= saved_allow_non_constant_expression_p;
if (allow_non_constant_p)
*non_constant_p = parser->non_constant_expression_p;
parser->non_constant_expression_p = saved_non_constant_expression_p;
return expression;
}
@ -5517,7 +5694,9 @@ cp_parser_labeled_statement (cp_parser* parser)
/* Consume the `case' token. */
cp_lexer_consume_token (parser->lexer);
/* Parse the constant-expression. */
expr = cp_parser_constant_expression (parser);
expr = cp_parser_constant_expression (parser,
/*allow_non_constant=*/false,
NULL);
/* Create the label. */
statement = finish_case_label (expr, NULL_TREE);
}
@ -8875,7 +9054,9 @@ cp_parser_enumerator_definition (cp_parser* parser, tree type)
/* Consume the `=' token. */
cp_lexer_consume_token (parser->lexer);
/* Parse the value. */
value = cp_parser_constant_expression (parser);
value = cp_parser_constant_expression (parser,
/*allow_non_constant=*/false,
NULL);
}
else
value = NULL_TREE;
@ -9870,7 +10051,34 @@ cp_parser_direct_declarator (cp_parser* parser,
/* If the next token is `]', then there is no
constant-expression. */
if (token->type != CPP_CLOSE_SQUARE)
bounds = cp_parser_constant_expression (parser);
{
bool non_constant_p;
bounds
= cp_parser_constant_expression (parser,
/*allow_non_constant=*/true,
&non_constant_p);
/* If we're in a template, but the constant-expression
isn't value dependent, simplify it. We're supposed
to treat:
template <typename T> void f(T[1 + 1]);
template <typename T> void f(T[2]);
as two declarations of the same function, for
example. */
if (processing_template_decl
&& !non_constant_p
&& !value_dependent_expression_p (bounds))
{
HOST_WIDE_INT saved_processing_template_decl;
saved_processing_template_decl = processing_template_decl;
processing_template_decl = 0;
bounds = build_expr_from_tree (bounds);
processing_template_decl = saved_processing_template_decl;
}
}
else
bounds = NULL_TREE;
/* Look for the closing `]'. */
@ -9924,11 +10132,14 @@ cp_parser_direct_declarator (cp_parser* parser,
is no harm in resolving the types here. */
if (TREE_CODE (scope) == TYPENAME_TYPE)
{
tree type;
/* Resolve the TYPENAME_TYPE. */
scope = cp_parser_resolve_typename_type (parser, scope);
type = resolve_typename_type (scope,
/*only_current_p=*/false);
/* If that failed, the declarator is invalid. */
if (scope == error_mark_node)
return error_mark_node;
if (type != error_mark_node)
scope = type;
/* Build a new DECLARATOR. */
declarator = build_nt (SCOPE_REF,
scope,
@ -11549,16 +11760,22 @@ cp_parser_class_head (cp_parser* parser,
/* Given:
template <typename T> struct S { struct T };
template <typename T> struct S::T { };
template <typename T> struct S<T>::T { };
we will get a TYPENAME_TYPE when processing the definition of
`S::T'. We need to resolve it to the actual type before we
try to define it. */
if (TREE_CODE (TREE_TYPE (type)) == TYPENAME_TYPE)
{
type = cp_parser_resolve_typename_type (parser, TREE_TYPE (type));
if (type != error_mark_node)
type = TYPE_NAME (type);
class_type = resolve_typename_type (TREE_TYPE (type),
/*only_current_p=*/false);
if (class_type != error_mark_node)
type = TYPE_NAME (class_type);
else
{
cp_parser_error (parser, "could not resolve typename type");
type = error_mark_node;
}
}
maybe_process_partial_specialization (TREE_TYPE (type));
@ -11889,7 +12106,10 @@ cp_parser_member_declaration (cp_parser* parser)
/* Consume the `:' token. */
cp_lexer_consume_token (parser->lexer);
/* Get the width of the bitfield. */
width = cp_parser_constant_expression (parser);
width
= cp_parser_constant_expression (parser,
/*allow_non_constant=*/false,
NULL);
/* Look for attributes that apply to the bitfield. */
attributes = cp_parser_attributes_opt (parser);
@ -12112,7 +12332,9 @@ cp_parser_constant_initializer (cp_parser* parser)
return error_mark_node;
}
return cp_parser_constant_expression (parser);
return cp_parser_constant_expression (parser,
/*allow_non_constant=*/false,
NULL);
}
/* Derived classes [gram.class.derived] */
@ -13148,58 +13370,6 @@ cp_parser_lookup_name_simple (cp_parser* parser, tree name)
/*check_dependency=*/true);
}
/* TYPE is a TYPENAME_TYPE. Returns the ordinary TYPE to which the
TYPENAME_TYPE corresponds. Note that this function peers inside
uninstantiated templates and therefore should be used only in
extremely limited situations. */
static tree
cp_parser_resolve_typename_type (cp_parser* parser, tree type)
{
tree scope;
tree name;
tree decl;
my_friendly_assert (TREE_CODE (type) == TYPENAME_TYPE,
20010702);
scope = TYPE_CONTEXT (type);
name = TYPE_IDENTIFIER (type);
/* If the SCOPE is itself a TYPENAME_TYPE, then we need to resolve
it first before we can figure out what NAME refers to. */
if (TREE_CODE (scope) == TYPENAME_TYPE)
scope = cp_parser_resolve_typename_type (parser, scope);
/* If we don't know what SCOPE refers to, then we cannot resolve the
TYPENAME_TYPE. */
if (scope == error_mark_node || TREE_CODE (scope) == TYPENAME_TYPE)
return error_mark_node;
/* If the SCOPE is a template type parameter, we have no way of
resolving the name. */
if (TREE_CODE (scope) == TEMPLATE_TYPE_PARM)
return type;
/* Enter the SCOPE so that name lookup will be resolved as if we
were in the class definition. In particular, SCOPE will no
longer be considered a dependent type. */
push_scope (scope);
/* Look up the declaration. */
decl = lookup_member (scope, name, /*protect=*/0, /*want_type=*/1);
/* If all went well, we got a TYPE_DECL for a non-typename. */
if (!decl
|| TREE_CODE (decl) != TYPE_DECL
|| TREE_CODE (TREE_TYPE (decl)) == TYPENAME_TYPE)
{
cp_parser_error (parser, "could not resolve typename type");
type = error_mark_node;
}
else
type = TREE_TYPE (decl);
/* Leave the SCOPE. */
pop_scope (scope);
return type;
}
/* If DECL is a TEMPLATE_DECL that can be treated like a TYPE_DECL in
the current context, return the TYPE_DECL. If TAG_NAME_P is
true, the DECL indicates the class being defined in a class-head,
@ -13547,7 +13717,15 @@ cp_parser_constructor_declarator_p (cp_parser *parser, bool friend_p)
{
type = TREE_TYPE (type_decl);
if (TREE_CODE (type) == TYPENAME_TYPE)
type = cp_parser_resolve_typename_type (parser, type);
{
type = resolve_typename_type (type,
/*only_current_p=*/false);
if (type == error_mark_node)
{
cp_parser_abort_tentative_parse (parser);
return false;
}
}
push_scope (type);
}
/* Look for the type-specifier. */
@ -13978,7 +14156,7 @@ cp_parser_late_parsing_default_args (cp_parser *parser, tree fn)
parser->local_variables_forbidden_p = true;
/* Parse the assignment-expression. */
if (DECL_CONTEXT (fn))
push_nested_class (DECL_CONTEXT (fn), 1);
push_nested_class (DECL_CONTEXT (fn));
TREE_PURPOSE (parameters) = cp_parser_assignment_expression (parser);
if (DECL_CONTEXT (fn))
pop_nested_class ();

View file

@ -171,8 +171,11 @@ static void copy_default_args_to_explicit_spec PARAMS ((tree));
static int invalid_nontype_parm_type_p PARAMS ((tree, tsubst_flags_t));
static int eq_local_specializations (const void *, const void *);
static tree template_for_substitution (tree);
static bool value_dependent_expression_p (tree);
static bool dependent_template_id_p (tree, tree);
static tree tsubst (tree, tree, tsubst_flags_t, tree);
static tree tsubst_expr (tree, tree, tsubst_flags_t, tree);
static tree tsubst_copy (tree, tree, tsubst_flags_t, tree);
static tree tsubst_copy_and_build (tree, tree, tsubst_flags_t, tree);
/* Make the current scope suitable for access checking when we are
processing T. T can be FUNCTION_DECL for instantiated function
@ -215,7 +218,7 @@ push_access_scope_real (t, args, context)
if (!context)
context = DECL_CONTEXT (t);
if (context && TYPE_P (context))
push_nested_class (context, 2);
push_nested_class (context);
else
push_to_top_level ();
@ -5043,7 +5046,7 @@ tsubst_friend_class (friend_tmpl, args)
if (TREE_CODE (context) == NAMESPACE_DECL)
push_nested_namespace (context);
else
push_nested_class (tsubst (context, args, tf_none, NULL_TREE), 2);
push_nested_class (tsubst (context, args, tf_none, NULL_TREE));
}
/* First, we look for a class template. */
@ -5328,7 +5331,7 @@ instantiate_class_template (type)
correctly. This is precisely analogous to what we do in
begin_class_definition when defining an ordinary non-template
class. */
pushclass (type, 1);
pushclass (type, true);
/* Now members are processed in the order of declaration. */
for (member = CLASSTYPE_DECL_LIST (pattern); member; member = TREE_CHAIN (member))
@ -6467,7 +6470,7 @@ tsubst_call_declarator_parms (parms, args, complain, in_decl)
This function is used for dealing with types, decls and the like;
for expressions, use tsubst_expr or tsubst_copy. */
tree
static tree
tsubst (t, args, complain, in_decl)
tree t, args;
tsubst_flags_t complain;
@ -7103,7 +7106,7 @@ tsubst (t, args, complain, in_decl)
template parms; to finish processing the resultant expression, use
tsubst_expr. */
tree
static tree
tsubst_copy (t, args, complain, in_decl)
tree t, args;
tsubst_flags_t complain;
@ -7505,7 +7508,7 @@ tsubst_copy (t, args, complain, in_decl)
/* Like tsubst_copy for expressions, etc. but also does semantic
processing. */
tree
static tree
tsubst_expr (t, args, complain, in_decl)
tree t, args;
tsubst_flags_t complain;
@ -7832,7 +7835,7 @@ tsubst_expr (t, args, complain, in_decl)
/* Like tsubst but deals with expressions and performs semantic
analysis. */
tree
static tree
tsubst_copy_and_build (t, args, complain, in_decl)
tree t, args;
tsubst_flags_t complain;
@ -11314,15 +11317,16 @@ dependent_type_p (type)
/* Returns TRUE if the EXPRESSION is value-dependent. */
static bool
bool
value_dependent_expression_p (tree expression)
{
if (!processing_template_decl)
return false;
/* A name declared with a dependent type. */
if (DECL_P (expression)
&& dependent_type_p (TREE_TYPE (expression)))
if (TREE_CODE (expression) == LOOKUP_EXPR
|| (DECL_P (expression)
&& dependent_type_p (TREE_TYPE (expression))))
return true;
/* A non-type template parameter. */
if ((TREE_CODE (expression) == CONST_DECL
@ -11370,11 +11374,14 @@ value_dependent_expression_p (tree expression)
case 'e':
{
int i;
for (i = 0;
i < TREE_CODE_LENGTH (TREE_CODE (expression));
++i)
if (value_dependent_expression_p
(TREE_OPERAND (expression, i)))
for (i = 0; i < first_rtl_op (TREE_CODE (expression)); ++i)
/* In some cases, some of the operands may be missing.
(For example, in the case of PREDECREMENT_EXPR, the
amount to increment by may be missing.) That doesn't
make the expression dependent. */
if (TREE_OPERAND (expression, i)
&& (value_dependent_expression_p
(TREE_OPERAND (expression, i))))
return true;
return false;
}
@ -11478,4 +11485,88 @@ dependent_template_p (tree tmpl)
return false;
}
/* TYPE is a TYPENAME_TYPE. Returns the ordinary TYPE to which the
TYPENAME_TYPE corresponds. Returns ERROR_MARK_NODE if no such TYPE
can be found. Note that this function peers inside uninstantiated
templates and therefore should be used only in extremely limited
situations. */
tree
resolve_typename_type (tree type, bool only_current_p)
{
tree scope;
tree name;
tree decl;
int quals;
my_friendly_assert (TREE_CODE (type) == TYPENAME_TYPE,
20010702);
scope = TYPE_CONTEXT (type);
name = TYPE_IDENTIFIER (type);
/* If the SCOPE is itself a TYPENAME_TYPE, then we need to resolve
it first before we can figure out what NAME refers to. */
if (TREE_CODE (scope) == TYPENAME_TYPE)
scope = resolve_typename_type (scope, only_current_p);
/* If we don't know what SCOPE refers to, then we cannot resolve the
TYPENAME_TYPE. */
if (scope == error_mark_node || TREE_CODE (scope) == TYPENAME_TYPE)
return error_mark_node;
/* If the SCOPE is a template type parameter, we have no way of
resolving the name. */
if (TREE_CODE (scope) == TEMPLATE_TYPE_PARM)
return type;
/* If the SCOPE is not the current instantiation, there's no reason
to look inside it. */
if (only_current_p && !currently_open_class (scope))
return error_mark_node;
/* Enter the SCOPE so that name lookup will be resolved as if we
were in the class definition. In particular, SCOPE will no
longer be considered a dependent type. */
push_scope (scope);
/* Look up the declaration. */
decl = lookup_member (scope, name, /*protect=*/0, /*want_type=*/1);
/* Obtain the set of qualifiers applied to the TYPE. */
quals = cp_type_quals (type);
/* For a TYPENAME_TYPE like "typename X::template Y<T>", we want to
find a TEMPLATE_DECL. Otherwise, we want to find a TYPE_DECL. */
if (!decl)
type = error_mark_node;
else if (TREE_CODE (TYPENAME_TYPE_FULLNAME (type)) == IDENTIFIER_NODE
&& TREE_CODE (decl) == TYPE_DECL)
type = TREE_TYPE (decl);
else if (TREE_CODE (TYPENAME_TYPE_FULLNAME (type)) == TEMPLATE_ID_EXPR
&& DECL_CLASS_TEMPLATE_P (decl))
{
tree tmpl;
tree args;
/* Obtain the template and the arguments. */
tmpl = TREE_OPERAND (TYPENAME_TYPE_FULLNAME (type), 0);
args = TREE_OPERAND (TYPENAME_TYPE_FULLNAME (type), 1);
/* Instantiate the template. */
type = lookup_template_class (tmpl, args, NULL_TREE, NULL_TREE,
/*entering_scope=*/0,
tf_error);
}
else
type = error_mark_node;
/* Qualify the resulting type. */
if (type != error_mark_node && quals)
type = cp_build_qualified_type (type, quals);
/* Leave the SCOPE. */
pop_scope (scope);
return type;
}
tree
resolve_typename_type_in_current_instantiation (tree type)
{
tree t;
t = resolve_typename_type (type, /*only_current_p=*/true);
return (t != error_mark_node) ? t : type;
}
#include "gt-cp-pt.h"

View file

@ -1434,7 +1434,7 @@ finish_call_expr (tree fn, tree args, bool disallow_virtual)
/* If the "function" is really an object of class type, it might
have an overloaded `operator ()'. */
tree result;
result = build_opfncall (CALL_EXPR, LOOKUP_NORMAL, fn, args, NULL_TREE);
result = build_new_op (CALL_EXPR, LOOKUP_NORMAL, fn, args, NULL_TREE);
if (result)
return result;
}
@ -1665,19 +1665,6 @@ begin_function_definition (decl_specs, attributes, declarator)
return 1;
}
/* Begin a constructor declarator of the form `SCOPE::NAME'. Returns
a SCOPE_REF. */
tree
begin_constructor_declarator (scope, name)
tree scope;
tree name;
{
tree result = build_nt (SCOPE_REF, scope, name);
enter_scope_of (result);
return result;
}
/* Finish an init-declarator. Returns a DECL. */
tree
@ -1831,7 +1818,7 @@ begin_class_definition (t)
pushtag (TYPE_IDENTIFIER (t), t, 0);
}
maybe_process_partial_specialization (t);
pushclass (t, 1);
pushclass (t, true);
TYPE_BEING_DEFINED (t) = 1;
TYPE_PACKED (t) = flag_pack_struct;
/* Reset the interface data, at the earliest possible
@ -2044,34 +2031,6 @@ finish_template_type (name, args, entering_scope)
return decl;
}
/* SR is a SCOPE_REF node. Enter the scope of SR, whether it is a
namespace scope or a class scope. */
void
enter_scope_of (sr)
tree sr;
{
tree scope = TREE_OPERAND (sr, 0);
if (TREE_CODE (scope) == NAMESPACE_DECL)
{
push_decl_namespace (scope);
TREE_COMPLEXITY (sr) = -1;
}
else if (scope != current_class_type)
{
if (TREE_CODE (scope) == TYPENAME_TYPE)
{
/* In a declarator for a template class member, the scope will
get here as an implicit typename, a TYPENAME_TYPE with a type. */
scope = TREE_TYPE (scope);
TREE_OPERAND (sr, 0) = scope;
}
push_nested_class (scope, 3);
TREE_COMPLEXITY (sr) = current_class_depth;
}
}
/* Finish processing a BASE_CLASS with the indicated ACCESS_SPECIFIER.
Return a TREE_LIST containing the ACCESS_SPECIFIER and the
BASE_CLASS, or NULL_TREE if an error occurred. The

View file

@ -946,6 +946,13 @@ comptypes (t1, t2, strict)
if (TYPE_PTRMEMFUNC_P (t2))
t2 = TYPE_PTRMEMFUNC_FN_TYPE (t2);
/* TYPENAME_TYPEs should be resolved if the qualifying scope is the
current instantiation. */
if (TREE_CODE (t1) == TYPENAME_TYPE)
t1 = resolve_typename_type_in_current_instantiation (t1);
if (TREE_CODE (t2) == TYPENAME_TYPE)
t2 = resolve_typename_type_in_current_instantiation (t2);
/* Different classes of types can't be compatible. */
if (TREE_CODE (t1) != TREE_CODE (t2))
return 0;
@ -2301,8 +2308,8 @@ build_x_indirect_ref (ptr, errorstring)
if (processing_template_decl)
return build_min_nt (INDIRECT_REF, ptr);
rval = build_opfncall (INDIRECT_REF, LOOKUP_NORMAL, ptr, NULL_TREE,
NULL_TREE);
rval = build_new_op (INDIRECT_REF, LOOKUP_NORMAL, ptr, NULL_TREE,
NULL_TREE);
if (rval)
return rval;
return build_indirect_ref (ptr, errorstring);
@ -2973,6 +2980,183 @@ build_x_binary_op (code, arg1, arg2)
return build_new_op (code, LOOKUP_NORMAL, arg1, arg2, NULL_TREE);
}
#if 0
tree
build_template_expr (enum tree_code code, tree op0, tree op1, tree op2)
{
tree type;
/* If any of the operands is erroneous the result is erroneous too. */
if (error_operand_p (op0)
|| (op1 && error_operand_p (op1))
|| (op2 && error_operand_p (op2)))
return error_mark_node;
if (dependent_type_p (TREE_TYPE (op0))
|| (op1 && dependent_type_p (TREE_TYPE (op1)))
|| (op2 && dependent_type_p (TREE_TYPE (op2))))
/* If at least one operand has a dependent type, we cannot
determine the type of the expression until instantiation time. */
type = NULL_TREE;
else
{
struct z_candidate *cand;
tree op0_type;
tree op1_type;
tree op2_type;
/* None of the operands is dependent, so we can compute the type
of the expression at this point. We must compute the type so
that in things like:
template <int I>
void f() { S<sizeof(I + 3)> s; ... }
we can tell that the type of "s" is non-dependent.
If we're processing a template argument, we do not want to
actually change the operands in any way. Adding conversions,
performing constant folding, etc., would all change mangled
names. For example, in:
template <int I>
void f(S<sizeof(3 + 4 + I)>);
we need to determine that "3 + 4 + I" has type "int", without
actually turning the expression into "7 + I". */
cand = find_overloaded_op (code, op0, op1, op2);
if (cand)
/* If an overloaded operator was found, the expression will
have the type returned by the function. */
type = non_reference (TREE_TYPE (cand->fn));
else
{
/* There is no overloaded operator so we can just use the
default rules for determining the type of the operand. */
op0_type = TREE_TYPE (op0);
op1_type = op1 ? TREE_TYPE (op1) : NULL_TREE;
op2_type = op2 ? TREE_TYPE (op2) : NULL_TREE;
type = NULL_TREE;
switch (code)
{
case MODIFY_EXPR:
/* [expr.ass]
The result of the assignment operation is the value
stored in the left operand. */
type = op0_type;
break;
case COMPONENT_REF:
/* Implement this case. */
break;
case POSTINCREMENT_EXPR:
case POSTDECREMENT_EXPR:
/* [expr.post.incr]
The type of the result is the cv-unqualified version
of the type of the operand. */
type = TYPE_MAIN_VARIANT (op0_type);
break;
case PREINCREMENT_EXPR:
case PREDECREMENT_EXPR:
/* [expr.pre.incr]
The value is the new value of the operand. */
type = op0_type;
break;
case INDIRECT_REF:
/* [expr.unary.op]
If the type of the expression is "pointer to T", the
type of the result is "T". */
type = TREE_TYPE (op0_type);
break;
case ADDR_EXPR:
/* [expr.unary.op]
If the type of the expression is "T", the type of the
result is "pointer to T". */
/* FIXME: Handle the pointer-to-member case. */
break;
case MEMBER_REF:
/* FIXME: Implement this case. */
break;
case LSHIFT_EXPR:
case RSHIFT_EXPR:
/* [expr.shift]
The type of the result is that of the promoted left
operand. */
break;
case PLUS_EXPR:
case MINUS_EXPR:
/* FIXME: Be careful of special pointer-arithmetic
cases. */
/* Fall through. */
case MAX_EXPR:
case MIN_EXPR:
/* These are GNU extensions; the result type is computed
as it would be for other arithmetic operators. */
/* Fall through. */
case BIT_AND_EXPR:
case BIT_XOR_EXPR:
case BIT_IOR_EXPR:
case MULT_EXPR:
case TRUNC_DIV_EXPR:
case TRUNC_MOD_EXPR:
/* [expr.bit.and], [expr.xor], [expr.or], [expr.mul]
The usual arithmetic conversions are performed on the
operands and determine the type of the result. */
/* FIXME: Check that this is possible. */
type = type_after_usual_arithmetic_conversions (t1, t2);
break;
case GT_EXPR:
case LT_EXPR:
case GE_EXPR:
case LE_EXPR:
case EQ_EXPR:
case NE_EXPR:
/* [expr.rel]
The type of the result is bool. */
type = boolean_type_node;
break;
case TRUTH_ANDIF_EXPR:
case TRUTH_ORIF_EXPR:
/* [expr.log.and], [expr.log.org]
The result is a bool. */
type = boolean_type_node;
break;
case COND_EXPR:
/* FIXME: Handle special rules for conditioanl
expressions. */
break;
case COMPOUND_EXPR:
type = op1_type;
break;
default:
abort ();
}
/* If the type of the expression could not be determined,
something is wrong. */
if (!type)
abort ();
/* If the type is erroneous, the expression is erroneous
too. */
if (type == error_mark_node)
return error_mark_node;
}
}
return build_min (code, type, op0, op1, op2, NULL_TREE);
}
#endif
/* Build a binary-operation expression without default conversions.
CODE is the kind of expression to build.
This function differs from `build' in several ways:
@ -4602,8 +4786,8 @@ build_x_compound_expr (list)
if (rest == NULL_TREE)
return build_compound_expr (list);
result = build_opfncall (COMPOUND_EXPR, LOOKUP_NORMAL,
TREE_VALUE (list), TREE_VALUE (rest), NULL_TREE);
result = build_new_op (COMPOUND_EXPR, LOOKUP_NORMAL,
TREE_VALUE (list), TREE_VALUE (rest), NULL_TREE);
if (result)
return build_x_compound_expr (tree_cons (NULL_TREE, result,
TREE_CHAIN (rest)));
@ -5235,8 +5419,8 @@ build_modify_expr (lhs, modifycode, rhs)
/* Do the default thing */;
else
{
result = build_opfncall (MODIFY_EXPR, LOOKUP_NORMAL,
lhs, rhs, make_node (NOP_EXPR));
result = build_new_op (MODIFY_EXPR, LOOKUP_NORMAL,
lhs, rhs, make_node (NOP_EXPR));
if (result == NULL_TREE)
return error_mark_node;
return result;
@ -5488,8 +5672,8 @@ build_x_modify_expr (lhs, modifycode, rhs)
if (modifycode != NOP_EXPR)
{
tree rval = build_opfncall (MODIFY_EXPR, LOOKUP_NORMAL, lhs, rhs,
make_node (modifycode));
tree rval = build_new_op (MODIFY_EXPR, LOOKUP_NORMAL, lhs, rhs,
make_node (modifycode));
if (rval)
return rval;
}

View file

@ -1044,8 +1044,8 @@ build_x_arrow (datum)
if (IS_AGGR_TYPE (type))
{
while ((rval = build_opfncall (COMPONENT_REF, LOOKUP_NORMAL, rval,
NULL_TREE, NULL_TREE)))
while ((rval = build_new_op (COMPONENT_REF, LOOKUP_NORMAL, rval,
NULL_TREE, NULL_TREE)))
{
if (rval == error_mark_node)
return error_mark_node;

View file

@ -1,3 +1,7 @@
2003-01-29 Mark Mitchell <mark@codesourcery.com>
* g++.dg/parser/constant1.C: New test.
2003-01-29 Kriang Lerdsuwanakij <lerdsuwa@users.sourceforge.net>
PR c++/8591

View file

@ -0,0 +1,13 @@
void f () {
switch (0) {
case (3, 0): // { dg-error "" }
break;
}
}
int g ();
struct S {
int i : (false ? g () : 1); // { dg-error "" }
};

View file

@ -1,3 +1,15 @@
2003-01-29 Mark Mitchell <mark@codesourcery.com>
* include/std/std_limits.h (numeric_limits<float>::has_infinity):
Use __FLT_HAS_INIFINITY__ to initialize.
(numeric_limits<float>::has_quiet_NaN): Likewise.
(numeric_limits<double>::has_infinity): Use __DBL_HAS_INIFINITY__
to initialize.
(numeric_limits<double>::has_quiet_NaN): Likewise.
(numeric_limits<long double>::has_infinity): Use
__LDBL_HAS_INIFINITY__ to initialize.
(numeric_limits<long_double>::has_quiet_NaN): Likewise.
2003-01-28 Nathan Sidwell <nathan@codesourcery.com>
PR c++/9433

View file

@ -1,6 +1,6 @@
// The template and inlines for the -*- C++ -*- numeric_limits classes.
// Copyright (C) 1999, 2000, 2001, 2002 Free Software Foundation, Inc.
// Copyright (C) 1999, 2000, 2001, 2002, 2003 Free Software Foundation, Inc.
//
// This file is part of the GNU ISO C++ Library. This library is free
// software; you can redistribute it and/or modify it under the
@ -893,10 +893,8 @@ namespace std
static const int max_exponent = __FLT_MAX_EXP__;
static const int max_exponent10 = __FLT_MAX_10_EXP__;
static const bool has_infinity
= __builtin_huge_valf () / 2 == __builtin_huge_valf ();
static const bool has_quiet_NaN
= __builtin_nanf ("") != __builtin_nanf ("");
static const bool has_infinity = __FLT_HAS_INFINITY__;
static const bool has_quiet_NaN = __FLT_HAS_QUIET_NAN__;
static const bool has_signaling_NaN = has_quiet_NaN;
static const float_denorm_style has_denorm
= __FLT_DENORM_MIN__ ? denorm_present : denorm_absent;
@ -951,10 +949,8 @@ namespace std
static const int max_exponent = __DBL_MAX_EXP__;
static const int max_exponent10 = __DBL_MAX_10_EXP__;
static const bool has_infinity
= __builtin_huge_val () / 2 == __builtin_huge_val ();
static const bool has_quiet_NaN
= __builtin_nan ("") != __builtin_nan ("");
static const bool has_infinity = __DBL_HAS_INFINITY__;
static const bool has_quiet_NaN = __DBL_HAS_QUIET_NAN__;
static const bool has_signaling_NaN = has_quiet_NaN;
static const float_denorm_style has_denorm
= __DBL_DENORM_MIN__ ? denorm_present : denorm_absent;
@ -1009,10 +1005,8 @@ namespace std
static const int max_exponent = __LDBL_MAX_EXP__;
static const int max_exponent10 = __LDBL_MAX_10_EXP__;
static const bool has_infinity
= __builtin_huge_vall () / 2 == __builtin_huge_vall ();
static const bool has_quiet_NaN
= __builtin_nanl ("") != __builtin_nanl ("");
static const bool has_infinity = __LDBL_HAS_INFINITY__;
static const bool has_quiet_NaN = __LDBL_HAS_QUIET_NAN__;
static const bool has_signaling_NaN = has_quiet_NaN;
static const float_denorm_style has_denorm
= __LDBL_DENORM_MIN__ ? denorm_present : denorm_absent;