diff options
author | Martin Liska <mliska@suse.cz> | 2017-08-08 06:46:51 +0200 |
---|---|---|
committer | Martin Liska <marxin@gcc.gnu.org> | 2017-08-08 04:46:51 +0000 |
commit | 314e6352040016aff26cc2cf0b9eb60c40ca859e (patch) | |
tree | 1c03471917bb6c90a9fca32e2ce7b5b594f9421d /gcc/attribs.c | |
parent | 082adc1e43fa073a9f7f5ab3bdaa2713a1cc2cdc (diff) | |
download | gcc-314e6352040016aff26cc2cf0b9eb60c40ca859e.tar.gz |
trans.c: Include header files.
.
2017-08-08 Martin Liska <mliska@suse.cz>
* gcc-interface/trans.c: Include header files.
2017-08-08 Martin Liska <mliska@suse.cz>
* objc-gnu-runtime-abi-01.c: Include header files.
* objc-next-runtime-abi-01.c: Likewise.
* objc-next-runtime-abi-02.c: Likewise.
2017-08-08 Martin Liska <mliska@suse.cz>
* asan.c: Include header files.
* attribs.c (build_decl_attribute_variant): New function moved
from tree.[ch].
(build_type_attribute_qual_variant): Likewise.
(cmp_attrib_identifiers): Likewise.
(simple_cst_list_equal): Likewise.
(omp_declare_simd_clauses_equal): Likewise.
(attribute_value_equal): Likewise.
(comp_type_attributes): Likewise.
(build_type_attribute_variant): Likewise.
(lookup_ident_attribute): Likewise.
(remove_attribute): Likewise.
(merge_attributes): Likewise.
(merge_type_attributes): Likewise.
(merge_decl_attributes): Likewise.
(merge_dllimport_decl_attributes): Likewise.
(handle_dll_attribute): Likewise.
(attribute_list_equal): Likewise.
(attribute_list_contained): Likewise.
* attribs.h (lookup_attribute): New function moved from tree.[ch].
(lookup_attribute_by_prefix): Likewise.
* bb-reorder.c: Include header files.
* builtins.c: Likewise.
* calls.c: Likewise.
* cfgexpand.c: Likewise.
* cgraph.c: Likewise.
* cgraphunit.c: Likewise.
* convert.c: Likewise.
* dwarf2out.c: Likewise.
* final.c: Likewise.
* fold-const.c: Likewise.
* function.c: Likewise.
* gimple-expr.c: Likewise.
* gimple-fold.c: Likewise.
* gimple-pretty-print.c: Likewise.
* gimple.c: Likewise.
* gimplify.c: Likewise.
* hsa-common.c: Likewise.
* hsa-gen.c: Likewise.
* internal-fn.c: Likewise.
* ipa-chkp.c: Likewise.
* ipa-cp.c: Likewise.
* ipa-devirt.c: Likewise.
* ipa-fnsummary.c: Likewise.
* ipa-inline.c: Likewise.
* ipa-visibility.c: Likewise.
* ipa.c: Likewise.
* lto-cgraph.c: Likewise.
* omp-expand.c: Likewise.
* omp-general.c: Likewise.
* omp-low.c: Likewise.
* omp-offload.c: Likewise.
* omp-simd-clone.c: Likewise.
* opts-global.c: Likewise.
* passes.c: Likewise.
* predict.c: Likewise.
* sancov.c: Likewise.
* sanopt.c: Likewise.
* symtab.c: Likewise.
* toplev.c: Likewise.
* trans-mem.c: Likewise.
* tree-chkp.c: Likewise.
* tree-eh.c: Likewise.
* tree-into-ssa.c: Likewise.
* tree-object-size.c: Likewise.
* tree-parloops.c: Likewise.
* tree-profile.c: Likewise.
* tree-ssa-ccp.c: Likewise.
* tree-ssa-live.c: Likewise.
* tree-ssa-loop.c: Likewise.
* tree-ssa-sccvn.c: Likewise.
* tree-ssa-structalias.c: Likewise.
* tree-ssa.c: Likewise.
* tree-streamer-in.c: Likewise.
* tree-vectorizer.c: Likewise.
* tree-vrp.c: Likewise.
* tsan.c: Likewise.
* ubsan.c: Likewise.
* varasm.c: Likewise.
* varpool.c: Likewise.
* tree.c: Remove functions moved to attribs.[ch].
* tree.h: Likewise.
* config/aarch64/aarch64.c: Add attrs.h header file.
* config/alpha/alpha.c: Likewise.
* config/arc/arc.c: Likewise.
* config/arm/arm.c: Likewise.
* config/avr/avr.c: Likewise.
* config/bfin/bfin.c: Likewise.
* config/c6x/c6x.c: Likewise.
* config/cr16/cr16.c: Likewise.
* config/cris/cris.c: Likewise.
* config/darwin.c: Likewise.
* config/epiphany/epiphany.c: Likewise.
* config/fr30/fr30.c: Likewise.
* config/frv/frv.c: Likewise.
* config/ft32/ft32.c: Likewise.
* config/h8300/h8300.c: Likewise.
* config/i386/winnt.c: Likewise.
* config/ia64/ia64.c: Likewise.
* config/iq2000/iq2000.c: Likewise.
* config/lm32/lm32.c: Likewise.
* config/m32c/m32c.c: Likewise.
* config/m32r/m32r.c: Likewise.
* config/m68k/m68k.c: Likewise.
* config/mcore/mcore.c: Likewise.
* config/microblaze/microblaze.c: Likewise.
* config/mips/mips.c: Likewise.
* config/mmix/mmix.c: Likewise.
* config/mn10300/mn10300.c: Likewise.
* config/moxie/moxie.c: Likewise.
* config/msp430/msp430.c: Likewise.
* config/nds32/nds32-isr.c: Likewise.
* config/nds32/nds32.c: Likewise.
* config/nios2/nios2.c: Likewise.
* config/nvptx/nvptx.c: Likewise.
* config/pa/pa.c: Likewise.
* config/pdp11/pdp11.c: Likewise.
* config/powerpcspe/powerpcspe.c: Likewise.
* config/riscv/riscv.c: Likewise.
* config/rl78/rl78.c: Likewise.
* config/rx/rx.c: Likewise.
* config/s390/s390.c: Likewise.
* config/sh/sh.c: Likewise.
* config/sol2.c: Likewise.
* config/sparc/sparc.c: Likewise.
* config/spu/spu.c: Likewise.
* config/stormy16/stormy16.c: Likewise.
* config/tilegx/tilegx.c: Likewise.
* config/tilepro/tilepro.c: Likewise.
* config/v850/v850.c: Likewise.
* config/vax/vax.c: Likewise.
* config/visium/visium.c: Likewise.
* config/xtensa/xtensa.c: Likewise.
2017-08-08 Martin Liska <mliska@suse.cz>
* call.c: Include header files.
* cp-gimplify.c: Likewise.
* cp-ubsan.c: Likewise.
* cvt.c: Likewise.
* init.c: Likewise.
* search.c: Likewise.
* semantics.c: Likewise.
* typeck.c: Likewise.
2017-08-08 Martin Liska <mliska@suse.cz>
* lto-lang.c: Include header files.
* lto-symtab.c: Likewise.
2017-08-08 Martin Liska <mliska@suse.cz>
* c-convert.c: Include header files.
* c-typeck.c: Likewise.
2017-08-08 Martin Liska <mliska@suse.cz>
* c-ada-spec.c: Include header files.
* c-ubsan.c: Likewise.
* c-warn.c: Likewise.
2017-08-08 Martin Liska <mliska@suse.cz>
* trans-types.c: Include header files.
From-SVN: r250946
Diffstat (limited to 'gcc/attribs.c')
-rw-r--r-- | gcc/attribs.c | 633 |
1 files changed, 633 insertions, 0 deletions
diff --git a/gcc/attribs.c b/gcc/attribs.c index 05fa8ef8692..faa0649e190 100644 --- a/gcc/attribs.c +++ b/gcc/attribs.c @@ -942,3 +942,636 @@ is_function_default_version (const tree decl) return (TREE_CODE (attr) == STRING_CST && strcmp (TREE_STRING_POINTER (attr), "default") == 0); } + +/* Return a declaration like DDECL except that its DECL_ATTRIBUTES + is ATTRIBUTE. */ + +tree +build_decl_attribute_variant (tree ddecl, tree attribute) +{ + DECL_ATTRIBUTES (ddecl) = attribute; + return ddecl; +} + +/* Return a type like TTYPE except that its TYPE_ATTRIBUTE + is ATTRIBUTE and its qualifiers are QUALS. + + Record such modified types already made so we don't make duplicates. */ + +tree +build_type_attribute_qual_variant (tree ttype, tree attribute, int quals) +{ + if (! attribute_list_equal (TYPE_ATTRIBUTES (ttype), attribute)) + { + tree ntype; + + /* Building a distinct copy of a tagged type is inappropriate; it + causes breakage in code that expects there to be a one-to-one + relationship between a struct and its fields. + build_duplicate_type is another solution (as used in + handle_transparent_union_attribute), but that doesn't play well + with the stronger C++ type identity model. */ + if (TREE_CODE (ttype) == RECORD_TYPE + || TREE_CODE (ttype) == UNION_TYPE + || TREE_CODE (ttype) == QUAL_UNION_TYPE + || TREE_CODE (ttype) == ENUMERAL_TYPE) + { + warning (OPT_Wattributes, + "ignoring attributes applied to %qT after definition", + TYPE_MAIN_VARIANT (ttype)); + return build_qualified_type (ttype, quals); + } + + ttype = build_qualified_type (ttype, TYPE_UNQUALIFIED); + ntype = build_distinct_type_copy (ttype); + + TYPE_ATTRIBUTES (ntype) = attribute; + + hashval_t hash = type_hash_canon_hash (ntype); + ntype = type_hash_canon (hash, ntype); + + /* If the target-dependent attributes make NTYPE different from + its canonical type, we will need to use structural equality + checks for this type. */ + if (TYPE_STRUCTURAL_EQUALITY_P (ttype) + || !comp_type_attributes (ntype, ttype)) + SET_TYPE_STRUCTURAL_EQUALITY (ntype); + else if (TYPE_CANONICAL (ntype) == ntype) + TYPE_CANONICAL (ntype) = TYPE_CANONICAL (ttype); + + ttype = build_qualified_type (ntype, quals); + } + else if (TYPE_QUALS (ttype) != quals) + ttype = build_qualified_type (ttype, quals); + + return ttype; +} + +/* Compare two identifier nodes representing attributes. + Return true if they are the same, false otherwise. */ + +static bool +cmp_attrib_identifiers (const_tree attr1, const_tree attr2) +{ + /* Make sure we're dealing with IDENTIFIER_NODEs. */ + gcc_checking_assert (TREE_CODE (attr1) == IDENTIFIER_NODE + && TREE_CODE (attr2) == IDENTIFIER_NODE); + + /* Identifiers can be compared directly for equality. */ + if (attr1 == attr2) + return true; + + return cmp_attribs (IDENTIFIER_POINTER (attr1), IDENTIFIER_LENGTH (attr1), + IDENTIFIER_POINTER (attr2), IDENTIFIER_LENGTH (attr2)); +} + +/* Compare two constructor-element-type constants. Return 1 if the lists + are known to be equal; otherwise return 0. */ + +static bool +simple_cst_list_equal (const_tree l1, const_tree l2) +{ + while (l1 != NULL_TREE && l2 != NULL_TREE) + { + if (simple_cst_equal (TREE_VALUE (l1), TREE_VALUE (l2)) != 1) + return false; + + l1 = TREE_CHAIN (l1); + l2 = TREE_CHAIN (l2); + } + + return l1 == l2; +} + +/* Check if "omp declare simd" attribute arguments, CLAUSES1 and CLAUSES2, are + the same. */ + +static bool +omp_declare_simd_clauses_equal (tree clauses1, tree clauses2) +{ + tree cl1, cl2; + for (cl1 = clauses1, cl2 = clauses2; + cl1 && cl2; + cl1 = OMP_CLAUSE_CHAIN (cl1), cl2 = OMP_CLAUSE_CHAIN (cl2)) + { + if (OMP_CLAUSE_CODE (cl1) != OMP_CLAUSE_CODE (cl2)) + return false; + if (OMP_CLAUSE_CODE (cl1) != OMP_CLAUSE_SIMDLEN) + { + if (simple_cst_equal (OMP_CLAUSE_DECL (cl1), + OMP_CLAUSE_DECL (cl2)) != 1) + return false; + } + switch (OMP_CLAUSE_CODE (cl1)) + { + case OMP_CLAUSE_ALIGNED: + if (simple_cst_equal (OMP_CLAUSE_ALIGNED_ALIGNMENT (cl1), + OMP_CLAUSE_ALIGNED_ALIGNMENT (cl2)) != 1) + return false; + break; + case OMP_CLAUSE_LINEAR: + if (simple_cst_equal (OMP_CLAUSE_LINEAR_STEP (cl1), + OMP_CLAUSE_LINEAR_STEP (cl2)) != 1) + return false; + break; + case OMP_CLAUSE_SIMDLEN: + if (simple_cst_equal (OMP_CLAUSE_SIMDLEN_EXPR (cl1), + OMP_CLAUSE_SIMDLEN_EXPR (cl2)) != 1) + return false; + default: + break; + } + } + return true; +} + + +/* Compare two attributes for their value identity. Return true if the + attribute values are known to be equal; otherwise return false. */ + +bool +attribute_value_equal (const_tree attr1, const_tree attr2) +{ + if (TREE_VALUE (attr1) == TREE_VALUE (attr2)) + return true; + + if (TREE_VALUE (attr1) != NULL_TREE + && TREE_CODE (TREE_VALUE (attr1)) == TREE_LIST + && TREE_VALUE (attr2) != NULL_TREE + && TREE_CODE (TREE_VALUE (attr2)) == TREE_LIST) + { + /* Handle attribute format. */ + if (is_attribute_p ("format", get_attribute_name (attr1))) + { + attr1 = TREE_VALUE (attr1); + attr2 = TREE_VALUE (attr2); + /* Compare the archetypes (printf/scanf/strftime/...). */ + if (!cmp_attrib_identifiers (TREE_VALUE (attr1), TREE_VALUE (attr2))) + return false; + /* Archetypes are the same. Compare the rest. */ + return (simple_cst_list_equal (TREE_CHAIN (attr1), + TREE_CHAIN (attr2)) == 1); + } + return (simple_cst_list_equal (TREE_VALUE (attr1), + TREE_VALUE (attr2)) == 1); + } + + if ((flag_openmp || flag_openmp_simd) + && TREE_VALUE (attr1) && TREE_VALUE (attr2) + && TREE_CODE (TREE_VALUE (attr1)) == OMP_CLAUSE + && TREE_CODE (TREE_VALUE (attr2)) == OMP_CLAUSE) + return omp_declare_simd_clauses_equal (TREE_VALUE (attr1), + TREE_VALUE (attr2)); + + return (simple_cst_equal (TREE_VALUE (attr1), TREE_VALUE (attr2)) == 1); +} + +/* Return 0 if the attributes for two types are incompatible, 1 if they + are compatible, and 2 if they are nearly compatible (which causes a + warning to be generated). */ +int +comp_type_attributes (const_tree type1, const_tree type2) +{ + const_tree a1 = TYPE_ATTRIBUTES (type1); + const_tree a2 = TYPE_ATTRIBUTES (type2); + const_tree a; + + if (a1 == a2) + return 1; + for (a = a1; a != NULL_TREE; a = TREE_CHAIN (a)) + { + const struct attribute_spec *as; + const_tree attr; + + as = lookup_attribute_spec (get_attribute_name (a)); + if (!as || as->affects_type_identity == false) + continue; + + attr = lookup_attribute (as->name, CONST_CAST_TREE (a2)); + if (!attr || !attribute_value_equal (a, attr)) + break; + } + if (!a) + { + for (a = a2; a != NULL_TREE; a = TREE_CHAIN (a)) + { + const struct attribute_spec *as; + + as = lookup_attribute_spec (get_attribute_name (a)); + if (!as || as->affects_type_identity == false) + continue; + + if (!lookup_attribute (as->name, CONST_CAST_TREE (a1))) + break; + /* We don't need to compare trees again, as we did this + already in first loop. */ + } + /* All types - affecting identity - are equal, so + there is no need to call target hook for comparison. */ + if (!a) + return 1; + } + if (lookup_attribute ("transaction_safe", CONST_CAST_TREE (a))) + return 0; + /* As some type combinations - like default calling-convention - might + be compatible, we have to call the target hook to get the final result. */ + return targetm.comp_type_attributes (type1, type2); +} + +/* Return a type like TTYPE except that its TYPE_ATTRIBUTE + is ATTRIBUTE. + + Record such modified types already made so we don't make duplicates. */ + +tree +build_type_attribute_variant (tree ttype, tree attribute) +{ + return build_type_attribute_qual_variant (ttype, attribute, + TYPE_QUALS (ttype)); +} + +/* A variant of lookup_attribute() that can be used with an identifier + as the first argument, and where the identifier can be either + 'text' or '__text__'. + + Given an attribute ATTR_IDENTIFIER, and a list of attributes LIST, + return a pointer to the attribute's list element if the attribute + is part of the list, or NULL_TREE if not found. If the attribute + appears more than once, this only returns the first occurrence; the + TREE_CHAIN of the return value should be passed back in if further + occurrences are wanted. ATTR_IDENTIFIER must be an identifier but + can be in the form 'text' or '__text__'. */ +static tree +lookup_ident_attribute (tree attr_identifier, tree list) +{ + gcc_checking_assert (TREE_CODE (attr_identifier) == IDENTIFIER_NODE); + + while (list) + { + gcc_checking_assert (TREE_CODE (get_attribute_name (list)) + == IDENTIFIER_NODE); + + if (cmp_attrib_identifiers (attr_identifier, + get_attribute_name (list))) + /* Found it. */ + break; + list = TREE_CHAIN (list); + } + + return list; +} + +/* Remove any instances of attribute ATTR_NAME in LIST and return the + modified list. */ + +tree +remove_attribute (const char *attr_name, tree list) +{ + tree *p; + gcc_checking_assert (attr_name[0] != '_'); + + for (p = &list; *p;) + { + tree l = *p; + + tree attr = get_attribute_name (l); + if (is_attribute_p (attr_name, attr)) + *p = TREE_CHAIN (l); + else + p = &TREE_CHAIN (l); + } + + return list; +} + +/* Return an attribute list that is the union of a1 and a2. */ + +tree +merge_attributes (tree a1, tree a2) +{ + tree attributes; + + /* Either one unset? Take the set one. */ + + if ((attributes = a1) == 0) + attributes = a2; + + /* One that completely contains the other? Take it. */ + + else if (a2 != 0 && ! attribute_list_contained (a1, a2)) + { + if (attribute_list_contained (a2, a1)) + attributes = a2; + else + { + /* Pick the longest list, and hang on the other list. */ + + if (list_length (a1) < list_length (a2)) + attributes = a2, a2 = a1; + + for (; a2 != 0; a2 = TREE_CHAIN (a2)) + { + tree a; + for (a = lookup_ident_attribute (get_attribute_name (a2), + attributes); + a != NULL_TREE && !attribute_value_equal (a, a2); + a = lookup_ident_attribute (get_attribute_name (a2), + TREE_CHAIN (a))) + ; + if (a == NULL_TREE) + { + a1 = copy_node (a2); + TREE_CHAIN (a1) = attributes; + attributes = a1; + } + } + } + } + return attributes; +} + +/* Given types T1 and T2, merge their attributes and return + the result. */ + +tree +merge_type_attributes (tree t1, tree t2) +{ + return merge_attributes (TYPE_ATTRIBUTES (t1), + TYPE_ATTRIBUTES (t2)); +} + +/* Given decls OLDDECL and NEWDECL, merge their attributes and return + the result. */ + +tree +merge_decl_attributes (tree olddecl, tree newdecl) +{ + return merge_attributes (DECL_ATTRIBUTES (olddecl), + DECL_ATTRIBUTES (newdecl)); +} + +#if TARGET_DLLIMPORT_DECL_ATTRIBUTES + +/* Specialization of merge_decl_attributes for various Windows targets. + + This handles the following situation: + + __declspec (dllimport) int foo; + int foo; + + The second instance of `foo' nullifies the dllimport. */ + +tree +merge_dllimport_decl_attributes (tree old, tree new_tree) +{ + tree a; + int delete_dllimport_p = 1; + + /* What we need to do here is remove from `old' dllimport if it doesn't + appear in `new'. dllimport behaves like extern: if a declaration is + marked dllimport and a definition appears later, then the object + is not dllimport'd. We also remove a `new' dllimport if the old list + contains dllexport: dllexport always overrides dllimport, regardless + of the order of declaration. */ + if (!VAR_OR_FUNCTION_DECL_P (new_tree)) + delete_dllimport_p = 0; + else if (DECL_DLLIMPORT_P (new_tree) + && lookup_attribute ("dllexport", DECL_ATTRIBUTES (old))) + { + DECL_DLLIMPORT_P (new_tree) = 0; + warning (OPT_Wattributes, "%q+D already declared with dllexport " + "attribute: dllimport ignored", new_tree); + } + else if (DECL_DLLIMPORT_P (old) && !DECL_DLLIMPORT_P (new_tree)) + { + /* Warn about overriding a symbol that has already been used, e.g.: + extern int __attribute__ ((dllimport)) foo; + int* bar () {return &foo;} + int foo; + */ + if (TREE_USED (old)) + { + warning (0, "%q+D redeclared without dllimport attribute " + "after being referenced with dll linkage", new_tree); + /* If we have used a variable's address with dllimport linkage, + keep the old DECL_DLLIMPORT_P flag: the ADDR_EXPR using the + decl may already have had TREE_CONSTANT computed. + We still remove the attribute so that assembler code refers + to '&foo rather than '_imp__foo'. */ + if (VAR_P (old) && TREE_ADDRESSABLE (old)) + DECL_DLLIMPORT_P (new_tree) = 1; + } + + /* Let an inline definition silently override the external reference, + but otherwise warn about attribute inconsistency. */ + else if (VAR_P (new_tree) || !DECL_DECLARED_INLINE_P (new_tree)) + warning (OPT_Wattributes, "%q+D redeclared without dllimport " + "attribute: previous dllimport ignored", new_tree); + } + else + delete_dllimport_p = 0; + + a = merge_attributes (DECL_ATTRIBUTES (old), DECL_ATTRIBUTES (new_tree)); + + if (delete_dllimport_p) + a = remove_attribute ("dllimport", a); + + return a; +} + +/* Handle a "dllimport" or "dllexport" attribute; arguments as in + struct attribute_spec.handler. */ + +tree +handle_dll_attribute (tree * pnode, tree name, tree args, int flags, + bool *no_add_attrs) +{ + tree node = *pnode; + bool is_dllimport; + + /* These attributes may apply to structure and union types being created, + but otherwise should pass to the declaration involved. */ + if (!DECL_P (node)) + { + if (flags & ((int) ATTR_FLAG_DECL_NEXT | (int) ATTR_FLAG_FUNCTION_NEXT + | (int) ATTR_FLAG_ARRAY_NEXT)) + { + *no_add_attrs = true; + return tree_cons (name, args, NULL_TREE); + } + if (TREE_CODE (node) == RECORD_TYPE + || TREE_CODE (node) == UNION_TYPE) + { + node = TYPE_NAME (node); + if (!node) + return NULL_TREE; + } + else + { + warning (OPT_Wattributes, "%qE attribute ignored", + name); + *no_add_attrs = true; + return NULL_TREE; + } + } + + if (!VAR_OR_FUNCTION_DECL_P (node) && TREE_CODE (node) != TYPE_DECL) + { + *no_add_attrs = true; + warning (OPT_Wattributes, "%qE attribute ignored", + name); + return NULL_TREE; + } + + if (TREE_CODE (node) == TYPE_DECL + && TREE_CODE (TREE_TYPE (node)) != RECORD_TYPE + && TREE_CODE (TREE_TYPE (node)) != UNION_TYPE) + { + *no_add_attrs = true; + warning (OPT_Wattributes, "%qE attribute ignored", + name); + return NULL_TREE; + } + + is_dllimport = is_attribute_p ("dllimport", name); + + /* Report error on dllimport ambiguities seen now before they cause + any damage. */ + if (is_dllimport) + { + /* Honor any target-specific overrides. */ + if (!targetm.valid_dllimport_attribute_p (node)) + *no_add_attrs = true; + + else if (TREE_CODE (node) == FUNCTION_DECL + && DECL_DECLARED_INLINE_P (node)) + { + warning (OPT_Wattributes, "inline function %q+D declared as " + " dllimport: attribute ignored", node); + *no_add_attrs = true; + } + /* Like MS, treat definition of dllimported variables and + non-inlined functions on declaration as syntax errors. */ + else if (TREE_CODE (node) == FUNCTION_DECL && DECL_INITIAL (node)) + { + error ("function %q+D definition is marked dllimport", node); + *no_add_attrs = true; + } + + else if (VAR_P (node)) + { + if (DECL_INITIAL (node)) + { + error ("variable %q+D definition is marked dllimport", + node); + *no_add_attrs = true; + } + + /* `extern' needn't be specified with dllimport. + Specify `extern' now and hope for the best. Sigh. */ + DECL_EXTERNAL (node) = 1; + /* Also, implicitly give dllimport'd variables declared within + a function global scope, unless declared static. */ + if (current_function_decl != NULL_TREE && !TREE_STATIC (node)) + TREE_PUBLIC (node) = 1; + } + + if (*no_add_attrs == false) + DECL_DLLIMPORT_P (node) = 1; + } + else if (TREE_CODE (node) == FUNCTION_DECL + && DECL_DECLARED_INLINE_P (node) + && flag_keep_inline_dllexport) + /* An exported function, even if inline, must be emitted. */ + DECL_EXTERNAL (node) = 0; + + /* Report error if symbol is not accessible at global scope. */ + if (!TREE_PUBLIC (node) && VAR_OR_FUNCTION_DECL_P (node)) + { + error ("external linkage required for symbol %q+D because of " + "%qE attribute", node, name); + *no_add_attrs = true; + } + + /* A dllexport'd entity must have default visibility so that other + program units (shared libraries or the main executable) can see + it. A dllimport'd entity must have default visibility so that + the linker knows that undefined references within this program + unit can be resolved by the dynamic linker. */ + if (!*no_add_attrs) + { + if (DECL_VISIBILITY_SPECIFIED (node) + && DECL_VISIBILITY (node) != VISIBILITY_DEFAULT) + error ("%qE implies default visibility, but %qD has already " + "been declared with a different visibility", + name, node); + DECL_VISIBILITY (node) = VISIBILITY_DEFAULT; + DECL_VISIBILITY_SPECIFIED (node) = 1; + } + + return NULL_TREE; +} + +#endif /* TARGET_DLLIMPORT_DECL_ATTRIBUTES */ + +/* Given two lists of attributes, return true if list l2 is + equivalent to l1. */ + +int +attribute_list_equal (const_tree l1, const_tree l2) +{ + if (l1 == l2) + return 1; + + return attribute_list_contained (l1, l2) + && attribute_list_contained (l2, l1); +} + +/* Given two lists of attributes, return true if list L2 is + completely contained within L1. */ +/* ??? This would be faster if attribute names were stored in a canonicalized + form. Otherwise, if L1 uses `foo' and L2 uses `__foo__', the long method + must be used to show these elements are equivalent (which they are). */ +/* ??? It's not clear that attributes with arguments will always be handled + correctly. */ + +int +attribute_list_contained (const_tree l1, const_tree l2) +{ + const_tree t1, t2; + + /* First check the obvious, maybe the lists are identical. */ + if (l1 == l2) + return 1; + + /* Maybe the lists are similar. */ + for (t1 = l1, t2 = l2; + t1 != 0 && t2 != 0 + && get_attribute_name (t1) == get_attribute_name (t2) + && TREE_VALUE (t1) == TREE_VALUE (t2); + t1 = TREE_CHAIN (t1), t2 = TREE_CHAIN (t2)) + ; + + /* Maybe the lists are equal. */ + if (t1 == 0 && t2 == 0) + return 1; + + for (; t2 != 0; t2 = TREE_CHAIN (t2)) + { + const_tree attr; + /* This CONST_CAST is okay because lookup_attribute does not + modify its argument and the return value is assigned to a + const_tree. */ + for (attr = lookup_ident_attribute (get_attribute_name (t2), + CONST_CAST_TREE (l1)); + attr != NULL_TREE && !attribute_value_equal (t2, attr); + attr = lookup_ident_attribute (get_attribute_name (t2), + TREE_CHAIN (attr))) + ; + + if (attr == NULL_TREE) + return 0; + } + + return 1; +} |