before this function is called. */
static tree
-fixed_type_or_null (tree instance, int* nonnull, int* cdtorp)
+fixed_type_or_null (tree instance, int *nonnull, int *cdtorp)
{
+#define RECUR(T) fixed_type_or_null((T), nonnull, cdtorp)
+
switch (TREE_CODE (instance))
{
case INDIRECT_REF:
if (POINTER_TYPE_P (TREE_TYPE (instance)))
return NULL_TREE;
else
- return fixed_type_or_null (TREE_OPERAND (instance, 0),
- nonnull, cdtorp);
+ return RECUR (TREE_OPERAND (instance, 0));
case CALL_EXPR:
/* This is a call to a constructor, hence it's never zero. */
*nonnull = 1;
return TREE_TYPE (instance);
}
- return fixed_type_or_null (TREE_OPERAND (instance, 0), nonnull, cdtorp);
+ return RECUR (TREE_OPERAND (instance, 0));
case PLUS_EXPR:
case MINUS_EXPR:
if (TREE_CODE (TREE_OPERAND (instance, 0)) == ADDR_EXPR)
- return fixed_type_or_null (TREE_OPERAND (instance, 0), nonnull, cdtorp);
+ return RECUR (TREE_OPERAND (instance, 0));
if (TREE_CODE (TREE_OPERAND (instance, 1)) == INTEGER_CST)
/* Propagate nonnull. */
- return fixed_type_or_null (TREE_OPERAND (instance, 0), nonnull, cdtorp);
+ return RECUR (TREE_OPERAND (instance, 0));
+
return NULL_TREE;
case NOP_EXPR:
case CONVERT_EXPR:
- return fixed_type_or_null (TREE_OPERAND (instance, 0), nonnull, cdtorp);
+ return RECUR (TREE_OPERAND (instance, 0));
case ADDR_EXPR:
instance = TREE_OPERAND (instance, 0);
if (t && DECL_P (t))
*nonnull = 1;
}
- return fixed_type_or_null (instance, nonnull, cdtorp);
+ return RECUR (instance);
case COMPONENT_REF:
/* If this component is really a base class reference, then the field
itself isn't definitive. */
if (DECL_FIELD_IS_BASE (TREE_OPERAND (instance, 1)))
- return fixed_type_or_null (TREE_OPERAND (instance, 0), nonnull, cdtorp);
- return fixed_type_or_null (TREE_OPERAND (instance, 1), nonnull, cdtorp);
+ return RECUR (TREE_OPERAND (instance, 0));
+ return RECUR (TREE_OPERAND (instance, 1));
case VAR_DECL:
case FIELD_DECL:
}
else if (TREE_CODE (TREE_TYPE (instance)) == REFERENCE_TYPE)
{
+ /* We only need one hash table because it is always left empty. */
+ static htab_t ht;
+ if (!ht)
+ ht = htab_create (37,
+ htab_hash_pointer,
+ htab_eq_pointer,
+ /*htab_del=*/NULL);
+
/* Reference variables should be references to objects. */
if (nonnull)
*nonnull = 1;
- /* DECL_VAR_MARKED_P is used to prevent recursion; a
+ /* Enter the INSTANCE in a table to prevent recursion; a
variable's initializer may refer to the variable
itself. */
if (TREE_CODE (instance) == VAR_DECL
&& DECL_INITIAL (instance)
- && !DECL_VAR_MARKED_P (instance))
+ && !htab_find (ht, instance))
{
tree type;
- DECL_VAR_MARKED_P (instance) = 1;
- type = fixed_type_or_null (DECL_INITIAL (instance),
- nonnull, cdtorp);
- DECL_VAR_MARKED_P (instance) = 0;
+ void **slot;
+
+ slot = htab_find_slot (ht, instance, INSERT);
+ *slot = instance;
+ type = RECUR (DECL_INITIAL (instance));
+ htab_clear_slot (ht, slot);
+
return type;
}
}
default:
return NULL_TREE;
}
+#undef RECUR
}
/* Return nonzero if the dynamic type of INSTANCE is known, and
{
tree t = TREE_TYPE (instance);
int cdtorp = 0;
-
tree fixed = fixed_type_or_null (instance, nonnull, &cdtorp);
if (fixed == NULL_TREE)
return 0;
DECL_IMPLICIT_TYPEDEF_P (in a TYPE_DECL)
3: DECL_IN_AGGR_P.
4: DECL_C_BIT_FIELD (in a FIELD_DECL)
- DECL_VAR_MARKED_P (in a VAR_DECL)
+ DECL_ANON_UNION_VAR_P (in a VAR_DECL)
DECL_SELF_REFERENCE_P (in a TYPE_DECL)
DECL_INVALID_OVERRIDER_P (in a FUNCTION_DECL)
5: DECL_INTERFACE_KNOWN.
(DECL_LANG_SPECIFIC (VAR_TEMPL_TYPE_OR_FUNCTION_DECL_CHECK (NODE)) \
->decl_flags.u.template_info)
-/* For a VAR_DECL, indicates that the variable has been processed.
- This flag is set and unset throughout the code; it is always
- used for a temporary purpose. */
-#define DECL_VAR_MARKED_P(NODE) \
+/* For a VAR_DECL, indicates that the variable is actually a
+ non-static data member of anonymous union that has been promoted to
+ variable status. */
+#define DECL_ANON_UNION_VAR_P(NODE) \
(DECL_LANG_FLAG_4 (VAR_DECL_CHECK (NODE)))
/* Template information for a RECORD_TYPE or UNION_TYPE. */
}
else if (toplevel_bindings_p () || DECL_NAMESPACE_SCOPE_P (newdecl))
{
- /* Objects declared at top level: */
- /* If at least one is a reference, it's ok. */
+ /* The objects have been declared at namespace scope. If either
+ is a member of an anonymous union, then this is an invalid
+ redeclaration. For example:
+
+ int i;
+ union { int i; };
+
+ is invalid. */
+ if (DECL_ANON_UNION_VAR_P (newdecl)
+ || DECL_ANON_UNION_VAR_P (olddecl))
+ return "redeclaration of %q#D";
+ /* If at least one declaration is a reference, there is no
+ conflict. For example:
+
+ int i = 3;
+ extern int i;
+
+ is valid. */
if (DECL_EXTERNAL (newdecl) || DECL_EXTERNAL (olddecl))
return NULL;
/* Reject two definitions. */