public inbox for binutils@sourceware.org
 help / color / mirror / Atom feed
* GOLD: RFA: Fixing a coverty error for aarch64.cc
@ 2017-01-18 16:03 Nick Clifton
  2017-01-18 18:20 ` Cary Coutant
  0 siblings, 1 reply; 8+ messages in thread
From: Nick Clifton @ 2017-01-18 16:03 UTC (permalink / raw)
  To: iant, ccoutant, rearnsha, marcus.shawcroft; +Cc: binutils

Hi Guys,

  Running coverty on the GOLD sources has flagged a potential error in
  the aarch64.cc source file:

    binutils-2.27/gold/aarch64.cc:800: bad_sizeof: The expression
    "sizeof (ST_E_835769_INSNS) / sizeof (ST_E_835769_INSNS[0])"
    is suspicious. Note that "ST_E_835769_INSNS" is a pointer and
    therefore the division will not return the number of array
    elements which may have been the intent.

  Given that the source code concerned looks like this:
----------------------------------------------------------------
    const static Insntype ST_E_843419_INSNS[] =
      {
        0x00000000,    /* Placeholder for erratum insn. */
        0x14000000,    /* b <label> */
      };

    // ST_E_835769 has the same stub template as ST_E_843419.
    const static Insntype* ST_E_835769_INSNS = ST_E_843419_INSNS;

  #define install_insn_template(T) \
    const static Stub_template<big_endian> template_##T = {  \
      T##_INSNS, sizeof(T##_INSNS) / sizeof(T##_INSNS[0]) }; \
    this->stub_templates_[T] = &template_##T

    install_insn_template(ST_NONE);
    install_insn_template(ST_ADRP_BRANCH);
    install_insn_template(ST_LONG_BRANCH_ABS);
    install_insn_template(ST_LONG_BRANCH_PCREL);
    install_insn_template(ST_E_843419);
    install_insn_template(ST_E_835769);
----------------------------------------------------------------

  The error looks quite reasonable to me.

  So - any objections to the patch below ?  It just changes
  ST_E_835769_INSNS to be an array, like the other stubs.  This may not
  be the most efficient solution, but I think that it is the simplest.

Cheers
  Nick

gold/ChangeLog
2017-01-18  Nick Clifton  <nickc@redhat.com>

	* aarch64.cc (Stub_template_repertoire): Change ST_E_835769_INSNS
	from a pointer to an array.

diff --git a/gold/aarch64.cc b/gold/aarch64.cc
index b207dcd..b282ccf 100644
--- a/gold/aarch64.cc
+++ b/gold/aarch64.cc
@@ -784,8 +784,14 @@ Stub_template_repertoire<big_endian>::Stub_template_repertoire()
       0x14000000,    /* b <label> */
     };
 
-  // ST_E_835769 has the same stub template as ST_E_843419.
-  const static Insntype* ST_E_835769_INSNS = ST_E_843419_INSNS;
+  // ST_E_835769 has the same stub template as ST_E_843419
+  // but we reproduce the array here so that the sizeof
+  // expressions in install_insn_template will work.
+  const static Insntype ST_E_835769_INSNS[] =
+    {
+      0x00000000,    /* Placeholder for erratum insn. */
+      0x14000000,    /* b <label> */
+    };
 
 #define install_insn_template(T) \
   const static Stub_template<big_endian> template_##T = {  \

^ permalink raw reply	[flat|nested] 8+ messages in thread

* Re: GOLD: RFA: Fixing a coverty error for aarch64.cc
  2017-01-18 16:03 GOLD: RFA: Fixing a coverty error for aarch64.cc Nick Clifton
@ 2017-01-18 18:20 ` Cary Coutant
  2017-01-20 11:50   ` Pedro Alves
  0 siblings, 1 reply; 8+ messages in thread
From: Cary Coutant @ 2017-01-18 18:20 UTC (permalink / raw)
  To: Nick Clifton; +Cc: Ian Lance Taylor, rearnsha, marcus.shawcroft, Binutils

>   So - any objections to the patch below ?  It just changes
>   ST_E_835769_INSNS to be an array, like the other stubs.  This may not
>   be the most efficient solution, but I think that it is the simplest.
>
> gold/ChangeLog
> 2017-01-18  Nick Clifton  <nickc@redhat.com>
>
>         * aarch64.cc (Stub_template_repertoire): Change ST_E_835769_INSNS
>         from a pointer to an array.
>
> diff --git a/gold/aarch64.cc b/gold/aarch64.cc
> index b207dcd..b282ccf 100644
> --- a/gold/aarch64.cc
> +++ b/gold/aarch64.cc
> @@ -784,8 +784,14 @@ Stub_template_repertoire<big_endian>::Stub_template_repertoire()
>        0x14000000,    /* b <label> */
>      };
>
> -  // ST_E_835769 has the same stub template as ST_E_843419.
> -  const static Insntype* ST_E_835769_INSNS = ST_E_843419_INSNS;
> +  // ST_E_835769 has the same stub template as ST_E_843419
> +  // but we reproduce the array here so that the sizeof
> +  // expressions in install_insn_template will work.
> +  const static Insntype ST_E_835769_INSNS[] =
> +    {
> +      0x00000000,    /* Placeholder for erratum insn. */
> +      0x14000000,    /* b <label> */
> +    };
>
>  #define install_insn_template(T) \
>    const static Stub_template<big_endian> template_##T = {  \

LGTM. I can't think of a simpler fix either.

Thanks!

-cary

^ permalink raw reply	[flat|nested] 8+ messages in thread

* Re: GOLD: RFA: Fixing a coverty error for aarch64.cc
  2017-01-18 18:20 ` Cary Coutant
@ 2017-01-20 11:50   ` Pedro Alves
  2017-01-24  1:07     ` Cary Coutant
  0 siblings, 1 reply; 8+ messages in thread
From: Pedro Alves @ 2017-01-20 11:50 UTC (permalink / raw)
  To: Cary Coutant, Nick Clifton
  Cc: Ian Lance Taylor, rearnsha, marcus.shawcroft, Binutils

I would suggest letting the compiler handle computing
array sizes.  Something like the below.  (Build tested
only, feel free to run with it).   If you restore the
pointer with something like:

 +  const static Insntype* ST_E_835769_INSNS = ST_E_843419_INSNS;
 +
 [...]
 -  // ST_E_835769 has the same stub template as ST_E_843419.
 -  install_insn_template_insns(ST_E_835769, ST_E_843419);
 +  install_insn_template(ST_E_835769);
 
Then the compiler catches the problem:

 src/gold/aarch64.cc:798:65: error: no matching function for call to ‘{anonymous}::Stub_template<false>::Stub_template(const Insntype*&)’
    const static Stub_template<big_endian> template_##T (I##_INSNS); \
                                                                 ^
 src/gold/aarch64.cc:802:3: note: in expansion of macro ‘install_insn_template_insns’
    install_insn_template_insns(T, T)
    ^
 src/gold/aarch64.cc:808:3: note: in expansion of macro ‘install_insn_template’
     install_insn_template(ST_E_835769);
     ^
 src/gold/aarch64.cc:711:3: note: candidate: template<long unsigned int insn_num_>{anonymous}::Stub_template<big_endian>::Stub_template(const typename {anonymous}::AArch64_insn_utilities<big_endian>::Insntype(&)[insn_num_])
    Stub_template
    ^
 src/gold/aarch64.cc:711:3: note:   template argument deduction/substitution failed:
 src/gold/aarch64.cc:798:65: note:   mismatched types ‘const Insntype [insn_num_]’ and ‘const Insntype* {aka const unsigned int*}’
    const static Stub_template<big_endian> template_##T (I##_INSNS); \
 

(ST_NONE_INSNS is removed because (const-expression) arrays of 0
length are not valid C++, and compilers reject them / SFINAE them
out when deciding which constructor to call.)

From c7cd91832535b3989ec8f41a3d1eb51c7acc0ee4 Mon Sep 17 00:00:00 2001
From: Pedro Alves <palves@redhat.com>
Date: Fri, 20 Jan 2017 10:52:05 +0000
Subject: [PATCH]

---
 gold/aarch64.cc | 27 +++++++++++++++++----------
 1 file changed, 17 insertions(+), 10 deletions(-)

diff --git a/gold/aarch64.cc b/gold/aarch64.cc
index facbbd8..ab80472 100644
--- a/gold/aarch64.cc
+++ b/gold/aarch64.cc
@@ -703,6 +703,16 @@ enum
 template<bool big_endian>
 struct Stub_template
 {
+  Stub_template ()
+    : insns(NULL), insn_num(0)
+  { }
+
+  template<size_t insn_num_>
+  Stub_template
+    (const typename AArch64_insn_utilities<big_endian>::Insntype (&insns_)[insn_num_])
+      : insns(insns_), insn_num(insn_num_)
+  { }
+
   const typename AArch64_insn_utilities<big_endian>::Insntype* insns;
   const int insn_num;
 };
@@ -746,8 +756,6 @@ template<bool big_endian>
 Stub_template_repertoire<big_endian>::Stub_template_repertoire()
 {
   // Insn array definitions.
-  const static Insntype ST_NONE_INSNS[] = {};
-
   const static Insntype ST_ADRP_BRANCH_INSNS[] =
     {
       0x90000010,	/*	adrp	ip0, X		   */
@@ -784,20 +792,19 @@ Stub_template_repertoire<big_endian>::Stub_template_repertoire()
       0x14000000,    /* b <label> */
     };
 
-  // ST_E_835769 has the same stub template as ST_E_843419.
-  const static Insntype* ST_E_835769_INSNS = ST_E_843419_INSNS;
-
-#define install_insn_template(T) \
-  const static Stub_template<big_endian> template_##T = {  \
-    T##_INSNS, sizeof(T##_INSNS) / sizeof(T##_INSNS[0]) }; \
+#define install_insn_template_insns(T, I)				\
+  const static Stub_template<big_endian> template_##T (I##_INSNS);	\
   this->stub_templates_[T] = &template_##T
 
-  install_insn_template(ST_NONE);
+#define install_insn_template(T)					\
+  install_insn_template_insns(T, T)
+
   install_insn_template(ST_ADRP_BRANCH);
   install_insn_template(ST_LONG_BRANCH_ABS);
   install_insn_template(ST_LONG_BRANCH_PCREL);
   install_insn_template(ST_E_843419);
-  install_insn_template(ST_E_835769);
+  // ST_E_835769 has the same stub template as ST_E_843419.
+  install_insn_template_insns(ST_E_835769, ST_E_843419);
 
 #undef install_insn_template
 }
-- 
2.5.5


^ permalink raw reply	[flat|nested] 8+ messages in thread

* Re: GOLD: RFA: Fixing a coverty error for aarch64.cc
  2017-01-20 11:50   ` Pedro Alves
@ 2017-01-24  1:07     ` Cary Coutant
  2017-01-25  0:50       ` Pedro Alves
  0 siblings, 1 reply; 8+ messages in thread
From: Cary Coutant @ 2017-01-24  1:07 UTC (permalink / raw)
  To: Pedro Alves
  Cc: Nick Clifton, Ian Lance Taylor, rearnsha, marcus.shawcroft, Binutils

> I would suggest letting the compiler handle computing
> array sizes.  Something like the below.  (Build tested
> only, feel free to run with it).   If you restore the
> pointer with something like:
>
>  +  const static Insntype* ST_E_835769_INSNS = ST_E_843419_INSNS;
>  +
>  [...]
>  -  // ST_E_835769 has the same stub template as ST_E_843419.
>  -  install_insn_template_insns(ST_E_835769, ST_E_843419);
>  +  install_insn_template(ST_E_835769);
>
> Then the compiler catches the problem:

I like your suggestion, but I'm curious whether this depends on any
more recent features of C++ or the compiler. Would this work, say,
with GCC 4.2 (which is close to the oldest compiler we claim will work
for building gold)? Would it work with 4.6?

I'm not averse to moving the line forward a bit, but I don't think I'd
want to move it too far forward in one jump, or for the sake of one
minor patch. (For example, at some point, I'd like to start using auto
types and range-based for loops, among other not-all-that-new-anymore
features.)

-cary

^ permalink raw reply	[flat|nested] 8+ messages in thread

* Re: GOLD: RFA: Fixing a coverty error for aarch64.cc
  2017-01-24  1:07     ` Cary Coutant
@ 2017-01-25  0:50       ` Pedro Alves
  2017-01-25  0:57         ` [GOLD] [PATCH 1/3] aarch64.cc:Stub_template_repertoire: Avoid unnecessary, duplicate insns array Pedro Alves
                           ` (2 more replies)
  0 siblings, 3 replies; 8+ messages in thread
From: Pedro Alves @ 2017-01-25  0:50 UTC (permalink / raw)
  To: Cary Coutant
  Cc: Nick Clifton, Ian Lance Taylor, rearnsha, marcus.shawcroft, Binutils

On 01/24/2017 01:07 AM, Cary Coutant wrote:
>> I would suggest letting the compiler handle computing
>> array sizes.  Something like the below.  (Build tested
>> only, feel free to run with it).   If you restore the
>> pointer with something like:
>>
>>  +  const static Insntype* ST_E_835769_INSNS = ST_E_843419_INSNS;
>>  +
>>  [...]
>>  -  // ST_E_835769 has the same stub template as ST_E_843419.
>>  -  install_insn_template_insns(ST_E_835769, ST_E_843419);
>>  +  install_insn_template(ST_E_835769);
>>
>> Then the compiler catches the problem:
> 
> I like your suggestion, but I'm curious whether this depends on any
> more recent features of C++ or the compiler. Would this work, say,
> with GCC 4.2 (which is close to the oldest compiler we claim will work
> for building gold)? Would it work with 4.6?

Yes, this is plain old C++98.  I've tried it with GCC 4.1, and it works.
Given the template usage, and given C++98/C++03, a couple restrictions apply.
For example, we wouldn't be able to pass a stack/local array to the
constructor.  (Restriction lifted in C++11.)

For a while now I've been thinking of adding a C++11 version of libiberty's
ARRAY_SIZE using the same mechanism to gdb.  C++11 (which 
GDB requires) makes it trivial:

 template <class T, size_t N>
 constexpr size_t
 array_size (const T (&array)[N]) noexcept
 { return N; }

Actually, this is exactly what one of C++17's std::size
overloads looks like.

It's doable in C++03 too, with the restriction mentioned
above, using a (widely known and used) sizeof trick.  (See below.)

> 
> I'm not averse to moving the line forward a bit, but I don't think I'd
> want to move it too far forward in one jump, or for the sake of one
> minor patch. (For example, at some point, I'd like to start using auto
> types and range-based for loops, among other not-all-that-new-anymore
> features.)

FWIW, gdb master requires C++11 nowadays, with GCC 4.8 as baseline.  We found
that the latest stable versions of all the major distros have that or
newer gcc version either as system compiler, or available as
optional package, and decided to make the jump.  It's well worth it, IMO.

I'm replying to this email with a small series of 3 patches.  The first
two are the just the same patch split in two, in case you want to
take the new macro without the template stuff.  The last one adds
a C++03 array_size to gold and uses it throughout.  I checked that this
all builds with g++ 5.3 and g++ 4.1, but I haven't run regression
tests.

Thanks,
Pedro Alves

^ permalink raw reply	[flat|nested] 8+ messages in thread

* [GOLD] [PATCH 1/3] aarch64.cc:Stub_template_repertoire: Avoid unnecessary, duplicate insns array
  2017-01-25  0:50       ` Pedro Alves
@ 2017-01-25  0:57         ` Pedro Alves
  2017-01-25  0:58         ` [GOLD] [PATCH 3/3] Introduce and use array_size Pedro Alves
  2017-01-25  0:58         ` [GOLD] [PATCH 2/3] aarch64.cc:Stub_template: add array ref constructor Pedro Alves
  2 siblings, 0 replies; 8+ messages in thread
From: Pedro Alves @ 2017-01-25  0:57 UTC (permalink / raw)
  To: Cary Coutant
  Cc: Nick Clifton, Ian Lance Taylor, rearnsha, marcus.shawcroft, Binutils

gold/ChangeLog:
2017-01-24  Pedro Alves  <palves@redhat.com>

	* aarch64.cc (Stub_template_repertoire): Delete ST_E_835769_INSNS
	array.  Add new install_insn_template_insns macro, factored out
	from install_insn_template, and use it to install the stub
	template for ST_E_835769.
---
 gold/aarch64.cc | 19 +++++++------------
 1 file changed, 7 insertions(+), 12 deletions(-)

diff --git a/gold/aarch64.cc b/gold/aarch64.cc
index b282ccf..bd9500e 100644
--- a/gold/aarch64.cc
+++ b/gold/aarch64.cc
@@ -784,28 +784,23 @@ Stub_template_repertoire<big_endian>::Stub_template_repertoire()
       0x14000000,    /* b <label> */
     };
 
-  // ST_E_835769 has the same stub template as ST_E_843419
-  // but we reproduce the array here so that the sizeof
-  // expressions in install_insn_template will work.
-  const static Insntype ST_E_835769_INSNS[] =
-    {
-      0x00000000,    /* Placeholder for erratum insn. */
-      0x14000000,    /* b <label> */
-    };
-
-#define install_insn_template(T) \
+#define install_insn_template_insns(T, I) \
   const static Stub_template<big_endian> template_##T = {  \
-    T##_INSNS, sizeof(T##_INSNS) / sizeof(T##_INSNS[0]) }; \
+    I##_INSNS, sizeof(I##_INSNS) / sizeof(I##_INSNS[0]) }; \
   this->stub_templates_[T] = &template_##T
+#define install_insn_template(T)		\
+  install_insn_template_insns(T, T)
 
   install_insn_template(ST_NONE);
   install_insn_template(ST_ADRP_BRANCH);
   install_insn_template(ST_LONG_BRANCH_ABS);
   install_insn_template(ST_LONG_BRANCH_PCREL);
   install_insn_template(ST_E_843419);
-  install_insn_template(ST_E_835769);
+  // ST_E_835769 has the same stub template as ST_E_843419.
+  install_insn_template_insns(ST_E_835769, ST_E_843419);
 
 #undef install_insn_template
+#undef install_insn_template_insns
 }
 
 
-- 
2.5.5


^ permalink raw reply	[flat|nested] 8+ messages in thread

* [GOLD] [PATCH 3/3] Introduce and use array_size
  2017-01-25  0:50       ` Pedro Alves
  2017-01-25  0:57         ` [GOLD] [PATCH 1/3] aarch64.cc:Stub_template_repertoire: Avoid unnecessary, duplicate insns array Pedro Alves
@ 2017-01-25  0:58         ` Pedro Alves
  2017-01-25  0:58         ` [GOLD] [PATCH 2/3] aarch64.cc:Stub_template: add array ref constructor Pedro Alves
  2 siblings, 0 replies; 8+ messages in thread
From: Pedro Alves @ 2017-01-25  0:58 UTC (permalink / raw)
  To: Cary Coutant
  Cc: Nick Clifton, Ian Lance Taylor, rearnsha, marcus.shawcroft, Binutils

This adds a type-safe version of libiberty.h's ARRAY_SIZE, and uses it
throughout.

If something calls array_size with a pointer by mistake instead of an
array, the code doesn't compile, unlike with the (sizeof (array) /
sizeof (array[0])), which is what ARRAY_SIZE does.

Unfortunately, until gold requires C++11, we can't use this with
stack/local arrays (14.3.1/2 "A local type, a type with no linkage, an
unnamed type or a type compounded from any of these types shall not be
used as a template-argument for a template type-parameter.")
Fortunately, the need to use array_size with local arrays is not so
common.  Arrays with local or unnamed type are easily worked around
(just move or name the type).

In mips.cc, this commit moves the definitions of some arrays before
their uses, otherwise at least gcc 4.1 complaints:

  ../../src/gold/mips.cc:2589: error: no matching function for call to 'array_size_require_array(const __uint32_t [])'
  ../../src/gold/mips.cc:2591: error: no matching function for call to 'array_size_require_array(const __uint32_t [])'
  ../../src/gold/mips.cc:2593: error: no matching function for call to 'array_size_require_array(const __uint32_t [])'

Not sure what the standard says here.  In any case, it seems pointless
to me to have multiple instances of the same arrays (one per template
instantiation), so the move actually makes the arrays be static
globals instead of template class statics, while at it.  This reduces
gold's -O2 text size by almost 1k.

gold/ChangeLog:
2017-01-24  Pedro Alves  <palves@redhat.com>

	* arm-reloc-property.cc (struct RAB_table_entry): New, moved from
	...
	(Arm_reloc_property::Arm_reloc_property): ... here.  Use
	array_size.
	* arm.cc (Stub_factory::Stub_factory): Use array_size.
	(Output_data_plt_arm_standard<big_endian>::do_fill_first_plt_entry)
	(Target_arm<big_endian>::aeabi_enum_name)
	(Target_arm<big_endian>::tag_cpu_name_value)
	(Output_data_plt_arm_nacl<big_endian>::do_fill_first_plt_entry):
	Use array_size.
	* defstd.cc (in_section_count, in_segment_count): Use array_size.
	* dynobj.cc (Dynobj::compute_bucket_count): Likewise.
	* gold.h (array_size_require_array, array_size): New.
	* layout.cc (Layout::special_ordering_of_input_section): Use
	array_size.
	(Layout::section_name_mapping_count): Use array_size.
	* mips.cc (Mips_output_data_plt) <plt0_entry_o32, plt0_entry_n32,
	plt0_entry_n64, plt0_entry_micromips_o32,
	plt0_entry_micromips32_o32, plt_entry, plt_entry_r6,
	plt_entry_mips16_o32, plt_entry_micromips_o32,
	plt_entry_micromips32_o32): Moved outsize the template class and
	made static const globals.
	(Mips_output_data_plt<size, big_endian>::get_plt_header_size)
	(Mips_output_data_plt<size, big_endian>::standard_plt_entry_size)
	(Mips_output_data_plt<size, big_endian>::do_write): Use
	array_size.
	* powerpc.cc (Target_powerpc<size, big_endian>::do_relax): Use
	array_size.
	* script.cc (script_keywords, version_script_keywords)
	(dynamic_list_keywords): Use array_size.
	(phdr_type_name): Give anonymous struct a name.
	(script_phdr_string_to_type): Use array_size.
---
 gold/arm-reloc-property.cc |  14 +-
 gold/arm.cc                |  16 +--
 gold/defstd.cc             |   4 +-
 gold/dynobj.cc             |   2 +-
 gold/gold.h                |  17 +++
 gold/layout.cc             |   7 +-
 gold/mips.cc               | 313 ++++++++++++++++++++-------------------------
 gold/powerpc.cc            |   4 +-
 gold/script.cc             |  15 +--
 9 files changed, 178 insertions(+), 214 deletions(-)

diff --git a/gold/arm-reloc-property.cc b/gold/arm-reloc-property.cc
index 7b17b57..8d83c0d 100644
--- a/gold/arm-reloc-property.cc
+++ b/gold/arm-reloc-property.cc
@@ -85,6 +85,12 @@ Arm_reloc_property::Tree_node::make_tree(const std::string& s)
   return node_stack[0];
 }
 
+struct RAB_table_entry
+{
+  Arm_reloc_property::Relative_address_base rab;
+  const char* name;
+};
+
 // Arm_reloc_property methods.
 
 // Constructor.
@@ -169,12 +175,6 @@ Arm_reloc_property::Arm_reloc_property(
       && node->child(0)->is_leaf()
       && node->child(0)->name() == "-")
     {
-      struct RAB_table_entry
-      {
-	Relative_address_base rab;
-	const char* name;
-      };
-
       static const RAB_table_entry rab_table[] =
       {
 	{ RAB_B_S, "( B S )" },
@@ -186,7 +186,7 @@ Arm_reloc_property::Arm_reloc_property(
       	{ RAB_tp, "tp" }
       };
 
-      static size_t rab_table_size = sizeof(rab_table) / sizeof(rab_table[0]);
+      static size_t rab_table_size = array_size(rab_table);
       const std::string rhs(node->child(2)->s_expression());
       for (size_t i = 0; i < rab_table_size; ++i)
 	if (rhs == rab_table[i].name)
diff --git a/gold/arm.cc b/gold/arm.cc
index ff472ea..dd3d629 100644
--- a/gold/arm.cc
+++ b/gold/arm.cc
@@ -4984,11 +4984,10 @@ Stub_factory::Stub_factory()
 #define DEF_STUB(x)	\
   do \
     { \
-      size_t array_size \
-	= sizeof(elf32_arm_stub_##x) / sizeof(elf32_arm_stub_##x[0]); \
       Stub_type type = arm_stub_##x; \
       this->stub_templates_[type] = \
-	new Stub_template(type, elf32_arm_stub_##x, array_size); \
+	new Stub_template(type, elf32_arm_stub_##x, \
+			  array_size (elf32_arm_stub_##x)); \
     } \
   while (0);
 
@@ -7888,8 +7887,7 @@ Output_data_plt_arm_standard<big_endian>::do_fill_first_plt_entry(
     Arm_address plt_address)
 {
   // Write first PLT entry.  All but the last word are constants.
-  const size_t num_first_plt_words = (sizeof(first_plt_entry)
-				      / sizeof(first_plt_entry[0]));
+  const size_t num_first_plt_words = array_size (first_plt_entry);
   for (size_t i = 0; i < num_first_plt_words - 1; i++)
     {
       if (parameters->options().be8())
@@ -11152,8 +11150,7 @@ Target_arm<big_endian>::aeabi_enum_name(unsigned int value)
 {
   static const char* aeabi_enum_names[] =
     { "", "variable-size", "32-bit", "" };
-  const size_t aeabi_enum_names_size =
-    sizeof(aeabi_enum_names) / sizeof(aeabi_enum_names[0]);
+  const size_t aeabi_enum_names_size = array_size(aeabi_enum_names);
 
   if (value < aeabi_enum_names_size)
     return std::string(aeabi_enum_names[value]);
@@ -11190,7 +11187,7 @@ Target_arm<big_endian>::tag_cpu_name_value(unsigned int value)
    "ARM v7E-M",
    "ARM v8"
  };
- const size_t name_table_size = sizeof(name_table) / sizeof(name_table[0]);
+ const size_t name_table_size = array_size(name_table);
 
   if (value < name_table_size)
     return std::string(name_table[value]);
@@ -13127,8 +13124,7 @@ Output_data_plt_arm_nacl<big_endian>::do_fill_first_plt_entry(
     Arm_address plt_address)
 {
   // Write first PLT entry.  All but first two words are constants.
-  const size_t num_first_plt_words = (sizeof(first_plt_entry)
-				      / sizeof(first_plt_entry[0]));
+  const size_t num_first_plt_words = array_size(first_plt_entry);
 
   int32_t got_displacement = got_address + 8 - (plt_address + 16);
 
diff --git a/gold/defstd.cc b/gold/defstd.cc
index a7fdd93..75ad7e5 100644
--- a/gold/defstd.cc
+++ b/gold/defstd.cc
@@ -122,7 +122,7 @@ const Define_symbol_in_section in_section[] =
   },
 };
 
-const int in_section_count = sizeof in_section / sizeof in_section[0];
+const int in_section_count = array_size (in_section);
 
 const Define_symbol_in_segment in_segment[] =
 {
@@ -268,7 +268,7 @@ const Define_symbol_in_segment in_segment[] =
   }
 };
 
-const int in_segment_count = sizeof in_segment / sizeof in_segment[0];
+const int in_segment_count = array_size (in_segment);
 
 } // End anonymous namespace.
 
diff --git a/gold/dynobj.cc b/gold/dynobj.cc
index 0d38418..9da502d 100644
--- a/gold/dynobj.cc
+++ b/gold/dynobj.cc
@@ -870,7 +870,7 @@ Dynobj::compute_bucket_count(const std::vector<uint32_t>& hashcodes,
     1, 3, 17, 37, 67, 97, 131, 197, 263, 521, 1031, 2053, 4099, 8209,
     16411, 32771, 65537, 131101, 262147
   };
-  const int buckets_count = sizeof buckets / sizeof buckets[0];
+  const int buckets_count = array_size (buckets);
 
   unsigned int symcount = hashcodes.size();
   unsigned int ret = 1;
diff --git a/gold/gold.h b/gold/gold.h
index ae36e2f..4f62c10 100644
--- a/gold/gold.h
+++ b/gold/gold.h
@@ -175,6 +175,23 @@ extern void do_gold_unreachable(const char*, int, const char*)
 
 #define gold_assert(expr) ((void)(!(expr) ? gold_unreachable(), 0 : 0))
 
+// Type-safe version of libiberty.h's ARRAY_SIZE.  If you pass in a
+// pointer by mistake instead of an array, you get a compile-time
+// error.
+//
+// Until we require C++11, we can't use this with non-static local
+// arrays (C++03 14.3.1/2 "A local type, a type with no linkage, an
+// unnamed type or a type compounded from any of these types shall not
+// be used as a template-argument for a template type-parameter.")
+// Fortunately, the need for computing sizes of local arrays is not
+// that common.  Once we require C++11, we can make this a constexpr
+// function instead (just like C++17's non-member std::size).
+
+template <typename T, std::size_t N>
+char (&array_size_require_array(T(&)[N]))[N];
+
+#define array_size(array) sizeof(array_size_require_array(array))
+
 // Print version information.
 extern void
 print_version(bool print_short);
diff --git a/gold/layout.cc b/gold/layout.cc
index 07a3590..5dda3b3 100644
--- a/gold/layout.cc
+++ b/gold/layout.cc
@@ -1130,9 +1130,7 @@ Layout::special_ordering_of_input_section(const char* name)
     ".text.hot"
   };
 
-  for (size_t i = 0;
-       i < sizeof(text_section_sort) / sizeof(text_section_sort[0]);
-       i++)
+  for (size_t i = 0; i < array_size (text_section_sort); i++)
     if (is_prefix_of(text_section_sort[i], name))
       return i;
 
@@ -5091,8 +5089,7 @@ const Layout::Section_name_mapping Layout::section_name_mapping[] =
 #undef MAPPING_INIT_EXACT
 
 const int Layout::section_name_mapping_count =
-  (sizeof(Layout::section_name_mapping)
-   / sizeof(Layout::section_name_mapping[0]));
+  array_size (Layout::section_name_mapping);
 
 // Choose the output section name to use given an input section name.
 // Set *PLEN to the length of the name.  *PLEN is initialized to the
diff --git a/gold/mips.cc b/gold/mips.cc
index 56af570..56480de 100644
--- a/gold/mips.cc
+++ b/gold/mips.cc
@@ -2445,6 +2445,132 @@ class Mips_output_data_reloc : public Output_data_reloc<sh_type, dynamic,
   }
 };
 
+// The format of the first PLT entry in an O32 executable.
+static const uint32_t plt0_entry_o32[] =
+{
+  0x3c1c0000,         // lui $28, %hi(&GOTPLT[0])
+  0x8f990000,         // lw $25, %lo(&GOTPLT[0])($28)
+  0x279c0000,         // addiu $28, $28, %lo(&GOTPLT[0])
+  0x031cc023,         // subu $24, $24, $28
+  0x03e07825,         // or $15, $31, zero
+  0x0018c082,         // srl $24, $24, 2
+  0x0320f809,         // jalr $25
+  0x2718fffe          // subu $24, $24, 2
+};
+
+// The format of the first PLT entry in an N32 executable.  Different
+// because gp ($28) is not available; we use t2 ($14) instead.
+static const uint32_t plt0_entry_n32[] =
+{
+  0x3c0e0000,         // lui $14, %hi(&GOTPLT[0])
+  0x8dd90000,         // lw $25, %lo(&GOTPLT[0])($14)
+  0x25ce0000,         // addiu $14, $14, %lo(&GOTPLT[0])
+  0x030ec023,         // subu $24, $24, $14
+  0x03e07825,         // or $15, $31, zero
+  0x0018c082,         // srl $24, $24, 2
+  0x0320f809,         // jalr $25
+  0x2718fffe          // subu $24, $24, 2
+};
+
+// The format of the first PLT entry in an N64 executable.  Different
+// from N32 because of the increased size of GOT entries.
+static const uint32_t plt0_entry_n64[] =
+{
+  0x3c0e0000,         // lui $14, %hi(&GOTPLT[0])
+  0xddd90000,         // ld $25, %lo(&GOTPLT[0])($14)
+  0x25ce0000,         // addiu $14, $14, %lo(&GOTPLT[0])
+  0x030ec023,         // subu $24, $24, $14
+  0x03e07825,         // or $15, $31, zero
+  0x0018c0c2,         // srl $24, $24, 3
+  0x0320f809,         // jalr $25
+  0x2718fffe          // subu $24, $24, 2
+};
+
+// The format of the microMIPS first PLT entry in an O32 executable.
+// We rely on v0 ($2) rather than t8 ($24) to contain the address
+// of the GOTPLT entry handled, so this stub may only be used when
+// all the subsequent PLT entries are microMIPS code too.
+//
+// The trailing NOP is for alignment and correct disassembly only.
+static const uint32_t plt0_entry_micromips_o32[] =
+{
+  0x7980, 0x0000,      // addiupc $3, (&GOTPLT[0]) - .
+  0xff23, 0x0000,      // lw $25, 0($3)
+  0x0535,              // subu $2, $2, $3
+  0x2525,              // srl $2, $2, 2
+  0x3302, 0xfffe,      // subu $24, $2, 2
+  0x0dff,              // move $15, $31
+  0x45f9,              // jalrs $25
+  0x0f83,              // move $28, $3
+  0x0c00               // nop
+};
+
+// The format of the microMIPS first PLT entry in an O32 executable
+// in the insn32 mode.
+static const uint32_t plt0_entry_micromips32_o32[] =
+{
+  0x41bc, 0x0000,      // lui $28, %hi(&GOTPLT[0])
+  0xff3c, 0x0000,      // lw $25, %lo(&GOTPLT[0])($28)
+  0x339c, 0x0000,      // addiu $28, $28, %lo(&GOTPLT[0])
+  0x0398, 0xc1d0,      // subu $24, $24, $28
+  0x001f, 0x7a90,      // or $15, $31, zero
+  0x0318, 0x1040,      // srl $24, $24, 2
+  0x03f9, 0x0f3c,      // jalr $25
+  0x3318, 0xfffe       // subu $24, $24, 2
+};
+
+// The format of subsequent standard entries in the PLT.
+static const uint32_t plt_entry[] =
+{
+  0x3c0f0000,           // lui $15, %hi(.got.plt entry)
+  0x01f90000,           // l[wd] $25, %lo(.got.plt entry)($15)
+  0x03200008,           // jr $25
+  0x25f80000            // addiu $24, $15, %lo(.got.plt entry)
+};
+
+// The format of subsequent R6 PLT entries.
+static const uint32_t plt_entry_r6[] =
+{
+  0x3c0f0000,           // lui $15, %hi(.got.plt entry)
+  0x01f90000,           // l[wd] $25, %lo(.got.plt entry)($15)
+  0x03200009,           // jr $25
+  0x25f80000            // addiu $24, $15, %lo(.got.plt entry)
+};
+
+// The format of subsequent MIPS16 o32 PLT entries.  We use v1 ($3) as a
+// temporary because t8 ($24) and t9 ($25) are not directly addressable.
+// Note that this differs from the GNU ld which uses both v0 ($2) and v1 ($3).
+// We cannot use v0 because MIPS16 call stubs from the CS toolchain expect
+// target function address in register v0.
+static const uint32_t plt_entry_mips16_o32[] =
+{
+  0xb303,              // lw $3, 12($pc)
+  0x651b,              // move $24, $3
+  0x9b60,              // lw $3, 0($3)
+  0xeb00,              // jr $3
+  0x653b,              // move $25, $3
+  0x6500,              // nop
+  0x0000, 0x0000       // .word (.got.plt entry)
+};
+
+// The format of subsequent microMIPS o32 PLT entries.  We use v0 ($2)
+// as a temporary because t8 ($24) is not addressable with ADDIUPC.
+const uint32_t plt_entry_micromips_o32[] =
+{
+  0x7900, 0x0000,      // addiupc $2, (.got.plt entry) - .
+  0xff22, 0x0000,      // lw $25, 0($2)
+  0x4599,              // jr $25
+  0x0f02               // move $24, $2
+};
+
+// The format of subsequent microMIPS o32 PLT entries in the insn32 mode.
+static const uint32_t plt_entry_micromips32_o32[] =
+{
+  0x41af, 0x0000,      // lui $15, %hi(.got.plt entry)
+  0xff2f, 0x0000,      // lw $25, %lo(.got.plt entry)($15)
+  0x0019, 0x0f3c,      // jr $25
+  0x330f, 0x0000       // addiu $24, $15, %lo(.got.plt entry)
+};
 
 // A class to handle the PLT data.
 
@@ -2543,19 +2669,6 @@ class Mips_output_data_plt : public Output_section_data
   { mapfile->print_output_data(this, _(".plt")); }
 
  private:
-  // Template for the first PLT entry.
-  static const uint32_t plt0_entry_o32[];
-  static const uint32_t plt0_entry_n32[];
-  static const uint32_t plt0_entry_n64[];
-  static const uint32_t plt0_entry_micromips_o32[];
-  static const uint32_t plt0_entry_micromips32_o32[];
-
-  // Template for subsequent PLT entries.
-  static const uint32_t plt_entry[];
-  static const uint32_t plt_entry_r6[];
-  static const uint32_t plt_entry_mips16_o32[];
-  static const uint32_t plt_entry_micromips_o32[];
-  static const uint32_t plt_entry_micromips32_o32[];
 
   // Set the final size.
   void
@@ -2586,17 +2699,15 @@ class Mips_output_data_plt : public Output_section_data
   get_plt_header_size() const
   {
     if (this->target_->is_output_n64())
-      return 4 * sizeof(plt0_entry_n64) / sizeof(plt0_entry_n64[0]);
+      return 4 * array_size(plt0_entry_n64);
     else if (this->target_->is_output_n32())
-      return 4 * sizeof(plt0_entry_n32) / sizeof(plt0_entry_n32[0]);
+      return 4 * array_size(plt0_entry_n32);
     else if (!this->is_plt_header_compressed())
-      return 4 * sizeof(plt0_entry_o32) / sizeof(plt0_entry_o32[0]);
+      return 4 * array_size(plt0_entry_o32);
     else if (this->target_->use_32bit_micromips_instructions())
-      return (2 * sizeof(plt0_entry_micromips32_o32)
-              / sizeof(plt0_entry_micromips32_o32[0]));
+      return 2 * array_size(plt0_entry_micromips32_o32);
     else
-      return (2 * sizeof(plt0_entry_micromips_o32)
-              / sizeof(plt0_entry_micromips_o32[0]));
+      return 2 * array_size(plt0_entry_micromips_o32);
   }
 
   // Return the PLT header entry.
@@ -2618,7 +2729,7 @@ class Mips_output_data_plt : public Output_section_data
   // Return the size of the standard PLT entry.
   unsigned int
   standard_plt_entry_size() const
-  { return 4 * sizeof(plt_entry) / sizeof(plt_entry[0]); }
+  { return 4 * array_size(plt_entry); }
 
   // Return the size of the compressed PLT entry.
   unsigned int
@@ -2627,14 +2738,11 @@ class Mips_output_data_plt : public Output_section_data
     gold_assert(!this->target_->is_output_newabi());
 
     if (!this->target_->is_output_micromips())
-      return (2 * sizeof(plt_entry_mips16_o32)
-              / sizeof(plt_entry_mips16_o32[0]));
+      return 2 * array_size(plt_entry_mips16_o32);
     else if (this->target_->use_32bit_micromips_instructions())
-      return (2 * sizeof(plt_entry_micromips32_o32)
-              / sizeof(plt_entry_micromips32_o32[0]));
+      return 2 * array_size(plt_entry_micromips32_o32);
     else
-      return (2 * sizeof(plt_entry_micromips_o32)
-              / sizeof(plt_entry_micromips_o32[0]));
+      return 2 * array_size(plt_entry_micromips_o32);
   }
 
   // The reloc section.
@@ -7161,147 +7269,6 @@ Mips_output_data_la25_stub<size, big_endian>::do_write(Output_file* of)
 
 // Mips_output_data_plt methods.
 
-// The format of the first PLT entry in an O32 executable.
-template<int size, bool big_endian>
-const uint32_t Mips_output_data_plt<size, big_endian>::plt0_entry_o32[] =
-{
-  0x3c1c0000,         // lui $28, %hi(&GOTPLT[0])
-  0x8f990000,         // lw $25, %lo(&GOTPLT[0])($28)
-  0x279c0000,         // addiu $28, $28, %lo(&GOTPLT[0])
-  0x031cc023,         // subu $24, $24, $28
-  0x03e07825,         // or $15, $31, zero
-  0x0018c082,         // srl $24, $24, 2
-  0x0320f809,         // jalr $25
-  0x2718fffe          // subu $24, $24, 2
-};
-
-// The format of the first PLT entry in an N32 executable.  Different
-// because gp ($28) is not available; we use t2 ($14) instead.
-template<int size, bool big_endian>
-const uint32_t Mips_output_data_plt<size, big_endian>::plt0_entry_n32[] =
-{
-  0x3c0e0000,         // lui $14, %hi(&GOTPLT[0])
-  0x8dd90000,         // lw $25, %lo(&GOTPLT[0])($14)
-  0x25ce0000,         // addiu $14, $14, %lo(&GOTPLT[0])
-  0x030ec023,         // subu $24, $24, $14
-  0x03e07825,         // or $15, $31, zero
-  0x0018c082,         // srl $24, $24, 2
-  0x0320f809,         // jalr $25
-  0x2718fffe          // subu $24, $24, 2
-};
-
-// The format of the first PLT entry in an N64 executable.  Different
-// from N32 because of the increased size of GOT entries.
-template<int size, bool big_endian>
-const uint32_t Mips_output_data_plt<size, big_endian>::plt0_entry_n64[] =
-{
-  0x3c0e0000,         // lui $14, %hi(&GOTPLT[0])
-  0xddd90000,         // ld $25, %lo(&GOTPLT[0])($14)
-  0x25ce0000,         // addiu $14, $14, %lo(&GOTPLT[0])
-  0x030ec023,         // subu $24, $24, $14
-  0x03e07825,         // or $15, $31, zero
-  0x0018c0c2,         // srl $24, $24, 3
-  0x0320f809,         // jalr $25
-  0x2718fffe          // subu $24, $24, 2
-};
-
-// The format of the microMIPS first PLT entry in an O32 executable.
-// We rely on v0 ($2) rather than t8 ($24) to contain the address
-// of the GOTPLT entry handled, so this stub may only be used when
-// all the subsequent PLT entries are microMIPS code too.
-//
-// The trailing NOP is for alignment and correct disassembly only.
-template<int size, bool big_endian>
-const uint32_t Mips_output_data_plt<size, big_endian>::
-plt0_entry_micromips_o32[] =
-{
-  0x7980, 0x0000,      // addiupc $3, (&GOTPLT[0]) - .
-  0xff23, 0x0000,      // lw $25, 0($3)
-  0x0535,              // subu $2, $2, $3
-  0x2525,              // srl $2, $2, 2
-  0x3302, 0xfffe,      // subu $24, $2, 2
-  0x0dff,              // move $15, $31
-  0x45f9,              // jalrs $25
-  0x0f83,              // move $28, $3
-  0x0c00               // nop
-};
-
-// The format of the microMIPS first PLT entry in an O32 executable
-// in the insn32 mode.
-template<int size, bool big_endian>
-const uint32_t Mips_output_data_plt<size, big_endian>::
-plt0_entry_micromips32_o32[] =
-{
-  0x41bc, 0x0000,      // lui $28, %hi(&GOTPLT[0])
-  0xff3c, 0x0000,      // lw $25, %lo(&GOTPLT[0])($28)
-  0x339c, 0x0000,      // addiu $28, $28, %lo(&GOTPLT[0])
-  0x0398, 0xc1d0,      // subu $24, $24, $28
-  0x001f, 0x7a90,      // or $15, $31, zero
-  0x0318, 0x1040,      // srl $24, $24, 2
-  0x03f9, 0x0f3c,      // jalr $25
-  0x3318, 0xfffe       // subu $24, $24, 2
-};
-
-// The format of subsequent standard entries in the PLT.
-template<int size, bool big_endian>
-const uint32_t Mips_output_data_plt<size, big_endian>::plt_entry[] =
-{
-  0x3c0f0000,           // lui $15, %hi(.got.plt entry)
-  0x01f90000,           // l[wd] $25, %lo(.got.plt entry)($15)
-  0x03200008,           // jr $25
-  0x25f80000            // addiu $24, $15, %lo(.got.plt entry)
-};
-
-// The format of subsequent R6 PLT entries.
-template<int size, bool big_endian>
-const uint32_t Mips_output_data_plt<size, big_endian>::plt_entry_r6[] =
-{
-  0x3c0f0000,           // lui $15, %hi(.got.plt entry)
-  0x01f90000,           // l[wd] $25, %lo(.got.plt entry)($15)
-  0x03200009,           // jr $25
-  0x25f80000            // addiu $24, $15, %lo(.got.plt entry)
-};
-
-// The format of subsequent MIPS16 o32 PLT entries.  We use v1 ($3) as a
-// temporary because t8 ($24) and t9 ($25) are not directly addressable.
-// Note that this differs from the GNU ld which uses both v0 ($2) and v1 ($3).
-// We cannot use v0 because MIPS16 call stubs from the CS toolchain expect
-// target function address in register v0.
-template<int size, bool big_endian>
-const uint32_t Mips_output_data_plt<size, big_endian>::plt_entry_mips16_o32[] =
-{
-  0xb303,              // lw $3, 12($pc)
-  0x651b,              // move $24, $3
-  0x9b60,              // lw $3, 0($3)
-  0xeb00,              // jr $3
-  0x653b,              // move $25, $3
-  0x6500,              // nop
-  0x0000, 0x0000       // .word (.got.plt entry)
-};
-
-// The format of subsequent microMIPS o32 PLT entries.  We use v0 ($2)
-// as a temporary because t8 ($24) is not addressable with ADDIUPC.
-template<int size, bool big_endian>
-const uint32_t Mips_output_data_plt<size, big_endian>::
-plt_entry_micromips_o32[] =
-{
-  0x7900, 0x0000,      // addiupc $2, (.got.plt entry) - .
-  0xff22, 0x0000,      // lw $25, 0($2)
-  0x4599,              // jr $25
-  0x0f02               // move $24, $2
-};
-
-// The format of subsequent microMIPS o32 PLT entries in the insn32 mode.
-template<int size, bool big_endian>
-const uint32_t Mips_output_data_plt<size, big_endian>::
-plt_entry_micromips32_o32[] =
-{
-  0x41af, 0x0000,      // lui $15, %hi(.got.plt entry)
-  0xff2f, 0x0000,      // lw $25, %lo(.got.plt entry)($15)
-  0x0019, 0x0f3c,      // jr $25
-  0x330f, 0x0000       // addiu $24, $15, %lo(.got.plt entry)
-};
-
 // Add an entry to the PLT for a symbol referenced by r_type relocation.
 
 template<int size, bool big_endian>
@@ -7455,10 +7422,7 @@ Mips_output_data_plt<size, big_endian>::do_write(Output_file* of)
       elfcpp::Swap<16, big_endian>::writeval(pov + 2,
                                              (gotpc_offset >> 2) & 0xffff);
       pov += 4;
-      for (unsigned int i = 2;
-           i < (sizeof(plt0_entry_micromips_o32)
-                / sizeof(plt0_entry_micromips_o32[0]));
-           i++)
+      for (unsigned int i = 2; i < array_size(plt0_entry_micromips_o32); i++)
         {
           elfcpp::Swap<16, big_endian>::writeval(pov, plt0_entry[i]);
           pov += 2;
@@ -7474,10 +7438,7 @@ Mips_output_data_plt<size, big_endian>::do_write(Output_file* of)
       elfcpp::Swap<16, big_endian>::writeval(pov + 8, plt0_entry[4]);
       elfcpp::Swap<16, big_endian>::writeval(pov + 10, gotplt_addr_low);
       pov += 12;
-      for (unsigned int i = 6;
-           i < (sizeof(plt0_entry_micromips32_o32)
-                / sizeof(plt0_entry_micromips32_o32[0]));
-           i++)
+      for (unsigned int i = 6; i < array_size(plt0_entry_micromips32_o32); i++)
         {
           elfcpp::Swap<16, big_endian>::writeval(pov, plt0_entry[i]);
           pov += 2;
diff --git a/gold/powerpc.cc b/gold/powerpc.cc
index a67c336..37bc7ce 100644
--- a/gold/powerpc.cc
+++ b/gold/powerpc.cc
@@ -3060,9 +3060,7 @@ Target_powerpc<size, big_endian>::do_relax(int pass,
 	    thread_safe = true;
 	  else
 	    {
-	      for (unsigned int i = 0;
-		   i < sizeof(thread_starter) / sizeof(thread_starter[0]);
-		   i++)
+	      for (unsigned int i = 0; i < array_size(thread_starter); i++)
 		{
 		  Symbol* sym = symtab->lookup(thread_starter[i], NULL);
 		  thread_safe = (sym != NULL
diff --git a/gold/script.cc b/gold/script.cc
index 67540a5..dfe6469 100644
--- a/gold/script.cc
+++ b/gold/script.cc
@@ -1821,8 +1821,7 @@ script_keyword_parsecodes[] =
 
 static const Keyword_to_parsecode
 script_keywords(&script_keyword_parsecodes[0],
-                (sizeof(script_keyword_parsecodes)
-                 / sizeof(script_keyword_parsecodes[0])));
+		array_size(script_keyword_parsecodes));
 
 static const Keyword_to_parsecode::Keyword_parsecode
 version_script_keyword_parsecodes[] =
@@ -1834,8 +1833,7 @@ version_script_keyword_parsecodes[] =
 
 static const Keyword_to_parsecode
 version_script_keywords(&version_script_keyword_parsecodes[0],
-                        (sizeof(version_script_keyword_parsecodes)
-                         / sizeof(version_script_keyword_parsecodes[0])));
+                        array_size(version_script_keyword_parsecodes));
 
 static const Keyword_to_parsecode::Keyword_parsecode
 dynamic_list_keyword_parsecodes[] =
@@ -1845,8 +1843,7 @@ dynamic_list_keyword_parsecodes[] =
 
 static const Keyword_to_parsecode
 dynamic_list_keywords(&dynamic_list_keyword_parsecodes[0],
-                      (sizeof(dynamic_list_keyword_parsecodes)
-                       / sizeof(dynamic_list_keyword_parsecodes[0])));
+                      array_size(dynamic_list_keyword_parsecodes));
 
 
 
@@ -3262,7 +3259,7 @@ script_add_phdr(void* closurev, const char* name, size_t namelen,
 
 #define PHDR_TYPE(NAME) { #NAME, sizeof(#NAME) - 1, elfcpp::NAME }
 
-static struct
+static struct phdr_type_name
 {
   const char* name;
   size_t namelen;
@@ -3285,9 +3282,7 @@ static struct
 extern "C" unsigned int
 script_phdr_string_to_type(void* closurev, const char* name, size_t namelen)
 {
-  for (unsigned int i = 0;
-       i < sizeof(phdr_type_names) / sizeof(phdr_type_names[0]);
-       ++i)
+  for (unsigned int i = 0; i < array_size(phdr_type_names); ++i)
     if (namelen == phdr_type_names[i].namelen
 	&& strncmp(name, phdr_type_names[i].name, namelen) == 0)
       return phdr_type_names[i].val;
-- 
2.5.5


^ permalink raw reply	[flat|nested] 8+ messages in thread

* [GOLD] [PATCH 2/3] aarch64.cc:Stub_template: add array ref constructor
  2017-01-25  0:50       ` Pedro Alves
  2017-01-25  0:57         ` [GOLD] [PATCH 1/3] aarch64.cc:Stub_template_repertoire: Avoid unnecessary, duplicate insns array Pedro Alves
  2017-01-25  0:58         ` [GOLD] [PATCH 3/3] Introduce and use array_size Pedro Alves
@ 2017-01-25  0:58         ` Pedro Alves
  2 siblings, 0 replies; 8+ messages in thread
From: Pedro Alves @ 2017-01-25  0:58 UTC (permalink / raw)
  To: Cary Coutant
  Cc: Nick Clifton, Ian Lance Taylor, rearnsha, marcus.shawcroft, Binutils

Add array ref constructor to catch problems like:
  https://sourceware.org/ml/binutils/2017-01/msg00282.html
at compile time.

gold/ChangeLog:
2017-01-24  Pedro Alves  <palves@redhat.com>

	* aarch64.cc (struct Stub_template) <Insntype>: New typedef.
	<insns>: Use it.
	<Stub_template>: New array and default construtors.
	(Stub_template_repertoire): Delete ST_NONE_INSNS and create
	corresponding empty template instead of calling
	install_insn_template.  Adjust install_insn_template_insns to call
	array constructor.
---
 gold/aarch64.cc | 24 +++++++++++++++++-------
 1 file changed, 17 insertions(+), 7 deletions(-)

diff --git a/gold/aarch64.cc b/gold/aarch64.cc
index bd9500e..c2531f3 100644
--- a/gold/aarch64.cc
+++ b/gold/aarch64.cc
@@ -703,7 +703,18 @@ enum
 template<bool big_endian>
 struct Stub_template
 {
-  const typename AArch64_insn_utilities<big_endian>::Insntype* insns;
+  typedef typename AArch64_insn_utilities<big_endian>::Insntype Insntype;
+
+  Stub_template ()
+    : insns(NULL), insn_num(0)
+  { }
+
+  template<size_t insn_num_>
+  Stub_template(const Insntype (&insns_)[insn_num_])
+    : insns(insns_), insn_num(insn_num_)
+  { }
+
+  const Insntype* insns;
   const int insn_num;
 };
 
@@ -746,8 +757,6 @@ template<bool big_endian>
 Stub_template_repertoire<big_endian>::Stub_template_repertoire()
 {
   // Insn array definitions.
-  const static Insntype ST_NONE_INSNS[] = {};
-
   const static Insntype ST_ADRP_BRANCH_INSNS[] =
     {
       0x90000010,	/*	adrp	ip0, X		   */
@@ -784,14 +793,15 @@ Stub_template_repertoire<big_endian>::Stub_template_repertoire()
       0x14000000,    /* b <label> */
     };
 
-#define install_insn_template_insns(T, I) \
-  const static Stub_template<big_endian> template_##T = {  \
-    I##_INSNS, sizeof(I##_INSNS) / sizeof(I##_INSNS[0]) }; \
+  const static Stub_template<big_endian> T_ST_NONE_INSNS;
+  this->stub_templates_[ST_NONE] = &T_ST_NONE_INSNS;
+
+#define install_insn_template_insns(T, I)				\
+  const static Stub_template<big_endian> template_##T (I##_INSNS);	\
   this->stub_templates_[T] = &template_##T
 #define install_insn_template(T)		\
   install_insn_template_insns(T, T)
 
-  install_insn_template(ST_NONE);
   install_insn_template(ST_ADRP_BRANCH);
   install_insn_template(ST_LONG_BRANCH_ABS);
   install_insn_template(ST_LONG_BRANCH_PCREL);
-- 
2.5.5


^ permalink raw reply	[flat|nested] 8+ messages in thread

end of thread, other threads:[~2017-01-25  0:58 UTC | newest]

Thread overview: 8+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2017-01-18 16:03 GOLD: RFA: Fixing a coverty error for aarch64.cc Nick Clifton
2017-01-18 18:20 ` Cary Coutant
2017-01-20 11:50   ` Pedro Alves
2017-01-24  1:07     ` Cary Coutant
2017-01-25  0:50       ` Pedro Alves
2017-01-25  0:57         ` [GOLD] [PATCH 1/3] aarch64.cc:Stub_template_repertoire: Avoid unnecessary, duplicate insns array Pedro Alves
2017-01-25  0:58         ` [GOLD] [PATCH 3/3] Introduce and use array_size Pedro Alves
2017-01-25  0:58         ` [GOLD] [PATCH 2/3] aarch64.cc:Stub_template: add array ref constructor Pedro Alves

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for read-only IMAP folder(s) and NNTP newsgroup(s).