LAMBDA_EXPR_STATIC_P (in LAMBDA_EXPR)
TARGET_EXPR_ELIDING_P (in TARGET_EXPR)
contract_semantic (in ASSERTION_, PRECONDITION_, POSTCONDITION_STMT)
+ TYPENAME_IS_UNION_P (in TYPENAME_TYPE)
4: IDENTIFIER_MARKED (IDENTIFIER_NODEs)
TREE_HAS_CONSTRUCTOR (in INDIRECT_REF, SAVE_EXPR, CONSTRUCTOR,
CALL_EXPR, or FIELD_DECL).
#define NON_UNION_CLASS_TYPE_P(T) \
(TREE_CODE (T) == RECORD_TYPE && TYPE_LANG_FLAG_5 (T))
+/* Nonzero if T is a class type and is a union. */
+#define UNION_TYPE_P(T) \
+ (TREE_CODE (T) == UNION_TYPE && TYPE_LANG_FLAG_5 (T))
+
/* Keep these checks in ascending code order. */
#define RECORD_OR_UNION_CODE_P(T) \
((T) == RECORD_TYPE || (T) == UNION_TYPE)
#define TYPENAME_IS_ENUM_P(NODE) \
(TREE_LANG_FLAG_0 (TYPENAME_TYPE_CHECK (NODE)))
-/* True if a TYPENAME_TYPE was declared as a "class", "struct", or
- "union". */
+/* True if a TYPENAME_TYPE was declared as a "class" or "struct". */
#define TYPENAME_IS_CLASS_P(NODE) \
(TREE_LANG_FLAG_1 (TYPENAME_TYPE_CHECK (NODE)))
+/* True if a TYPENAME_TYPE was declared as a "union". */
+#define TYPENAME_IS_UNION_P(NODE) \
+ (TREE_LANG_FLAG_3 (TYPENAME_TYPE_CHECK (NODE)))
+
/* True if a TYPENAME_TYPE is in the process of being resolved. */
#define TYPENAME_IS_RESOLVING_P(NODE) \
(TREE_LANG_FLAG_2 (TYPENAME_TYPE_CHECK (NODE)))
tree template_id;
bool enum_p;
bool class_p;
+ bool union_p;
};
struct typename_hasher : ggc_ptr_hash<tree_node>
&& TYPE_CONTEXT (t1) == t2->scope
&& TYPENAME_TYPE_FULLNAME (t1) == t2->template_id
&& TYPENAME_IS_ENUM_P (t1) == t2->enum_p
- && TYPENAME_IS_CLASS_P (t1) == t2->class_p);
+ && TYPENAME_IS_CLASS_P (t1) == t2->class_p
+ && TYPENAME_IS_UNION_P (t1) == t2->union_p);
}
};
ti.name = name;
ti.template_id = fullname;
ti.enum_p = tag_type == enum_type;
- ti.class_p = (tag_type == class_type
- || tag_type == record_type
- || tag_type == union_type);
+ ti.class_p = (tag_type == class_type || tag_type == record_type);
+ ti.union_p = tag_type == union_type;
hashval_t hash = typename_hasher::hash (&ti);
/* See if we already have this type. */
TYPENAME_TYPE_FULLNAME (t) = ti.template_id;
TYPENAME_IS_ENUM_P (t) = ti.enum_p;
TYPENAME_IS_CLASS_P (t) = ti.class_p;
+ TYPENAME_IS_UNION_P (t) = ti.union_p;
/* Build the corresponding TYPE_DECL. */
tree d = build_decl (input_location, TYPE_DECL, name, t);
pp_cxx_ws_string (pp,
TYPENAME_IS_ENUM_P (t) ? "enum"
: TYPENAME_IS_CLASS_P (t) ? "class"
+ : TYPENAME_IS_UNION_P (t) ? "union"
: "typename");
dump_typename (pp, t, flags);
break;
tag_type = enum_type;
else if (TYPENAME_IS_CLASS_P (type))
tag_type = class_type;
+ else if (TYPENAME_IS_UNION_P (type))
+ tag_type = union_type;
u (int (tag_type));
}
}
return;
bool seen_as_union = TREE_CODE (type) == UNION_TYPE;
- if (seen_as_union != (class_key == union_type))
+ if (class_key != typename_type
+ && TREE_CODE (type) != TYPENAME_TYPE
+ && seen_as_union != (class_key == union_type))
{
auto_diagnostic_group d;
if (permerror (input_location, "%qs tag used in naming %q#T",
return error_mark_node;
}
- /* FIXME: TYPENAME_IS_CLASS_P conflates 'class' vs 'struct' vs 'union'
- tags. TYPENAME_TYPE should probably remember the exact tag that
- was written. */
+ /* FIXME: TYPENAME_IS_CLASS_P conflates 'class' vs 'struct' tags.
+ TYPENAME_TYPE should probably remember the exact tag that
+ was written for -Wmismatched-tags. */
enum tag_types tag_type
- = TYPENAME_IS_CLASS_P (t) ? class_type
- : TYPENAME_IS_ENUM_P (t) ? enum_type
- : typename_type;
+ = (TYPENAME_IS_CLASS_P (t) ? class_type
+ : TYPENAME_IS_UNION_P (t) ? union_type
+ : TYPENAME_IS_ENUM_P (t) ? enum_type
+ : typename_type);
tsubst_flags_t tcomplain = complain | tf_keep_type_decl;
tcomplain |= tst_ok_flag | qualifying_scope_flag;
f = make_typename_type (ctx, f, tag_type, tcomplain);
else
return error_mark_node;
}
- else if (TYPENAME_IS_CLASS_P (t) && !CLASS_TYPE_P (f))
+ else if (TYPENAME_IS_CLASS_P (t) && !NON_UNION_CLASS_TYPE_P (f))
{
if (complain & tf_error)
- error ("%qT resolves to %qT, which is not a class type",
+ error ("%qT resolves to %qT, which is not a non-union "
+ "class type", t, f);
+ else
+ return error_mark_node;
+ }
+ else if (TYPENAME_IS_UNION_P (t) && !UNION_TYPE_P (f))
+ {
+ if (complain & tf_error)
+ error ("%qT resolves to %qT, which is not a union type",
t, f);
else
return error_mark_node;
--- /dev/null
+// PR c++/83469
+// { dg-do compile }
+
+struct S {
+ union U { int m; };
+};
+
+template <typename T>
+void
+f ()
+{
+ union T::U u;
+}
+
+int
+main()
+{
+ f<S>();
+}
--- /dev/null
+// PR c++/83469
+// { dg-do compile }
+
+struct S {
+ union U { int m; };
+};
+
+template <typename T>
+void
+f ()
+{
+ struct T::U u; // { dg-error "not a non-union class type" }
+}
+
+int
+main()
+{
+ f<S>();
+}
--- /dev/null
+// PR c++/83469
+// { dg-do compile }
+
+struct S {
+ struct C { int m; };
+};
+
+template <typename T>
+void
+f ()
+{
+ union T::C u; // { dg-error "not a union type" }
+}
+
+int
+main()
+{
+ f<S>();
+}
--- /dev/null
+// PR c++/93809
+// { dg-do compile }
+
+class C { };
+enum E { };
+struct S { };
+union U { };
+
+typedef typename ::C C2;
+typedef typename ::E E2;
+typedef typename ::S S2;
+typedef typename ::U U2;
--- /dev/null
+// PR c++/93809
+// { dg-do compile { target c++11 } }
+
+union U {};
+auto var = new (typename ::U);
--- /dev/null
+// PR c++/93809
+// { dg-do compile }
+
+typedef union{} U;
+typename ::U foo () { return U(); }
template < typename T >
struct enable_if< true, T >::type
-f( T x ); // { dg-error "not a class type" }
+f( T x ); // { dg-error "not a non-union class type" }
void
g( void )
N::U u1;
typename N::U u2; // { dg-bogus "-Wredundant-tags" }
- // { dg-bogus "'class' tag used in naming 'union N::U" "pr93809" { xfail *-*-*} .-1 }
+ // { dg-bogus "'class' tag used in naming 'union N::U" "pr93809" { target *-*-*} .-1 }
union N::U u3; // { dg-warning "-Wredundant-tags" }