[PATCH gcc/* v3 2/2] gcc: stop using 'int' to represent sets of qualifiers
Arsen Arsenović
aarsenovic@baylibre.com
Sat Sep 5 13:07:42 GMT 2026
The set of all qualifiers present on a type consists of the const,
volatile, restrict and atomic qualification, which may be either present
or absent, and the address space qualifier, which may be one of many
values (one of which is the "generic" address space, present on all
platforms, used in absence of another address space; it is also the
address space qualifier on which all standard library routines operate).
For the former four, 'int' serves us okay; using ints as sets is a
well-understood pattern (but it leads to problems like those described
here when those ints cease to be sets). Since they're either present or
absent, treating an int as a bit-set is convenient and simple. But,
with the introduction of address space qualifiers into the mix, the
semantics of these operators becomes incorrect.
Take, for instance, the following line of code:
quals_union = quals1 | quals2;
... (where quals1, quals2 are TYPE_QUALS of some types)
Only in cases where DECODE_QUAL_ADDR_SPACE (quals1) ==
DECODE_QUAL_ADDR_SPACE (quals2), or where one of those address spaces is
generic, and the other a super/subset of the generic address space, does
this yields what the author intended. In all other cases, the operation
above yields subtly incorrect results, while the compiler is (naturally)
silent about it.
This issue is not theoretical either. In the implementation of the C++
Named Address Spaces support currently being worked on and discussed on
the mailing list[2], the following broken testcase arose (for the GCN
target; __flat address space is AS1, __lds is AS2, and __gds is AS3;
__flat is a superset address space to __lds):
template<typename T>
__flat T *
foo ();
void
bar ()
{ **foo<__lds int> (); }
The above testcase produces the diagnostic:
<stdin>:1:52: error: invalid type argument of unary '*' (have '__gds int')
It is obvious how this came about: the frontend used '|' to merge two
sets of qualifiers, presuming that such a merge can never fail, because
the union of two sets is a valid and complete function, and that the
bit-OR of these two bitsets is the union of the corresponding two sets
of qualifiers.
However, this is not so: with the introduction of address spaces, the
union of two sets of qualifiers ceases to coincide with the bit-OR
operator, and the union becomes a partial function.
To demonstrate the former, we can use the testcase above. In it, the
C++ frontend was trying to take the union of the qualifier sets {__lds}
and {__flat}. These were previously represented as 0x0100 and 0x0200.
Ergo, the result of the bit-op was 0x0300.
0x0300 corresponds to the qualifier set {__gds}. This is how we got the
bad diagnostic above. This is an instance of the "bit-OR no longer
coincides with set union (except by accident)" problem; the union of
those two sets (in most cases, anyway) is {__flat}.
But, even if we were to fix this initial problem, we still have the
problem of the union of qualifier sets becoming a partial function.
This one can be demonstrated in C, as the C frontend already deals with
this problem in an ad-hoc fashion.
In the following case, the __lds and __global address spaces are
distinct (though they are both subsets of the __flat address space):
typedef __lds int lds_int;
void foo (__global lds_int *x);
... the C frontend issues the diagnostic:
<stdin>:2:31: error: conflicting named address spaces (__global vs __lds)
It had to do so because the union of the qualifier sets {__lds} and
{__global} for the purposes of this declaration does not exist.[1]
The way the C FE handles this is ad-hoc: in 'grokdeclarator', it has a
specific check that covers this case:
if (!ADDR_SPACE_GENERIC_P (as1) && !ADDR_SPACE_GENERIC_P (as2) && as1 != as2)
error_at (loc, "conflicting named address spaces (%s vs %s)",
c_addr_space_name (as1), c_addr_space_name (as2));
Thus, it is quite easy for developers to forget this check.
What's worse, there is a lot of existing code that presumes that the set
of qualifiers is actually the set of the four "simple" present/absent
qualifier (CVRA). If that presumption changes, there's no way to
diagnose all sites where this presumption is now broken (as it is in the
C++ NAS support patch).
The C++ type system is completely capable of encoding the restrictions
above, and ergo diagnosing misuse. Making use of that is the goal of
this patch.
First, we make a distinction between cv_qualifier and qualifier_set, as
many frontends do not care about anything but the cv-qualifiers, and
because the former have operations not applicable to the latter.
The former models the CVRA qualifiers, which are either present or
absent.
In this revision, I left it as an unscoped enum, but fixed its
underlying type as 'unsigned char' (so that its size is known to be less
than that of qualifier_set). It may be desirable to make it an enum
class, to forbid the usage of operators like + on it. This is a lower
priority since there's no existing code that does so.
The latter (qualifier_set) models the set of all qualifiers, i.e. CVRA +
the address space qualifier (at the moment).
The interesting bits of the patch are in tree-core.h and tree.h. These
two provide the new types and matching helper functions. It may be
worth breaking them out into bits-style headers, though. I've tried to
curb the growth of those headers too much, but the constexpr operators
and functions were actually needed a few times.
For cv_qualifiers, I've provided binary bitwise operations, in order to
inhibit integer promotion. This makes it so that manual casting isn't
necessary when using cv_qualifier values.
For qualifier_set, tree.h lost operations that were made redundant/wrong
by the change. In their place, I've provided functions for modifying
and reading qualifier_set values.
Note, however, the decision to drop operator& for qualifier_sets. As it
turns out, many places in the codebase used patterns like 'q & ~p' to
remove qualifier P from set Q, but this became incorrect, as it loses
the address space qualifier also.
This operation was also often used for simple presence checks, by simply
checking 'q & p', so I initially made operator& return 'bool', but this
turned out to silently change the meaning of some existing code, where
a pattern like 'int cqual = q & TYPE_QUALS_CONST' appeared.
Hence, I decided it is better not to provide this operator as it opens
the possibility for easy misuse, and because 'without', 'intercept' and
'has' are quite short anyway.
Qualifier sets may be decomposed into (currently) a pair, that may be
destructured via std::tie. This was provided as such to allow inducing
errors should a new component ever appear on qualifiers sets, even
though this is quite an unlikely eventuality. In essence, should
qualifier sets grow to contain one more member, all the places that do:
std::tie (cvquals, addrspace) = quals.split ();
... would yell, letting us know what to fix.
The qualifier set type is 16 bits, and trivially copyable and
destructible, and so, fits into registers on most machines. Most of the
operations on the qualifier set type are also provided as constexpr
functions, and so, should be very easy for the compiler to optimize
away.
The two union operations provided for qualifier sets now are merge and
join. These differ in that the former is apt for finding qualification
that can be used in common for two objects, and that the latter can be
used to add qualification to an existing qualifier set
"syntactically" (i.e. as if the keywords were just added to the original
source code from which the qualifier set was constructed). These two
operations were most common in the C++ frontend, especially the latter.
This version of the patch does not extensively refactor the C frontend
to utilize the new operations; since it is a blocker for the C++ Named
Address Spaces support, I didn't prioritize that.
Reg-strapped on x86_64-linux-gnu, powerpc64le-linux-gnu, and
(currently being) tested on amdgcn-amdhsa and s390x-ibm-linux-gnu.
Build-tested for rl78-elf.
No functional changes intended.
[1] Note that there's actually a few distinct union operations that
could exist, depending on the context. For instance, one would
expect '__AS1 some_typedef', where 'some_typedef' is in the generic
address space, to always be acceptable in a declaration, but, for
two values __AS1 T* p1 and T* pG, the expression cond ? p1 : pG is
not acceptable if __AS1 is not subset of the generic address space
or vice-versa, despite both performing something that can be
described as a qualifier-set union of {__AS1} and {}.
[2] https://inbox.sourceware.org/gcc-patches/87zf2098ah.fsf@euler.schwinge.ddns.net/
gcc/ada/ChangeLog:
* gcc-interface/decl.cc (gnat_to_gnu_entity): Update uses of
qualifiers not to use 'int'.
(gnat_to_gnu_component_type): Ditto.
* gcc-interface/gigi.h (ada_type_quals): New. Helper function
returning qualifiers for a type relevant to Ada.
(change_qualified_type): Update not to use 'int' for qualifiers.
* gcc-interface/utils.cc (update_pointer_to): Use ada_type_quals
instead of TYPE_QUALS.
gcc/ChangeLog:
* attribs.cc (decl_attributes): Update to use qualifier_sets
instead of ints for qualifiers.
(build_type_attribute_qual_variant): Ditto.
(attr_access::array_as_string): Ditto.
* attribs.h (build_type_attribute_qual_variant): Ditto.
* config/aarch64/aarch64-acle-builtins.cc
(function_resolver::infer_pointer_type): Use TYPE_UNQUALIFIED
instead of zero literal.
* config/arm/arm-c.cc (arm_resolve_cde_builtin): Use
TYPE_UNQUALIFIED instead of zero literal.
* config/arm/arm-mve-builtins.cc
(function_resolver::infer_pointer_type): Use TYPE_UNQUALIFIED
instead of zero literal.
* config/gcn/gcn-tree.cc (gcn_goacc_get_worker_red_decl): Update
not to use 'int' for qualifiers, and to use new qualifier_set
APIs.
(gcn_goacc_adjust_private_decl): Ditto.
(gcn_goacc_create_worker_broadcast_record): Ditto.
* config/i386/i386-builtins.cc (ix86_get_builtin_type): Use
cv_qualifier instead of 'int' when dealing with qualifiers.
* config/i386/i386.cc (ix86_stack_protect_guard): Update
not to use 'int' for qualifiers, and to use new qualifier_set
APIs.
* config/rl78/rl78.cc (rl78_insert_attributes): Update
not to use 'int' for qualifiers, and to use new qualifier_set
APIs.
* config/rs6000/rs6000-c.cc (altivec_resolve_overloaded_builtin):
Update not to use 'int' for qualifiers, and to use new
qualifier_set APIs.
* config/s390/s390-c.cc (s390_fn_types_compatible): Update to
use new qualifier APIs.
* coretypes.h (ADDR_SPACE_GENERIC): Make sure the constant is of
type addr_space_t.
* dwarf2out.cc (decl_quals): Use cv_qualifier instead of 'int'
for qualifiers.
(modified_type_die): Ditto.
(add_type_attribute): Ditto.
(subrange_type_die): Ditto.
(get_nearest_type_subqualifiers): Ditto.
(struct dwarf_qual_info_t): Ditto.
(qualified_die_p): Ditto.
(override_type_for_decl_p): Ditto.
* gimple-lower-bitint.cc (bitint_large_huge::limb_access): Use
new qualifier_set APIs.
(bitint_large_huge::build_bit_field_ref): Ditto.
(bitint_large_huge::lower_stmt): Ditto.
* gimplify.cc: Use new qualifier_set APIs.
* ipa-free-lang-data.cc (free_lang_data_in_type): Use new
qualifier_set APIs.
* langhooks.h (struct qualifier_set): Forward-declare.
(struct lang_hooks_for_tree_dump): Make TYPE_QUALS return
qualifier_set.
* langhooks-def.h (lhd_tree_dump_type_quals): Update signature
to match above change.
* langhooks.cc (lhd_tree_dump_dump_tree): Ditto.
* omp-low.cc (install_var_field): Update to use new
qualifier_set APIs.
* omp-oacc-neuter-broadcast.cc (install_var_field): Update to
use new qualifier_set APIs.
* omp-offload.cc (oacc_rewrite_var_decl): Update to use new
qualifier_set APIs.
* tree-core.h: Add C++ mode-line.
(tree_base): Use addr_space_t for 'address_space', to prevent
Wnarrowing.
(enum cv_qualifier): Set underlying type to 'unsigned char'.
(TYPE_QUAL_ALL): New. Mask of all elements of cv_qualifier.
(operator|): New. Returns union of two CV-qualifier sets.
(operator|=): New. As above, but mutates LHS.
(operator&): New. Returns intersection of two CV-qualifier
sets.
(operator&=): New. As above, but mutates LHS.
(operator^): New. Returns symmetric difference of two
CV-qualifier sets.
(operator^=): New. As above, but mutates LHS.
(operator~): New. Flips state of all CV-qualifiers from present
to absent in a CV-qualifier set and vice-versa, returning a new
CV-qualifier set.
* tree-dump.cc (dequeue_and_dump): Update to use new qualifier
set APIs, and handle address spaces.
* tree-pretty-print.cc (dump_generic_node): Update to use new
qualifier set APIs.
* tree-profile.cc (tree_profiling): Update to use new qualifier
set APIs.
* tree-sra.cc (build_ref_for_offset): Update to use new
qualifier set APIs.
* tree-ssa-address.cc (move_hint_to_base): Update to use new
qualifier set APIs.
* tree-switch-conversion.cc (switch_conversion::build_one_array):
Update to use new qualifier set APIs.
* tree-vect-stmts.cc (get_related_vectype_for_scalar_type):
Update to use new qualifier set APIs.
* tree.cc (set_type_quals): Update to use qualifier_set instead
of 'int'.
(qualifier_set::merge): New.
(qualifier_set::join): New.
(qualifier_set::compatible_with): New.
(qualifier_set::debug): New.
(check_base_type): Update to use new qualifier_set APIs.
(check_qualified_type): Ditto.
(get_qualified_type): Ditto.
(build_qualified_type): Ditto.
* tree.h (ENCODE_QUAL_ADDR_SPACE): Drop.
(DECODE_QUAL_ADDR_SPACE): Drop.
(CLEAR_QUAL_ADDR_SPACE): Drop.
(KEEP_QUAL_ADDR_SPACE): Drop.
(struct qualifier_set): New. Provides a representation for a
set of CV-qualifiers and an address space qualifier, as well as
various operations that pertain to such sets.
(TYPE_QUALS): Update to produce a qualifier_set.
(operator|): New. Convenience operator for adding CV-qualifiers
to a qualifier_set.
(operator|=): New. Like the above, but mutates LHS.
(operator^): New. Convenience operator for taking the symmetric
difference between a qualifier_set and a CV-qualifier set.
(operator^=): New. Like the above, but mutates LHS.
(TYPE_QUALS_NO_ADDR_SPACE): Update to produce cv_qualifier.
(TYPE_QUALS_NO_ADDR_SPACE_NO_ATOMIC): Ditto.
(check_qualified_type): Update signature to use qualifier_set
instead of ints.
(get_qualified_type): Ditto.
(build_qualified_type): Ditto.
(build_type_variant): Ditto.
* ubsan.cc (instrument_bool_enum_load): Update to use new
qualifier set APIs.
* vtable-verify.cc (vtbl_map_get_node): Update to use new
qualifier set APIs.
(find_or_create_vtbl_map_node): Ditto.
* doc/generic.texi (Types): Move information about
qualification...
(Qualifier Representation): ... to this new node. Document how
qualifiers are represented.
(cv_qualifier): New node. Document the cv_qualifier type.
(qualifier_set): New node. Document the qualifier_set type.
(Avoiding qualifier_set): New node. Document how do avoid the
extra complexity of qualifier_set, and how to later get it back.
(Types for C++): Remove non-applicable index entries. Reword
documentation for cp_type_quals to reference the nodes above
where applicable.
gcc/c-family/ChangeLog:
* c-ada-spec.cc (dump_ada_node): Update to use new qualifier set
APIs.
* c-common.cc (c_apply_type_quals_to_decl): Update to receive
cv_qualifier.
(complete_array_type): Use qualifier_set instead of 'int' for
sets of qualifiers.
(get_atomic_generic_size): Update to use new qualifier set APIs.
* c-common.h (c_apply_type_quals_to_decl): Update to receive
cv_qualifier. Provide an overload that takes a qualifier_set as
convenience.
(c_build_qualified_type): Update to receive qualifier_set
instead of an int.
* c-format.cc (deref_n_times): Use TYPE_UNQUALIFIED instead of
constant zero.
* c-pretty-print.cc (pp_c_cv_qualifiers): Update to receive
cv_qualifier.
(pp_c_type_qualifier_list): Stop using 'int' for CV-qualifier
sets.
(c_pretty_printer::direct_abstract_declarator): Ditto.
* c-pretty-print.h (pp_c_cv_qualifiers): Update to receive
cv_qualifier.
gcc/c/ChangeLog:
* c-decl.cc (diagnose_mismatched_decls): Ditto.
(quals_from_declspecs): Update to return qualifier sets.
(build_array_declarator): Use qualifier_set instead of ints.
(diagnose_uninitialized_cst_member): Update to use new
qualifier_set APIs.
(grokdeclarator): Ditto.
(get_parm_info): Update to use new qualifier_set APIs.
(c_update_type_canonical): Ditto.
(finish_struct): Ditto.
(make_pointer_declarator): Use qualifier_set instead of ints.
* c-objc-common.cc (c_tree_printer): Convert %v arg to
cv_qualifier.
* c-parser.cc (c_parser_typeof_specifier): Ditto.
(c_parser_postfix_expression_after_paren_type): Ditto.
* c-tree.h (struct c_declarator): Update to use qualifier_set
instead of ints.
(quals_from_declspecs): Update to use qualifier_set.
* c-typeck.cc (qualify_type): Update to use new qualifier_set
APIs.
(c_build_type_attribute_qual_variant): Update to use
qualifier_set.
(composite_type_internal): Ditto.
(common_pointer_type): Ditto.
(c_common_type): Ditto.
(function_types_compatible_p): Ditto.
(build_component_ref): Ditto.
(build_unary_op): Ditto.
(build_conditional_expr): Ditto.
(handle_warn_cast_qual): Ditto.
(convert_for_assignment): Ditto.
(build_binary_op): Ditto.
(c_build_qualified_type): Ditto.
gcc/cp/ChangeLog:
* call.cc (strip_top_quals): Use TYPE_UNQUALIFIED instead of 0.
(standard_conversion): Update to use qualifier_set APIs.
* class.cc (build_simple_base_path): Update to use qualifier_set
instead of int.
* cp-objcp-common.h (cp_type_quals_as_set): New.
(LANG_HOOKS_TREE_DUMP_TYPE_QUALS_FN): Use the above.
* cp-objcp-common.cc (cp_type_quals_as_set): New. Wraps
cp_type_quals, to converting its cv_qualifier to qualifier_set.
* cp-tree.h (cp_cv_quals): Change to be cv_qualifier.
(build_stub_type): Update to receive cv_qualifier.
(cp_build_qualified_type): Ditto.
(cp_type_quals): Update to return cv_qualifier.
(type_memfn_quals): Ditto.
(cp_apply_type_quals_to_decl): Update to take cv_qualifier.
* decl.cc (get_type_quals): Update to use and return
cv_qualifier.
(cp_finish_decomp): Replace usages of TYPE_QUALS with
cp_type_quals.
(grokdeclarator): Update to use cv_qualifier.
(grokparms): Use TYPE_UNQUALIFIED instead of literal zero.
* error.cc (dump_lambda_function): Update to use qualifier_set
APIs.
* mangle.cc (write_CV_qualifiers_for_type): Ditto.
* method.cc (do_build_copy_constructor): Update to use
cv_qualifier instead of int.
(do_build_copy_assign): Ditto.
(build_stub_type): Update to receive cv_qualifier.
(get_copy_ctor): Update to use cv_qualifier instead of int.
(get_copy_assign): Ditto.
(walk_field_subobs): Update to receive cv_qualifier.
(synthesized_method_base_walk): Ditto.
(synthesized_method_walk): Ditto.
(implicitly_declare_fn): Update to use cv_qualifier.
* module.cc (trees_in::tree_node): Cast read-in qualifiers to
cv_qualifier.
* pt.cc (tsubst): Update to use cv_qualifier instead of int.
(resolve_typename_type): Ditto.
* reflect.cc (type_of): Ditto.
(eval_remove_volatile): Ditto.
(eval_add_const): Ditto.
(eval_add_volatile): Ditto.
(eval_add_cv): Ditto.
(eval_make_signed): Ditto.
* semantics.cc (finish_non_static_data_member): Ditto.
(finish_decltype_type): Ditto.
* tree.cc (c_build_qualified_type): Update to receive
qualifier_set, in line with original.
(cp_build_qualified_type): Update to receive qualifier_set.
(cp_check_qualified_type): Update to receive cv_qualifier.
(cv_unqualified): Update to use cv_qualifier.
(build_cp_fntype_variant): Ditto.
(maybe_dummy_object): Ditto.
* typeck.cc (original_type): Ditto.
(composite_pointer_type_r): Ditto.
(merge_types): Ditto.
(build_class_member_access_expr): Ditto.
(cp_type_quals): Update to return cv_qualifier.
(type_memfn_quals): Ditto.
(cp_apply_type_quals_to_decl): Update to receive cv_qualifier.
(casts_away_constness_r): Use cv_qualifier instead of int for
representing CV-qualification.
gcc/d/ChangeLog:
* d-codegen.cc (build_vthis_function): Update to use new
qualifier_set APIs.
* types.cc (insert_type_modifiers): Use cv_qualifier instead
of int.
gcc/fortran/ChangeLog:
* trans-openmp.cc (gfc_omp_finish_clause): Update to use new
qualifier_set APIs.
* trans-types.cc (gfc_nonrestricted_type): Ditto.
gcc/jit/ChangeLog:
* dummy-frontend.cc (tree_type_to_jit_type):Update to use new
qualifier_set APIs.
gcc/objc/ChangeLog:
* objc-act.cc (objc_push_parm): Use TYPE_QUALS instead of
inlining its definition.
gcc/rust/ChangeLog:
* backend/rust-tree.cc (rs_type_quals): Update to use and return
cv_qualifier.
(type_memfn_quals): Ditto.
(rs_build_qualified_type_real): Update to receive and use
cv_qualifiers.
(cv_unqualified): Update to use cv_qualifier.
(strip_top_quals): Replace literal zero with TYPE_UNQUALIFIED.
* backend/rust-tree.h (rs_type_quals): Update to return
cv_qualifier.
(type_memfn_quals): Ditto.
(rs_build_qualified_type_real): Update to receive
cv_qualifier. Remove duplicate declaration.
(rs_build_qualified_type): Remove duplicate definition.
libcc1/ChangeLog:
* libcc1plugin.cc (plugin_build_qualified_type): Update to use
qualifier_set.
* libcp1plugin.cc (plugin_build_method_type): Fix up
initialization of cp_cv_quals.
(plugin_build_qualified_type): Ditto.
---
gcc/ada/gcc-interface/decl.cc | 15 +-
gcc/ada/gcc-interface/gigi.h | 14 +-
gcc/ada/gcc-interface/utils.cc | 3 +-
gcc/attribs.cc | 7 +-
gcc/attribs.h | 2 +-
gcc/c-family/c-ada-spec.cc | 6 +-
gcc/c-family/c-common.cc | 20 +-
gcc/c-family/c-common.h | 8 +-
gcc/c-family/c-format.cc | 2 +-
gcc/c-family/c-pretty-print.cc | 9 +-
gcc/c-family/c-pretty-print.h | 2 +-
gcc/c/c-decl.cc | 90 ++--
gcc/c/c-objc-common.cc | 4 +-
gcc/c/c-parser.cc | 8 +-
gcc/c/c-tree.h | 6 +-
gcc/c/c-typeck.cc | 84 ++--
gcc/config/aarch64/aarch64-acle-builtins.cc | 2 +-
gcc/config/arm/arm-c.cc | 3 +-
gcc/config/arm/arm-mve-builtins.cc | 2 +-
gcc/config/avr/avr.cc | 8 +-
gcc/config/gcn/gcn-tree.cc | 11 +-
gcc/config/i386/i386-builtins.cc | 2 +-
gcc/config/i386/i386.cc | 2 +-
gcc/config/rl78/rl78.cc | 2 +-
gcc/config/rs6000/rs6000-c.cc | 6 +-
gcc/config/s390/s390-c.cc | 6 +-
gcc/coretypes.h | 2 +-
gcc/cp/call.cc | 4 +-
gcc/cp/class.cc | 2 +-
gcc/cp/cp-objcp-common.cc | 7 +
gcc/cp/cp-objcp-common.h | 3 +-
gcc/cp/cp-tree.h | 12 +-
gcc/cp/decl.cc | 12 +-
gcc/cp/error.cc | 2 +-
gcc/cp/mangle.cc | 7 +-
gcc/cp/method.cc | 32 +-
gcc/cp/module.cc | 3 +-
gcc/cp/pt.cc | 11 +-
gcc/cp/reflect.cc | 12 +-
gcc/cp/semantics.cc | 4 +-
gcc/cp/tree.cc | 34 +-
gcc/cp/typeck.cc | 42 +-
gcc/d/d-codegen.cc | 2 +-
gcc/d/types.cc | 2 +-
gcc/doc/generic.texi | 460 +++++++++++++++++++-
gcc/dwarf2out.cc | 46 +-
gcc/fortran/trans-openmp.cc | 2 +-
gcc/fortran/trans-types.cc | 3 +-
gcc/gimple-lower-bitint.cc | 21 +-
gcc/gimplify.cc | 13 +-
gcc/ipa-free-lang-data.cc | 5 +-
gcc/jit/dummy-frontend.cc | 2 +-
gcc/langhooks-def.h | 2 +-
gcc/langhooks.cc | 2 +-
gcc/langhooks.h | 5 +-
gcc/objc/objc-act.cc | 6 +-
gcc/omp-low.cc | 4 +-
gcc/omp-oacc-neuter-broadcast.cc | 4 +-
gcc/omp-offload.cc | 15 +-
gcc/rust/backend/rust-tree.cc | 35 +-
gcc/rust/backend/rust-tree.h | 10 +-
gcc/tree-core.h | 74 +++-
gcc/tree-dump.cc | 7 +-
gcc/tree-pretty-print.cc | 14 +-
gcc/tree-profile.cc | 2 +-
gcc/tree-sra.cc | 3 +-
gcc/tree-ssa-address.cc | 3 +-
gcc/tree-switch-conversion.cc | 3 +-
gcc/tree-vect-stmts.cc | 3 +-
gcc/tree.cc | 180 +++++++-
gcc/tree.h | 282 ++++++++++--
gcc/ubsan.cc | 4 +-
gcc/vtable-verify.cc | 6 +-
libcc1/libcc1plugin.cc | 2 +-
libcc1/libcp1plugin.cc | 4 +-
75 files changed, 1343 insertions(+), 396 deletions(-)
diff --git a/gcc/ada/gcc-interface/decl.cc b/gcc/ada/gcc-interface/decl.cc
index be2df77fcfff..b444bc255d93 100644
--- a/gcc/ada/gcc-interface/decl.cc
+++ b/gcc/ada/gcc-interface/decl.cc
@@ -3045,9 +3045,10 @@ gnat_to_gnu_entity (Entity_Id gnat_entity, tree gnu_expr, bool definition)
process_attributes (&gnu_type, &attr_list, false, gnat_entity);
if (Treat_As_Volatile (gnat_entity))
{
- const int quals
+ const auto quals
= TYPE_QUAL_VOLATILE
- | (Is_Full_Access (gnat_entity) ? TYPE_QUAL_ATOMIC : 0);
+ | (Is_Full_Access (gnat_entity)
+ ? TYPE_QUAL_ATOMIC : TYPE_UNQUALIFIED);
gnu_type = change_qualified_type (gnu_type, quals);
}
/* Make it artificial only if the base type was artificial too.
@@ -4996,9 +4997,10 @@ gnat_to_gnu_entity (Entity_Id gnat_entity, tree gnu_expr, bool definition)
if (Treat_As_Volatile (gnat_entity)
&& !Is_Packed_Array_Impl_Type (gnat_entity))
{
- const int quals
+ const auto quals
= TYPE_QUAL_VOLATILE
- | (Is_Full_Access (gnat_entity) ? TYPE_QUAL_ATOMIC : 0);
+ | (Is_Full_Access (gnat_entity)
+ ? TYPE_QUAL_ATOMIC : TYPE_UNQUALIFIED);
/* This is required by free_lang_data_in_type to disable the ODR. */
if (TREE_CODE (gnu_type) == ENUMERAL_TYPE)
TYPE_STUB_DECL (gnu_type)
@@ -5670,9 +5672,10 @@ gnat_to_gnu_component_type (Entity_Id gnat_array, bool definition,
if (Has_Volatile_Components (gnat_array))
{
- const int quals
+ const auto quals
= TYPE_QUAL_VOLATILE
- | (Has_Atomic_Components (gnat_array) ? TYPE_QUAL_ATOMIC : 0);
+ | (Has_Atomic_Components (gnat_array)
+ ? TYPE_QUAL_ATOMIC : TYPE_UNQUALIFIED);
gnu_type = change_qualified_type (gnu_type, quals);
}
diff --git a/gcc/ada/gcc-interface/gigi.h b/gcc/ada/gcc-interface/gigi.h
index f4d791195187..3fd85debd9be 100644
--- a/gcc/ada/gcc-interface/gigi.h
+++ b/gcc/ada/gcc-interface/gigi.h
@@ -1248,11 +1248,23 @@ gnat_signed_type_for (tree type_node)
return gnat_signed_or_unsigned_type_for (0, type_node);
}
+/* Like TYPE_QUALS, but doesn't return qualifiers that GNAT doesn't use. */
+static inline cv_qualifier
+ada_type_quals (const_tree type)
+{
+ addr_space_t as;
+ cv_qualifier cv;
+ std::tie (cv, as) = TYPE_QUALS (type).split ();
+ /* Ada does not support address spaces (at the moment). */
+ gcc_assert (ADDR_SPACE_GENERIC_P (as));
+ return cv;
+}
+
/* Like build_qualified_type, but TYPE_QUALS is added to the existing
qualifiers on TYPE. */
static inline tree
-change_qualified_type (tree type, int type_quals)
+change_qualified_type (tree type, cv_qualifier type_quals)
{
/* Qualifiers must be put on the associated array type. */
if (TREE_CODE (type) == UNCONSTRAINED_ARRAY_TYPE)
diff --git a/gcc/ada/gcc-interface/utils.cc b/gcc/ada/gcc-interface/utils.cc
index f74b6361b404..81d53baa390b 100644
--- a/gcc/ada/gcc-interface/utils.cc
+++ b/gcc/ada/gcc-interface/utils.cc
@@ -4656,7 +4656,8 @@ update_pointer_to (tree old_type, tree new_type)
initial set, and will often end up with OLD_TYPE == NEW_TYPE then. */
new_type
= build_qualified_type (new_type,
- TYPE_QUALS (old_type) | TYPE_QUALS (new_type));
+ ada_type_quals (old_type)
+ | ada_type_quals (new_type));
/* If old type and new type are identical, there is nothing to do. */
if (old_type == new_type)
diff --git a/gcc/attribs.cc b/gcc/attribs.cc
index cd4be1bd6c5f..abb62fcb352d 100644
--- a/gcc/attribs.cc
+++ b/gcc/attribs.cc
@@ -726,7 +726,7 @@ decl_attributes (tree *node, tree attributes, int flags,
tree *anode = node;
const struct attribute_spec *spec
= lookup_scoped_attribute_spec (ns, name);
- int fn_ptr_quals = 0;
+ qualifier_set fn_ptr_quals {};
tree fn_ptr_tmp = NULL_TREE;
const bool cxx11_attr_p = cxx11_attribute_p (attr);
@@ -1307,7 +1307,8 @@ build_decl_attribute_variant (tree ddecl, tree attribute)
Record such modified types already made so we don't make duplicates. */
tree
-build_type_attribute_qual_variant (tree otype, tree attribute, int quals)
+build_type_attribute_qual_variant (tree otype, tree attribute,
+ qualifier_set quals)
{
tree ttype = otype;
if (! attribute_list_equal (TYPE_ATTRIBUTES (ttype), attribute))
@@ -2712,7 +2713,7 @@ attr_access::array_as_string (tree type) const
arat = build_tree_list (get_identifier ("array "), flag);
}
- const int quals = TYPE_QUALS (type);
+ const auto quals = TYPE_QUALS (type);
type = build_array_type (eltype, index_type);
type = build_type_attribute_qual_variant (type, arat, quals);
}
diff --git a/gcc/attribs.h b/gcc/attribs.h
index 9f9abc5e4c32..b3881d9a91e2 100644
--- a/gcc/attribs.h
+++ b/gcc/attribs.h
@@ -67,7 +67,7 @@ extern void handle_ignored_attributes_option (vec<char *> *);
extern tree build_type_attribute_variant (tree, tree);
extern tree build_decl_attribute_variant (tree, tree);
-extern tree build_type_attribute_qual_variant (tree, tree, int);
+extern tree build_type_attribute_qual_variant (tree, tree, qualifier_set);
extern bool simple_cst_list_equal (const_tree, const_tree);
extern bool attribute_value_equal (const_tree, const_tree);
diff --git a/gcc/c-family/c-ada-spec.cc b/gcc/c-family/c-ada-spec.cc
index b06f78742a0b..857c3c8711a3 100644
--- a/gcc/c-family/c-ada-spec.cc
+++ b/gcc/c-family/c-ada-spec.cc
@@ -2313,7 +2313,7 @@ dump_ada_node (pretty_printer *pp, tree node, tree type, int spc,
else
{
tree ref_type = TREE_TYPE (node);
- const unsigned int quals = TYPE_QUALS (ref_type);
+ const auto quals = TYPE_QUALS (ref_type);
bool is_access;
if (VOID_TYPE_P (ref_type))
@@ -2377,12 +2377,12 @@ dump_ada_node (pretty_printer *pp, tree node, tree type, int spc,
is_access = true;
pp_string (pp, "access ");
- if (quals & TYPE_QUAL_CONST)
+ if (quals.has (TYPE_QUAL_CONST))
pp_string (pp, "constant ");
else if (!name_only)
pp_string (pp, "all ");
}
- else if (quals & TYPE_QUAL_CONST)
+ else if (quals.has (TYPE_QUAL_CONST))
{
is_access = false;
pp_string (pp, "in ");
diff --git a/gcc/c-family/c-common.cc b/gcc/c-family/c-common.cc
index 6380bec4515d..ed259446b353 100644
--- a/gcc/c-family/c-common.cc
+++ b/gcc/c-family/c-common.cc
@@ -3876,7 +3876,7 @@ static void def_builtin_1 (enum built_in_function fncode,
/* Apply the TYPE_QUALS to the new DECL. */
void
-c_apply_type_quals_to_decl (int type_quals, tree decl)
+c_apply_type_quals_to_decl (cv_qualifier type_quals, tree decl)
{
tree type = TREE_TYPE (decl);
@@ -7354,7 +7354,8 @@ int
complete_array_type (tree *ptype, tree initial_value, bool do_default)
{
tree maxindex, type, main_type, elt, unqual_elt;
- int failure = 0, quals;
+ int failure = 0;
+ qualifier_set quals;
bool overflow_p = false;
maxindex = size_zero_node;
@@ -7448,10 +7449,13 @@ complete_array_type (tree *ptype, tree initial_value, bool do_default)
type = *ptype;
elt = TREE_TYPE (type);
quals = TYPE_QUALS (strip_array_types (elt));
- if (quals == 0)
+ if (!quals)
unqual_elt = elt;
else
- unqual_elt = c_build_qualified_type (elt, KEEP_QUAL_ADDR_SPACE (quals));
+ unqual_elt = c_build_qualified_type (elt,
+ /* Keep only the address space. */
+ {TYPE_UNQUALIFIED,
+ quals.addr_space ()});
/* Using build_distinct_type_copy and modifying things afterward instead
of using build_array_type to create a new type preserves all of the
@@ -7487,7 +7491,7 @@ complete_array_type (tree *ptype, tree initial_value, bool do_default)
TYPE_CANONICAL (TYPE_DOMAIN (main_type)),
TYPE_TYPELESS_STORAGE (main_type));
- if (quals == 0)
+ if (!quals)
type = main_type;
else
type = c_build_qualified_type (main_type, quals);
@@ -8021,9 +8025,9 @@ get_atomic_generic_size (location_t loc, tree function,
{
auto_diagnostic_group d;
- int quals = TYPE_QUALS (TREE_TYPE (type));
+ auto quals = TYPE_QUALS (TREE_TYPE (type));
/* Must not write to an argument of a const-qualified type. */
- if (outputs & (1 << x) && quals & TYPE_QUAL_CONST)
+ if (outputs & (1 << x) && quals.has (TYPE_QUAL_CONST))
{
if (c_dialect_cxx ())
{
@@ -8040,7 +8044,7 @@ get_atomic_generic_size (location_t loc, tree function,
function);
}
/* Only the first argument is allowed to be volatile. */
- if (x > 0 && quals & TYPE_QUAL_VOLATILE)
+ if (x > 0 && quals.has (TYPE_QUAL_VOLATILE))
{
if (c_dialect_cxx ())
{
diff --git a/gcc/c-family/c-common.h b/gcc/c-family/c-common.h
index 197db508c163..f9177b5239d3 100644
--- a/gcc/c-family/c-common.h
+++ b/gcc/c-family/c-common.h
@@ -897,7 +897,10 @@ extern bool decl_with_nonnull_addr_p (const_tree);
extern tree c_fully_fold (tree, bool, bool *, bool = false);
extern tree c_wrap_maybe_const (tree, bool);
extern tree c_common_truthvalue_conversion (location_t, tree);
-extern void c_apply_type_quals_to_decl (int, tree);
+extern void c_apply_type_quals_to_decl (cv_qualifier, tree);
+inline void
+c_apply_type_quals_to_decl (qualifier_set qs, tree decl)
+{ c_apply_type_quals_to_decl (qs.cv_quals (), decl); }
extern tree c_sizeof_or_alignof_type (location_t, tree, bool, bool, int);
extern tree c_alignof_expr (location_t, tree);
extern tree c_countof_type (location_t, tree);
@@ -975,7 +978,8 @@ extern tree pointer_int_sum (location_t, enum tree_code, tree, tree,
bool = true);
/* Add qualifiers to a type, in the fashion for C. */
-extern tree c_build_qualified_type (tree, int, tree = NULL_TREE, size_t = 0);
+extern tree c_build_qualified_type (tree, qualifier_set, tree = NULL_TREE,
+ size_t = 0);
/* Build tree nodes and builtin functions common to both C and C++ language
frontends. */
diff --git a/gcc/c-family/c-format.cc b/gcc/c-family/c-format.cc
index 1eb8f90747d5..baae9a3bc693 100644
--- a/gcc/c-family/c-format.cc
+++ b/gcc/c-family/c-format.cc
@@ -4391,7 +4391,7 @@ deref_n_times (tree type, int n)
type = TREE_TYPE (type);
}
/* Strip off any "const" etc. */
- return build_qualified_type (type, 0);
+ return build_qualified_type (type, TYPE_UNQUALIFIED);
}
/* Lookup the format code for FORMAT_LEN within FLI,
diff --git a/gcc/c-family/c-pretty-print.cc b/gcc/c-family/c-pretty-print.cc
index b084163e6a35..429134f68d02 100644
--- a/gcc/c-family/c-pretty-print.cc
+++ b/gcc/c-family/c-pretty-print.cc
@@ -168,7 +168,8 @@ pp_c_exclamation (c_pretty_printer *pp)
/* Print out the external representation of QUALIFIERS. */
void
-pp_c_cv_qualifiers (c_pretty_printer *pp, int qualifiers, bool func_type)
+pp_c_cv_qualifiers (c_pretty_printer *pp, cv_qualifier qualifiers,
+ bool func_type)
{
const char *p = pp_last_position_in_text (pp);
@@ -242,7 +243,7 @@ pp_c_space_for_pointer_operator (c_pretty_printer *pp, tree t)
void
pp_c_type_qualifier_list (c_pretty_printer *pp, tree t)
{
- int qualifiers;
+ cv_qualifier qualifiers;
if (!t || t == error_mark_node)
return;
@@ -252,7 +253,7 @@ pp_c_type_qualifier_list (c_pretty_printer *pp, tree t)
if (TREE_CODE (t) != ARRAY_TYPE)
{
- qualifiers = TYPE_QUALS (t);
+ qualifiers = TYPE_QUALS_NO_ADDR_SPACE (t);
pp_c_cv_qualifiers (pp, qualifiers,
TREE_CODE (t) == FUNCTION_TYPE);
}
@@ -627,7 +628,7 @@ c_pretty_printer::direct_abstract_declarator (tree t)
case ARRAY_TYPE:
pp_c_left_bracket (this);
- if (int quals = TYPE_QUALS (t))
+ if (auto quals = TYPE_QUALS_NO_ADDR_SPACE (t))
{
/* Print the array qualifiers such as in "T[const restrict 3]". */
pp_c_cv_qualifiers (this, quals, false);
diff --git a/gcc/c-family/c-pretty-print.h b/gcc/c-family/c-pretty-print.h
index 90ae3d033eed..de1dfccb8cbc 100644
--- a/gcc/c-family/c-pretty-print.h
+++ b/gcc/c-family/c-pretty-print.h
@@ -128,7 +128,7 @@ void pp_c_space_for_pointer_operator (c_pretty_printer *, tree);
void pp_c_tree_decl_identifier (c_pretty_printer *, tree);
void pp_c_function_definition (c_pretty_printer *, tree);
void pp_c_attributes_display (c_pretty_printer *, tree);
-void pp_c_cv_qualifiers (c_pretty_printer *pp, int qualifiers, bool func_type);
+void pp_c_cv_qualifiers (c_pretty_printer *pp, cv_qualifier, bool func_type);
void pp_c_type_qualifier_list (c_pretty_printer *, tree);
void pp_c_parameter_type_list (c_pretty_printer *, tree);
void pp_c_specifier_qualifier_list (c_pretty_printer *, tree);
diff --git a/gcc/c/c-decl.cc b/gcc/c/c-decl.cc
index 42d35a87a179..5fa8116f4956 100644
--- a/gcc/c/c-decl.cc
+++ b/gcc/c/c-decl.cc
@@ -2320,13 +2320,15 @@ diagnose_mismatched_decls (tree newdecl, tree olddecl,
}
else
{
- int new_quals = TYPE_QUALS (newtype);
- int old_quals = TYPE_QUALS (oldtype);
+ auto new_quals = TYPE_QUALS (newtype);
+ auto old_quals = TYPE_QUALS (oldtype);
if (new_quals != old_quals)
{
- addr_space_t new_addr = DECODE_QUAL_ADDR_SPACE (new_quals);
- addr_space_t old_addr = DECODE_QUAL_ADDR_SPACE (old_quals);
+ addr_space_t new_addr, old_addr;
+ cv_qualifier new_cv, old_cv;
+ std::tie (new_cv, new_addr) = new_quals.split ();
+ std::tie (old_cv, old_addr) = old_quals.split ();
if (new_addr != old_addr)
{
if (ADDR_SPACE_GENERIC_P (new_addr))
@@ -2345,8 +2347,7 @@ diagnose_mismatched_decls (tree newdecl, tree olddecl,
newdecl);
}
- if (CLEAR_QUAL_ADDR_SPACE (new_quals)
- != CLEAR_QUAL_ADDR_SPACE (old_quals))
+ if (new_cv != old_cv)
error ("conflicting type qualifiers for %q+D", newdecl);
}
else
@@ -5440,14 +5441,13 @@ shadow_tag_warned (const struct c_declspecs *declspecs, int warned)
bits. SPECS represents declaration specifiers that the grammar
only permits to contain type qualifiers and attributes. */
-int
+qualifier_set
quals_from_declspecs (const struct c_declspecs *specs)
{
- int quals = ((specs->const_p ? TYPE_QUAL_CONST : 0)
- | (specs->volatile_p ? TYPE_QUAL_VOLATILE : 0)
- | (specs->restrict_p ? TYPE_QUAL_RESTRICT : 0)
- | (specs->atomic_p ? TYPE_QUAL_ATOMIC : 0)
- | (ENCODE_QUAL_ADDR_SPACE (specs->address_space)));
+ auto cv_quals = cv_qualifier ((specs->const_p ? TYPE_QUAL_CONST : 0)
+ | (specs->volatile_p ? TYPE_QUAL_VOLATILE : 0)
+ | (specs->restrict_p ? TYPE_QUAL_RESTRICT : 0)
+ | (specs->atomic_p ? TYPE_QUAL_ATOMIC : 0));
gcc_assert (!specs->type
&& !specs->decl_attr
&& specs->typespec_word == cts_none
@@ -5465,7 +5465,7 @@ quals_from_declspecs (const struct c_declspecs *specs)
&& !specs->inline_p
&& !specs->noreturn_p
&& !specs->thread_p);
- return quals;
+ return {cv_quals, specs->address_space};
}
/* Construct an array declarator. LOC is the location of the
@@ -5497,7 +5497,7 @@ build_array_declarator (location_t loc,
else
{
declarator->u.array.attrs = NULL_TREE;
- declarator->u.array.quals = 0;
+ declarator->u.array.quals = qualifier_set {};
}
declarator->u.array.static_p = static_p;
declarator->u.array.vla_unspec_p = vla_unspec_p;
@@ -5984,7 +5984,7 @@ diagnose_uninitialized_cst_member (tree decl, tree type)
continue;
field_type = strip_array_types (TREE_TYPE (field));
- if (TYPE_QUALS (field_type) & TYPE_QUAL_CONST)
+ if (TYPE_QUALS (field_type).has (TYPE_QUAL_CONST))
{
auto_diagnostic_group d;
if (warning_at (DECL_SOURCE_LOCATION (decl), OPT_Wc___compat,
@@ -6880,14 +6880,14 @@ grokdeclarator (const struct c_declarator *declarator,
int restrictp;
int volatilep;
int atomicp;
- int type_quals = TYPE_UNQUALIFIED;
+ qualifier_set type_quals {};
tree name = NULL_TREE;
bool funcdef_flag = false;
bool funcdef_syntax = false;
bool size_varies = false;
bool size_error = false;
tree decl_attr = declspecs->decl_attr;
- int array_ptr_quals = TYPE_UNQUALIFIED;
+ qualifier_set array_ptr_quals {};
tree array_ptr_attrs = NULL_TREE;
bool array_parm_static = false;
bool array_parm_vla_unspec_p = false;
@@ -7099,11 +7099,11 @@ grokdeclarator (const struct c_declarator *declarator,
orig_qual_type = type;
type = c_build_qualified_type (type, TYPE_UNQUALIFIED);
}
- type_quals = ((constp ? TYPE_QUAL_CONST : 0)
- | (restrictp ? TYPE_QUAL_RESTRICT : 0)
- | (volatilep ? TYPE_QUAL_VOLATILE : 0)
- | (atomicp ? TYPE_QUAL_ATOMIC : 0)
- | ENCODE_QUAL_ADDR_SPACE (address_space));
+ type_quals = {(constp ? TYPE_QUAL_CONST : TYPE_UNQUALIFIED)
+ | (restrictp ? TYPE_QUAL_RESTRICT : TYPE_UNQUALIFIED)
+ | (volatilep ? TYPE_QUAL_VOLATILE : TYPE_UNQUALIFIED)
+ | (atomicp ? TYPE_QUAL_ATOMIC : TYPE_UNQUALIFIED),
+ address_space};
if (type_quals != TYPE_QUALS (element_type))
orig_qual_type = NULL_TREE;
@@ -7582,10 +7582,10 @@ grokdeclarator (const struct c_declarator *declarator,
modify the shared type, so we gcc_assert (itype)
below. */
{
- addr_space_t as = DECODE_QUAL_ADDR_SPACE (type_quals);
+ addr_space_t as = type_quals.addr_space ();
if (!ADDR_SPACE_GENERIC_P (as) && as != TYPE_ADDR_SPACE (type))
type = c_build_qualified_type (type,
- ENCODE_QUAL_ADDR_SPACE (as));
+ {TYPE_UNQUALIFIED, as});
if (array_parm_vla_unspec_p)
type = c_build_array_type_unspecified (type);
/* The GCC extension for zero-length arrays differs from
@@ -7712,11 +7712,11 @@ grokdeclarator (const struct c_declarator *declarator,
actually removed from the return type when
determining the function type. For C23, _Atomic is
removed as well. */
- int quals_used = type_quals;
+ auto quals_used = type_quals;
if (flag_isoc23)
- quals_used = 0;
+ quals_used = qualifier_set {};
else if (flag_isoc11)
- quals_used &= TYPE_QUAL_ATOMIC;
+ quals_used = quals_used.intersect (TYPE_QUAL_ATOMIC);
if (quals_used && VOID_TYPE_P (type) && really_funcdef)
pedwarn (specs_loc, 0,
"function definition has qualified void "
@@ -7730,7 +7730,7 @@ grokdeclarator (const struct c_declarator *declarator,
DR#423 resolution is not entirely clear about
this. */
if (flag_isoc11
- && (type_quals & TYPE_QUAL_RESTRICT)
+ && (type_quals.has (TYPE_QUAL_RESTRICT))
&& (!POINTER_TYPE_P (type)
|| !C_TYPE_OBJECT_OR_INCOMPLETE_P (TREE_TYPE (type))))
error_at (loc, "invalid use of %<restrict%>");
@@ -7758,12 +7758,12 @@ grokdeclarator (const struct c_declarator *declarator,
{
/* Merge any constancy or volatility into the target type
for the pointer. */
- if ((type_quals & TYPE_QUAL_ATOMIC)
+ if (type_quals.has (TYPE_QUAL_ATOMIC)
&& TREE_CODE (type) == FUNCTION_TYPE)
{
error_at (loc,
"%<_Atomic%>-qualified function type");
- type_quals &= ~TYPE_QUAL_ATOMIC;
+ type_quals = type_quals.without (TYPE_QUAL_ATOMIC);
}
else if (pedantic && TREE_CODE (type) == FUNCTION_TYPE
&& type_quals)
@@ -7813,7 +7813,7 @@ grokdeclarator (const struct c_declarator *declarator,
/* Warn about address space used for things other than static memory or
pointers. */
- address_space = DECODE_QUAL_ADDR_SPACE (type_quals);
+ address_space = type_quals.addr_space ();
if (!ADDR_SPACE_GENERIC_P (address_space))
{
if (decl_context == NORMAL)
@@ -7871,13 +7871,13 @@ grokdeclarator (const struct c_declarator *declarator,
/* C11 makes it implementation-defined (6.7.2.1#5) whether
atomic types are permitted for bit-fields; we have no code to
make bit-field accesses atomic, so disallow them. */
- if (type_quals & TYPE_QUAL_ATOMIC)
+ if (type_quals.has (TYPE_QUAL_ATOMIC))
{
if (name)
error_at (loc, "bit-field %qE has atomic type", name);
else
error_at (loc, "bit-field has atomic type");
- type_quals &= ~TYPE_QUAL_ATOMIC;
+ type_quals = type_quals.without (TYPE_QUAL_ATOMIC);
}
}
@@ -7926,12 +7926,12 @@ grokdeclarator (const struct c_declarator *declarator,
if (storage_class == csc_typedef)
{
tree decl;
- if ((type_quals & TYPE_QUAL_ATOMIC)
+ if ((type_quals.has (TYPE_QUAL_ATOMIC))
&& TREE_CODE (type) == FUNCTION_TYPE)
{
error_at (loc,
"%<_Atomic%>-qualified function type");
- type_quals &= ~TYPE_QUAL_ATOMIC;
+ type_quals = type_quals.without (TYPE_QUAL_ATOMIC);
}
else if (pedantic && TREE_CODE (type) == FUNCTION_TYPE
&& type_quals)
@@ -7980,12 +7980,12 @@ grokdeclarator (const struct c_declarator *declarator,
and fields. */
gcc_assert (storage_class == csc_none && !threadp
&& !declspecs->inline_p && !declspecs->noreturn_p);
- if ((type_quals & TYPE_QUAL_ATOMIC)
+ if (type_quals.has (TYPE_QUAL_ATOMIC)
&& TREE_CODE (type) == FUNCTION_TYPE)
{
error_at (loc,
"%<_Atomic%>-qualified function type");
- type_quals &= ~TYPE_QUAL_ATOMIC;
+ type_quals = type_quals.without (TYPE_QUAL_ATOMIC);
}
else if (pedantic && TREE_CODE (type) == FUNCTION_TYPE
&& type_quals)
@@ -8079,11 +8079,11 @@ grokdeclarator (const struct c_declarator *declarator,
}
else if (TREE_CODE (type) == FUNCTION_TYPE)
{
- if (type_quals & TYPE_QUAL_ATOMIC)
+ if (type_quals.has (TYPE_QUAL_ATOMIC))
{
error_at (loc,
"%<_Atomic%>-qualified function type");
- type_quals &= ~TYPE_QUAL_ATOMIC;
+ type_quals = type_quals.without (TYPE_QUAL_ATOMIC);
}
else if (type_quals)
pedwarn (loc, OPT_Wpedantic,
@@ -8200,11 +8200,11 @@ grokdeclarator (const struct c_declarator *declarator,
FUNCTION_DECL, declarator->u.id.id, type);
decl = build_decl_attribute_variant (decl, decl_attr);
- if (type_quals & TYPE_QUAL_ATOMIC)
+ if (type_quals.has (TYPE_QUAL_ATOMIC))
{
error_at (loc,
"%<_Atomic%>-qualified function type");
- type_quals &= ~TYPE_QUAL_ATOMIC;
+ type_quals = type_quals.without (TYPE_QUAL_ATOMIC);
}
else if (pedantic && type_quals && !DECL_IN_SYSTEM_HEADER (decl))
pedwarn (loc, OPT_Wpedantic,
@@ -8303,8 +8303,8 @@ grokdeclarator (const struct c_declarator *declarator,
if (c_type_variably_modified_p (type))
error_at (loc, "%<constexpr%> object has variably modified "
"type");
- if (type_quals
- & (TYPE_QUAL_VOLATILE | TYPE_QUAL_RESTRICT | TYPE_QUAL_ATOMIC))
+ if (type_quals.has
+ (TYPE_QUAL_VOLATILE | TYPE_QUAL_RESTRICT | TYPE_QUAL_ATOMIC))
error_at (loc, "invalid qualifiers for %<constexpr%> object");
else
{
@@ -9712,7 +9712,7 @@ finish_struct (location_t loc, tree t, tree fieldlist, tree attributes,
/* Any field that is volatile, restrict-qualified or atomic
means the type cannot be used for a constexpr object. */
if (TYPE_QUALS (t1)
- & (TYPE_QUAL_VOLATILE | TYPE_QUAL_RESTRICT | TYPE_QUAL_ATOMIC))
+ .has (TYPE_QUAL_VOLATILE | TYPE_QUAL_RESTRICT | TYPE_QUAL_ATOMIC))
C_TYPE_FIELDS_NON_CONSTEXPR (t) = 1;
else if (RECORD_OR_UNION_TYPE_P (t1) && C_TYPE_FIELDS_NON_CONSTEXPR (t1))
C_TYPE_FIELDS_NON_CONSTEXPR (t) = 1;
@@ -12047,7 +12047,7 @@ make_pointer_declarator (struct c_declspecs *type_quals_attrs,
struct c_declarator *target)
{
tree attrs;
- int quals = 0;
+ qualifier_set quals {};
struct c_declarator *itarget = target;
struct c_declarator *ret = XOBNEW (&parser_obstack, struct c_declarator);
if (type_quals_attrs)
diff --git a/gcc/c/c-objc-common.cc b/gcc/c/c-objc-common.cc
index 15f981bfc525..ea21f1cc7c72 100644
--- a/gcc/c/c-objc-common.cc
+++ b/gcc/c/c-objc-common.cc
@@ -385,7 +385,9 @@ c_tree_printer (pretty_printer *pp, text_info *text, const char *spec,
return true;
case 'v':
- pp_c_cv_qualifiers (cpp, va_arg (*text->m_args_ptr, int), hash);
+ pp_c_cv_qualifiers (cpp,
+ cv_qualifier (va_arg (*text->m_args_ptr, int)),
+ hash);
return true;
default:
diff --git a/gcc/c/c-parser.cc b/gcc/c/c-parser.cc
index 9dc5ba1e3a13..8b7913788689 100644
--- a/gcc/c/c-parser.cc
+++ b/gcc/c/c-parser.cc
@@ -4833,12 +4833,12 @@ c_parser_typeof_specifier (c_parser *parser)
if (is_unqual)
{
bool is_array = TREE_CODE (ret.spec) == ARRAY_TYPE;
- int quals = TYPE_QUALS (strip_array_types (ret.spec));
- if ((is_array ? quals & ~TYPE_QUAL_ATOMIC : quals)
+ auto quals = TYPE_QUALS (strip_array_types (ret.spec));
+ if ((is_array ? quals.without (TYPE_QUAL_ATOMIC) : quals)
!= TYPE_UNQUALIFIED)
{
ret.spec = TYPE_MAIN_VARIANT (ret.spec);
- if (quals & TYPE_QUAL_ATOMIC && is_array)
+ if (quals.has (TYPE_QUAL_ATOMIC) && is_array)
ret.spec = c_build_qualified_type (ret.spec,
TYPE_QUAL_ATOMIC);
}
@@ -13818,7 +13818,7 @@ c_parser_postfix_expression_after_paren_type (c_parser *parser,
restrict qualified or have a member with such a qualifier.
const qualification is implicitly added. */
if (TYPE_QUALS (type_no_array)
- & (TYPE_QUAL_VOLATILE | TYPE_QUAL_RESTRICT | TYPE_QUAL_ATOMIC))
+ .has (TYPE_QUAL_VOLATILE | TYPE_QUAL_RESTRICT | TYPE_QUAL_ATOMIC))
error_at (type_loc, "invalid qualifiers for %<constexpr%> object");
else if (RECORD_OR_UNION_TYPE_P (type_no_array)
&& C_TYPE_FIELDS_NON_CONSTEXPR (type_no_array))
diff --git a/gcc/c/c-tree.h b/gcc/c/c-tree.h
index 0800230873b7..a1eab8bcda38 100644
--- a/gcc/c/c-tree.h
+++ b/gcc/c/c-tree.h
@@ -567,7 +567,7 @@ struct c_declarator {
/* The array dimension, or NULL for [] and [*]. */
tree dimen;
/* The qualifiers inside []. */
- int quals;
+ qualifier_set quals;
/* The attributes (currently ignored) inside []. */
tree attrs;
/* Whether [static] was used. */
@@ -576,7 +576,7 @@ struct c_declarator {
bool vla_unspec_p : 1;
} array;
/* For pointers, the qualifiers on the pointer type. */
- int pointer_quals;
+ qualifier_set pointer_quals;
/* For attributes. */
tree attrs;
} u;
@@ -685,7 +685,7 @@ extern void record_inline_static (location_t, tree, tree,
enum c_inline_static_type);
extern void c_init_decl_processing (void);
extern void c_print_identifier (FILE *, tree, int);
-extern int quals_from_declspecs (const struct c_declspecs *);
+extern qualifier_set quals_from_declspecs (const struct c_declspecs *);
extern struct c_declarator *build_array_declarator (location_t, tree,
struct c_declspecs *,
bool, bool);
diff --git a/gcc/c/c-typeck.cc b/gcc/c/c-typeck.cc
index ed234f075ca8..539981abfcd9 100644
--- a/gcc/c/c-typeck.cc
+++ b/gcc/c/c-typeck.cc
@@ -362,9 +362,9 @@ qualify_type (tree type, tree like)
}
return c_build_qualified_type (type,
- TYPE_QUALS_NO_ADDR_SPACE (type)
- | TYPE_QUALS_NO_ADDR_SPACE_NO_ATOMIC (like)
- | ENCODE_QUAL_ADDR_SPACE (as_common));
+ {TYPE_QUALS_NO_ADDR_SPACE (type)
+ | TYPE_QUALS_NO_ADDR_SPACE_NO_ATOMIC (like),
+ as_common});
}
@@ -511,11 +511,11 @@ c_build_function_type (tree type, tree args, bool no)
tree
c_build_array_type (tree type, tree domain)
{
- int type_quals = TYPE_QUALS (type);
+ auto type_quals = TYPE_QUALS (type);
/* Identify typeless storage as introduced in C2Y
and supported also in earlier language modes. */
- bool typeless = (char_type_p (type) && !(type_quals & TYPE_QUAL_ATOMIC))
+ bool typeless = (char_type_p (type) && !(type_quals.has (TYPE_QUAL_ATOMIC)))
|| (AGGREGATE_TYPE_P (type) && TYPE_TYPELESS_STORAGE (type));
tree ret = build_array_type (type, domain, typeless);
@@ -554,7 +554,7 @@ c_build_array_type_zero_size (tree type)
}
tree
-c_build_type_attribute_qual_variant (tree type, tree attrs, int quals)
+c_build_type_attribute_qual_variant (tree type, tree attrs, qualifier_set quals)
{
tree ret = build_type_attribute_qual_variant (type, attrs, quals);
return c_set_type_bits (ret, type);
@@ -920,7 +920,7 @@ composite_type_internal (tree t1, tree t2, tree cond,
up TYPE_MAIN_VARIANT correctly, we need to form the
composite of the unqualified types and add the qualifiers
back at the end. */
- int quals = TYPE_QUALS (strip_array_types (elt));
+ auto quals = TYPE_QUALS (strip_array_types (elt));
tree unqual_elt = c_build_qualified_type (elt, TYPE_UNQUALIFIED);
if ((!d1 || d1_zero) && (!d2 || d2_zero) && (d1 || d2))
@@ -1136,9 +1136,9 @@ static tree
common_pointer_type (tree t1, tree t2, tree cond)
{
tree attributes;
- unsigned target_quals;
+ qualifier_set target_quals;
addr_space_t as1, as2, as_common;
- int quals1, quals2;
+ cv_qualifier quals1, quals2;
/* Save time if the two types are the same. */
@@ -1183,7 +1183,7 @@ common_pointer_type (tree t1, tree t2, tree cond)
if (!addr_space_superset (as1, as2, &as_common))
gcc_unreachable ();
- target_quals |= ENCODE_QUAL_ADDR_SPACE (as_common);
+ target_quals.set_as (as_common);
t1 = c_build_pointer_type (c_build_qualified_type (target, target_quals));
return c_build_type_attribute_variant (t1, attributes);
@@ -2142,10 +2142,12 @@ function_types_compatible_p (const_tree f1, const_tree f2,
pedwarn (input_location, 0, "function return types not compatible due to %<volatile%>");
if (TYPE_VOLATILE (ret1))
ret1 = build_qualified_type (TYPE_MAIN_VARIANT (ret1),
- TYPE_QUALS (ret1) & ~TYPE_QUAL_VOLATILE);
+ TYPE_QUALS (ret1)
+ .without (TYPE_QUAL_VOLATILE));
if (TYPE_VOLATILE (ret2))
ret2 = build_qualified_type (TYPE_MAIN_VARIANT (ret2),
- TYPE_QUALS (ret2) & ~TYPE_QUAL_VOLATILE);
+ TYPE_QUALS (ret2)
+ .without (TYPE_QUAL_VOLATILE));
bool ignore_pargs = data->ignore_promoting_args;
data->ignore_promoting_args = false;
@@ -3411,7 +3413,7 @@ build_component_ref (location_t loc, tree datum, tree component,
do
{
tree subdatum = TREE_VALUE (field);
- int quals;
+ qualifier_set quals;
tree subtype;
bool use_datum_quals;
@@ -3427,7 +3429,17 @@ build_component_ref (location_t loc, tree datum, tree component,
quals = TYPE_QUALS (strip_array_types (TREE_TYPE (subdatum)));
if (use_datum_quals)
- quals |= TYPE_QUALS (TREE_TYPE (datum));
+ {
+ /* SUBDATUM refers to a field, which lack their own address
+ space. */
+ gcc_assert (ADDR_SPACE_GENERIC_P (quals.addr_space ()));
+ addr_space_t datum_as;
+ cv_qualifier datum_cv;
+ std::tie (datum_cv, datum_as)
+ = TYPE_QUALS (TREE_TYPE (datum)).split ();
+ quals |= datum_cv;
+ quals.set_as (datum_as);
+ }
subtype = c_build_qualified_type (TREE_TYPE (subdatum), quals);
ref = build3 (COMPONENT_REF, subtype, datum, subdatum,
@@ -6298,8 +6310,7 @@ build_unary_op (location_t location, enum tree_code code, tree xarg,
&& (TREE_READONLY (arg) || TREE_THIS_VOLATILE (arg))
&& TREE_CODE (argtype) == FUNCTION_TYPE)
{
- int orig_quals = TYPE_QUALS (strip_array_types (argtype));
- int quals = orig_quals;
+ auto quals = TYPE_QUALS (strip_array_types (argtype));
if (TREE_READONLY (arg))
quals |= TYPE_QUAL_CONST;
@@ -6922,7 +6933,7 @@ build_conditional_expr (location_t colon_loc, tree ifexp, bool ifexp_bcp,
}
tree t2_stripped = strip_array_types (t2);
if ((TREE_CODE (t2) == ARRAY_TYPE)
- && (TYPE_QUALS (t2_stripped) & ~TYPE_QUALS (t1)))
+ && !TYPE_QUALS (t1).compatible_with (TYPE_QUALS (t2_stripped)))
{
if (!flag_isoc23)
warning_at (colon_loc, OPT_Wdiscarded_array_qualifiers,
@@ -6947,7 +6958,7 @@ build_conditional_expr (location_t colon_loc, tree ifexp, bool ifexp_bcp,
result_type = objc_common_type (type1, type2);
else
{
- int qual = ENCODE_QUAL_ADDR_SPACE (as_common);
+ qualifier_set qual {TYPE_UNQUALIFIED, as_common};
enum diagnostics::kind kind = diagnostics::kind::permerror;
if (!flag_isoc99)
/* This downgrade to a warning ensures that -std=gnu89
@@ -7342,7 +7353,7 @@ handle_warn_cast_qual (location_t loc, tree type, tree otype)
{
in_type = TREE_TYPE (in_type);
in_otype = TREE_TYPE (in_otype);
- if ((TYPE_QUALS (in_type) &~ TYPE_QUALS (in_otype)) != 0
+ if (!TYPE_QUALS (in_otype).compatible_with (TYPE_QUALS (in_type))
&& !is_const)
{
warning_at (loc, OPT_Wcast_qual,
@@ -8732,14 +8743,14 @@ convert_for_assignment (location_t location, location_t expr_loc, tree type,
|| (VOID_TYPE_P (ttr) && !TYPE_ATOMIC (ttr))
|| comp_target_types (location, memb_type, rhstype))
{
- int lquals = TYPE_QUALS (ttl) & ~TYPE_QUAL_ATOMIC;
- int rquals = TYPE_QUALS (ttr) & ~TYPE_QUAL_ATOMIC;
+ auto lquals = TYPE_QUALS (ttl).without (TYPE_QUAL_ATOMIC);
+ auto rquals = TYPE_QUALS (ttr).without (TYPE_QUAL_ATOMIC);
/* If this type won't generate any warnings, use it. */
if (lquals == rquals
|| ((TREE_CODE (ttr) == FUNCTION_TYPE
&& TREE_CODE (ttl) == FUNCTION_TYPE)
- ? ((lquals | rquals) == rquals)
- : ((lquals | rquals) == lquals)))
+ ? (rquals.compatible_with (lquals))
+ : (lquals.compatible_with (rquals))))
break;
/* Keep looking for a better type, but remember this one. */
@@ -8790,7 +8801,8 @@ convert_for_assignment (location_t location, location_t expr_loc, tree type,
"unqualified"),
G_("return makes %q#v qualified function "
"pointer from unqualified"),
- TYPE_QUALS (ttl) & ~TYPE_QUALS (ttr));
+ TYPE_QUALS_NO_ADDR_SPACE (ttl)
+ & ~TYPE_QUALS_NO_ADDR_SPACE (ttr));
}
else if (TYPE_QUALS_NO_ADDR_SPACE (ttr)
& ~TYPE_QUALS_NO_ADDR_SPACE (ttl))
@@ -8804,7 +8816,8 @@ convert_for_assignment (location_t location, location_t expr_loc, tree type,
"from pointer target type"),
G_("return discards %qv qualifier from "
"pointer target type"),
- TYPE_QUALS (ttr) & ~TYPE_QUALS (ttl));
+ TYPE_QUALS_NO_ADDR_SPACE (ttr)
+ & ~TYPE_QUALS_NO_ADDR_SPACE (ttl));
memb = marginal_memb;
}
@@ -9067,7 +9080,8 @@ convert_for_assignment (location_t location, location_t expr_loc, tree type,
"from pointer target type"),
G_("return discards %qv qualifier from "
"pointer target type"),
- TYPE_QUALS (ttr) & ~TYPE_QUALS (ttl));
+ TYPE_QUALS_NO_ADDR_SPACE (ttr)
+ & ~TYPE_QUALS_NO_ADDR_SPACE (ttl));
}
else if (pedantic
&& ((VOID_TYPE_P (ttl) && TREE_CODE (ttr) == FUNCTION_TYPE)
@@ -9110,7 +9124,8 @@ convert_for_assignment (location_t location, location_t expr_loc, tree type,
"from pointer target type"),
G_("return discards %qv qualifier from "
"pointer target type"),
- TYPE_QUALS (ttr) & ~TYPE_QUALS (ttl));
+ TYPE_QUALS_NO_ADDR_SPACE (ttr)
+ & ~TYPE_QUALS_NO_ADDR_SPACE (ttl));
else if (warn_quals_ped)
pedwarn_c11 (location, OPT_Wc11_c23_compat,
"array with qualifier on the element is not qualified before C23");
@@ -9178,7 +9193,8 @@ convert_for_assignment (location_t location, location_t expr_loc, tree type,
"function pointer from unqualified"),
G_("return makes %q#v qualified function "
"pointer from unqualified"),
- TYPE_QUALS (ttl) & ~TYPE_QUALS (ttr));
+ TYPE_QUALS_NO_ADDR_SPACE (ttl)
+ & ~TYPE_QUALS_NO_ADDR_SPACE (ttr));
}
}
/* Avoid warning about the volatile ObjC EH puts on decls. */
@@ -14970,7 +14986,7 @@ build_binary_op (location_t location, enum tree_code code,
if (result_type == NULL_TREE)
{
- int qual = ENCODE_QUAL_ADDR_SPACE (as_common);
+ qualifier_set qual {TYPE_UNQUALIFIED, as_common};
result_type = c_build_pointer_type
(c_build_qualified_type (void_type_node, qual));
}
@@ -15104,7 +15120,7 @@ build_binary_op (location_t location, enum tree_code code,
}
else
{
- int qual = ENCODE_QUAL_ADDR_SPACE (as_common);
+ qualifier_set qual {TYPE_UNQUALIFIED, as_common};
result_type = c_build_pointer_type
(c_build_qualified_type (void_type_node, qual));
pedwarn (location, OPT_Wcompare_distinct_pointer_types,
@@ -18685,8 +18701,8 @@ c_finish_transaction (location_t loc, tree block, int flags)
type was derived). */
tree
-c_build_qualified_type (tree type, int type_quals, tree orig_qual_type,
- size_t orig_qual_indirect)
+c_build_qualified_type (tree type, qualifier_set type_quals,
+ tree orig_qual_type, size_t orig_qual_indirect)
{
if (type == error_mark_node)
return type;
@@ -18747,12 +18763,12 @@ c_build_qualified_type (tree type, int type_quals, tree orig_qual_type,
/* A restrict-qualified pointer type must be a pointer to object or
incomplete type. Note that the use of POINTER_TYPE_P also allows
REFERENCE_TYPEs, which is appropriate for C++. */
- if ((type_quals & TYPE_QUAL_RESTRICT)
+ if ((type_quals.has (TYPE_QUAL_RESTRICT))
&& (!POINTER_TYPE_P (type)
|| !C_TYPE_OBJECT_OR_INCOMPLETE_P (TREE_TYPE (type))))
{
error ("invalid use of %<restrict%>");
- type_quals &= ~TYPE_QUAL_RESTRICT;
+ type_quals.remove (TYPE_QUAL_RESTRICT);
}
tree var_type = (orig_qual_type && orig_qual_indirect == 0
diff --git a/gcc/config/aarch64/aarch64-acle-builtins.cc b/gcc/config/aarch64/aarch64-acle-builtins.cc
index b1a25d5cc4ed..6225fde153a8 100644
--- a/gcc/config/aarch64/aarch64-acle-builtins.cc
+++ b/gcc/config/aarch64/aarch64-acle-builtins.cc
@@ -1289,7 +1289,7 @@ function_resolver::infer_pointer_type (unsigned int argno,
{
error_at (location, "passing %qT to argument %d of %qE, but %qT is not"
" a valid SVE element type", actual, argno + 1, fndecl,
- build_qualified_type (target, 0));
+ build_qualified_type (target, TYPE_UNQUALIFIED));
return NUM_TYPE_SUFFIXES;
}
unsigned int bits = type_suffixes[type].element_bits;
diff --git a/gcc/config/arm/arm-c.cc b/gcc/config/arm/arm-c.cc
index 65002481c209..8a87e7a26daf 100644
--- a/gcc/config/arm/arm-c.cc
+++ b/gcc/config/arm/arm-c.cc
@@ -95,7 +95,8 @@ arm_resolve_cde_builtin (location_t loc, tree fndecl, void *arglist)
a constant parameter to mean that the return value of the builtin is
also constant. */
if (i == 1)
- to_return = build_qualified_type (param_type, 0 MEM_STAT_INFO);
+ to_return = build_qualified_type (param_type, TYPE_UNQUALIFIED
+ MEM_STAT_INFO);
/* The only requirement of these intrinsics on the type of the variable
is that it's 128 bits wide. All other types are valid and we simply
diff --git a/gcc/config/arm/arm-mve-builtins.cc b/gcc/config/arm/arm-mve-builtins.cc
index 30c363cbeca4..be40627d191a 100644
--- a/gcc/config/arm/arm-mve-builtins.cc
+++ b/gcc/config/arm/arm-mve-builtins.cc
@@ -1271,7 +1271,7 @@ function_resolver::infer_pointer_type (unsigned int argno)
{
error_at (location, "passing %qT to argument %d of %qE, but %qT is not"
" a valid MVE element type", actual, argno + 1, fndecl,
- build_qualified_type (target, 0));
+ build_qualified_type (target, TYPE_UNQUALIFIED));
return NUM_TYPE_SUFFIXES;
}
diff --git a/gcc/config/avr/avr.cc b/gcc/config/avr/avr.cc
index 5c51e0d26cf0..35d70bc5bb23 100644
--- a/gcc/config/avr/avr.cc
+++ b/gcc/config/avr/avr.cc
@@ -11971,7 +11971,8 @@ avr_addr_space_for_artificial_rodata (tree /*type*/,
{
return avr_rodata_in_flash_p ()
? ADDR_SPACE_GENERIC
- : avropt_n_flash > 1 ? ADDR_SPACE_FLASHX : ADDR_SPACE_FLASH;
+ : ((addr_space_t) (avropt_n_flash > 1
+ ? ADDR_SPACE_FLASHX : ADDR_SPACE_FLASH));
}
@@ -16513,7 +16514,7 @@ avr_ftype_strlen (addr_space_t as)
{
tree const_AS_char_node
= build_qualified_type (char_type_node,
- TYPE_QUAL_CONST | ENCODE_QUAL_ADDR_SPACE (as));
+ qualifier_set {TYPE_QUAL_CONST, as});
tree const_AS_ptr_type_node
= build_pointer_type_for_mode (const_AS_char_node,
avr_addr_space_pointer_mode (as), false);
@@ -16570,8 +16571,7 @@ avr_init_builtins (void)
tree const_memx_void_node
= build_qualified_type (void_type_node,
- TYPE_QUAL_CONST
- | ENCODE_QUAL_ADDR_SPACE (ADDR_SPACE_MEMX));
+ qualifier_set {TYPE_QUAL_CONST, ADDR_SPACE_MEMX});
tree const_memx_ptr_type_node
= build_pointer_type_for_mode (const_memx_void_node, PSImode, false);
diff --git a/gcc/config/gcn/gcn-tree.cc b/gcc/config/gcn/gcn-tree.cc
index cfad5cbda46f..4512634c340f 100644
--- a/gcc/config/gcn/gcn-tree.cc
+++ b/gcc/config/gcn/gcn-tree.cc
@@ -315,8 +315,7 @@ gcn_goacc_get_worker_red_decl (tree type, unsigned offset)
tree var_type
= build_qualified_type (type,
- (TYPE_QUALS (type)
- | ENCODE_QUAL_ADDR_SPACE (ADDR_SPACE_LDS)));
+ (TYPE_QUALS (type).with_as (ADDR_SPACE_LDS)));
gcc_assert (offset
< (machfun->reduction_limit - machfun->reduction_base));
@@ -536,8 +535,8 @@ gcn_goacc_adjust_private_decl (location_t, tree var, int level)
tree type = TREE_TYPE (var);
tree lds_type = build_qualified_type (type,
- TYPE_QUALS_NO_ADDR_SPACE (type)
- | ENCODE_QUAL_ADDR_SPACE (ADDR_SPACE_LDS));
+ TYPE_QUALS (type)
+ .with_as (ADDR_SPACE_LDS));
machine_function *machfun = cfun->machine;
TREE_TYPE (var) = lds_type;
@@ -565,8 +564,8 @@ gcn_goacc_create_worker_broadcast_record (tree record_type, bool sender,
unsigned HOST_WIDE_INT offset)
{
tree type = build_qualified_type (record_type,
- TYPE_QUALS_NO_ADDR_SPACE (record_type)
- | ENCODE_QUAL_ADDR_SPACE (ADDR_SPACE_LDS));
+ TYPE_QUALS (record_type)
+ .with_as (ADDR_SPACE_LDS));
if (!sender)
{
diff --git a/gcc/config/i386/i386-builtins.cc b/gcc/config/i386/i386-builtins.cc
index a34d977b7577..7ad83df83738 100644
--- a/gcc/config/i386/i386-builtins.cc
+++ b/gcc/config/i386/i386-builtins.cc
@@ -159,7 +159,7 @@ ix86_get_builtin_type (enum ix86_builtin_type tcode)
}
else
{
- int quals;
+ cv_qualifier quals;
index = tcode - IX86_BT_LAST_VECT - 1;
if (tcode <= IX86_BT_LAST_PTR)
diff --git a/gcc/config/i386/i386.cc b/gcc/config/i386/i386.cc
index 3f00ddaa5479..ebd4d1cd33e2 100644
--- a/gcc/config/i386/i386.cc
+++ b/gcc/config/i386/i386.cc
@@ -25856,7 +25856,7 @@ ix86_stack_protect_guard (void)
if (TARGET_SSP_TLS_GUARD)
{
tree type_node = lang_hooks.types.type_for_mode (ptr_mode, 1);
- int qual = ENCODE_QUAL_ADDR_SPACE (ix86_stack_protector_guard_reg);
+ qualifier_set qual {TYPE_UNQUALIFIED, ix86_stack_protector_guard_reg};
tree type = build_qualified_type (type_node, qual);
tree t;
diff --git a/gcc/config/rl78/rl78.cc b/gcc/config/rl78/rl78.cc
index 193a5fa080b2..3fc111f36595 100644
--- a/gcc/config/rl78/rl78.cc
+++ b/gcc/config/rl78/rl78.cc
@@ -4732,7 +4732,7 @@ rl78_insert_attributes (tree decl, tree *attributes ATTRIBUTE_UNUSED)
{
tree type = TREE_TYPE (decl);
tree attr = TYPE_ATTRIBUTES (type);
- int q = TYPE_QUALS_NO_ADDR_SPACE (type) | ENCODE_QUAL_ADDR_SPACE (ADDR_SPACE_FAR);
+ auto q = TYPE_QUALS (type).with_as (ADDR_SPACE_FAR);
TREE_TYPE (decl) = build_type_attribute_qual_variant (type, attr, q);
}
diff --git a/gcc/config/rs6000/rs6000-c.cc b/gcc/config/rs6000/rs6000-c.cc
index 4984ec1c35a6..db469ca38387 100644
--- a/gcc/config/rs6000/rs6000-c.cc
+++ b/gcc/config/rs6000/rs6000-c.cc
@@ -1948,14 +1948,14 @@ altivec_resolve_overloaded_builtin (location_t loc, tree fndecl,
matching further down. */
if (POINTER_TYPE_P (decl_type)
&& POINTER_TYPE_P (type)
- && TYPE_QUALS (TREE_TYPE (type)) != 0)
+ && TYPE_QUALS (TREE_TYPE (type)).nonempty_p ())
{
if (TYPE_READONLY (TREE_TYPE (type))
&& !TYPE_READONLY (TREE_TYPE (decl_type)))
warning (0, "passing argument %d of %qE discards %qs "
"qualifier from pointer target type", n + 1, fndecl,
"const");
- type = build_qualified_type (TREE_TYPE (type), 0);
+ type = build_qualified_type (TREE_TYPE (type), TYPE_UNQUALIFIED);
type = build_pointer_type (type);
arg = c_fold_convert (type, arg);
}
@@ -1966,7 +1966,7 @@ altivec_resolve_overloaded_builtin (location_t loc, tree fndecl,
&& POINTER_TYPE_P (type)
&& TYPE_READONLY (TREE_TYPE (type)))
{
- type = build_qualified_type (TREE_TYPE (type), 0);
+ type = build_qualified_type (TREE_TYPE (type), TYPE_UNQUALIFIED);
type = build_pointer_type (type);
arg = c_fold_convert (type, arg);
}
diff --git a/gcc/config/s390/s390-c.cc b/gcc/config/s390/s390-c.cc
index 3aa27c9034c0..b271cb0c748e 100644
--- a/gcc/config/s390/s390-c.cc
+++ b/gcc/config/s390/s390-c.cc
@@ -845,10 +845,10 @@ s390_fn_types_compatible (enum s390_builtin_ov_type_index typeindex,
/* If the incoming pointer argument has more qualifiers than the
argument type it can still be an imperfect match. */
if (POINTER_TYPE_P (b_arg_type) && POINTER_TYPE_P (in_type)
- && !(TYPE_QUALS (TREE_TYPE (in_type))
- & ~TYPE_QUALS (TREE_TYPE (b_arg_type)))
&& (TYPE_QUALS (TREE_TYPE (b_arg_type))
- & ~TYPE_QUALS (TREE_TYPE (in_type))))
+ .compatible_with (TYPE_QUALS (TREE_TYPE (in_type))))
+ && (TYPE_QUALS (TREE_TYPE (b_arg_type))
+ != TYPE_QUALS (TREE_TYPE (in_type))))
{
tree qual_in_type =
build_qualified_type (TREE_TYPE (in_type),
diff --git a/gcc/coretypes.h b/gcc/coretypes.h
index 5cc602ed7e5d..d0d61d5f0451 100644
--- a/gcc/coretypes.h
+++ b/gcc/coretypes.h
@@ -191,7 +191,7 @@ class bitmap_view;
typedef unsigned char addr_space_t;
/* The value of addr_space_t that represents the generic address space. */
-#define ADDR_SPACE_GENERIC 0
+#define ADDR_SPACE_GENERIC ((addr_space_t) 0)
#define ADDR_SPACE_GENERIC_P(AS) ((AS) == ADDR_SPACE_GENERIC)
/* The major intermediate representations of GCC. */
diff --git a/gcc/cp/call.cc b/gcc/cp/call.cc
index ecf1c870d8be..9617039d6f6b 100644
--- a/gcc/cp/call.cc
+++ b/gcc/cp/call.cc
@@ -1280,7 +1280,7 @@ strip_top_quals (tree t)
{
if (TREE_CODE (t) == ARRAY_TYPE)
return t;
- return cp_build_qualified_type (t, 0);
+ return cp_build_qualified_type (t, TYPE_UNQUALIFIED);
}
/* Returns the standard conversion path (see [conv]) from type FROM to type
@@ -1453,7 +1453,7 @@ standard_conversion (tree to, tree from, tree expr, bool c_cast_p,
{
tree nfrom = TREE_TYPE (from);
/* Don't try to apply restrict to void. */
- int quals = cp_type_quals (nfrom) & ~TYPE_QUAL_RESTRICT;
+ auto quals = cp_type_quals (nfrom) & ~TYPE_QUAL_RESTRICT;
from_pointee = cp_build_qualified_type (void_type_node, quals);
from = build_pointer_type (from_pointee);
conv = build_conv (ck_ptr, from, conv);
diff --git a/gcc/cp/class.cc b/gcc/cp/class.cc
index fac5815390f0..f2f47802b283 100644
--- a/gcc/cp/class.cc
+++ b/gcc/cp/class.cc
@@ -593,7 +593,7 @@ build_simple_base_path (tree expr, tree binfo)
/* We don't use build_class_member_access_expr here, as that
has unnecessary checks, and more importantly results in
recursive calls to dfs_walk_once. */
- int type_quals = cp_type_quals (TREE_TYPE (expr));
+ auto type_quals = cp_type_quals (TREE_TYPE (expr));
expr = build3 (COMPONENT_REF,
cp_build_qualified_type (type, type_quals),
diff --git a/gcc/cp/cp-objcp-common.cc b/gcc/cp/cp-objcp-common.cc
index 8c9930bb2f37..da58084349fb 100644
--- a/gcc/cp/cp-objcp-common.cc
+++ b/gcc/cp/cp-objcp-common.cc
@@ -743,4 +743,11 @@ cp_handle_option (size_t scode, const char *arg, HOST_WIDE_INT value,
return c_common_handle_option (scode, arg, value, kind, loc, handlers);
}
+/* Like cp_type_quals, but returns a qualifier set. Will become unnecessary
+ once the C++ FE supports named address spaces. */
+
+qualifier_set
+cp_type_quals_as_set (const_tree type)
+{ return { cp_type_quals (type) }; }
+
#include "gt-cp-cp-objcp-common.h"
diff --git a/gcc/cp/cp-objcp-common.h b/gcc/cp/cp-objcp-common.h
index ed29e65e4f3e..acd6f97ac5e5 100644
--- a/gcc/cp/cp-objcp-common.h
+++ b/gcc/cp/cp-objcp-common.h
@@ -42,6 +42,7 @@ extern tree cxx_simulate_enum_decl (location_t, const char *,
vec<string_int_pair> *);
extern tree cxx_simulate_record_decl (location_t, const char *,
array_slice<const tree>);
+extern qualifier_set cp_type_quals_as_set (const_tree type);
/* Lang hooks that are shared between C++ and ObjC++ are defined here. Hooks
specific to C++ or ObjC++ go in cp/cp-lang.cc and objcp/objcp-lang.cc,
@@ -142,7 +143,7 @@ static const scoped_attribute_specs *const cp_objcp_attribute_table[] =
#undef LANG_HOOKS_TREE_DUMP_DUMP_TREE_FN
#define LANG_HOOKS_TREE_DUMP_DUMP_TREE_FN cp_dump_tree
#undef LANG_HOOKS_TREE_DUMP_TYPE_QUALS_FN
-#define LANG_HOOKS_TREE_DUMP_TYPE_QUALS_FN cp_type_quals
+#define LANG_HOOKS_TREE_DUMP_TYPE_QUALS_FN cp_type_quals_as_set
#undef LANG_HOOKS_MAKE_TYPE
#define LANG_HOOKS_MAKE_TYPE cxx_make_type_hook
diff --git a/gcc/cp/cp-tree.h b/gcc/cp/cp-tree.h
index 369d2a9119d3..e7c6d89dc3bc 100644
--- a/gcc/cp/cp-tree.h
+++ b/gcc/cp/cp-tree.h
@@ -6849,7 +6849,7 @@ inline tree ovl_op_identifier (tree_code code) { return ovl_op_identifier (false
/* A type-qualifier, or bitmask therefore, using the TYPE_QUAL
constants. */
-typedef int cp_cv_quals;
+typedef cv_qualifier cp_cv_quals;
/* Non-static member functions have an optional virt-specifier-seq.
There is a VIRT_SPEC value for each virt-specifier.
@@ -7968,7 +7968,7 @@ extern tree get_copy_ctor (tree, tsubst_flags_t);
extern tree get_copy_assign (tree);
extern tree get_default_ctor (tree);
extern tree get_dtor (tree, tsubst_flags_t);
-extern tree build_stub_type (tree, int, bool);
+extern tree build_stub_type (tree, cv_qualifier, bool);
extern tree build_stub_object (tree);
extern bool is_stub_object (tree);
extern tree build_invoke (tree, const_tree,
@@ -8830,7 +8830,7 @@ extern tree make_ptrmem_cst (tree, tree);
extern tree cp_build_type_attribute_variant (tree, tree);
extern tree cp_build_reference_type (tree, bool);
extern tree move (tree);
-extern tree cp_build_qualified_type (tree, int,
+extern tree cp_build_qualified_type (tree, cv_qualifier,
tsubst_flags_t = tf_warning_or_error);
extern tree cp_build_function_type (tree, tree);
extern bool cv_qualified_p (const_tree);
@@ -8993,14 +8993,14 @@ extern bool error_type_p (const_tree);
extern bool ptr_reasonably_similar (const_tree, const_tree);
extern tree build_ptrmemfunc (tree, tree, int, bool,
tsubst_flags_t);
-extern int cp_type_quals (const_tree);
-extern int type_memfn_quals (const_tree);
+extern cv_qualifier cp_type_quals (const_tree);
+extern cv_qualifier type_memfn_quals (const_tree);
extern cp_ref_qualifier type_memfn_rqual (const_tree);
extern tree apply_memfn_quals (tree, cp_cv_quals,
cp_ref_qualifier = REF_QUAL_NONE);
extern bool cp_has_mutable_p (const_tree);
extern bool at_least_as_qualified_p (const_tree, const_tree);
-extern void cp_apply_type_quals_to_decl (int, tree);
+extern void cp_apply_type_quals_to_decl (cv_qualifier, tree);
extern tree build_ptrmemfunc1 (tree, tree, tree);
extern void expand_ptrmemfunc_cst (tree, tree *, tree *);
extern tree type_after_usual_arithmetic_conversions (tree, tree);
diff --git a/gcc/cp/decl.cc b/gcc/cp/decl.cc
index 6e45321e9710..9f73801960d6 100644
--- a/gcc/cp/decl.cc
+++ b/gcc/cp/decl.cc
@@ -6276,10 +6276,10 @@ warn_misplaced_attr_for_class_type (location_t location,
/* Returns the cv-qualifiers that apply to the type specified
by the DECLSPECS. */
-static int
+static cv_qualifier
get_type_quals (const cp_decl_specifier_seq *declspecs)
{
- int type_quals = TYPE_UNQUALIFIED;
+ auto type_quals = TYPE_UNQUALIFIED;
if (decl_spec_seq_has_spec_p (declspecs, ds_const))
type_quals |= TYPE_QUAL_CONST;
@@ -10988,7 +10988,7 @@ cp_finish_decomp (tree decl, cp_decomp *decomp, bool test_p)
eltscnt = 2;
if (pack != -1 ? count - 1 > eltscnt : count != eltscnt)
goto cnt_mismatch;
- eltype = cp_build_qualified_type (TREE_TYPE (type), TYPE_QUALS (type));
+ eltype = cp_build_qualified_type (TREE_TYPE (type), cp_type_quals (type));
for (unsigned int i = 0; i < count; i++)
{
if ((unsigned) pack == i)
@@ -11034,7 +11034,7 @@ cp_finish_decomp (tree decl, cp_decomp *decomp, bool test_p)
}
if (pack != -1 ? count - 1 > eltscnt : count != eltscnt)
goto cnt_mismatch;
- eltype = cp_build_qualified_type (TREE_TYPE (type), TYPE_QUALS (type));
+ eltype = cp_build_qualified_type (TREE_TYPE (type), cp_type_quals (type));
for (unsigned int i = 0; i < count; i++)
{
if ((unsigned) pack == i)
@@ -14167,7 +14167,7 @@ grokdeclarator (const cp_declarator *declarator,
a member function. */
cp_ref_qualifier rqual = REF_QUAL_NONE;
/* cv-qualifiers that apply to the type specified by the DECLSPECS. */
- int type_quals = get_type_quals (declspecs);
+ auto type_quals = get_type_quals (declspecs);
tree raises = NULL_TREE;
int template_count = 0;
tree returned_attrs = NULL_TREE;
@@ -17593,7 +17593,7 @@ grokparms (tree parmlist, tree *parms)
/* Top-level qualifiers on the parameters are
ignored for function types. */
- type = cp_build_qualified_type (type, 0);
+ type = cp_build_qualified_type (type, TYPE_UNQUALIFIED);
if (TREE_CODE (type) == METHOD_TYPE)
{
error ("parameter %qD invalidly declared method type", decl);
diff --git a/gcc/cp/error.cc b/gcc/cp/error.cc
index a5332864bc89..9e9eab7da092 100644
--- a/gcc/cp/error.cc
+++ b/gcc/cp/error.cc
@@ -1915,7 +1915,7 @@ dump_lambda_function (cxx_pretty_printer *pp,
pp_c_ws_string (pp, "static");
}
else if (!(TYPE_QUALS (class_of_this_parm (TREE_TYPE (fn)))
- & TYPE_QUAL_CONST))
+ .has (TYPE_QUAL_CONST)))
{
pp->set_padding (pp_before);
pp_c_ws_string (pp, "mutable");
diff --git a/gcc/cp/mangle.cc b/gcc/cp/mangle.cc
index b2697f27c329..146ba447ce9d 100644
--- a/gcc/cp/mangle.cc
+++ b/gcc/cp/mangle.cc
@@ -2892,7 +2892,12 @@ write_CV_qualifiers_for_type (const tree type)
/* Note that we do not use cp_type_quals below; given "const
int[3]", the "const" is emitted with the "int", not with the
array. */
- cp_cv_quals quals = TYPE_QUALS (type);
+ cv_qualifier quals;
+ addr_space_t as;
+ std::tie (quals, as) = TYPE_QUALS (type).split ();
+
+ /* No address space support yet. */
+ gcc_checking_assert (ADDR_SPACE_GENERIC_P (as));
if (quals & TYPE_QUAL_RESTRICT)
{
diff --git a/gcc/cp/method.cc b/gcc/cp/method.cc
index bf882b9619c0..20c1462bb72e 100644
--- a/gcc/cp/method.cc
+++ b/gcc/cp/method.cc
@@ -736,7 +736,7 @@ do_build_copy_constructor (tree fndecl)
if (!inh)
{
- int cvquals = cp_type_quals (TREE_TYPE (parm));
+ auto cvquals = cp_type_quals (TREE_TYPE (parm));
for (tree fields = TYPE_FIELDS (current_class_type);
fields; fields = DECL_CHAIN (fields))
@@ -767,7 +767,7 @@ do_build_copy_constructor (tree fndecl)
types.) */
if (!TYPE_REF_P (expr_type))
{
- int quals = cvquals;
+ auto quals = cvquals;
if (DECL_MUTABLE_P (field))
quals &= ~TYPE_QUAL_CONST;
@@ -820,7 +820,7 @@ do_build_copy_assign (tree fndecl)
else
{
tree fields;
- int cvquals = cp_type_quals (TREE_TYPE (parm));
+ auto cvquals = cp_type_quals (TREE_TYPE (parm));
int i;
tree binfo, base_binfo;
@@ -856,7 +856,7 @@ do_build_copy_assign (tree fndecl)
tree init = parm;
tree field = fields;
tree expr_type;
- int quals;
+ cv_qualifier quals;
if (TREE_CODE (field) != FIELD_DECL || DECL_ARTIFICIAL (field))
continue;
@@ -1900,7 +1900,7 @@ maybe_synthesize_method (tree fndecl)
rvalue if RVALUE is true. */
tree
-build_stub_type (tree type, int quals, bool rvalue)
+build_stub_type (tree type, cv_qualifier quals, bool rvalue)
{
tree argtype
= cp_build_qualified_type (type, quals,
@@ -2209,8 +2209,8 @@ get_default_ctor (tree type)
tree
get_copy_ctor (tree type, tsubst_flags_t complain)
{
- int quals = (TYPE_HAS_CONST_COPY_CTOR (type)
- ? TYPE_QUAL_CONST : TYPE_UNQUALIFIED);
+ auto quals = (TYPE_HAS_CONST_COPY_CTOR (type)
+ ? TYPE_QUAL_CONST : TYPE_UNQUALIFIED);
tree argtype = build_stub_type (type, quals, false);
tree fn = locate_fn_flags (type, complete_ctor_identifier, argtype,
LOOKUP_NORMAL, complain);
@@ -2224,8 +2224,8 @@ get_copy_ctor (tree type, tsubst_flags_t complain)
tree
get_copy_assign (tree type)
{
- int quals = (TYPE_HAS_CONST_COPY_ASSIGN (type)
- ? TYPE_QUAL_CONST : TYPE_UNQUALIFIED);
+ auto quals = (TYPE_HAS_CONST_COPY_ASSIGN (type)
+ ? TYPE_QUAL_CONST : TYPE_UNQUALIFIED);
tree argtype = build_stub_type (type, quals, false);
tree fn = locate_fn_flags (type, assign_op_identifier, argtype,
LOOKUP_NORMAL, tf_warning_or_error);
@@ -2700,7 +2700,7 @@ process_subob_fn (tree fn, special_function_kind sfk, tree *spec_p,
static void
walk_field_subobs (tree fields, special_function_kind sfk, tree fnname,
- int quals, tree *spec_p, bool *trivial_p,
+ cv_qualifier quals, tree *spec_p, bool *trivial_p,
bool *deleted_p, bool *constexpr_p,
bool diag, int flags, tsubst_flags_t complain,
bool dtor_from_ctor)
@@ -2866,7 +2866,7 @@ walk_field_subobs (tree fields, special_function_kind sfk, tree fnname,
if (SFK_COPY_P (sfk) || SFK_MOVE_P (sfk))
{
- int mem_quals = cp_type_quals (mem_type) | quals;
+ auto mem_quals = cp_type_quals (mem_type) | quals;
if (DECL_MUTABLE_P (field))
mem_quals &= ~TYPE_QUAL_CONST;
argtype = build_stub_type (mem_type, mem_quals, SFK_MOVE_P (sfk));
@@ -2947,9 +2947,9 @@ walk_field_subobs (tree fields, special_function_kind sfk, tree fnname,
static tree
synthesized_method_base_walk (tree binfo, tree base_binfo,
- special_function_kind sfk, tree fnname, int quals,
- tree *inheriting_ctor, tree inherited_parms,
- int flags, bool diag,
+ special_function_kind sfk, tree fnname,
+ cv_qualifier quals, tree *inheriting_ctor,
+ tree inherited_parms, int flags, bool diag,
tree *spec_p, bool *trivial_p,
bool *deleted_p, bool *constexpr_p)
{
@@ -3139,7 +3139,7 @@ synthesized_method_walk (tree ctype, special_function_kind sfk, bool const_p,
/* We're in get_defaulted_eh_spec; we don't actually want any walking
diagnostics, we just want complain set. */
diag = false;
- int quals = const_p ? TYPE_QUAL_CONST : TYPE_UNQUALIFIED;
+ auto quals = const_p ? TYPE_QUAL_CONST : TYPE_UNQUALIFIED;
for (binfo = TYPE_BINFO (ctype), i = 0;
BINFO_BASE_ITERATE (binfo, i, base_binfo); ++i)
@@ -3540,7 +3540,7 @@ implicitly_declare_fn (special_function_kind kind, tree type,
else
return_type = void_type_node;
- int this_quals = TYPE_UNQUALIFIED;
+ auto this_quals = TYPE_UNQUALIFIED;
switch (kind)
{
case sfk_destructor:
diff --git a/gcc/cp/module.cc b/gcc/cp/module.cc
index e61cd700d8fb..c67a8fea958b 100644
--- a/gcc/cp/module.cc
+++ b/gcc/cp/module.cc
@@ -10812,7 +10812,8 @@ trees_in::tree_node (bool is_use)
int quals = i ();
if (quals >= 0 && !get_overrun ())
- res = cp_build_qualified_type (res, quals);
+ res = cp_build_qualified_type (res,
+ static_cast<cv_qualifier> (quals));
int tag = i ();
if (!tag)
diff --git a/gcc/cp/pt.cc b/gcc/cp/pt.cc
index dd0efa541120..a679cf393de4 100644
--- a/gcc/cp/pt.cc
+++ b/gcc/cp/pt.cc
@@ -17319,7 +17319,7 @@ tsubst (tree t, tree args, tsubst_flags_t complain, tree in_decl)
else
{
/* We don't have an instantiation yet, so drop the typedef. */
- int quals = cp_type_quals (t);
+ auto quals = cp_type_quals (t);
t = DECL_ORIGINAL_TYPE (decl);
t = cp_build_qualified_type (t, quals,
complain | tf_ignore_bad_quals);
@@ -17501,11 +17501,9 @@ tsubst (tree t, tree args, tsubst_flags_t complain, tree in_decl)
if (code == TEMPLATE_TYPE_PARM)
{
- int quals;
-
gcc_assert (TYPE_P (arg));
- quals = cp_type_quals (arg) | cp_type_quals (t);
+ auto quals = cp_type_quals (arg) | cp_type_quals (t);
return cp_build_qualified_type
(arg, quals, complain | tf_ignore_bad_quals);
@@ -17598,7 +17596,7 @@ tsubst (tree t, tree args, tsubst_flags_t complain, tree in_decl)
/* If we get here, we must have been looking at a parm for a
more deeply nested template. Make a new version of this
template parameter, but with a lower level. */
- int quals;
+ cv_qualifier quals;
switch (code)
{
case TEMPLATE_TYPE_PARM:
@@ -31198,7 +31196,6 @@ resolve_typename_type (tree type, bool only_current_p)
tree scope;
tree name;
tree decl;
- int quals;
tree pushed_scope;
tree result;
@@ -31320,7 +31317,7 @@ resolve_typename_type (tree type, bool only_current_p)
}
/* Qualify the resulting type. */
- quals = cp_type_quals (type);
+ auto quals = cp_type_quals (type);
if (quals)
result = cp_build_qualified_type (result, cp_type_quals (result) | quals);
diff --git a/gcc/cp/reflect.cc b/gcc/cp/reflect.cc
index 7e962fdc19e5..c5b50ca8e6cd 100644
--- a/gcc/cp/reflect.cc
+++ b/gcc/cp/reflect.cc
@@ -2623,7 +2623,7 @@ type_of (tree r, reflect_kind kind)
r = TREE_TYPE (TREE_VALUE (TREE_VALUE (r)));
if (CLASS_TYPE_P (r))
{
- int quals = cp_type_quals (r);
+ auto quals = cp_type_quals (r);
quals |= TYPE_QUAL_CONST;
r = cp_build_qualified_type (r, quals);
}
@@ -5371,7 +5371,7 @@ static tree
eval_remove_volatile (location_t loc, tree type)
{
type = strip_typedefs (type);
- int quals = cp_type_quals (type);
+ auto quals = cp_type_quals (type);
quals &= ~TYPE_QUAL_VOLATILE;
type = cp_build_qualified_type (type, quals);
return get_reflection_raw (loc, type);
@@ -5401,7 +5401,7 @@ eval_add_const (location_t loc, tree type)
type = strip_typedefs (type);
if (!TYPE_REF_P (type) && !FUNC_OR_METHOD_TYPE_P (type))
{
- int quals = cp_type_quals (type);
+ auto quals = cp_type_quals (type);
quals |= TYPE_QUAL_CONST;
type = cp_build_qualified_type (type, quals);
}
@@ -5419,7 +5419,7 @@ eval_add_volatile (location_t loc, tree type)
type = strip_typedefs (type);
if (!TYPE_REF_P (type) && !FUNC_OR_METHOD_TYPE_P (type))
{
- int quals = cp_type_quals (type);
+ auto quals = cp_type_quals (type);
quals |= TYPE_QUAL_VOLATILE;
type = cp_build_qualified_type (type, quals);
}
@@ -5437,7 +5437,7 @@ eval_add_cv (location_t loc, tree type)
type = strip_typedefs (type);
if (!TYPE_REF_P (type) && !FUNC_OR_METHOD_TYPE_P (type))
{
- int quals = cp_type_quals (type);
+ auto quals = cp_type_quals (type);
quals |= (TYPE_QUAL_CONST | TYPE_QUAL_VOLATILE);
type = cp_build_qualified_type (type, quals);
}
@@ -5528,7 +5528,7 @@ eval_make_signed (location_t loc, const constexpr_ctx *ctx, tree type,
ret = c_common_signed_or_unsigned_type (unsignedp, type);
if (ret != type)
{
- int quals = cp_type_quals (type);
+ auto quals = cp_type_quals (type);
quals &= (TYPE_QUAL_CONST | TYPE_QUAL_VOLATILE);
ret = cp_build_qualified_type (ret, quals);
}
diff --git a/gcc/cp/semantics.cc b/gcc/cp/semantics.cc
index bb952e2f62cb..1c9865b2345d 100644
--- a/gcc/cp/semantics.cc
+++ b/gcc/cp/semantics.cc
@@ -2808,7 +2808,7 @@ finish_non_static_data_member (tree decl, tree object, tree qualifying_scope,
else
{
/* Set the cv qualifiers. */
- int quals = cp_type_quals (TREE_TYPE (object));
+ auto quals = cp_type_quals (TREE_TYPE (object));
if (DECL_MUTABLE_P (decl))
quals &= ~TYPE_QUAL_CONST;
@@ -13556,7 +13556,7 @@ finish_decltype_type (tree expr, bool id_expression_or_member_access_p,
if (type && !TYPE_REF_P (type))
{
- int quals;
+ cv_qualifier quals;
if (current_function_decl
&& LAMBDA_FUNCTION_P (current_function_decl)
&& DECL_XOBJ_MEMBER_FUNCTION_P (current_function_decl))
diff --git a/gcc/cp/tree.cc b/gcc/cp/tree.cc
index 1d88d6c574ba..515bdae2d4fb 100644
--- a/gcc/cp/tree.cc
+++ b/gcc/cp/tree.cc
@@ -1474,10 +1474,16 @@ move (tree expr)
the C version of this function does not properly maintain canonical
types (which are not used in C). */
tree
-c_build_qualified_type (tree type, int type_quals, tree /* orig_qual_type */,
+c_build_qualified_type (tree type, qualifier_set type_quals,
+ tree /* orig_qual_type */,
size_t /* orig_qual_indirect */)
{
- return cp_build_qualified_type (type, type_quals);
+ cv_qualifier cv_quals;
+ addr_space_t as;
+ std::tie (cv_quals, as) = type_quals.split ();
+ /* No address space support yet. */
+ gcc_assert (ADDR_SPACE_GENERIC_P (as));
+ return cp_build_qualified_type (type, cv_quals);
}
@@ -1502,11 +1508,11 @@ c_build_qualified_type (tree type, int type_quals, tree /* orig_qual_type */,
in a similar manner for restricting non-pointer types. */
tree
-cp_build_qualified_type (tree type, int type_quals,
+cp_build_qualified_type (tree type, cv_qualifier type_quals,
tsubst_flags_t complain /* = tf_warning_or_error */)
{
tree result;
- int bad_quals = TYPE_UNQUALIFIED;
+ auto bad_quals = TYPE_UNQUALIFIED;
if (type == error_mark_node)
return type;
@@ -1645,12 +1651,10 @@ cp_build_function_type (tree value_type, tree arg_types)
tree
cv_unqualified (tree type)
{
- int quals;
-
if (type == error_mark_node)
return type;
- quals = cp_type_quals (type);
+ auto quals = cp_type_quals (type);
quals &= ~(TYPE_QUAL_CONST|TYPE_QUAL_VOLATILE);
return cp_build_qualified_type (type, quals);
}
@@ -2454,8 +2458,9 @@ build_qualified_name (tree type, tree scope, tree name, bool template_p)
parameters. */
static bool
-cp_check_qualified_type (const_tree cand, const_tree base, int type_quals,
- cp_ref_qualifier rqual, tree raises, bool late)
+cp_check_qualified_type (const_tree cand, const_tree base,
+ cv_qualifier type_quals, cp_ref_qualifier rqual,
+ tree raises, bool late)
{
return (TYPE_QUALS (cand) == type_quals
&& check_base_type (cand, base)
@@ -2943,7 +2948,14 @@ tree
build_cp_fntype_variant (tree type, cp_ref_qualifier rqual,
tree raises, bool late)
{
- cp_cv_quals type_quals = TYPE_QUALS (type);
+ cv_qualifier type_quals;
+ addr_space_t as;
+ std::tie (type_quals, as) = TYPE_QUALS (type).split ();
+ /* AS here is the address space of the method or function. For the latter,
+ it won't ever make sense. For the former, it may, one day, if we support
+ address space qualification on non-static member functions. But not
+ today. */
+ gcc_assert (ADDR_SPACE_GENERIC_P (as));
if (cp_check_qualified_type (type, type, type_quals, rqual, raises, late))
return type;
@@ -4675,7 +4687,7 @@ maybe_dummy_object (tree type, tree* binfop)
non-lambda) 'this' if available. */
if (ctype)
{
- int quals = TYPE_UNQUALIFIED;
+ auto quals = TYPE_UNQUALIFIED;
if (tree lambda = CLASSTYPE_LAMBDA_EXPR (ctype))
{
if (tree cap = lambda_expr_this_capture (lambda, false))
diff --git a/gcc/cp/typeck.cc b/gcc/cp/typeck.cc
index 712b95ab245c..3ad9a6ce5695 100644
--- a/gcc/cp/typeck.cc
+++ b/gcc/cp/typeck.cc
@@ -241,7 +241,7 @@ commonparms (tree p1, tree p2)
static tree
original_type (tree t)
{
- int quals = cp_type_quals (t);
+ auto quals = cp_type_quals (t);
while (t != error_mark_node
&& TYPE_NAME (t) != NULL_TREE)
{
@@ -719,9 +719,9 @@ composite_pointer_type_r (const op_location_t &location,
return error_mark_node;
result_type = void_type_node;
}
- const int q1 = cp_type_quals (pointee1);
- const int q2 = cp_type_quals (pointee2);
- const int quals = q1 | q2;
+ const auto q1 = cp_type_quals (pointee1);
+ const auto q2 = cp_type_quals (pointee2);
+ const auto quals = q1 | q2;
result_type = cp_build_qualified_type (result_type,
(quals | (*add_const
? TYPE_QUAL_CONST
@@ -987,7 +987,7 @@ merge_types (tree t1, tree t2)
/* For two pointers, do this recursively on the target type. */
{
tree target = merge_types (TREE_TYPE (t1), TREE_TYPE (t2));
- int quals = cp_type_quals (t1);
+ auto quals = cp_type_quals (t1);
if (code1 == POINTER_TYPE)
{
@@ -1005,9 +1005,8 @@ merge_types (tree t1, tree t2)
case OFFSET_TYPE:
{
- int quals;
tree pointee;
- quals = cp_type_quals (t1);
+ auto quals = cp_type_quals (t1);
pointee = merge_types (TYPE_PTRMEM_POINTED_TO_TYPE (t1),
TYPE_PTRMEM_POINTED_TO_TYPE (t2));
t1 = build_ptrmem_type (TYPE_PTRMEM_CLASS_TYPE (t1),
@@ -3047,7 +3046,7 @@ build_class_member_access_expr (cp_expr object, tree member,
{
/* A non-static data member. */
bool null_object_p;
- int type_quals;
+ cv_qualifier type_quals;
tree member_type;
if (INDIRECT_REF_P (object))
@@ -12130,10 +12129,11 @@ comp_ptr_ttypes_const (tree to, tree from, compare_bounds_t cb)
/* Returns the type qualifiers for this type, including the qualifiers on the
elements for an array type. */
-int
+cv_qualifier
cp_type_quals (const_tree type)
{
- int quals;
+ cv_qualifier quals;
+ addr_space_t as;
/* This CONST_CAST is okay because strip_array_types returns its
argument unmodified and we assign it to a const_tree. */
type = strip_array_types (const_cast<tree> (type));
@@ -12141,7 +12141,10 @@ cp_type_quals (const_tree type)
/* Quals on a FUNCTION_TYPE are memfn quals. */
|| TREE_CODE (type) == FUNCTION_TYPE)
return TYPE_UNQUALIFIED;
- quals = TYPE_QUALS (type);
+
+ std::tie (quals, as) = TYPE_QUALS (type).split ();
+ /* No address space support yet. */
+ gcc_assert (ADDR_SPACE_GENERIC_P (as));
/* METHOD and REFERENCE_TYPEs should never have quals. */
gcc_assert ((TREE_CODE (type) != METHOD_TYPE
&& !TYPE_REF_P (type))
@@ -12168,11 +12171,18 @@ type_memfn_rqual (const_tree type)
/* Returns the function-cv-quals for TYPE, which must be a FUNCTION_TYPE or
METHOD_TYPE. */
-int
+cv_qualifier
type_memfn_quals (const_tree type)
{
if (TREE_CODE (type) == FUNCTION_TYPE)
- return TYPE_QUALS (type);
+ {
+ cv_qualifier quals;
+ addr_space_t as;
+ std::tie (quals, as) = TYPE_QUALS (type).split ();
+ /* No address space support yet. */
+ gcc_assert (ADDR_SPACE_GENERIC_P (as));
+ return quals;
+ }
else if (TREE_CODE (type) == METHOD_TYPE)
return cp_type_quals (class_of_this_parm (type));
else
@@ -12231,7 +12241,7 @@ cp_has_mutable_p (const_tree type)
initializer is non-constant. */
void
-cp_apply_type_quals_to_decl (int type_quals, tree decl)
+cp_apply_type_quals_to_decl (cv_qualifier type_quals, tree decl)
{
tree type = TREE_TYPE (decl);
@@ -12264,8 +12274,8 @@ cp_apply_type_quals_to_decl (int type_quals, tree decl)
static void
casts_away_constness_r (tree *t1, tree *t2, tsubst_flags_t complain)
{
- int quals1;
- int quals2;
+ cv_qualifier quals1;
+ cv_qualifier quals2;
/* [expr.const.cast]
diff --git a/gcc/d/d-codegen.cc b/gcc/d/d-codegen.cc
index 0f51fd70eb64..7422354bb499 100644
--- a/gcc/d/d-codegen.cc
+++ b/gcc/d/d-codegen.cc
@@ -2487,7 +2487,7 @@ build_vthis_function (tree basetype, tree type)
tree fntype = build_function_type (TREE_TYPE (type), argtypes);
/* Copy volatile qualifiers from the original function type. */
- if (TYPE_QUALS (type) & TYPE_QUAL_VOLATILE)
+ if (TYPE_QUALS (type).has (TYPE_QUAL_VOLATILE))
fntype = build_qualified_type (fntype, TYPE_QUAL_VOLATILE);
if (RECORD_OR_UNION_TYPE_P (basetype))
diff --git a/gcc/d/types.cc b/gcc/d/types.cc
index 4ad28993b89f..a55baebcee1b 100644
--- a/gcc/d/types.cc
+++ b/gcc/d/types.cc
@@ -226,7 +226,7 @@ make_struct_type (const char *name, int nfields, ...)
tree
insert_type_modifiers (tree type, unsigned mod)
{
- int quals = 0;
+ cv_qualifier quals = TYPE_UNQUALIFIED;
switch (mod)
{
diff --git a/gcc/doc/generic.texi b/gcc/doc/generic.texi
index 42a04e34eda4..3cfa037ba281 100644
--- a/gcc/doc/generic.texi
+++ b/gcc/doc/generic.texi
@@ -306,11 +306,6 @@ The elements are indexed from zero.
@tindex OPAQUE_TYPE
@tindex UNKNOWN_TYPE
@tindex OFFSET_TYPE
-@findex TYPE_UNQUALIFIED
-@findex TYPE_QUAL_CONST
-@findex TYPE_QUAL_VOLATILE
-@findex TYPE_QUAL_RESTRICT
-@findex TYPE_MAIN_VARIANT
@cindex qualified type
@findex TYPE_SIZE
@findex TYPE_ALIGN
@@ -339,13 +334,8 @@ use the @code{RECORD_TYPE} code. Therefore, when writing a
particular type, you should take care to handle pointers to member
functions under the @code{RECORD_TYPE} case label.
-The following functions and macros deal with cv-qualification of types:
-@ftable @code
-@item TYPE_MAIN_VARIANT
-This macro returns the unqualified version of a type. It may be applied
-to an unqualified type, but it is not always the identity function in
-that case.
-@end ftable
+A type may have qualifiers, as described below, in @ref{Qualifier
+Representation}.
A few other macros and functions are usable with all types:
@ftable @code
@@ -602,6 +592,433 @@ A node for @code{char}.
It may sometimes be useful to compare one of these variables with a type
in hand, using @code{same_type_p}.
+@menu
+* Qualifier Representation:: Qualifiers and qualified types.
+@end menu
+
+@node Qualifier Representation
+@subsection Qualifiers and qualified types
+@cindex qualified type
+@cindex qualifiers
+Types in GCC may be qualified with (in C syntax) @code{const},
+@code{volatile}, @code{restrict}, @code{_Atomic} qualifiers, and with
+an address space qualifiers.
+
+The following @code{tree.h} macros allow accessing each qualifier
+separately:
+
+@table @code
+@findex TYPE_READONLY
+@item TYPE_READONLY
+Accesses the @code{const} qualification of the given type. Boolean
+value, @code{true} if type is @code{const}-qualified.
+
+@findex TYPE_VOLATILE
+@item TYPE_VOLATILE
+Accesses the @code{volatile} qualification of the given type. Boolean
+value, @code{true} if type is @code{volatile}-qualified.
+
+@findex TYPE_RESTRICT
+@item TYPE_RESTRICT
+Accesses the @code{restrict} qualification of the given type. Boolean
+value, @code{true} if type is @code{restrict}-qualified.
+
+@findex TYPE_ATOMIC
+@item TYPE_ATOMIC
+Accesses the @code{_Atomic} qualification of the given type. Boolean
+value, @code{true} if type is @code{_Atomic}-qualified.
+
+@findex TYPE_ADDR_SPACE
+@item TYPE_ADDR_SPACE
+Accesses the address space qualifier of a given type. Always present.
+
+@tindex addr_space_t
+The the address space qualifier is represented by the
+@code{addr_space_t} type, and this macro produces a value of that type.
+
+It is a @code{unsigned char}, where each value represents a distinct
+address space. @xref{Named Address Spaces}, for a description of address
+spaces.
+
+Unlike with CV qualifiers, an address space qualifier is present on all
+types. Types not otherwise qualified with a named address space are
+qualified with the @emph{generic address space}, which is syntactically
+an empty string in C.
+
+@findex ADDR_SPACE_GENERIC
+@findex ADDR_SPACE_GENERIC_P
+The generic address space is represented by the
+@code{ADDR_SPACE_GENERIC} constant, which can be tested for using
+@code{ADDR_SPACE_GENERIC_P}. In C, there's no syntax for the generic
+address space: all types not otherwise qualified are in the generic
+address space.
+@end table
+
+In addition to individual access, it is possible to work with aggregates
+of qualifiers:
+
+@ftable @code
+@item TYPE_QUALS
+This macro returns the set of qualifiers attached to a given type. The
+result is of type @code{qualifier_set} (described below) and contains
+both the cv-qualifiers and address space qualifier.
+
+@item TYPE_QUALS_NO_ADDR_SPACE
+Like @code{TYPE_QUALS}, but without the address space qualifier. Thus,
+this macro returns only the cv-qualifiers, and its result is of type
+@code{cv_qualifier}, described below.
+
+@item TYPE_QUALS_NO_ADDR_SPACE_NO_ATOMIC
+Like @code{TYPE_QUALS_NO_ADDR_SPACE}, but also excluding the
+@code{_Atomic} qualifier, thus returning only the ``access'' qualifiers
+(@code{const}, @code{volatile}, @code{restrict}).
+@end ftable
+
+The types that represent these aggregates are described in the following
+sections.
+
+@findex TYPE_MAIN_VARIANT
+To get the unqualified version of a type, use the
+@code{TYPE_MAIN_VARIANT} macro. It also may be applied to an
+unqualified type, but it is not always the identity function in that
+case.
+@c XXX when? On an over-aligned type (as returned by
+@c build_aligned_type?)
+
+@findex get_qualified_type
+@findex build_qualified_type
+To get the @var{qs}-qualified version of a type @var{t} if one exists,
+you can call @code{get_qualified_type} with @var{t} and @var{qs}. The
+returned type will be @var{qs}-qualified, or @code{NULL_TREE} if a
+so-qualified variant does not exist already.
+
+Instead, if you call @code{build_qualified_type}, and there is not
+already a variant with the requisite qualification, it will be built.
+Thus, @code{build_qualified_type} always returns a @var{qs}-qualified
+variant of @var{t}.
+
+@menu
+* cv_qualifier:: The CV-style qualifiers, that are either present or
+ absent.
+* qualifier_set:: The type representing the set of all possible
+ qualifiers.
+* Avoiding qualifier_set:: Avoiding the complexity of qualifier sets in
+ frontends that only use CV qualifiers.
+@end menu
+
+@node cv_qualifier
+@subsubsection @code{cv_qualifier}
+@tindex cv_qualifier
+The four CV-qualifiers---@code{const}, @code{volatile}, @code{restrict},
+and @code{_Atomic}---are represented by the @code{cv_qualifier} type.
+
+This type is an enum which represents a set of zero or more of the
+qualifiers named above, and which may be operated on with the ``usual''
+bit operations (bit-or represents union, bit-and intersection, etc.).
+
+The following named constants are provided by the @code{cv_qualifier}
+type:
+
+@ftable @code
+@item TYPE_UNQUALIFIED
+Represents no qualification, i.e. the empty set of CV-qualifiers. This
+value is zero, i.e.@: @code{!TYPE_UNQUALIFIED} holds.
+
+@item TYPE_QUAL_CONST
+Represents the @code{const} qualifier and, thus, the singleton set of
+just that qualifier.
+
+@item TYPE_QUAL_VOLATILE
+Represents the @code{volatile} qualifier and, thus, the singleton set of
+just that qualifier.
+
+@item TYPE_QUAL_RESTRICT
+Represents the @code{restrict} qualifier and, thus, the singleton set of
+just that qualifier.
+
+@item TYPE_QUAL_ATOMIC
+Represents the @code{_Atomic} qualifier and, thus, the singleton set of
+just that qualifier.
+
+@item TYPE_QUAL_ALL
+Represents the set of all @emph{CV-qualifiers}, and thus represents the
+set containing the @code{const}, @code{volatile}, @code{restrict}, and
+@code{_Atomic} qualifiers (i.e.@: the universe).
+@end ftable
+
+@code{cv_qualifier} also provides convenience operator overloads for the
+bit-OR, bit-AND, bit-XOR and bit-NOT operators (and the assignment
+variants thereof) which inhibit integer promotion.
+
+A @code{cv_qualifier} may implicitly be converted into the
+@code{qualifier_set} type described below, as such a conversion is
+always safe (no information is lost; only a generic address space
+qualifier is gained).
+
+@node qualifier_set
+@subsubsection @code{qualifier_set}
+@tindex qualifier_set
+The @code{qualifier_set} type represents the set of @emph{all}
+qualifiers together.
+
+The @code{qualifier_set} type is equality-comparable, and can be dumped
+to standard error.
+
+@deftypemethod qualifier_set void debug () const
+Dump the contents of @var{this} to standard error, for instance, the
+qualifier set containing @code{const}, @code{_Atomic}, and address space
+3 would print as @code{@{const, _Atomic, AS3@}}.
+@end deftypemethod
+
+A default-constructed qualifier set corresponds to the ``default''
+qualification in C, i.e.@: the syntactically empty qualifier set. This
+qualifier set includes only the generic address space qualifier.
+
+You can check for such a qualifier set:
+
+@deftypemethod qualifier_set bool nonempty_p () const
+@deftypemethodx qualifier_set {} {operator bool} () const
+@code{true} iff @var{this} is syntactically nonempty, i.e.@: if it
+contains any qualifier other than the generic address space qualifier.
+@end deftypemethod
+
+A @code{qualifier_set} is, in fact, an aggregate of the two components
+named above. As such, it is possible to construct a
+@code{qualifier_set} from one or both of the above, and break it back
+down into its constituent parts.
+
+@deftypemethod qualifier_set {pair<cv_qualifier, addr_space_t>} @
+ split () const
+This function breaks a @code{qualifier_set} into its constituent parts.
+It is intended to be used in combination with @code{std::tie}:
+
+@example Cplusplus
+qualifier_set qs = @r{given};
+cv_qualifier cv;
+addr_space_t as;
+std::tie (cv, as) = qs.split ();
+@end example
+
+Usually, if you need to process the constituent parts of a qualifier set
+separately, this is what you want. By doing something like the above,
+if a new component is added to @code{qualifier_set}s, all places that
+need to process all the components become compile errors, and thus
+handling new qualifiers can be guided by the compiler.
+@end deftypemethod
+
+It is also possible to access the individual components of a qualifier
+set:
+
+@deftypemethod qualifier_set cv_qualifier cv_quals () const
+@deftypemethodx qualifier_set addr_space_t addr_space () const
+Returns the respective component of this @code{qualifier_set}.
+
+Most of the time, if you need one of the components, you need both.
+Consider using @code{split} (described above), so that adding a new
+component to a qualifier set raises a build error.
+@end deftypemethod
+
+@code{qualifier_set} themselves form a partially-ordered set, with
+@code{compatible_with} representing their ordering relation.
+
+@deftypemethod qualifier_set bool compatible_with @
+ (qualifier_set @var{other}, @
+ bool @var{pointee} = false) const
+Returns @code{true} if qualifiers in @var{other} can be replaced with
+qualifiers in @var{this} safely.
+
+If not @var{pointee}, such a replacement is safe iff @code{@var{cv2} int
+*} can be converted into @code{@var{cv1} int *} where @var{cv1} are the
+qualifiers in @var{this} and @var{cv2} the qualifiers in @var{other}.
+
+Otherwise, such a replacement is safe iff @code{@var{cv2} int * const *}
+can be converted into @code{@var{cv1} int * const *} where @var{cv1} are
+the qualifiers in @var{this} and @var{cv2} the qualifiers in
+@var{other}.
+@end deftypemethod
+
+To add, remove, query the presence of or change the elements of
+qualifier sets, the following functions are available:
+
+@deftypemethod qualifier_set bool has (cv_qualifier @var{other_cv})
+@code{true} iff any qualifier in @var{other_cv} is part of @var{this},
+i.e.@: if their intersection is nonempty.
+@end deftypemethod
+
+@deftypemethod qualifier_set void add (cv_qualifier @var{qual})
+@deftypemethodx qualifier_set qualifier_set @
+ with (cv_qualifier @var{qual}) const
+Add @var{qual} to the current qualifier set, if not already present.
+
+The former variant mutates an existing qualifier set, and the latter
+returns a new qualifier set.
+
+These operations can also be invoked via the assignment and
+non-assignment bit-OR operators, respectively.
+@end deftypemethod
+
+@deftypemethod qualifier_set void remove (cv_qualifier @var{qual})
+@deftypemethodx qualifier_set qualifier_set @
+ without (cv_qualifier @var{qual}) const
+Remove @var{qual} to the current qualifier set, if present.
+
+The former variant mutates an existing qualifier set, and the latter
+returns a new qualifier set.
+@end deftypemethod
+
+@deftypemethod qualifier_set void set_as (addr_space_t @var{as})
+@deftypemethodx qualifier_set qualifier_set @
+ with_as (addr_space_t @var{as}) const
+Replace address space qualifier in @var{this} with @var{as}.
+
+The former variant mutates an existing qualifier set, and the latter
+returns a new qualifier set.
+@end deftypemethod
+
+@deftypemethod qualifier_set cv_qualifier @
+ intersect (cv_qualifier @var{qual}) const
+Returns the @code{cv_qualifier}s present in both @var{this} and
+@var{qual}.
+@end deftypemethod
+
+@deftypemethod qualifier_set cv_qualifier @
+ symmetric_difference @
+ (cv_qualifier @var{qual}) const
+Returns the symmetric difference of @var{this} and @var{qual}.
+
+As the latter lacks an address space qualifier, the address space
+qualifier of @var{this} is kept.
+
+This operation can also be invoked via the assignment and non-assignment
+bit-XOR operators.
+@end deftypemethod
+
+@code{qualifier_set} provides fewer operations than @code{cv_qualifier}.
+This is because not all set operations make sense on a
+@code{qualifier_set}.
+
+For instance, there is @emph{not} necessarily always a union of two
+@code{qualifier_set} values, and it does not make sense to ask for the
+intersection of two @code{qualifier_set} values, due to the address
+space qualifier.
+
+Instead, @code{qualifier_set} provides two partial operations for
+the union of two qualifier sets, depending on situation:
+
+@deftypemethod qualifier_set expected<qualifier_set, merge_error> @
+ merge (qualifier_set @var{other}, @
+ bool @var{strict_addr_space} @
+ = false) const
+
+Attempt to produce a @code{qualifier_set} that's a @emph{merge} of the
+qualifiers in @var{this} and in @var{other}. Such a qualifier set can
+be used instead of either @var{this} or @var{other} safely (i.e. it is
+compatible with both), though perhaps through a conversion.
+
+This corresponds to trying to find a common type for two expressions,
+for instance to determine the type of a conditional expression.
+
+Such a qualifier set may not exist. If so, an @code{unexpected} value
+is returned containing a reason why.
+
+If @var{strict_addr_space}, address space differences are forbidden.
+This corresponds to the @var{pointee} case in @code{compatible_with}.
+
+You may consider writing a wrapper for this function for your front-end,
+which emits a diagnostic and performs error recovery.
+@end deftypemethod
+
+@deftypemethod qualifier_set expected<qualifier_set, join_error> @
+ join (qualifier_set @var{other}) const
+
+Attempt to produce a @code{qualifier_set} that's a @emph{syntactic join}
+of the qualifiers in @var{this} and in @var{other}.
+
+Such a qualifier set is gotten by syntactically concatenating the two
+qualifier sets, i.e. if @var{other} is syntactically:
+
+@example
+@{x_1, x_2, ..., x_n@}
+@end example
+
+@noindent
+and @var{this} is syntactically:
+
+@example
+@{y_1, y_2, ..., y_m@}
+@end example
+
+@noindent
+then the resulting qualifier set is:
+
+@example
+@{x_1, x_2, ..., x_n, y_1, y_2, ..., y_m@}
+@end example
+
+This corresponds to adding extra qualifiers when using a type alias, as
+in:
+
+@example C
+typedef const int cint;
+volatile cint x;
+@end example
+
+@noindent
+where the qualification of the type of @var{x} is the join of the
+qualifier set containing @code{const} (and the generic address space),
+and the qualifier set containing @code{volatile} (and the generic
+address space).
+
+Such a qualifier set may not exist. If so, an @code{unexpected} value
+is returned containing a reason why.
+
+You should consider writing a wrapper for this function for your
+front-end, which emits a diagnostic and performs error recovery.
+@end deftypemethod
+
+@node Avoiding qualifier_set
+@subsubsection Avoiding @code{qualifier_set}
+The two types described prior were designed to permit front-ends that do
+not support address space qualification to avoid incurring extra
+complexity for handling it, while also preventing mishandling address
+space qualifiers, if the frontend is ever to start supporting them.
+
+Thus, a frontend can opt to avoid using @code{qualifier_set}, and stick
+only with @code{cv_qualifier} in a way which allows a later change to
+permit address space qualification.
+
+To do so, implement a function, say @code{@var{lang}_type_quals}, that
+returns @code{cv_qualifier} instead of @code{qualifier_set}, and use it
+instead of @code{TYPE_QUALS}, that looks like:
+
+@example Cplusplus
+cv_qualifier
+@var{lang}_type_quals (const_tree type)
+@{
+ cv_qualifier quals;
+ addr_space_t as;
+ std::tie (quals, as) = TYPE_QUALS (type).split ();
+ /* No address space support yet. */
+ gcc_assert (ADDR_SPACE_GENERIC_P (as));
+ return quals;
+@}
+@end example
+
+@noindent
+then, you can use @code{cv_qualifier} in the rest of the frontend.
+
+As a @code{cv_qualifier} can convert implicitly to a
+@code{qualifier_set}, GCC core functions can accept @code{cv_qualifier}
+values already.
+
+If, at some point, your frontend gains support for address space
+qualification, it suffices to update this function to return
+@code{qualifier_set} and then fix the ensuing compiler errors.
+
+Because @code{qualifier_set} lacks those operations of
+@code{cv_qualifier} that require extra work, each place where extra work
+is now needed will be diagnosed at compile time.
+
@c ---------------------------------------------------------------------
@c Declarations
@c ---------------------------------------------------------------------
@@ -2987,11 +3404,6 @@ should submit your patches for inclusion in GCC@.
@tindex TYPENAME_TYPE
@tindex TYPEOF_TYPE
@findex cp_type_quals
-@findex TYPE_UNQUALIFIED
-@findex TYPE_QUAL_CONST
-@findex TYPE_QUAL_VOLATILE
-@findex TYPE_QUAL_RESTRICT
-@findex TYPE_MAIN_VARIANT
@cindex qualified type
@findex TYPE_SIZE
@findex TYPE_ALIGN
@@ -3019,12 +3431,14 @@ the type @code{const int ()[7]}, denoting an array of seven @code{int}s.
The following functions and macros deal with cv-qualification of types:
@ftable @code
@item cp_type_quals
-This function returns the set of type qualifiers applied to this type.
-This value is @code{TYPE_UNQUALIFIED} if no qualifiers have been
-applied. The @code{TYPE_QUAL_CONST} bit is set if the type is
-@code{const}-qualified. The @code{TYPE_QUAL_VOLATILE} bit is set if the
-type is @code{volatile}-qualified. The @code{TYPE_QUAL_RESTRICT} bit is
-set if the type is @code{restrict}-qualified.
+This function returns the set of type qualifiers applied to this type,
+as a @code{cv_qualifier}.
+
+As the C++ frontend currently does not support address space
+qualification, this function cannot be applied to types that have a
+non-generic address space.
+
+@xref{cv_qualifier}, for a description of the @code{cv_qualifier} type.
@item CP_TYPE_CONST_P
This macro holds if the type is @code{const}-qualified.
diff --git a/gcc/dwarf2out.cc b/gcc/dwarf2out.cc
index 0b974d63c805..e7d93fa17c63 100644
--- a/gcc/dwarf2out.cc
+++ b/gcc/dwarf2out.cc
@@ -3866,8 +3866,8 @@ static void output_line_info (bool);
static void output_file_names (void);
static bool is_base_type (tree);
static dw_die_ref subrange_type_die (tree, tree, tree, tree, dw_die_ref);
-static int decl_quals (const_tree);
-static dw_die_ref modified_type_die (tree, int, tree, bool, dw_die_ref);
+static cv_qualifier decl_quals (const_tree);
+static dw_die_ref modified_type_die (tree, cv_qualifier, tree, bool, dw_die_ref);
static dw_die_ref generic_parameter_die (tree, tree, bool, dw_die_ref);
static dw_die_ref template_parameter_pack_die (tree, tree, dw_die_ref);
static unsigned int debugger_reg_number (const_rtx);
@@ -3935,7 +3935,7 @@ static dw_die_ref scope_die_for (tree, dw_die_ref);
static inline bool local_scope_p (dw_die_ref);
static inline bool class_scope_p (dw_die_ref);
static inline bool class_or_namespace_scope_p (dw_die_ref);
-static void add_type_attribute (dw_die_ref, tree, int, bool, dw_die_ref);
+static void add_type_attribute (dw_die_ref, tree, cv_qualifier, bool, dw_die_ref);
static void add_calling_convention_attribute (dw_die_ref, tree);
static const char *type_tag (const_tree);
static tree member_declared_type (const_tree);
@@ -13580,7 +13580,7 @@ subrange_type_die (tree type, tree low, tree high, tree bias,
the decl node. This will normally be augmented with the
cv_qualifiers of the underlying type in add_type_attribute. */
-static int
+static cv_qualifier
decl_quals (const_tree decl)
{
return ((TREE_READONLY (decl)
@@ -13597,11 +13597,13 @@ decl_quals (const_tree decl)
of the given TYPE_QUALS, and return its qualifiers. Ignore all
qualifiers outside QUAL_MASK. */
-static int
-get_nearest_type_subqualifiers (tree type, int type_quals, int qual_mask)
+static cv_qualifier
+get_nearest_type_subqualifiers (tree type, cv_qualifier type_quals,
+ cv_qualifier qual_mask)
{
tree t;
- int best_rank = 0, best_qual = 0, max_rank;
+ int best_rank = 0, max_rank;
+ cv_qualifier best_qual = TYPE_UNQUALIFIED;
type_quals &= qual_mask;
max_rank = popcount_hwi (type_quals) - 1;
@@ -13609,7 +13611,7 @@ get_nearest_type_subqualifiers (tree type, int type_quals, int qual_mask)
for (t = TYPE_MAIN_VARIANT (type); t && best_rank < max_rank;
t = TYPE_NEXT_VARIANT (t))
{
- int q = TYPE_QUALS (t) & qual_mask;
+ auto q = TYPE_QUALS (t).intersect (qual_mask);
if ((q & type_quals) == q && q != type_quals
&& check_base_type (t, type))
@@ -13627,7 +13629,7 @@ get_nearest_type_subqualifiers (tree type, int type_quals, int qual_mask)
return best_qual;
}
-struct dwarf_qual_info_t { int q; enum dwarf_tag t; };
+struct dwarf_qual_info_t { cv_qualifier q; enum dwarf_tag t; };
static const dwarf_qual_info_t dwarf_qual_info[] =
{
{ TYPE_QUAL_CONST, DW_TAG_const_type },
@@ -13642,7 +13644,7 @@ static const unsigned int dwarf_qual_info_size = ARRAY_SIZE (dwarf_qual_info);
qualifiers added compared to the returned DIE. */
static dw_die_ref
-qualified_die_p (dw_die_ref die, int *mask, unsigned int depth)
+qualified_die_p (dw_die_ref die, cv_qualifier *mask, unsigned int depth)
{
unsigned int i;
for (i = 0; i < dwarf_qual_info_size; i++)
@@ -13898,7 +13900,7 @@ maybe_gen_btf_decl_tag_dies (tree t, dw_die_ref target)
in the reverse storage order wrt the target order. */
static dw_die_ref
-modified_type_die (tree type, int cv_quals, tree type_attrs, bool reverse,
+modified_type_die (tree type, cv_qualifier cv_quals, tree type_attrs, bool reverse,
dw_die_ref context_die)
{
enum tree_code code = TREE_CODE (type);
@@ -13911,8 +13913,8 @@ modified_type_die (tree type, int cv_quals, tree type_attrs, bool reverse,
dw_die_ref mod_scope;
struct array_descr_info info;
/* Only these cv-qualifiers are currently handled. */
- const int cv_qual_mask = (TYPE_QUAL_CONST | TYPE_QUAL_VOLATILE
- | TYPE_QUAL_RESTRICT | TYPE_QUAL_ATOMIC);
+ const auto cv_qual_mask = (TYPE_QUAL_CONST | TYPE_QUAL_VOLATILE
+ | TYPE_QUAL_RESTRICT | TYPE_QUAL_ATOMIC);
/* DW_AT_endianity is specified only for base types in the standard. */
const bool reverse_type
= need_endianity_attribute_p (reverse)
@@ -14023,7 +14025,7 @@ modified_type_die (tree type, int cv_quals, tree type_attrs, bool reverse,
}
else
{
- int dquals = TYPE_QUALS_NO_ADDR_SPACE (dtype);
+ auto dquals = TYPE_QUALS_NO_ADDR_SPACE (dtype);
dquals &= cv_qual_mask;
if ((dquals & ~cv_quals) != TYPE_UNQUALIFIED
|| (cv_quals == dquals && DECL_ORIGINAL_TYPE (name) != type))
@@ -14065,7 +14067,7 @@ modified_type_die (tree type, int cv_quals, tree type_attrs, bool reverse,
if (cv_quals)
{
- int sub_quals = 0, first_quals = 0;
+ cv_qualifier sub_quals = TYPE_UNQUALIFIED, first_quals = TYPE_UNQUALIFIED;
unsigned i;
dw_die_ref first = NULL, last = NULL;
@@ -14086,7 +14088,7 @@ modified_type_die (tree type, int cv_quals, tree type_attrs, bool reverse,
needed = true;
else if (needed && (dwarf_qual_info[i].q & cv_quals))
{
- sub_quals = 0;
+ sub_quals = TYPE_UNQUALIFIED;
break;
}
}
@@ -14111,7 +14113,7 @@ modified_type_die (tree type, int cv_quals, tree type_attrs, bool reverse,
count < (1U << dwarf_qual_info_size);
count++, last = last->die_sib)
{
- int quals = 0;
+ cv_qualifier quals = TYPE_UNQUALIFIED;
if (last == mod_scope->die_child)
break;
if (qualified_die_p (last->die_sib, &quals, dwarf_qual_info_size)
@@ -14128,7 +14130,7 @@ modified_type_die (tree type, int cv_quals, tree type_attrs, bool reverse,
{
for (d = first->die_sib; ; d = d->die_sib)
{
- int quals = 0;
+ cv_qualifier quals = TYPE_UNQUALIFIED;
qualified_die_p (d, &quals, dwarf_qual_info_size);
if (quals == (first_quals | dwarf_qual_info[i].q))
break;
@@ -22746,7 +22748,7 @@ class_or_namespace_scope_p (dw_die_ref context_die)
adds a DW_AT_type attribute below the given die. */
static void
-add_type_attribute (dw_die_ref object_die, tree type, int cv_quals,
+add_type_attribute (dw_die_ref object_die, tree type, cv_qualifier cv_quals,
bool reverse, dw_die_ref context_die)
{
enum tree_code code = TREE_CODE (type);
@@ -22771,7 +22773,7 @@ add_type_attribute (dw_die_ref object_die, tree type, int cv_quals,
return;
type_die = modified_type_die (type,
- cv_quals | TYPE_QUALS (type),
+ cv_quals | TYPE_QUALS_NO_ADDR_SPACE (type),
TYPE_ATTRIBUTES (type),
reverse,
context_die);
@@ -24869,7 +24871,7 @@ override_type_for_decl_p (tree decl, dw_die_ref old_die,
dw_die_ref context_die)
{
tree type = TREE_TYPE (decl);
- int cv_quals;
+ cv_qualifier cv_quals;
if (decl_by_reference_p (decl))
{
@@ -24881,7 +24883,7 @@ override_type_for_decl_p (tree decl, dw_die_ref old_die,
dw_die_ref type_die
= modified_type_die (type,
- cv_quals | TYPE_QUALS (type),
+ cv_quals | TYPE_QUALS_NO_ADDR_SPACE (type),
TYPE_ATTRIBUTES (type),
false,
context_die);
diff --git a/gcc/fortran/trans-openmp.cc b/gcc/fortran/trans-openmp.cc
index 3e4375f6d601..988a7528be86 100644
--- a/gcc/fortran/trans-openmp.cc
+++ b/gcc/fortran/trans-openmp.cc
@@ -1731,7 +1731,7 @@ gfc_omp_finish_clause (tree c, gimple_seq *pre_p, bool openacc)
bool always_modifier = false;
if (!openacc
- && !(TYPE_QUALS (TREE_TYPE (ptr)) & TYPE_QUAL_RESTRICT))
+ && !TYPE_QUALS (TREE_TYPE (ptr)).has (TYPE_QUAL_RESTRICT))
always_modifier = true;
if (present)
diff --git a/gcc/fortran/trans-types.cc b/gcc/fortran/trans-types.cc
index bb7c1406c5a0..ad613e703fdd 100644
--- a/gcc/fortran/trans-types.cc
+++ b/gcc/fortran/trans-types.cc
@@ -2361,7 +2361,8 @@ gfc_nonrestricted_type (tree t)
else
ret = build_reference_type (totype);
ret = build_qualified_type (ret,
- TYPE_QUALS (t) & ~TYPE_QUAL_RESTRICT);
+ TYPE_QUALS (t)
+ .without (TYPE_QUAL_RESTRICT));
}
break;
diff --git a/gcc/gimple-lower-bitint.cc b/gcc/gimple-lower-bitint.cc
index e36534ba13d6..4e5e8a2ee99d 100644
--- a/gcc/gimple-lower-bitint.cc
+++ b/gcc/gimple-lower-bitint.cc
@@ -642,8 +642,8 @@ bitint_large_huge::limb_access (tree type, tree var, tree idx, bool write_p,
if (DECL_P (var) && tree_fits_uhwi_p (idx))
{
if (as != TYPE_ADDR_SPACE (ltype))
- ltype = build_qualified_type (ltype, TYPE_QUALS (ltype)
- | ENCODE_QUAL_ADDR_SPACE (as));
+ ltype = build_qualified_type (ltype,
+ TYPE_QUALS (ltype).with_as (as));
tree ptype = build_pointer_type (strip_array_types (TREE_TYPE (var)));
unsigned HOST_WIDE_INT off = tree_to_uhwi (idx) * m_limb_size;
if (bitint_big_endian)
@@ -657,8 +657,8 @@ bitint_large_huge::limb_access (tree type, tree var, tree idx, bool write_p,
else if (TREE_CODE (var) == MEM_REF && tree_fits_uhwi_p (idx))
{
if (as != TYPE_ADDR_SPACE (ltype))
- ltype = build_qualified_type (ltype, TYPE_QUALS (ltype)
- | ENCODE_QUAL_ADDR_SPACE (as));
+ ltype = build_qualified_type (ltype,
+ TYPE_QUALS (ltype).with_as (as));
unsigned HOST_WIDE_INT off = tree_to_uhwi (idx) * m_limb_size;
if (bitint_big_endian)
off += m_limb_size - tree_to_uhwi (TYPE_SIZE_UNIT (ltype));
@@ -675,8 +675,8 @@ bitint_large_huge::limb_access (tree type, tree var, tree idx, bool write_p,
{
ltype = m_limb_type;
if (as != TYPE_ADDR_SPACE (ltype))
- ltype = build_qualified_type (ltype, TYPE_QUALS (ltype)
- | ENCODE_QUAL_ADDR_SPACE (as));
+ ltype = build_qualified_type (ltype,
+ TYPE_QUALS (ltype).with_as (as));
var = unshare_expr (var);
if (TREE_CODE (TREE_TYPE (var)) != ARRAY_TYPE
|| !useless_type_conversion_p (m_limb_type,
@@ -715,8 +715,8 @@ bitint_large_huge::build_bit_field_ref (tree ftype, tree obj,
tree ltype = m_limb_type;
addr_space_t as = TYPE_ADDR_SPACE (TREE_TYPE (obj));
if (as != TYPE_ADDR_SPACE (ltype))
- ltype = build_qualified_type (ltype, TYPE_QUALS (ltype)
- | ENCODE_QUAL_ADDR_SPACE (as));
+ ltype = build_qualified_type (ltype,
+ TYPE_QUALS (ltype).with_as (as));
tree atype = build_array_type_nelts (ltype, nelts);
obj = build1 (VIEW_CONVERT_EXPR, atype, obj);
}
@@ -6518,8 +6518,7 @@ bitint_large_huge::lower_stmt (gimple *stmt)
if (as != TYPE_ADDR_SPACE (ltype))
ltype
= build_qualified_type (ltype,
- TYPE_QUALS (ltype)
- | ENCODE_QUAL_ADDR_SPACE (as));
+ TYPE_QUALS (ltype).with_as (as));
rhs1 = build1 (VIEW_CONVERT_EXPR, ltype, unshare_expr (mem));
gimple_assign_set_rhs1 (stmt, rhs1);
}
@@ -6624,7 +6623,7 @@ bitint_large_huge::lower_stmt (gimple *stmt)
ltype
= build_qualified_type (ltype,
TYPE_QUALS (TREE_TYPE (lhs))
- | ENCODE_QUAL_ADDR_SPACE (as));
+ .with_as (as));
lhs = build1 (VIEW_CONVERT_EXPR, ltype, lhs);
gimple_assign_set_lhs (stmt, lhs);
gimple_assign_set_rhs1 (stmt, rhs1);
diff --git a/gcc/gimplify.cc b/gcc/gimplify.cc
index 0f8bf533ba75..6e6fef614e04 100644
--- a/gcc/gimplify.cc
+++ b/gcc/gimplify.cc
@@ -3153,12 +3153,19 @@ canonicalize_component_ref (tree *expr_p)
#ifdef ENABLE_TYPES_CHECKING
tree old_type = TREE_TYPE (expr);
#endif
- int type_quals;
+ auto type_quals = TYPE_QUALS (type);
+ gcc_checking_assert (/* Fields should lack address space
+ qualification. */
+ ADDR_SPACE_GENERIC_P (type_quals.addr_space ()));
/* We need to preserve qualifiers and propagate them from
operand 0. */
- type_quals = TYPE_QUALS (type)
- | TYPE_QUALS (TREE_TYPE (TREE_OPERAND (expr, 0)));
+ addr_space_t op_as;
+ cv_qualifier op_cv;
+ std::tie (op_cv, op_as)
+ = TYPE_QUALS (TREE_TYPE (TREE_OPERAND (expr, 0))).split ();
+ type_quals |= op_cv;
+ type_quals.set_as (op_as);
if (TYPE_QUALS (type) != type_quals)
type = build_qualified_type (TYPE_MAIN_VARIANT (type), type_quals);
diff --git a/gcc/ipa-free-lang-data.cc b/gcc/ipa-free-lang-data.cc
index 3ff3f9638ff3..04df50d62074 100644
--- a/gcc/ipa-free-lang-data.cc
+++ b/gcc/ipa-free-lang-data.cc
@@ -444,9 +444,8 @@ free_lang_data_in_type (tree type, class free_lang_data_d *fld)
tree arg_type = TREE_VALUE (p);
if (TYPE_READONLY (arg_type) || TYPE_VOLATILE (arg_type))
{
- int quals = TYPE_QUALS (arg_type)
- & ~TYPE_QUAL_CONST
- & ~TYPE_QUAL_VOLATILE;
+ auto quals = (TYPE_QUALS (arg_type)
+ .without (TYPE_QUAL_CONST | TYPE_QUAL_VOLATILE));
TREE_VALUE (p) = build_qualified_type (arg_type, quals);
if (!fld->pset.add (TREE_VALUE (p)))
free_lang_data_in_type (TREE_VALUE (p), fld);
diff --git a/gcc/jit/dummy-frontend.cc b/gcc/jit/dummy-frontend.cc
index 4df9eada65bd..e54d4822c5ad 100644
--- a/gcc/jit/dummy-frontend.cc
+++ b/gcc/jit/dummy-frontend.cc
@@ -1344,7 +1344,7 @@ recording::type* tree_type_to_jit_type (tree type)
tree tp = TYPE_MAIN_VARIANT (type);
for ( ; tp != NULL ; tp = TYPE_NEXT_VARIANT (tp))
{
- if (TYPE_QUALS (tp) == 0 && type != tp)
+ if (!TYPE_QUALS (tp) && type != tp)
{
recording::type* result = tree_type_to_jit_type (tp);
if (result != NULL)
diff --git a/gcc/langhooks-def.h b/gcc/langhooks-def.h
index 9546b8f0d003..76cc9474b7ed 100644
--- a/gcc/langhooks-def.h
+++ b/gcc/langhooks-def.h
@@ -177,7 +177,7 @@ extern const char *lhd_get_sarif_source_language (const char *);
/* Tree dump hooks. */
extern bool lhd_tree_dump_dump_tree (void *, tree);
-extern int lhd_tree_dump_type_quals (const_tree);
+extern qualifier_set lhd_tree_dump_type_quals (const_tree);
extern tree lhd_make_node (enum tree_code);
#define LANG_HOOKS_TREE_DUMP_DUMP_TREE_FN lhd_tree_dump_dump_tree
diff --git a/gcc/langhooks.cc b/gcc/langhooks.cc
index d55e2ca78560..8711386bb206 100644
--- a/gcc/langhooks.cc
+++ b/gcc/langhooks.cc
@@ -262,7 +262,7 @@ lhd_tree_dump_dump_tree (void *di ATTRIBUTE_UNUSED, tree t ATTRIBUTE_UNUSED)
/* lang_hooks.tree_dump.type_qual: Determine type qualifiers in a
language-specific way. */
-int
+qualifier_set
lhd_tree_dump_type_quals (const_tree t)
{
return TYPE_QUALS (t);
diff --git a/gcc/langhooks.h b/gcc/langhooks.h
index 5af4efcb86c6..c1b08862b375 100644
--- a/gcc/langhooks.h
+++ b/gcc/langhooks.h
@@ -28,6 +28,9 @@ struct gimplify_omp_ctx;
struct array_descr_info;
+/* Forward-declaration for qualifier_set in tree.h. */
+struct qualifier_set;
+
/* A print hook for print_tree (). */
typedef void (*lang_print_tree_hook) (FILE *, tree, int indent);
@@ -53,7 +56,7 @@ struct lang_hooks_for_tree_dump
bool (*dump_tree) (void *, tree);
/* Determine type qualifiers in a language-specific way. */
- int (*type_quals) (const_tree);
+ qualifier_set (*type_quals) (const_tree);
};
/* Hooks related to types. */
diff --git a/gcc/objc/objc-act.cc b/gcc/objc/objc-act.cc
index 3ed82fe823ec..7179dddc40f0 100644
--- a/gcc/objc/objc-act.cc
+++ b/gcc/objc/objc-act.cc
@@ -8456,11 +8456,7 @@ objc_push_parm (tree parm)
= lang_hooks.types.type_promotes_to (TREE_TYPE (parm));
/* Record constancy and volatility. */
- c_apply_type_quals_to_decl
- ((TYPE_READONLY (TREE_TYPE (parm)) ? TYPE_QUAL_CONST : 0)
- | (TYPE_RESTRICT (TREE_TYPE (parm)) ? TYPE_QUAL_RESTRICT : 0)
- | (TYPE_ATOMIC (TREE_TYPE (parm)) ? TYPE_QUAL_ATOMIC : 0)
- | (TYPE_VOLATILE (TREE_TYPE (parm)) ? TYPE_QUAL_VOLATILE : 0), parm);
+ c_apply_type_quals_to_decl (TYPE_QUALS (TREE_TYPE (parm)), parm);
objc_parmlist = chainon (objc_parmlist, parm);
}
diff --git a/gcc/omp-low.cc b/gcc/omp-low.cc
index 567f0f82f2ca..f715756f1098 100644
--- a/gcc/omp-low.cc
+++ b/gcc/omp-low.cc
@@ -835,7 +835,9 @@ install_var_field (tree var, bool by_ref, int mask, omp_context *ctx,
the pointed-to type will be ignored by points-to analysis. */
if (POINTER_TYPE_P (type)
&& TYPE_RESTRICT (type))
- type = build_qualified_type (type, TYPE_QUALS (type) & ~TYPE_QUAL_RESTRICT);
+ type = build_qualified_type (type,
+ TYPE_QUALS (type)
+ .without (TYPE_QUAL_RESTRICT));
if (mask & 4)
{
diff --git a/gcc/omp-oacc-neuter-broadcast.cc b/gcc/omp-oacc-neuter-broadcast.cc
index ef3f02bf0b5a..8ce248d0ea23 100644
--- a/gcc/omp-oacc-neuter-broadcast.cc
+++ b/gcc/omp-oacc-neuter-broadcast.cc
@@ -573,7 +573,9 @@ install_var_field (tree var, tree record_type, field_map_t *fields)
if (POINTER_TYPE_P (type)
&& TYPE_RESTRICT (type))
- type = build_qualified_type (type, TYPE_QUALS (type) & ~TYPE_QUAL_RESTRICT);
+ type = build_qualified_type (type,
+ TYPE_QUALS (type)
+ .without (TYPE_QUAL_RESTRICT));
tree field = build_decl (BUILTINS_LOCATION, FIELD_DECL, name, type);
diff --git a/gcc/omp-offload.cc b/gcc/omp-offload.cc
index 3c37956a28c5..4e6084af637b 100644
--- a/gcc/omp-offload.cc
+++ b/gcc/omp-offload.cc
@@ -1897,26 +1897,31 @@ oacc_rewrite_var_decl (tree *tp, int *walk_subtrees, void *data)
if (!new_decl)
return NULL;
- int base_quals = TYPE_QUALS (TREE_TYPE (*new_decl));
+ auto base_quals = TYPE_QUALS (TREE_TYPE (*new_decl));
+ cv_qualifier base_cv;
+ addr_space_t base_as;
+ std::tie (base_cv, base_as) = base_quals.split ();
tree field = TREE_OPERAND (*tp, 1);
/* Adjust the type of the field. */
- int field_quals = TYPE_QUALS (TREE_TYPE (field));
+ auto field_quals = TYPE_QUALS (TREE_TYPE (field));
if (TREE_CODE (field) == FIELD_DECL && field_quals != base_quals)
{
tree *field_type = &TREE_TYPE (field);
while (TREE_CODE (*field_type) == ARRAY_TYPE)
field_type = &TREE_TYPE (*field_type);
- field_quals |= base_quals;
+ field_quals |= base_cv;
+ field_quals.set_as (base_as);
*field_type = build_qualified_type (*field_type, field_quals);
}
/* Adjust the type of the component ref itself. */
tree comp_type = TREE_TYPE (*tp);
- int comp_quals = TYPE_QUALS (comp_type);
+ auto comp_quals = TYPE_QUALS (comp_type);
if (TREE_CODE (*tp) == COMPONENT_REF && comp_quals != base_quals)
{
- comp_quals |= base_quals;
+ comp_quals |= base_cv;
+ comp_quals.set_as (base_as);
TREE_TYPE (*tp)
= build_qualified_type (comp_type, comp_quals);
}
diff --git a/gcc/rust/backend/rust-tree.cc b/gcc/rust/backend/rust-tree.cc
index 6588ff249593..a03d67c6daee 100644
--- a/gcc/rust/backend/rust-tree.cc
+++ b/gcc/rust/backend/rust-tree.cc
@@ -956,10 +956,9 @@ decl_maybe_constant_var_p (tree decl)
/* Returns the type qualifiers for this type, including the qualifiers on the
elements for an array type. */
-int
+cv_qualifier
rs_type_quals (const_tree type)
{
- int quals;
/* This CONST_CAST is okay because strip_array_types returns its
argument unmodified and we assign it to a const_tree. */
type = strip_array_types (const_cast<tree> (type));
@@ -967,12 +966,17 @@ rs_type_quals (const_tree type)
/* Quals on a FUNCTION_TYPE are memfn quals. */
|| TREE_CODE (type) == FUNCTION_TYPE)
return TYPE_UNQUALIFIED;
- quals = TYPE_QUALS (type);
+
+ addr_space_t addr_space;
+ cv_qualifier quals;
+ std::tie (quals, addr_space) = TYPE_QUALS (type).split ();
/* METHOD and REFERENCE_TYPEs should never have quals. */
// gcc_assert (
// (TREE_CODE (type) != METHOD_TYPE && !TYPE_REF_P (type))
// || ((quals & (TYPE_QUAL_CONST | TYPE_QUAL_VOLATILE)) ==
// TYPE_UNQUALIFIED));
+ /* At the moment, the Rust front-end does not do address spaces. */
+ gcc_assert (ADDR_SPACE_GENERIC_P (addr_space));
return quals;
}
@@ -1297,15 +1301,24 @@ lookup_add (tree fns, tree lookup)
/* Returns the function-cv-quals for TYPE, which must be a FUNCTION_TYPE or
METHOD_TYPE. */
-int
+cv_qualifier
type_memfn_quals (const_tree type)
{
+ qualifier_set quals;
if (TREE_CODE (type) == FUNCTION_TYPE)
- return TYPE_QUALS (type);
+ quals = TYPE_QUALS (type);
else if (TREE_CODE (type) == METHOD_TYPE)
- return rs_type_quals (class_of_this_parm (type));
+ quals = rs_type_quals (class_of_this_parm (type));
else
rust_unreachable ();
+
+ addr_space_t as;
+ cv_qualifier cv;
+ std::tie (cv, as) = quals.split ();
+ /* These should never include an address space, at least for the time
+ being. */
+ gcc_checking_assert (ADDR_SPACE_GENERIC_P (as));
+ return cv;
}
// forked from gcc/cp/pt.cc find_parameter_pack_data
@@ -2507,11 +2520,11 @@ build_cplus_array_type (tree elt_type, tree index_type, int dependent)
in a similar manner for restricting non-pointer types. */
tree
-rs_build_qualified_type_real (tree type, int type_quals,
+rs_build_qualified_type_real (tree type, cv_qualifier type_quals,
tsubst_flags_t complain)
{
tree result;
- int bad_quals = TYPE_UNQUALIFIED;
+ auto bad_quals = TYPE_UNQUALIFIED;
if (type == error_mark_node)
return type;
@@ -3328,12 +3341,10 @@ check_for_uninitialized_const_var (tree decl, bool constexpr_context_p,
tree
cv_unqualified (tree type)
{
- int quals;
-
if (type == error_mark_node)
return type;
- quals = rs_type_quals (type);
+ auto quals = rs_type_quals (type);
quals &= ~(TYPE_QUAL_CONST | TYPE_QUAL_VOLATILE);
return rs_build_qualified_type (type, quals);
}
@@ -3848,7 +3859,7 @@ strip_top_quals (tree t)
{
if (TREE_CODE (t) == ARRAY_TYPE)
return t;
- return rs_build_qualified_type (t, 0);
+ return rs_build_qualified_type (t, TYPE_UNQUALIFIED);
}
// forked from gcc/cp/typeck2.cc cxx_incomplete_type_inform
diff --git a/gcc/rust/backend/rust-tree.h b/gcc/rust/backend/rust-tree.h
index 21edfe389f4a..14a5faac7e9f 100644
--- a/gcc/rust/backend/rust-tree.h
+++ b/gcc/rust/backend/rust-tree.h
@@ -2976,7 +2976,7 @@ extern bool maybe_constexpr_fn (tree);
extern bool var_in_maybe_constexpr_fn (tree);
-extern int rs_type_quals (const_tree type);
+extern cv_qualifier rs_type_quals (const_tree type);
inline bool type_unknown_p (const_tree);
@@ -3004,7 +3004,7 @@ extern bool builtin_pack_fn_p (tree);
extern tree make_conv_op_name (tree);
-extern int type_memfn_quals (const_tree);
+extern cv_qualifier type_memfn_quals (const_tree);
struct c_fileinfo *get_fileinfo (const char *);
@@ -3024,7 +3024,7 @@ extern bool rs_tree_equal (tree, tree);
extern bool compparms (const_tree, const_tree);
-extern tree rs_build_qualified_type_real (tree, int, tsubst_flags_t);
+extern tree rs_build_qualified_type_real (tree, cv_qualifier, tsubst_flags_t);
#define rs_build_qualified_type(TYPE, QUALS) \
rs_build_qualified_type_real ((TYPE), (QUALS), tf_warning_or_error)
extern bool cv_qualified_p (const_tree);
@@ -3215,10 +3215,6 @@ enum
ce_exact
};
-extern tree rs_build_qualified_type_real (tree, int, tsubst_flags_t);
-#define rs_build_qualified_type(TYPE, QUALS) \
- rs_build_qualified_type_real ((TYPE), (QUALS), tf_warning_or_error)
-
extern tree rs_walk_subtrees (tree *, int *, walk_tree_fn, void *,
hash_set<tree> *);
#define rs_walk_tree(tp, func, data, pset) \
diff --git a/gcc/tree-core.h b/gcc/tree-core.h
index 1687b1f94672..d7f89de937a8 100644
--- a/gcc/tree-core.h
+++ b/gcc/tree-core.h
@@ -1,4 +1,4 @@
-/* Core data structures for the 'tree' type.
+/* Core data structures for the 'tree' type. -*- C++ -*-
Copyright (C) 1989-2026 Free Software Foundation, Inc.
This file is part of GCC.
@@ -20,6 +20,7 @@ along with GCC; see the file COPYING3. If not see
#ifndef GCC_TREE_CORE_H
#define GCC_TREE_CORE_H
+#include "coretypes.h"
#include "symtab.h"
/* This file contains all the data structures that define the 'tree' type.
@@ -696,17 +697,76 @@ enum omp_memory_order {
};
#define OMP_FAIL_MEMORY_ORDER_SHIFT 3
-/* There is a TYPE_QUAL value for each type qualifier. They can be
- combined by bitwise-or to form the complete set of qualifiers for a
- type. */
-enum cv_qualifier {
+/* The cv_qualifier enum represents a set of the CV-style qualifiers (const,
+ volatile, restrict and atomic). These are either present or absent on a
+ given type. This set can be manipulated using the "usual" bit operations.
+
+ Note that this type does *not* represent all possible qualifiers. Address
+ space qualification in particular is carried by addr_space_t. The set of
+ all qualifiers a given type may carry is represented by qualifier_set. */
+enum cv_qualifier : unsigned char {
TYPE_UNQUALIFIED = 0x0,
TYPE_QUAL_CONST = 0x1,
TYPE_QUAL_VOLATILE = 0x2,
TYPE_QUAL_RESTRICT = 0x4,
- TYPE_QUAL_ATOMIC = 0x8
+ TYPE_QUAL_ATOMIC = 0x8,
+
+ /* Useful as a mask. */
+ TYPE_QUAL_ALL = (TYPE_QUAL_CONST
+ | TYPE_QUAL_VOLATILE
+ | TYPE_QUAL_RESTRICT
+ | TYPE_QUAL_ATOMIC)
};
+/* Convenience operator, making it so that the bit-ops of two CV-qualifiers is
+ also of type cv_qualifier, rather than 'int'. This is sound for
+ CV-qualifiers as they act like sets (unlike general qualifier sets, which
+ are slightly more complex). */
+
+constexpr cv_qualifier
+operator| (cv_qualifier l, cv_qualifier r)
+{
+ return (cv_qualifier) ((static_cast<unsigned char> (l)
+ | static_cast<unsigned char> (r))
+ & TYPE_QUAL_ALL);
+}
+constexpr cv_qualifier &
+operator|= (cv_qualifier &l, cv_qualifier r)
+{
+ return l = l | r;
+}
+
+constexpr cv_qualifier
+operator& (cv_qualifier l, cv_qualifier r)
+{
+ return (cv_qualifier) (static_cast<unsigned char> (l)
+ & static_cast<unsigned char> (r)
+ & TYPE_QUAL_ALL);
+}
+constexpr cv_qualifier &
+operator&= (cv_qualifier &l, cv_qualifier r)
+{
+ return l = l & r;
+}
+
+constexpr cv_qualifier
+operator^ (cv_qualifier l, cv_qualifier r)
+{
+ return (cv_qualifier) ((static_cast<unsigned char> (l)
+ ^ static_cast<unsigned char> (r))
+ & TYPE_QUAL_ALL);
+}
+constexpr cv_qualifier &
+operator^= (cv_qualifier &l, cv_qualifier r)
+{
+ return l = l ^ r;
+}
+
+
+constexpr cv_qualifier
+operator~ (cv_qualifier x)
+{ return (cv_qualifier) (~static_cast<unsigned char> (x) & TYPE_QUAL_ALL); }
+
/* Standard named or nameless data types of the C compiler. */
enum tree_index : unsigned {
TI_ERROR_MARK,
@@ -1193,7 +1253,7 @@ struct GTY(()) tree_base {
For CONSTRUCTOR nodes this holds the clobber_kind enum.
The C++ front-end uses this in IDENTIFIER_NODE, REFLECT_EXPR, and
NAMESPACE_DECL. */
- unsigned address_space : 8;
+ addr_space_t address_space : 8;
} bits;
/* The following fields are present in tree_base to save space. The
diff --git a/gcc/tree-dump.cc b/gcc/tree-dump.cc
index 6f96cceff56c..85487c992b9e 100644
--- a/gcc/tree-dump.cc
+++ b/gcc/tree-dump.cc
@@ -367,7 +367,9 @@ dequeue_and_dump (dump_info_p di)
else if (code_class == tcc_type)
{
/* All types have qualifiers. */
- int quals = lang_hooks.tree_dump.type_quals (t);
+ cv_qualifier quals;
+ addr_space_t as;
+ std::tie (quals, as) = lang_hooks.tree_dump.type_quals (t).split ();
if (quals != TYPE_UNQUALIFIED)
{
@@ -378,6 +380,9 @@ dequeue_and_dump (dump_info_p di)
di->column += 14;
}
+ if (!ADDR_SPACE_GENERIC_P (as))
+ dump_int (di, "addr-space", as);
+
/* All types have associated declarations. */
dump_child ("name", TYPE_NAME (t));
diff --git a/gcc/tree-pretty-print.cc b/gcc/tree-pretty-print.cc
index 316945c00ede..56e0b303f95c 100644
--- a/gcc/tree-pretty-print.cc
+++ b/gcc/tree-pretty-print.cc
@@ -2322,7 +2322,7 @@ dump_generic_node (pretty_printer *pp, tree node, int spc, dump_flags_t flags,
case BITINT_TYPE:
case OPAQUE_TYPE:
{
- unsigned int quals = TYPE_QUALS (node);
+ auto quals = TYPE_QUALS_NO_ADDR_SPACE (node);
enum tree_code_class tclass;
if (quals & TYPE_QUAL_ATOMIC)
@@ -2496,17 +2496,17 @@ dump_generic_node (pretty_printer *pp, tree node, int spc, dump_flags_t flags,
}
else
{
- unsigned int quals = TYPE_QUALS (node);
+ auto quals = TYPE_QUALS (node);
dump_generic_node (pp, TREE_TYPE (node), spc, flags, false);
pp_space (pp);
pp_string (pp, str);
- if (quals & TYPE_QUAL_CONST)
+ if (quals.has (TYPE_QUAL_CONST))
pp_string (pp, " const");
- if (quals & TYPE_QUAL_VOLATILE)
+ if (quals.has (TYPE_QUAL_VOLATILE))
pp_string (pp, " volatile");
- if (quals & TYPE_QUAL_RESTRICT)
+ if (quals.has (TYPE_QUAL_RESTRICT))
pp_string (pp, " restrict");
if (!ADDR_SPACE_GENERIC_P (TYPE_ADDR_SPACE (node)))
@@ -2532,7 +2532,7 @@ dump_generic_node (pretty_printer *pp, tree node, int spc, dump_flags_t flags,
case ARRAY_TYPE:
{
- unsigned int quals = TYPE_QUALS (node);
+ auto quals = TYPE_QUALS_NO_ADDR_SPACE (node);
tree tmp;
if (quals & TYPE_QUAL_ATOMIC)
@@ -2562,7 +2562,7 @@ dump_generic_node (pretty_printer *pp, tree node, int spc, dump_flags_t flags,
case UNION_TYPE:
case QUAL_UNION_TYPE:
{
- unsigned int quals = TYPE_QUALS (node);
+ auto quals = TYPE_QUALS_NO_ADDR_SPACE (node);
if (quals & TYPE_QUAL_ATOMIC)
pp_string (pp, "atomic ");
diff --git a/gcc/tree-profile.cc b/gcc/tree-profile.cc
index 882a31a6806d..36f4828bf8aa 100644
--- a/gcc/tree-profile.cc
+++ b/gcc/tree-profile.cc
@@ -2114,7 +2114,7 @@ tree_profiling (void)
tree fntype = gimple_call_fntype (call);
if (fntype && TYPE_READONLY (fntype))
{
- int quals = TYPE_QUALS (fntype) & ~TYPE_QUAL_CONST;
+ auto quals = TYPE_QUALS (fntype).without (TYPE_QUAL_CONST);
fntype = build_qualified_type (fntype, quals);
gimple_call_set_fntype (call, fntype);
}
diff --git a/gcc/tree-sra.cc b/gcc/tree-sra.cc
index f951a38442a5..173536f69df6 100644
--- a/gcc/tree-sra.cc
+++ b/gcc/tree-sra.cc
@@ -1904,8 +1904,7 @@ build_ref_for_offset (location_t loc, tree base, poly_int64 offset,
addr_space_t as = TYPE_ADDR_SPACE (TREE_TYPE (base));
if (as != TYPE_ADDR_SPACE (exp_type))
exp_type = build_qualified_type (exp_type,
- TYPE_QUALS (exp_type)
- | ENCODE_QUAL_ADDR_SPACE (as));
+ TYPE_QUALS (exp_type).with_as (as));
poly_int64 byte_offset = exact_div (offset, BITS_PER_UNIT);
get_object_alignment_1 (base, &align, &misalign);
diff --git a/gcc/tree-ssa-address.cc b/gcc/tree-ssa-address.cc
index 30baf81d7892..d10de56b3acb 100644
--- a/gcc/tree-ssa-address.cc
+++ b/gcc/tree-ssa-address.cc
@@ -450,7 +450,6 @@ move_hint_to_base (tree type, struct mem_address *parts, tree base_hint,
{
unsigned i;
tree val = NULL_TREE;
- int qual;
for (i = 0; i < addr->n; i++)
{
@@ -469,7 +468,7 @@ move_hint_to_base (tree type, struct mem_address *parts, tree base_hint,
to TYPE directly, as the back-end will assume registers of pointer
type are aligned, and just the base itself may not actually be.
We use void pointer to the type's address space instead. */
- qual = ENCODE_QUAL_ADDR_SPACE (TYPE_ADDR_SPACE (type));
+ qualifier_set qual {TYPE_UNQUALIFIED, TYPE_ADDR_SPACE (type)};
type = build_qualified_type (void_type_node, qual);
parts->base = fold_convert (build_pointer_type (type), val);
aff_combination_remove_elt (addr, i);
diff --git a/gcc/tree-switch-conversion.cc b/gcc/tree-switch-conversion.cc
index f3e77647daae..5e19e90880f8 100644
--- a/gcc/tree-switch-conversion.cc
+++ b/gcc/tree-switch-conversion.cc
@@ -1007,8 +1007,7 @@ switch_conversion::build_one_array (int num, tree arr_index_type,
ARTIFICIAL_RODATA_CSWITCH);
if (!ADDR_SPACE_GENERIC_P (as))
{
- int quals = (TYPE_QUALS_NO_ADDR_SPACE (value_type)
- | ENCODE_QUAL_ADDR_SPACE (as));
+ qualifier_set quals {TYPE_QUALS_NO_ADDR_SPACE (value_type), as};
value_type = build_qualified_type (value_type, quals);
array_type = build_array_type (value_type, arr_index_type);
}
diff --git a/gcc/tree-vect-stmts.cc b/gcc/tree-vect-stmts.cc
index 09e45d0629a3..c6322849393d 100644
--- a/gcc/tree-vect-stmts.cc
+++ b/gcc/tree-vect-stmts.cc
@@ -13421,7 +13421,8 @@ get_related_vectype_for_scalar_type (machine_mode prevailing_mode,
type. */
if (TYPE_ADDR_SPACE (orig_scalar_type) != TYPE_ADDR_SPACE (vectype))
return build_qualified_type
- (vectype, KEEP_QUAL_ADDR_SPACE (TYPE_QUALS (orig_scalar_type)));
+ (vectype, qualifier_set {TYPE_UNQUALIFIED,
+ TYPE_ADDR_SPACE (orig_scalar_type)});
return vectype;
}
diff --git a/gcc/tree.cc b/gcc/tree.cc
index 69a7c7e6d34d..5a47dbf22d04 100644
--- a/gcc/tree.cc
+++ b/gcc/tree.cc
@@ -77,6 +77,9 @@ along with GCC; see the file COPYING3. If not see
#include "ubsan.h"
#include "attr-callback.h"
+/* For qualifier_set::{join,merge}. */
+#include "stdbackport/expected"
+
/* Names of tree components.
Used for printing out the tree and error messages. */
#define DEFTREECODE(SYM, NAME, TYPE, LEN) NAME,
@@ -283,7 +286,7 @@ static GTY ((cache ("gt_value_expr_mark")))
static GTY ((cache))
hash_table<tree_vec_map_cache_hasher> *debug_args_for_decl;
-static void set_type_quals (tree, int);
+static void set_type_quals (tree, qualifier_set);
static void print_type_hash_statistics (void);
static void print_debug_expr_statistics (void);
static void print_value_expr_statistics (void);
@@ -5697,17 +5700,166 @@ protected_set_expr_location_if_unset (tree t, location_t loc)
protected_set_expr_location (t, loc);
}
-/* Set the type qualifiers for TYPE to TYPE_QUALS, which is a bitmask
- of the various TYPE_QUAL values. */
+
+/* Attempt to produce a qualifier_set that's a merge of qualifiers in THIS and
+ OTHER. Such a qualifier set can be used instead of either THIS or OTHER
+ safely. (i.e. if a type was qualified by either THIS or OTHER, it can be
+ qualified by their merge instead safely, possibly through a conversion)
+
+ This operation may fail. In that case, the error value returned provides
+ reasoning for the failure.
+
+ If STRICT_ADDR_SPACE, then no address space mismatch is permitted. This is
+ useful if merging below the top-level of pointers (i.e. in a case such as
+ 'AS1 T**' vs 'AS2 T**').
+
+ You'll need to include stdbackport/expected to use this. */
+
+gcc::expected<qualifier_set, qualifier_set::merge_error>
+qualifier_set::merge (qualifier_set other,
+ bool strict_addr_space /* = false */) const
+{
+ using ME = qualifier_set::merge_error;
+
+ if (has (TYPE_QUAL_ATOMIC) != other.has (TYPE_QUAL_ATOMIC))
+ return gcc::make_unexpected (ME::atomic_mismatch);
+
+ auto cv_merged = cv_quals () | other.cv_quals ();
+ auto as1 = addr_space ();
+ auto as2 = other.addr_space ();
+
+ addr_space_t as_super;
+ if (as1 == as2)
+ as_super = as1;
+ else if (!strict_addr_space
+ && targetm.addr_space.subset_p (as1, as2))
+ as_super = as2;
+ else if (!strict_addr_space
+ && targetm.addr_space.subset_p (as2, as1))
+ as_super = as1;
+ else
+ return gcc::make_unexpected (ME::disjoint_address_spaces);
+
+ return qualifier_set {cv_merged, as_super};
+}
+
+/* Return a qualifier set that has all the qualifiers of THIS and OTHER.
+ Unlike 'merge', this operation operates purely syntactically; if THIS is
+ {q1_1, q1_2, ..., q1_i} and OTHER {q2_1, q2_2, ..., q2_j}, then returns the
+ qualifier set obtained by concatenating the sequences q1 and q2 without
+ duplicates, if such a qualifier set is valid.
+
+ Specifically, this implies that if THIS or OTHER both (syntactically)
+ contain an address space qualifier, and they're different, the operation
+ fails (even if one is subset of the other).
+
+ This operation may fail. In that case, the error value returned provides
+ reasoning for the failure.
+
+ You'll need to include stdbackport/expected to use this. */
+
+gcc::expected<qualifier_set, qualifier_set::join_error>
+qualifier_set::join (qualifier_set other) const
+{
+ using JE = qualifier_set::join_error;
+ auto cv_merged = cv_quals () | other.cv_quals ();
+ auto as1 = addr_space ();
+ auto as2 = other.addr_space ();
+
+ addr_space_t as = ADDR_SPACE_GENERIC;
+ if (as1 == as2)
+ as = as1;
+ else if (!ADDR_SPACE_GENERIC_P (as1) && !ADDR_SPACE_GENERIC_P (as2))
+ return gcc::make_unexpected (JE::double_addr_space);
+ else if (ADDR_SPACE_GENERIC_P (as1))
+ as = as2;
+ else
+ as = as1;
+
+ return qualifier_set {cv_merged, as};
+}
+
+/* Returns true if qualifiers in OTHER can be replaced with qualifiers in THIS
+ safely.
+
+ If !POINTEE, such a replacement is safe iff 'cv2 int *' can be converted
+ into 'cv1 int *' where cv1 are the qualifiers in THIS and cv2 the qualifiers
+ in OTHER.
+
+ Otherwise, such a replacement is safe iff 'cv2 int * const *' can be
+ converted into 'cv1 int * const *' with cv1 and cv2 as above. */
+
+bool
+qualifier_set::compatible_with (qualifier_set other,
+ bool pointee /* = false */) const
+{
+ /* Compatible if THIS contains all of CVR of OTHER, has the same value of
+ the _Atomic qualifier as OTHER, and has a superset address space.
+
+ If POINTEE, then it must be possible to reinterpret the value of one
+ qualification as a value of the other qualification, and thus, the
+ address spaces must be strictly equal. */
+ auto cv_this = cv_quals ();
+ auto cv_other = other.cv_quals ();
+ auto as_this = addr_space ();
+ auto as_other = other.addr_space ();
+ return ((cv_this & cv_other) == cv_other
+ /* Differences in the _Atomic qualifier cannot be crossed. */
+ && (cv_this & TYPE_QUAL_ATOMIC) == (cv_other & TYPE_QUAL_ATOMIC)
+ && (as_this == as_other
+ || (!pointee
+ && targetm.addr_space.subset_p (as_other, as_this))));
+}
+
+DEBUG_FUNCTION void
+qualifier_set::debug () const
+{
+ putc ('{', stderr);
+ cv_qualifier cv;
+ addr_space_t as;
+ std::tie (cv, as) = split ();
+ bool has_previous = false;
+ auto handle_bit = [&] (cv_qualifier bit, const char *lbl)
+ {
+ if (!(cv & bit))
+ return;
+
+ if (has_previous)
+ fputs (", ", stderr);
+
+ has_previous = true;
+ fputs (lbl, stderr);
+ };
+
+ handle_bit (TYPE_QUAL_CONST, "const");
+ handle_bit (TYPE_QUAL_VOLATILE, "volatile");
+ handle_bit (TYPE_QUAL_RESTRICT, "restrict");
+ handle_bit (TYPE_QUAL_ATOMIC, "_Atomic");
+
+ /* If new bits appear, let the developer know. */
+ static_assert ((TYPE_QUAL_CONST | TYPE_QUAL_VOLATILE | TYPE_QUAL_RESTRICT
+ | TYPE_QUAL_ATOMIC)
+ == TYPE_QUAL_ALL,
+ "new qualifiers added, update handle_bit calls above");
+
+ if (has_previous)
+ fputs (", ", stderr);
+
+ fprintf (stderr, "AS%d", as);
+
+ fputs ("}\n", stderr);
+}
+
+/* Set the type qualifiers for TYPE to TYPE_QUALS. */
static void
-set_type_quals (tree type, int type_quals)
+set_type_quals (tree type, qualifier_set type_quals)
{
- TYPE_READONLY (type) = (type_quals & TYPE_QUAL_CONST) != 0;
- TYPE_VOLATILE (type) = (type_quals & TYPE_QUAL_VOLATILE) != 0;
- TYPE_RESTRICT (type) = (type_quals & TYPE_QUAL_RESTRICT) != 0;
- TYPE_ATOMIC (type) = (type_quals & TYPE_QUAL_ATOMIC) != 0;
- TYPE_ADDR_SPACE (type) = DECODE_QUAL_ADDR_SPACE (type_quals);
+ TYPE_READONLY (type) = type_quals.has (TYPE_QUAL_CONST);
+ TYPE_VOLATILE (type) = type_quals.has (TYPE_QUAL_VOLATILE);
+ TYPE_RESTRICT (type) = type_quals.has (TYPE_QUAL_RESTRICT);
+ TYPE_ATOMIC (type) = type_quals.has (TYPE_QUAL_ATOMIC);
+ TYPE_ADDR_SPACE (type) = type_quals.addr_space ();
}
/* Returns true iff CAND and BASE have equivalent language-specific
@@ -5783,7 +5935,7 @@ check_base_type (const_tree cand, const_tree base)
return true;
/* Atomic types increase minimal alignment. We must to do so as well
or we get duplicated canonical types. See PR88686. */
- if ((TYPE_QUALS (cand) & TYPE_QUAL_ATOMIC))
+ if (TYPE_QUALS (cand).has (TYPE_QUAL_ATOMIC))
{
/* See if this object can map to a basic atomic type. */
tree atomic_type = find_atomic_core_type (cand);
@@ -5796,7 +5948,7 @@ check_base_type (const_tree cand, const_tree base)
/* Returns true iff CAND is equivalent to BASE with TYPE_QUALS. */
bool
-check_qualified_type (const_tree cand, const_tree base, int type_quals)
+check_qualified_type (const_tree cand, const_tree base, qualifier_set type_quals)
{
return (TYPE_QUALS (cand) == type_quals
&& check_base_type (cand, base)
@@ -5827,7 +5979,7 @@ check_aligned_type (const_tree cand, const_tree base, unsigned int align)
return NULL_TREE. */
tree
-get_qualified_type (tree type, int type_quals)
+get_qualified_type (tree type, qualifier_set type_quals)
{
if (TYPE_QUALS (type) == type_quals)
return type;
@@ -5859,7 +6011,7 @@ get_qualified_type (tree type, int type_quals)
exist. This function never returns NULL_TREE. */
tree
-build_qualified_type (tree type, int type_quals MEM_STAT_DECL)
+build_qualified_type (tree type, qualifier_set type_quals MEM_STAT_DECL)
{
tree t;
@@ -5872,7 +6024,7 @@ build_qualified_type (tree type, int type_quals MEM_STAT_DECL)
t = build_variant_type_copy (type PASS_MEM_STAT);
set_type_quals (t, type_quals);
- if (((type_quals & TYPE_QUAL_ATOMIC) == TYPE_QUAL_ATOMIC))
+ if (type_quals.has (TYPE_QUAL_ATOMIC))
{
/* See if this object can map to a basic atomic type. */
tree atomic_type = find_atomic_core_type (type);
diff --git a/gcc/tree.h b/gcc/tree.h
index 3fb643ea0fb4..a2e793d77ab6 100644
--- a/gcc/tree.h
+++ b/gcc/tree.h
@@ -21,8 +21,10 @@ along with GCC; see the file COPYING3. If not see
#define GCC_TREE_H
#include "tree-core.h"
+#include "coretypes.h"
#include "options.h"
#include "vec.h"
+#include "stdbackport/expectedfwd"
/* Convert a target-independent built-in function code to a combined_fn. */
@@ -2579,39 +2581,256 @@ extern tree vector_element_bits_tree (const_tree);
/* The address space the type is in. */
#define TYPE_ADDR_SPACE(NODE) (TYPE_CHECK (NODE)->base.u.bits.address_space)
-/* Encode/decode the named memory support as part of the qualifier. If more
- than 8 qualifiers are added, these macros need to be adjusted. */
-#define ENCODE_QUAL_ADDR_SPACE(NUM) (((NUM) & 0xFF) << 8)
-#define DECODE_QUAL_ADDR_SPACE(X) (((X) >> 8) & 0xFF)
+/* A qualifier set is the aggregate of all qualifiers on a given type. It
+ consists of the 'const', 'volatile', 'restrict', and 'atomic' qualification,
+ which are all either present or absent, and an address space qualifier,
+ which is always present (but possibly ADDR_SPACE_GENERIC). */
-/* Return all qualifiers except for the address space qualifiers. */
-#define CLEAR_QUAL_ADDR_SPACE(X) ((X) & ~0xFF00)
+struct qualifier_set
+{
+ /* Construct an empty qualifier set with the generic address space. Such a
+ qualifier set corresponds to unqualified types.
-/* Only keep the address space out of the qualifiers and discard the other
- qualifiers. */
-#define KEEP_QUAL_ADDR_SPACE(X) ((X) & 0xFF00)
+ This constructor is guaranteed to be trivial, so that it is possible to
+ initialize an empty qualifier set in a given location using a zeroing
+ 'memset'. */
+ qualifier_set () = default;
-/* The set of type qualifiers for this type. */
-#define TYPE_QUALS(NODE) \
- ((int) ((TYPE_READONLY (NODE) * TYPE_QUAL_CONST) \
- | (TYPE_VOLATILE (NODE) * TYPE_QUAL_VOLATILE) \
- | (TYPE_ATOMIC (NODE) * TYPE_QUAL_ATOMIC) \
- | (TYPE_RESTRICT (NODE) * TYPE_QUAL_RESTRICT) \
- | (ENCODE_QUAL_ADDR_SPACE (TYPE_ADDR_SPACE (NODE)))))
+ /* Construct a qualifier set containing the qualifiers CV_QUALS and the
+ generic address space. */
+ constexpr
+ qualifier_set (cv_qualifier cv_quals)
+ : m_cv_quals {cv_quals}
+ , m_addr_space {ADDR_SPACE_GENERIC}
+ {}
+
+ /* Construct a qualifier set containing the qualifiers CV_QUALS and the
+ address space AS. */
+ constexpr
+ qualifier_set (cv_qualifier cv_quals, addr_space_t as)
+ : m_cv_quals {cv_quals}
+ , m_addr_space {as}
+ {}
+
+ /* Add QUAL to this qualifier set. */
+ constexpr void
+ add (cv_qualifier qual)
+ {
+ m_cv_quals |= qual;
+ }
+
+ /* Remove QUAL from this qualifier set. */
+ constexpr void
+ remove (cv_qualifier qual)
+ {
+ m_cv_quals &= ~qual;
+ }
+
+ /* Set the address space of this qualifier set to AS. */
+ constexpr void
+ set_as (addr_space_t as)
+ {
+ this->m_addr_space = as;
+ }
+
+ /* Returns a new qualifier set, with QUAL added (as with 'add'). */
+ WARN_UNUSED_RESULT constexpr qualifier_set
+ with (cv_qualifier qual) const
+ {
+ auto ret = *this;
+ ret.add (qual);
+ return ret;
+ }
+
+ /* Returns a new qualifier set, with QUAL removed (as with 'remove'). */
+ WARN_UNUSED_RESULT constexpr qualifier_set
+ without (cv_qualifier qual) const
+ {
+ auto ret = *this;
+ ret.remove (qual);
+ return ret;
+ }
+
+ /* Return this qualifier set, with address space set to AS. */
+ WARN_UNUSED_RESULT constexpr qualifier_set
+ with_as (addr_space_t as) const
+ {
+ auto ret = *this;
+ ret.set_as (as);
+ return ret;
+ }
+
+ /* Get CV qualifiers of this qualifier set.
+
+ Using this getter alone is usually a mistake; most of the time, where
+ there is a qualifier_set, there should be handling for all its components,
+ rather than just one of them. Prefer using 'split' at least once in a
+ given hunk. */
+ constexpr cv_qualifier
+ cv_quals () const
+ { return m_cv_quals; }
+
+ /* Get address space qualifier of this qualifier set.
+
+ Using this getter alone is usually a mistake; most of the time, where
+ there is a qualifier_set, there should be handling for all its components,
+ rather than just one of them. Prefer using 'split' at least once in a
+ given hunk. */
+ constexpr addr_space_t
+ addr_space () const
+ { return m_addr_space; }
+
+ /* Return all qualifiers both in this qualifier set and in OTHER_CV. */
+ WARN_UNUSED_RESULT constexpr cv_qualifier
+ intersect (cv_qualifier other_cv) const
+ { return cv_quals () & other_cv; }
+
+ /* Return true iff any of OTHER_CV are contained in THIS. */
+ constexpr bool
+ has (cv_qualifier other_cv) const
+ { return intersect (other_cv); }
+
+ /* Get the symmetric difference of this qualifier set with CV-qualifiers
+ QUAL. Of course, as QUAL lacks an address space, the address space of
+ this qualifier set is preserved. */
+ WARN_UNUSED_RESULT constexpr qualifier_set
+ symmetric_difference (cv_qualifier qual) const
+ {
+ return {cv_quals () ^ qual, addr_space ()};
+ }
+
+ bool compatible_with (qualifier_set subset, bool nop_only = false) const;
+
+ enum class merge_error : unsigned char
+ {
+ /* The address spaces of the to-be-merged qualifier sets were disjoint,
+ i.e. neither contained the other. */
+ disjoint_address_spaces,
+
+ /* The to-be-merged qualifier sets differed in TYPE_QUAL_ATOMIC. */
+ atomic_mismatch,
+ };
+
+ gcc::expected<qualifier_set, merge_error>
+ merge (qualifier_set other, bool strict_addr_space = false) const;
+
+ enum class join_error : unsigned char
+ {
+ /* The joined qualifier set would've contained two address space
+ qualifiers. */
+ double_addr_space,
+ };
+
+ gcc::expected<qualifier_set, join_error> join (qualifier_set other) const;
+
+ friend constexpr bool
+ operator== (const qualifier_set &a, const qualifier_set &b)
+ {
+ return ((a.cv_quals () == b.cv_quals ())
+ && (a.addr_space () == b.addr_space ()));
+ }
+
+ friend constexpr bool
+ operator!= (const qualifier_set &a, const qualifier_set &b)
+ {
+ return !(a == b);
+ }
+
+ /* Split this qualifier set into its constituent parts. Useful where you
+ need to make sure you've handled all the components of a qualifier
+ set. */
+
+ constexpr std::pair<cv_qualifier, addr_space_t>
+ split () const
+ { return std::make_pair (cv_quals (), addr_space ()); }
+
+ /* True iff this qualifier set is different to {ADDR_SPACE_GENERIC} (i.e. if
+ it is syntactically non-empty). */
+ constexpr bool
+ nonempty_p () const
+ { return *this != qualifier_set {}; }
+
+ /* Shorthand for 'nonempty_p', for use in conditions. */
+ explicit constexpr
+ operator bool () const
+ { return nonempty_p (); }
+
+ /* Dump the contents of this qualifier set to stderr. */
+ void debug () const;
+
+private:
+ cv_qualifier m_cv_quals;
+ addr_space_t m_addr_space;
+};
+static_assert (std::is_trivially_copyable<qualifier_set>::value, "");
+static_assert (std::is_trivially_destructible<qualifier_set>::value, "");
+static_assert (std::is_trivially_default_constructible<qualifier_set>::value,
+ "");
+static_assert ((qualifier_set {}
+ == qualifier_set {TYPE_UNQUALIFIED,
+ ADDR_SPACE_GENERIC}),
+ "We want the trivial default constructor to create a "
+ "syntactically-empty qualifier set");
+
+/* Operators & and &= are intentionally omitted, as they permit losing
+ information too easily, and silently changed the meaning of existing code.
+ Use 'compatible_with', 'intersect' and 'has' instead. */
+
+/* For OR (union) and XOR (mutual difference) operations, we could keep an
+ address space, ergo we must return qualifier_sets. */
+
+constexpr qualifier_set
+operator| (qualifier_set qs, cv_qualifier cvs)
+{
+ return qs.with (cvs);
+}
+
+constexpr qualifier_set
+operator| (cv_qualifier cvs, qualifier_set qs)
+{
+ return qs.with (cvs);
+}
+
+constexpr qualifier_set
+operator^ (qualifier_set qs, cv_qualifier cvs)
+{
+ return qs.symmetric_difference (cvs);
+}
+
+constexpr qualifier_set
+operator^ (cv_qualifier cvs, qualifier_set qs)
+{
+ return qs.symmetric_difference (cvs);
+}
+
+constexpr qualifier_set &
+operator|= (qualifier_set &qs, cv_qualifier quals)
+{
+ return qs = qs | quals;
+}
+constexpr qualifier_set &
+operator^= (qualifier_set &qs, cv_qualifier quals)
+{
+ return qs = qs ^ quals;
+}
/* The same as TYPE_QUALS without the address space qualifications. */
-#define TYPE_QUALS_NO_ADDR_SPACE(NODE) \
- ((int) ((TYPE_READONLY (NODE) * TYPE_QUAL_CONST) \
- | (TYPE_VOLATILE (NODE) * TYPE_QUAL_VOLATILE) \
- | (TYPE_ATOMIC (NODE) * TYPE_QUAL_ATOMIC) \
- | (TYPE_RESTRICT (NODE) * TYPE_QUAL_RESTRICT)))
+#define TYPE_QUALS_NO_ADDR_SPACE(NODE) \
+ (cv_qualifier ((TYPE_READONLY (NODE) * TYPE_QUAL_CONST) \
+ | (TYPE_VOLATILE (NODE) * TYPE_QUAL_VOLATILE) \
+ | (TYPE_ATOMIC (NODE) * TYPE_QUAL_ATOMIC) \
+ | (TYPE_RESTRICT (NODE) * TYPE_QUAL_RESTRICT)))
+
+/* The set of type qualifiers for this type. */
+#define TYPE_QUALS(NODE) \
+ (qualifier_set {(TYPE_QUALS_NO_ADDR_SPACE (NODE)), (TYPE_ADDR_SPACE (NODE))})
/* The same as TYPE_QUALS without the address space and atomic
qualifications. */
-#define TYPE_QUALS_NO_ADDR_SPACE_NO_ATOMIC(NODE) \
- ((int) ((TYPE_READONLY (NODE) * TYPE_QUAL_CONST) \
- | (TYPE_VOLATILE (NODE) * TYPE_QUAL_VOLATILE) \
- | (TYPE_RESTRICT (NODE) * TYPE_QUAL_RESTRICT)))
+#define TYPE_QUALS_NO_ADDR_SPACE_NO_ATOMIC(NODE) \
+ (cv_qualifier ((TYPE_READONLY (NODE) * TYPE_QUAL_CONST) \
+ | (TYPE_VOLATILE (NODE) * TYPE_QUAL_VOLATILE) \
+ | (TYPE_RESTRICT (NODE) * TYPE_QUAL_RESTRICT)))
/* These flags are available for each language front end to use internally. */
#define TYPE_LANG_FLAG_0(NODE) (TYPE_CHECK (NODE)->type_common.lang_flag_0)
@@ -5281,18 +5500,18 @@ extern bool check_base_type (const_tree cand, const_tree base);
/* Check whether CAND is suitable to be returned from get_qualified_type
(BASE, TYPE_QUALS). */
-extern bool check_qualified_type (const_tree, const_tree, int);
+extern bool check_qualified_type (const_tree, const_tree, qualifier_set);
/* Return a version of the TYPE, qualified as indicated by the
TYPE_QUALS, if one exists. If no qualified version exists yet,
return NULL_TREE. */
-extern tree get_qualified_type (tree, int);
+extern tree get_qualified_type (tree, qualifier_set);
/* Like get_qualified_type, but creates the type if it does not
exist. This function never returns NULL_TREE. */
-extern tree build_qualified_type (tree, int CXX_MEM_STAT_INFO);
+extern tree build_qualified_type (tree, qualifier_set CXX_MEM_STAT_INFO);
/* Create a variant of type T with alignment ALIGN. */
@@ -5304,9 +5523,10 @@ extern tree build_aligned_type (tree, unsigned int);
build_qualified_type instead. */
#define build_type_variant(TYPE, CONST_P, VOLATILE_P) \
- build_qualified_type ((TYPE), \
- ((CONST_P) ? TYPE_QUAL_CONST : 0) \
- | ((VOLATILE_P) ? TYPE_QUAL_VOLATILE : 0))
+ (build_qualified_type \
+ ((TYPE), \
+ (((CONST_P) ? TYPE_QUAL_CONST : TYPE_UNQUALIFIED) \
+ | ((VOLATILE_P) ? TYPE_QUAL_VOLATILE : TYPE_UNQUALIFIED))))
/* Make a copy of a type node. */
diff --git a/gcc/ubsan.cc b/gcc/ubsan.cc
index 79a863b46ce6..e2596c25643a 100644
--- a/gcc/ubsan.cc
+++ b/gcc/ubsan.cc
@@ -1775,8 +1775,8 @@ instrument_bool_enum_load (gimple_stmt_iterator *gsi)
addr_space_t as = TYPE_ADDR_SPACE (TREE_TYPE (rhs));
if (as != TYPE_ADDR_SPACE (utype))
- utype = build_qualified_type (utype, TYPE_QUALS (utype)
- | ENCODE_QUAL_ADDR_SPACE (as));
+ utype = build_qualified_type (utype,
+ TYPE_QUALS (utype).with_as (as));
bool ends_bb = stmt_ends_bb_p (stmt);
location_t loc = gimple_location (stmt);
tree lhs = gimple_assign_lhs (stmt);
diff --git a/gcc/vtable-verify.cc b/gcc/vtable-verify.cc
index 05e14b24788d..1ffaa949fa94 100644
--- a/gcc/vtable-verify.cc
+++ b/gcc/vtable-verify.cc
@@ -378,7 +378,6 @@ vtbl_map_get_node (tree class_type)
tree class_type_decl;
tree class_name;
- unsigned int type_quals;
if (!vtbl_map_hash)
return NULL;
@@ -390,7 +389,7 @@ vtbl_map_get_node (tree class_type)
class_type_decl = TYPE_NAME (class_type);
/* Verify that there aren't any qualifiers on the type. */
- type_quals = TYPE_QUALS (TREE_TYPE (class_type_decl));
+ auto type_quals = TYPE_QUALS (TREE_TYPE (class_type_decl));
gcc_assert (type_quals == TYPE_UNQUALIFIED);
/* Get the mangled name for the unqualified type. */
@@ -417,7 +416,6 @@ find_or_create_vtbl_map_node (tree base_class_type)
struct vtbl_map_node *node;
struct vtbl_map_node **slot;
tree class_type_decl;
- unsigned int type_quals;
if (!vtbl_map_hash)
vtbl_map_hash = new vtbl_map_table_type (10);
@@ -426,7 +424,7 @@ find_or_create_vtbl_map_node (tree base_class_type)
class_type_decl = TYPE_NAME (base_class_type);
/* Verify that there aren't any type qualifiers on type. */
- type_quals = TYPE_QUALS (TREE_TYPE (class_type_decl));
+ auto type_quals = TYPE_QUALS (TREE_TYPE (class_type_decl));
gcc_assert (type_quals == TYPE_UNQUALIFIED);
gcc_assert (HAS_DECL_ASSEMBLER_NAME_P (class_type_decl));
diff --git a/libcc1/libcc1plugin.cc b/libcc1/libcc1plugin.cc
index 8b875eb0605b..cf5585e3d828 100644
--- a/libcc1/libcc1plugin.cc
+++ b/libcc1/libcc1plugin.cc
@@ -699,7 +699,7 @@ plugin_build_qualified_type (cc1_plugin::connection *,
enum gcc_qualifiers qualifiers)
{
tree unqualified_type = convert_in (unqualified_type_in);
- int quals = 0;
+ qualifier_set quals {};
if ((qualifiers & GCC_QUALIFIER_CONST) != 0)
quals |= TYPE_QUAL_CONST;
diff --git a/libcc1/libcp1plugin.cc b/libcc1/libcp1plugin.cc
index e62c6ef9b9bd..e331fbdcd5fd 100644
--- a/libcc1/libcp1plugin.cc
+++ b/libcc1/libcp1plugin.cc
@@ -1999,7 +1999,7 @@ plugin_build_method_type (cc1_plugin::connection *self,
{
tree class_type = convert_in (class_type_in);
tree func_type = convert_in (func_type_in);
- cp_cv_quals quals = 0;
+ cp_cv_quals quals {};
cp_ref_qualifier rquals;
if ((quals_in & GCC_CP_QUALIFIER_CONST) != 0)
@@ -3401,7 +3401,7 @@ plugin_build_qualified_type (cc1_plugin::connection *,
enum gcc_cp_qualifiers qualifiers)
{
tree unqualified_type = convert_in (unqualified_type_in);
- cp_cv_quals quals = 0;
+ cp_cv_quals quals {};
if ((qualifiers & GCC_CP_QUALIFIER_CONST) != 0)
quals |= TYPE_QUAL_CONST;
--
2.55.0
More information about the Gcc-rust
mailing list