Merge branch 'master' into iter
diff --git a/src/hb-aat-fdsc-table.hh b/src/hb-aat-fdsc-table.hh
index a1af595..1188e35 100644
--- a/src/hb-aat-fdsc-table.hh
+++ b/src/hb-aat-fdsc-table.hh
@@ -74,7 +74,7 @@
 
 struct fdsc
 {
-  enum { tableTag = HB_AAT_TAG_fdsc };
+  static constexpr hb_tag_t tableTag = HB_AAT_TAG_fdsc;
 
   enum {
     Weight	 = HB_TAG ('w','g','h','t'),
diff --git a/src/hb-aat-layout-ankr-table.hh b/src/hb-aat-layout-ankr-table.hh
index f6f1246..236e4aa 100644
--- a/src/hb-aat-layout-ankr-table.hh
+++ b/src/hb-aat-layout-ankr-table.hh
@@ -58,7 +58,7 @@
 
 struct ankr
 {
-  enum { tableTag = HB_AAT_TAG_ankr };
+  static constexpr hb_tag_t tableTag = HB_AAT_TAG_ankr;
 
   const Anchor &get_anchor (hb_codepoint_t glyph_id,
 			    unsigned int i,
diff --git a/src/hb-aat-layout-bsln-table.hh b/src/hb-aat-layout-bsln-table.hh
index 5bc59cb..9139d28 100644
--- a/src/hb-aat-layout-bsln-table.hh
+++ b/src/hb-aat-layout-bsln-table.hh
@@ -116,7 +116,7 @@
 
 struct bsln
 {
-  enum { tableTag = HB_AAT_TAG_bsln };
+  static constexpr hb_tag_t tableTag = HB_AAT_TAG_bsln;
 
   bool sanitize (hb_sanitize_context_t *c) const
   {
diff --git a/src/hb-aat-layout-common.hh b/src/hb-aat-layout-common.hh
index 85332b0..27ade28 100644
--- a/src/hb-aat-layout-common.hh
+++ b/src/hb-aat-layout-common.hh
@@ -77,7 +77,7 @@
 template <typename T>
 struct LookupSegmentSingle
 {
-  enum { TerminationWordCount = 2 };
+  static constexpr unsigned TerminationWordCount = 2u;
 
   int cmp (hb_codepoint_t g) const
   { return g < first ? -1 : g <= last ? 0 : +1 ; }
@@ -136,7 +136,7 @@
 template <typename T>
 struct LookupSegmentArray
 {
-  enum { TerminationWordCount = 2 };
+  static constexpr unsigned TerminationWordCount = 2u;
 
   const T* get_value (hb_codepoint_t glyph_id, const void *base) const
   {
@@ -207,7 +207,7 @@
 template <typename T>
 struct LookupSingle
 {
-  enum { TerminationWordCount = 1 };
+  static constexpr unsigned TerminationWordCount = 1u;
 
   int cmp (hb_codepoint_t g) const { return glyph.cmp (g); }
 
@@ -511,9 +511,10 @@
   const Entry<Extra> *get_entries () const
   { return (this+entryTable).arrayZ; }
 
-  const Entry<Extra> *get_entryZ (int state, unsigned int klass) const
+  const Entry<Extra> &get_entry (int state, unsigned int klass) const
   {
-    if (unlikely (klass >= nClasses)) return nullptr;
+    if (unlikely (klass >= nClasses))
+      klass = StateTable<Types, Entry<Extra> >::CLASS_OUT_OF_BOUNDS;
 
     const HBUSHORT *states = (this+stateArrayTable).arrayZ;
     const Entry<Extra> *entries = (this+entryTable).arrayZ;
@@ -521,7 +522,7 @@
     unsigned int entry = states[state * nClasses + klass];
     DEBUG_MSG (APPLY, nullptr, "e%u", entry);
 
-    return &entries[entry];
+    return entries[entry];
   }
 
   bool sanitize (hb_sanitize_context_t *c,
@@ -529,6 +530,7 @@
   {
     TRACE_SANITIZE (this);
     if (unlikely (!(c->check_struct (this) &&
+		    nClasses >= 4 /* Ensure pre-defined classes fit.  */ &&
 		    classTable.sanitize (c, this)))) return_trace (false);
 
     const HBUSHORT *states = (this+stateArrayTable).arrayZ;
@@ -571,7 +573,7 @@
 				       -min_state,
 				       row_stride)))
 	  return_trace (false);
-	if ((c->max_ops -= state_neg - min_state) < 0)
+	if ((c->max_ops -= state_neg - min_state) <= 0)
 	  return_trace (false);
 	{ /* Sweep new states. */
 	  const HBUSHORT *stop = &states[min_state * num_classes];
@@ -590,7 +592,7 @@
 				       max_state + 1,
 				       row_stride)))
 	  return_trace (false);
-	if ((c->max_ops -= max_state - state_pos + 1) < 0)
+	if ((c->max_ops -= max_state - state_pos + 1) <= 0)
 	  return_trace (false);
 	{ /* Sweep new states. */
 	  if (unlikely (hb_unsigned_mul_overflows ((max_state + 1), num_classes)))
@@ -606,7 +608,7 @@
 
       if (unlikely (!c->check_array (entries, num_entries)))
 	return_trace (false);
-      if ((c->max_ops -= num_entries - entry) < 0)
+      if ((c->max_ops -= num_entries - entry) <= 0)
 	return_trace (false);
       { /* Sweep new entries. */
 	const Entry<Extra> *stop = &entries[num_entries];
@@ -669,7 +671,7 @@
 
 struct ObsoleteTypes
 {
-  enum { extended = false };
+  static constexpr bool extended = false;
   typedef HBUINT16 HBUINT;
   typedef HBUINT8 HBUSHORT;
   typedef ClassTable<HBUINT8> ClassTypeNarrow;
@@ -699,7 +701,7 @@
 };
 struct ExtendedTypes
 {
-  enum { extended = true };
+  static constexpr bool extended = true;
   typedef HBUINT32 HBUINT;
   typedef HBUINT16 HBUSHORT;
   typedef Lookup<HBUINT16> ClassTypeNarrow;
@@ -745,16 +747,13 @@
       buffer->clear_output ();
 
     int state = StateTable<Types, EntryData>::STATE_START_OF_TEXT;
-    bool last_was_dont_advance = false;
     for (buffer->idx = 0; buffer->successful;)
     {
       unsigned int klass = buffer->idx < buffer->len ?
 			   machine.get_class (buffer->info[buffer->idx].codepoint, num_glyphs) :
 			   (unsigned) StateTable<Types, EntryData>::CLASS_END_OF_TEXT;
       DEBUG_MSG (APPLY, nullptr, "c%u at %u", klass, buffer->idx);
-      const Entry<EntryData> *entry = machine.get_entryZ (state, klass);
-      if (unlikely (!entry))
-	break;
+      const Entry<EntryData> &entry = machine.get_entry (state, klass);
 
       /* Unsafe-to-break before this if not in state 0, as things might
        * go differently if we start from state 0 here.
@@ -765,31 +764,28 @@
 	/* If there's no action and we're just epsilon-transitioning to state 0,
 	 * safe to break. */
 	if (c->is_actionable (this, entry) ||
-	    !(entry->newState == StateTable<Types, EntryData>::STATE_START_OF_TEXT &&
-	      entry->flags == context_t::DontAdvance))
+	    !(entry.newState == StateTable<Types, EntryData>::STATE_START_OF_TEXT &&
+	      entry.flags == context_t::DontAdvance))
 	  buffer->unsafe_to_break_from_outbuffer (buffer->backtrack_len () - 1, buffer->idx + 1);
       }
 
       /* Unsafe-to-break if end-of-text would kick in here. */
       if (buffer->idx + 2 <= buffer->len)
       {
-	const Entry<EntryData> *end_entry = machine.get_entryZ (state, 0);
+	const Entry<EntryData> &end_entry = machine.get_entry (state, StateTable<Types, EntryData>::CLASS_END_OF_TEXT);
 	if (c->is_actionable (this, end_entry))
 	  buffer->unsafe_to_break (buffer->idx, buffer->idx + 2);
       }
 
-      if (unlikely (!c->transition (this, entry)))
-	break;
+      c->transition (this, entry);
 
-      last_was_dont_advance = (entry->flags & context_t::DontAdvance) && buffer->max_ops-- > 0;
-
-      state = machine.new_state (entry->newState);
+      state = machine.new_state (entry.newState);
       DEBUG_MSG (APPLY, nullptr, "s%d", state);
 
       if (buffer->idx == buffer->len)
 	break;
 
-      if (!last_was_dont_advance)
+      if (!(entry.flags & context_t::DontAdvance) || buffer->max_ops-- <= 0)
 	buffer->next_glyph ();
     }
 
diff --git a/src/hb-aat-layout-feat-table.hh b/src/hb-aat-layout-feat-table.hh
index acc4d04..ab23ee0 100644
--- a/src/hb-aat-layout-feat-table.hh
+++ b/src/hb-aat-layout-feat-table.hh
@@ -154,7 +154,7 @@
 
 struct feat
 {
-  enum { tableTag = HB_AAT_TAG_feat };
+  static constexpr hb_tag_t tableTag = HB_AAT_TAG_feat;
 
   bool has_data () const { return version.to_int (); }
 
diff --git a/src/hb-aat-layout-just-table.hh b/src/hb-aat-layout-just-table.hh
index d39945a..d53f8f1 100644
--- a/src/hb-aat-layout-just-table.hh
+++ b/src/hb-aat-layout-just-table.hh
@@ -382,7 +382,7 @@
 
 struct just
 {
-  enum { tableTag = HB_AAT_TAG_just };
+  static constexpr hb_tag_t tableTag = HB_AAT_TAG_just;
 
   bool sanitize (hb_sanitize_context_t *c) const
   {
diff --git a/src/hb-aat-layout-kerx-table.hh b/src/hb-aat-layout-kerx-table.hh
index b86c513..a64c807 100644
--- a/src/hb-aat-layout-kerx-table.hh
+++ b/src/hb-aat-layout-kerx-table.hh
@@ -170,11 +170,11 @@
     DEFINE_SIZE_STATIC (2);
   };
 
-  static bool performAction (const Entry<EntryData> *entry)
-  { return entry->data.kernActionIndex != 0xFFFF; }
+  static bool performAction (const Entry<EntryData> &entry)
+  { return entry.data.kernActionIndex != 0xFFFF; }
 
-  static unsigned int kernActionIndex (const Entry<EntryData> *entry)
-  { return entry->data.kernActionIndex; }
+  static unsigned int kernActionIndex (const Entry<EntryData> &entry)
+  { return entry.data.kernActionIndex; }
 };
 template <>
 struct Format1Entry<false>
@@ -192,11 +192,11 @@
 
   typedef void EntryData;
 
-  static bool performAction (const Entry<EntryData> *entry)
-  { return entry->flags & Offset; }
+  static bool performAction (const Entry<EntryData> &entry)
+  { return entry.flags & Offset; }
 
-  static unsigned int kernActionIndex (const Entry<EntryData> *entry)
-  { return entry->flags & Offset; }
+  static unsigned int kernActionIndex (const Entry<EntryData> &entry)
+  { return entry.flags & Offset; }
 };
 
 template <typename KernSubTableHeader>
@@ -210,7 +210,7 @@
 
   struct driver_context_t
   {
-    enum { in_place = true };
+    static constexpr bool in_place = true;
     enum
     {
       DontAdvance	= Format1EntryT::DontAdvance,
@@ -228,15 +228,15 @@
 	crossStream (table->header.coverage & table->header.CrossStream) {}
 
     bool is_actionable (StateTableDriver<Types, EntryData> *driver HB_UNUSED,
-			const Entry<EntryData> *entry)
+			const Entry<EntryData> &entry)
     {
       return Format1EntryT::performAction (entry);
     }
-    bool transition (StateTableDriver<Types, EntryData> *driver,
-		     const Entry<EntryData> *entry)
+    void transition (StateTableDriver<Types, EntryData> *driver,
+		     const Entry<EntryData> &entry)
     {
       hb_buffer_t *buffer = driver->buffer;
-      unsigned int flags = entry->flags;
+      unsigned int flags = entry.flags;
 
       if (flags & Format1EntryT::Reset)
 	depth = 0;
@@ -259,7 +259,7 @@
 	if (!c->sanitizer.check_array (actions, depth, tuple_count))
 	{
 	  depth = 0;
-	  return false;
+	  return;
 	}
 
 	hb_mask_t kern_mask = c->plan->kern_mask;
@@ -334,8 +334,6 @@
 	  }
 	}
       }
-
-      return true;
     }
 
     private:
@@ -471,7 +469,7 @@
 
   struct driver_context_t
   {
-    enum { in_place = true };
+    static constexpr bool in_place = true;
     enum Flags
     {
       Mark		= 0x8000,	/* If set, remember this glyph as the marked glyph. */
@@ -498,16 +496,16 @@
 	mark (0) {}
 
     bool is_actionable (StateTableDriver<Types, EntryData> *driver HB_UNUSED,
-			const Entry<EntryData> *entry)
+			const Entry<EntryData> &entry)
     {
-      return entry->data.ankrActionIndex != 0xFFFF;
+      return entry.data.ankrActionIndex != 0xFFFF;
     }
-    bool transition (StateTableDriver<Types, EntryData> *driver,
-		     const Entry<EntryData> *entry)
+    void transition (StateTableDriver<Types, EntryData> *driver,
+		     const Entry<EntryData> &entry)
     {
       hb_buffer_t *buffer = driver->buffer;
 
-      if (mark_set && entry->data.ankrActionIndex != 0xFFFF && buffer->idx < buffer->len)
+      if (mark_set && entry.data.ankrActionIndex != 0xFFFF && buffer->idx < buffer->len)
       {
 	hb_glyph_position_t &o = buffer->cur_pos();
 	switch (action_type)
@@ -515,9 +513,8 @@
 	  case 0: /* Control Point Actions.*/
 	  {
 	    /* indexed into glyph outline. */
-	    const HBUINT16 *data = &ankrData[entry->data.ankrActionIndex];
-	    if (!c->sanitizer.check_array (data, 2))
-	      return false;
+	    const HBUINT16 *data = &ankrData[entry.data.ankrActionIndex];
+	    if (!c->sanitizer.check_array (data, 2)) return;
 	    HB_UNUSED unsigned int markControlPoint = *data++;
 	    HB_UNUSED unsigned int currControlPoint = *data++;
 	    hb_position_t markX = 0;
@@ -532,7 +529,7 @@
 							      currControlPoint,
 							      HB_DIRECTION_LTR /*XXX*/,
 							      &currX, &currY))
-	      return true; /* True, such that the machine continues. */
+	      return;
 
 	    o.x_offset = markX - currX;
 	    o.y_offset = markY - currY;
@@ -542,9 +539,8 @@
 	  case 1: /* Anchor Point Actions. */
 	  {
 	   /* Indexed into 'ankr' table. */
-	    const HBUINT16 *data = &ankrData[entry->data.ankrActionIndex];
-	    if (!c->sanitizer.check_array (data, 2))
-	      return false;
+	    const HBUINT16 *data = &ankrData[entry.data.ankrActionIndex];
+	    if (!c->sanitizer.check_array (data, 2)) return;
 	    unsigned int markAnchorPoint = *data++;
 	    unsigned int currAnchorPoint = *data++;
 	    const Anchor &markAnchor = c->ankr_table->get_anchor (c->buffer->info[mark].codepoint,
@@ -561,9 +557,8 @@
 
 	  case 2: /* Control Point Coordinate Actions. */
 	  {
-	    const FWORD *data = (const FWORD *) &ankrData[entry->data.ankrActionIndex];
-	    if (!c->sanitizer.check_array (data, 4))
-	      return false;
+	    const FWORD *data = (const FWORD *) &ankrData[entry.data.ankrActionIndex];
+	    if (!c->sanitizer.check_array (data, 4)) return;
 	    int markX = *data++;
 	    int markY = *data++;
 	    int currX = *data++;
@@ -579,13 +574,11 @@
 	buffer->scratch_flags |= HB_BUFFER_SCRATCH_FLAG_HAS_GPOS_ATTACHMENT;
       }
 
-      if (entry->flags & Mark)
+      if (entry.flags & Mark)
       {
 	mark_set = true;
 	mark = buffer->idx;
       }
-
-      return true;
     }
 
     private:
@@ -979,8 +972,8 @@
 {
   friend struct KerxTable<kerx>;
 
-  enum { tableTag = HB_AAT_TAG_kerx };
-  enum { minVersion = 2u };
+  static constexpr hb_tag_t tableTag = HB_AAT_TAG_kerx;
+  static constexpr unsigned minVersion = 2u;
 
   typedef KerxSubTableHeader SubTableHeader;
   typedef SubTableHeader::Types Types;
diff --git a/src/hb-aat-layout-lcar-table.hh b/src/hb-aat-layout-lcar-table.hh
index 27c601d..4be799f 100644
--- a/src/hb-aat-layout-lcar-table.hh
+++ b/src/hb-aat-layout-lcar-table.hh
@@ -40,7 +40,7 @@
 
 struct lcar
 {
-  enum { tableTag = HB_AAT_TAG_lcar };
+  static constexpr hb_tag_t tableTag = HB_AAT_TAG_lcar;
 
   unsigned int get_lig_carets (hb_font_t      *font,
 			       hb_direction_t  direction,
diff --git a/src/hb-aat-layout-morx-table.hh b/src/hb-aat-layout-morx-table.hh
index d8a90bb..4a1d959 100644
--- a/src/hb-aat-layout-morx-table.hh
+++ b/src/hb-aat-layout-morx-table.hh
@@ -54,7 +54,7 @@
 
   struct driver_context_t
   {
-    enum { in_place = true };
+    static constexpr bool in_place = true;
     enum Flags
     {
       MarkFirst		= 0x8000,	/* If set, make the current glyph the first
@@ -74,15 +74,15 @@
 	start (0), end (0) {}
 
     bool is_actionable (StateTableDriver<Types, EntryData> *driver HB_UNUSED,
-			const Entry<EntryData> *entry)
+			const Entry<EntryData> &entry)
     {
-      return (entry->flags & Verb) && start < end;
+      return (entry.flags & Verb) && start < end;
     }
-    bool transition (StateTableDriver<Types, EntryData> *driver,
-		     const Entry<EntryData> *entry)
+    void transition (StateTableDriver<Types, EntryData> *driver,
+		     const Entry<EntryData> &entry)
     {
       hb_buffer_t *buffer = driver->buffer;
-      unsigned int flags = entry->flags;
+      unsigned int flags = entry.flags;
 
       if (flags & MarkFirst)
 	start = buffer->idx;
@@ -152,8 +152,6 @@
 	  }
 	}
       }
-
-      return true;
     }
 
     public:
@@ -204,7 +202,7 @@
 
   struct driver_context_t
   {
-    enum { in_place = true };
+    static constexpr bool in_place = true;
     enum Flags
     {
       SetMark		= 0x8000,	/* If set, make the current glyph the marked glyph. */
@@ -223,39 +221,39 @@
 	subs (table+table->substitutionTables) {}
 
     bool is_actionable (StateTableDriver<Types, EntryData> *driver,
-			const Entry<EntryData> *entry)
+			const Entry<EntryData> &entry)
     {
       hb_buffer_t *buffer = driver->buffer;
 
       if (buffer->idx == buffer->len && !mark_set)
         return false;
 
-      return entry->data.markIndex != 0xFFFF || entry->data.currentIndex != 0xFFFF;
+      return entry.data.markIndex != 0xFFFF || entry.data.currentIndex != 0xFFFF;
     }
-    bool transition (StateTableDriver<Types, EntryData> *driver,
-		     const Entry<EntryData> *entry)
+    void transition (StateTableDriver<Types, EntryData> *driver,
+		     const Entry<EntryData> &entry)
     {
       hb_buffer_t *buffer = driver->buffer;
 
       /* Looks like CoreText applies neither mark nor current substitution for
        * end-of-text if mark was not explicitly set. */
       if (buffer->idx == buffer->len && !mark_set)
-        return true;
+        return;
 
       const GlyphID *replacement;
 
       replacement = nullptr;
       if (Types::extended)
       {
-	if (entry->data.markIndex != 0xFFFF)
+	if (entry.data.markIndex != 0xFFFF)
 	{
-	  const Lookup<GlyphID> &lookup = subs[entry->data.markIndex];
+	  const Lookup<GlyphID> &lookup = subs[entry.data.markIndex];
 	  replacement = lookup.get_value (buffer->info[mark].codepoint, driver->num_glyphs);
 	}
       }
       else
       {
-	unsigned int offset = entry->data.markIndex + buffer->info[mark].codepoint;
+	unsigned int offset = entry.data.markIndex + buffer->info[mark].codepoint;
 	const UnsizedArrayOf<GlyphID> &subs_old = (const UnsizedArrayOf<GlyphID> &) subs;
 	replacement = &subs_old[Types::wordOffsetToIndex (offset, table, subs_old.arrayZ)];
 	if (!replacement->sanitize (&c->sanitizer) || !*replacement)
@@ -272,15 +270,15 @@
       unsigned int idx = MIN (buffer->idx, buffer->len - 1);
       if (Types::extended)
       {
-	if (entry->data.currentIndex != 0xFFFF)
+	if (entry.data.currentIndex != 0xFFFF)
 	{
-	  const Lookup<GlyphID> &lookup = subs[entry->data.currentIndex];
+	  const Lookup<GlyphID> &lookup = subs[entry.data.currentIndex];
 	  replacement = lookup.get_value (buffer->info[idx].codepoint, driver->num_glyphs);
 	}
       }
       else
       {
-	unsigned int offset = entry->data.currentIndex + buffer->info[idx].codepoint;
+	unsigned int offset = entry.data.currentIndex + buffer->info[idx].codepoint;
 	const UnsizedArrayOf<GlyphID> &subs_old = (const UnsizedArrayOf<GlyphID> &) subs;
 	replacement = &subs_old[Types::wordOffsetToIndex (offset, table, subs_old.arrayZ)];
 	if (!replacement->sanitize (&c->sanitizer) || !*replacement)
@@ -292,13 +290,11 @@
 	ret = true;
       }
 
-      if (entry->flags & SetMark)
+      if (entry.flags & SetMark)
       {
 	mark_set = true;
 	mark = buffer->idx;
       }
-
-      return true;
     }
 
     public:
@@ -385,11 +381,11 @@
     DEFINE_SIZE_STATIC (2);
   };
 
-  static bool performAction (const Entry<EntryData> *entry)
-  { return entry->flags & PerformAction; }
+  static bool performAction (const Entry<EntryData> &entry)
+  { return entry.flags & PerformAction; }
 
-  static unsigned int ligActionIndex (const Entry<EntryData> *entry)
-  { return entry->data.ligActionIndex; }
+  static unsigned int ligActionIndex (const Entry<EntryData> &entry)
+  { return entry.data.ligActionIndex; }
 };
 template <>
 struct LigatureEntry<false>
@@ -407,11 +403,11 @@
 
   typedef void EntryData;
 
-  static bool performAction (const Entry<EntryData> *entry)
-  { return entry->flags & Offset; }
+  static bool performAction (const Entry<EntryData> &entry)
+  { return entry.flags & Offset; }
 
-  static unsigned int ligActionIndex (const Entry<EntryData> *entry)
-  { return entry->flags & Offset; }
+  static unsigned int ligActionIndex (const Entry<EntryData> &entry)
+  { return entry.flags & Offset; }
 };
 
 
@@ -425,7 +421,7 @@
 
   struct driver_context_t
   {
-    enum { in_place = false };
+    static constexpr bool in_place = false;
     enum
     {
       DontAdvance	= LigatureEntryT::DontAdvance,
@@ -453,26 +449,23 @@
 	match_length (0) {}
 
     bool is_actionable (StateTableDriver<Types, EntryData> *driver HB_UNUSED,
-			const Entry<EntryData> *entry)
+			const Entry<EntryData> &entry)
     {
       return LigatureEntryT::performAction (entry);
     }
-    bool transition (StateTableDriver<Types, EntryData> *driver,
-		     const Entry<EntryData> *entry)
+    void transition (StateTableDriver<Types, EntryData> *driver,
+		     const Entry<EntryData> &entry)
     {
       hb_buffer_t *buffer = driver->buffer;
 
       DEBUG_MSG (APPLY, nullptr, "Ligature transition at %u", buffer->idx);
-      if (entry->flags & LigatureEntryT::SetComponent)
+      if (entry.flags & LigatureEntryT::SetComponent)
       {
-        if (unlikely (match_length >= ARRAY_LENGTH (match_positions)))
-	  return false;
-
 	/* Never mark same index twice, in case DontAdvance was used... */
-	if (match_length && match_positions[match_length - 1] == buffer->out_len)
+	if (match_length && match_positions[(match_length - 1u) % ARRAY_LENGTH (match_positions)] == buffer->out_len)
 	  match_length--;
 
-	match_positions[match_length++] = buffer->out_len;
+	match_positions[match_length++ % ARRAY_LENGTH (match_positions)] = buffer->out_len;
 	DEBUG_MSG (APPLY, nullptr, "Set component at %u", buffer->out_len);
       }
 
@@ -482,10 +475,10 @@
 	unsigned int end = buffer->out_len;
 
 	if (unlikely (!match_length))
-	  return true;
+	  return;
 
 	if (buffer->idx >= buffer->len)
-	  return false; // TODO Work on previous instead?
+	  return; /* TODO Work on previous instead? */
 
 	unsigned int cursor = match_length;
 
@@ -506,9 +499,9 @@
 	  }
 
 	  DEBUG_MSG (APPLY, nullptr, "Moving to stack position %u", cursor - 1);
-	  buffer->move_to (match_positions[--cursor]);
+	  buffer->move_to (match_positions[--cursor % ARRAY_LENGTH (match_positions)]);
 
-	  if (unlikely (!actionData->sanitize (&c->sanitizer))) return false;
+	  if (unlikely (!actionData->sanitize (&c->sanitizer))) break;
 	  action = *actionData;
 
 	  uint32_t uoffset = action & LigActionOffset;
@@ -518,7 +511,7 @@
 	  unsigned int component_idx = buffer->cur().codepoint + offset;
 	  component_idx = Types::wordOffsetToIndex (component_idx, table, component.arrayZ);
 	  const HBUINT16 &componentData = component[component_idx];
-	  if (unlikely (!componentData.sanitize (&c->sanitizer))) return false;
+	  if (unlikely (!componentData.sanitize (&c->sanitizer))) break;
 	  ligature_idx += componentData;
 
 	  DEBUG_MSG (APPLY, nullptr, "Action store %u last %u",
@@ -528,23 +521,23 @@
 	  {
 	    ligature_idx = Types::offsetToIndex (ligature_idx, table, ligature.arrayZ);
 	    const GlyphID &ligatureData = ligature[ligature_idx];
-	    if (unlikely (!ligatureData.sanitize (&c->sanitizer))) return false;
+	    if (unlikely (!ligatureData.sanitize (&c->sanitizer))) break;
 	    hb_codepoint_t lig = ligatureData;
 
 	    DEBUG_MSG (APPLY, nullptr, "Produced ligature %u", lig);
 	    buffer->replace_glyph (lig);
 
-	    unsigned int lig_end = match_positions[match_length - 1] + 1;
+	    unsigned int lig_end = match_positions[(match_length - 1u) % ARRAY_LENGTH (match_positions)] + 1u;
 	    /* Now go and delete all subsequent components. */
-	    while (match_length - 1 > cursor)
+	    while (match_length - 1u > cursor)
 	    {
 	      DEBUG_MSG (APPLY, nullptr, "Skipping ligature component");
-	      buffer->move_to (match_positions[--match_length]);
+	      buffer->move_to (match_positions[--match_length % ARRAY_LENGTH (match_positions)]);
 	      buffer->replace_glyph (DELETED_GLYPH);
 	    }
 
 	    buffer->move_to (lig_end);
-	    buffer->merge_out_clusters (match_positions[cursor], buffer->out_len);
+	    buffer->merge_out_clusters (match_positions[cursor % ARRAY_LENGTH (match_positions)], buffer->out_len);
 	  }
 
 	  actionData++;
@@ -552,8 +545,6 @@
 	while (!(action & LigActionLast));
 	buffer->move_to (end);
       }
-
-      return true;
     }
 
     public:
@@ -661,7 +652,7 @@
 
   struct driver_context_t
   {
-    enum { in_place = false };
+    static constexpr bool in_place = false;
     enum Flags
     {
       SetMark		= 0x8000,	/* If set, mark the current glyph. */
@@ -714,28 +705,29 @@
 		      hb_aat_apply_context_t *c_) :
 	ret (false),
 	c (c_),
-	mark_set (false),
 	mark (0),
 	insertionAction (table+table->insertionAction) {}
 
     bool is_actionable (StateTableDriver<Types, EntryData> *driver HB_UNUSED,
-			const Entry<EntryData> *entry)
+			const Entry<EntryData> &entry)
     {
-      return (entry->flags & (CurrentInsertCount | MarkedInsertCount)) &&
-	     (entry->data.currentInsertIndex != 0xFFFF ||entry->data.markedInsertIndex != 0xFFFF);
+      return (entry.flags & (CurrentInsertCount | MarkedInsertCount)) &&
+	     (entry.data.currentInsertIndex != 0xFFFF ||entry.data.markedInsertIndex != 0xFFFF);
     }
-    bool transition (StateTableDriver<Types, EntryData> *driver,
-		     const Entry<EntryData> *entry)
+    void transition (StateTableDriver<Types, EntryData> *driver,
+		     const Entry<EntryData> &entry)
     {
       hb_buffer_t *buffer = driver->buffer;
-      unsigned int flags = entry->flags;
+      unsigned int flags = entry.flags;
 
-      if (entry->data.markedInsertIndex != 0xFFFF && mark_set)
+      unsigned mark_loc = buffer->out_len;
+
+      if (entry.data.markedInsertIndex != 0xFFFF)
       {
 	unsigned int count = (flags & MarkedInsertCount);
-	unsigned int start = entry->data.markedInsertIndex;
+	unsigned int start = entry.data.markedInsertIndex;
 	const GlyphID *glyphs = &insertionAction[start];
-	if (unlikely (!c->sanitizer.check_array (glyphs, count))) return false;
+	if (unlikely (!c->sanitizer.check_array (glyphs, count))) count = 0;
 
 	bool before = flags & MarkedInsertBefore;
 
@@ -755,12 +747,15 @@
 	buffer->unsafe_to_break_from_outbuffer (mark, MIN (buffer->idx + 1, buffer->len));
       }
 
-      if (entry->data.currentInsertIndex != 0xFFFF)
+      if (flags & SetMark)
+	mark = mark_loc;
+
+      if (entry.data.currentInsertIndex != 0xFFFF)
       {
 	unsigned int count = (flags & CurrentInsertCount) >> 5;
-	unsigned int start = entry->data.currentInsertIndex;
+	unsigned int start = entry.data.currentInsertIndex;
 	const GlyphID *glyphs = &insertionAction[start];
-	if (unlikely (!c->sanitizer.check_array (glyphs, count))) return false;
+	if (unlikely (!c->sanitizer.check_array (glyphs, count))) count = 0;
 
 	bool before = flags & CurrentInsertBefore;
 
@@ -791,21 +786,12 @@
 	 */
 	buffer->move_to ((flags & DontAdvance) ? end : end + count);
       }
-
-      if (flags & SetMark)
-      {
-	mark_set = true;
-	mark = buffer->out_len;
-      }
-
-      return true;
     }
 
     public:
     bool ret;
     private:
     hb_aat_apply_context_t *c;
-    bool mark_set;
     unsigned int mark;
     const UnsizedArrayOf<GlyphID> &insertionAction;
   };
@@ -1097,7 +1083,7 @@
 template <typename Types>
 struct mortmorx
 {
-  enum { tableTag = HB_AAT_TAG_morx };
+  static constexpr hb_tag_t tableTag = HB_AAT_TAG_morx;
 
   bool has_data () const { return version != 0; }
 
@@ -1159,11 +1145,11 @@
 
 struct morx : mortmorx<ExtendedTypes>
 {
-  enum { tableTag = HB_AAT_TAG_morx };
+  static constexpr hb_tag_t tableTag = HB_AAT_TAG_morx;
 };
 struct mort : mortmorx<ObsoleteTypes>
 {
-  enum { tableTag = HB_AAT_TAG_mort };
+  static constexpr hb_tag_t tableTag = HB_AAT_TAG_mort;
 };
 
 
diff --git a/src/hb-aat-layout-trak-table.hh b/src/hb-aat-layout-trak-table.hh
index 3fe7d43..0c8e455 100644
--- a/src/hb-aat-layout-trak-table.hh
+++ b/src/hb-aat-layout-trak-table.hh
@@ -160,7 +160,7 @@
 
 struct trak
 {
-  enum { tableTag = HB_AAT_TAG_trak };
+  static constexpr hb_tag_t tableTag = HB_AAT_TAG_trak;
 
   bool has_data () const { return version.to_int (); }
 
diff --git a/src/hb-aat-ltag-table.hh b/src/hb-aat-ltag-table.hh
index 9a6a280..6f34a00 100644
--- a/src/hb-aat-ltag-table.hh
+++ b/src/hb-aat-ltag-table.hh
@@ -60,7 +60,7 @@
 
 struct ltag
 {
-  enum { tableTag = HB_AAT_TAG_ltag };
+  static constexpr hb_tag_t tableTag = HB_AAT_TAG_ltag;
 
   hb_language_t get_language (unsigned int i) const
   {
diff --git a/src/hb-algs.hh b/src/hb-algs.hh
index 90f4c87..b4e79e8 100644
--- a/src/hb-algs.hh
+++ b/src/hb-algs.hh
@@ -272,10 +272,13 @@
 template <typename T> static inline T*
 hb_addressof (const T& arg)
 {
+#pragma GCC diagnostic push
+#pragma GCC diagnostic ignored "-Wcast-align"
   /* https://en.cppreference.com/w/cpp/memory/addressof */
   return reinterpret_cast<T*>(
 	   &const_cast<char&>(
 	      reinterpret_cast<const volatile char&>(arg)));
+#pragma GCC diagnostic pop
 }
 
 /* ASCII tag/character handling */
@@ -570,26 +573,26 @@
 
 struct HbOpOr
 {
-  enum { passthru_left = true };
-  enum { passthru_right = true };
+  static constexpr bool passthru_left = true;
+  static constexpr bool passthru_right = true;
   template <typename T> static void process (T &o, const T &a, const T &b) { o = a | b; }
 };
 struct HbOpAnd
 {
-  enum { passthru_left = false };
-  enum { passthru_right = false };
+  static constexpr bool passthru_left = false;
+  static constexpr bool passthru_right = false;
   template <typename T> static void process (T &o, const T &a, const T &b) { o = a & b; }
 };
 struct HbOpMinus
 {
-  enum { passthru_left = true };
-  enum { passthru_right = false };
+  static constexpr bool passthru_left = true;
+  static constexpr bool passthru_right = false;
   template <typename T> static void process (T &o, const T &a, const T &b) { o = a & ~b; }
 };
 struct HbOpXor
 {
-  enum { passthru_left = true };
-  enum { passthru_right = true };
+  static constexpr bool passthru_left = true;
+  static constexpr bool passthru_right = true;
   template <typename T> static void process (T &o, const T &a, const T &b) { o = a ^ b; }
 };
 
diff --git a/src/hb-array.hh b/src/hb-array.hh
index 6fd362f..62075c4 100644
--- a/src/hb-array.hh
+++ b/src/hb-array.hh
@@ -55,7 +55,7 @@
    * Iterator implementation.
    */
   typedef Type& __item_t__;
-  enum { is_random_access_iterator = true };
+  static constexpr bool is_random_access_iterator = true;
   Type& __item_at__ (unsigned i) const
   {
     if (unlikely (i >= length)) return CrapOrNull (Type);
@@ -200,8 +200,8 @@
 {
   typedef hb_iter_t<hb_sorted_array_t<Type>, Type&> iter_base_t;
   HB_ITER_USING (iter_base_t);
-  enum { is_random_access_iterator = true };
-  enum { is_sorted_iterator = true };
+  static constexpr bool is_random_access_iterator = true;
+  static constexpr bool is_sorted_iterator = true;
 
   hb_sorted_array_t () : hb_array_t<Type> () {}
   hb_sorted_array_t (const hb_array_t<Type> &o) : hb_array_t<Type> (o) {}
diff --git a/src/hb-buffer.hh b/src/hb-buffer.hh
index 8a3170c..330f88b 100644
--- a/src/hb-buffer.hh
+++ b/src/hb-buffer.hh
@@ -119,7 +119,7 @@
   /* Text before / after the main buffer contents.
    * Always in Unicode, and ordered outward.
    * Index 0 is for "pre-context", 1 for "post-context". */
-  enum { CONTEXT_LENGTH = 5 };
+  static constexpr unsigned CONTEXT_LENGTH = 5u;
   hb_codepoint_t context[2][CONTEXT_LENGTH];
   unsigned int context_len[2];
 
diff --git a/src/hb-cff-interp-common.hh b/src/hb-cff-interp-common.hh
index 7b0b829..72e9e06 100644
--- a/src/hb-cff-interp-common.hh
+++ b/src/hb-cff-interp-common.hh
@@ -477,7 +477,7 @@
   unsigned int get_count () const { return count; }
   bool is_empty () const { return count == 0; }
 
-  enum { kSizeLimit = LIMIT };
+  static constexpr unsigned kSizeLimit = LIMIT;
 
   protected:
   bool error;
diff --git a/src/hb-common.h b/src/hb-common.h
index 247a02d..2b29e44 100644
--- a/src/hb-common.h
+++ b/src/hb-common.h
@@ -108,7 +108,7 @@
 typedef uint32_t hb_tag_t;
 
 #define HB_TAG(c1,c2,c3,c4) ((hb_tag_t)((((uint32_t)(c1)&0xFF)<<24)|(((uint32_t)(c2)&0xFF)<<16)|(((uint32_t)(c3)&0xFF)<<8)|((uint32_t)(c4)&0xFF)))
-#define HB_UNTAG(tag)   (((tag)>>24)&0xFF), (((tag)>>16)&0xFF), (((tag)>>8)&0xFF), ((tag)&0xFF)
+#define HB_UNTAG(tag)   (uint8_t)(((tag)>>24)&0xFF), (uint8_t)(((tag)>>16)&0xFF), (uint8_t)(((tag)>>8)&0xFF), (uint8_t)((tag)&0xFF)
 
 #define HB_TAG_NONE HB_TAG(0,0,0,0)
 #define HB_TAG_MAX HB_TAG(0xff,0xff,0xff,0xff)
diff --git a/src/hb-font.cc b/src/hb-font.cc
index afd20df..817a1a7 100644
--- a/src/hb-font.cc
+++ b/src/hb-font.cc
@@ -139,13 +139,10 @@
     for (unsigned int i = 0; i < count; i++)
     {
       if (!font->get_nominal_glyph (*first_unicode, first_glyph))
-        return i;
+	return i;
 
-#pragma GCC diagnostic push
-#pragma GCC diagnostic ignored "-Wcast-align"
-      first_unicode = &StructAtOffset<hb_codepoint_t> (first_unicode, unicode_stride);
-      first_glyph = &StructAtOffset<hb_codepoint_t> (first_glyph, glyph_stride);
-#pragma GCC diagnostic pop
+      first_unicode = &StructAtOffsetUnaligned<hb_codepoint_t> (first_unicode, unicode_stride);
+      first_glyph = &StructAtOffsetUnaligned<hb_codepoint_t> (first_glyph, glyph_stride);
     }
     return count;
   }
@@ -241,11 +238,8 @@
     for (unsigned int i = 0; i < count; i++)
     {
       *first_advance = font->get_glyph_h_advance (*first_glyph);
-#pragma GCC diagnostic push
-#pragma GCC diagnostic ignored "-Wcast-align"
-      first_glyph = &StructAtOffset<hb_codepoint_t> (first_glyph, glyph_stride);
-      first_advance = &StructAtOffset<hb_position_t> (first_advance, advance_stride);
-#pragma GCC diagnostic pop
+      first_glyph = &StructAtOffsetUnaligned<hb_codepoint_t> (first_glyph, glyph_stride);
+      first_advance = &StructAtOffsetUnaligned<hb_position_t> (first_advance, advance_stride);
     }
     return;
   }
@@ -256,10 +250,7 @@
   for (unsigned int i = 0; i < count; i++)
   {
     *first_advance = font->parent_scale_x_distance (*first_advance);
-#pragma GCC diagnostic push
-#pragma GCC diagnostic ignored "-Wcast-align"
-    first_advance = &StructAtOffset<hb_position_t> (first_advance, advance_stride);
-#pragma GCC diagnostic pop
+    first_advance = &StructAtOffsetUnaligned<hb_position_t> (first_advance, advance_stride);
   }
 }
 
@@ -279,11 +270,8 @@
     for (unsigned int i = 0; i < count; i++)
     {
       *first_advance = font->get_glyph_v_advance (*first_glyph);
-#pragma GCC diagnostic push
-#pragma GCC diagnostic ignored "-Wcast-align"
-      first_glyph = &StructAtOffset<hb_codepoint_t> (first_glyph, glyph_stride);
-      first_advance = &StructAtOffset<hb_position_t> (first_advance, advance_stride);
-#pragma GCC diagnostic pop
+      first_glyph = &StructAtOffsetUnaligned<hb_codepoint_t> (first_glyph, glyph_stride);
+      first_advance = &StructAtOffsetUnaligned<hb_position_t> (first_advance, advance_stride);
     }
     return;
   }
@@ -294,10 +282,7 @@
   for (unsigned int i = 0; i < count; i++)
   {
     *first_advance = font->parent_scale_y_distance (*first_advance);
-#pragma GCC diagnostic push
-#pragma GCC diagnostic ignored "-Wcast-align"
-    first_advance = &StructAtOffset<hb_position_t> (first_advance, advance_stride);
-#pragma GCC diagnostic pop
+    first_advance = &StructAtOffsetUnaligned<hb_position_t> (first_advance, advance_stride);
   }
 }
 
diff --git a/src/hb-ft.cc b/src/hb-ft.cc
index 2f866f4..1900f30 100644
--- a/src/hb-ft.cc
+++ b/src/hb-ft.cc
@@ -228,11 +228,8 @@
        done < count && (*first_glyph = FT_Get_Char_Index (ft_font->ft_face, *first_unicode));
        done++)
   {
-#pragma GCC diagnostic push
-#pragma GCC diagnostic ignored "-Wcast-align"
-    first_unicode = &StructAtOffset<hb_codepoint_t> (first_unicode, unicode_stride);
-    first_glyph = &StructAtOffset<hb_codepoint_t> (first_glyph, glyph_stride);
-#pragma GCC diagnostic pop
+    first_unicode = &StructAtOffsetUnaligned<hb_codepoint_t> (first_unicode, unicode_stride);
+    first_glyph = &StructAtOffsetUnaligned<hb_codepoint_t> (first_glyph, glyph_stride);
   }
   /* We don't need to do ft_font->symbol dance here, since HB calls the singular
    * nominal_glyph() for what we don't handle here. */
@@ -295,11 +292,8 @@
     }
 
     *first_advance = (v * mult + (1<<9)) >> 10;
-#pragma GCC diagnostic push
-#pragma GCC diagnostic ignored "-Wcast-align"
-    first_glyph = &StructAtOffset<hb_codepoint_t> (first_glyph, glyph_stride);
-    first_advance = &StructAtOffset<hb_position_t> (first_advance, advance_stride);
-#pragma GCC diagnostic pop
+    first_glyph = &StructAtOffsetUnaligned<hb_codepoint_t> (first_glyph, glyph_stride);
+    first_advance = &StructAtOffsetUnaligned<hb_position_t> (first_advance, advance_stride);
   }
 }
 
diff --git a/src/hb-iter.hh b/src/hb-iter.hh
index 0f0b4de..b538ddf 100644
--- a/src/hb-iter.hh
+++ b/src/hb-iter.hh
@@ -54,10 +54,10 @@
 {
   typedef Iter iter_t;
   typedef Item item_t;
-  enum { item_size = hb_static_size (Item) };
-  enum { is_iterator = true };
-  enum { is_random_access_iterator = false };
-  enum { is_sorted_iterator = false };
+  static constexpr unsigned item_size = hb_static_size (Item);
+  static constexpr bool is_iterator = true;
+  static constexpr bool is_random_access_iterator = false;
+  static constexpr bool is_sorted_iterator = false;
 
   private:
   /* https://en.wikipedia.org/wiki/Curiously_recurring_template_pattern */
@@ -213,7 +213,7 @@
   hb_map_iter_t (const Iter& it, Proj&& f) : it (it), f (f) {}
 
   typedef decltype (hb_declval (Proj) (hb_declval (typename Iter::item_t))) __item_t__;
-  enum { is_random_access_iterator = Iter::is_random_access_iterator };
+  static constexpr bool is_random_access_iterator = Iter::is_random_access_iterator;
   __item_t__ __item__ () const { return f (*it); }
   __item_t__ __item_at__ (unsigned i) const { return f (it[i]); }
   bool __more__ () const { return bool (it); }
@@ -255,7 +255,7 @@
   { while (it && !p (f (*it))) ++it; }
 
   typedef typename Iter::item_t __item_t__;
-  enum { is_sorted_iterator = Iter::is_sorted_iterator };
+  static constexpr bool is_sorted_iterator = Iter::is_sorted_iterator;
   __item_t__ __item__ () const { return *it; }
   bool __more__ () const { return bool (it); }
   void __next__ () { do ++it; while (it && !p (f (*it))); }
@@ -295,12 +295,12 @@
   hb_zip_iter_t (A a, B b) : a (a), b (b) {}
 
   typedef hb_pair_t<typename A::item_t, typename B::item_t> __item_t__;
-  enum { is_random_access_iterator =
+  static constexpr bool is_random_access_iterator =
 	   A::is_random_access_iterator &&
-	   B::is_random_access_iterator };
-  enum { is_sorted_iterator =
+	   B::is_random_access_iterator;
+  static constexpr bool is_sorted_iterator =
 	   A::is_sorted_iterator &&
-	   B::is_sorted_iterator };
+	   B::is_sorted_iterator;
   __item_t__ __item__ () const { return __item_t__ (*a, *b); }
   __item_t__ __item_at__ (unsigned i) const { return __item_t__ (a[i], b[i]); }
   bool __more__ () const { return a && b; }
diff --git a/src/hb-machinery.hh b/src/hb-machinery.hh
index f1ac848..ccad561 100644
--- a/src/hb-machinery.hh
+++ b/src/hb-machinery.hh
@@ -64,6 +64,22 @@
 template<typename Type>
 static inline Type& StructAtOffset(void *P, unsigned int offset)
 { return * reinterpret_cast<Type*> ((char *) P + offset); }
+template<typename Type>
+static inline const Type& StructAtOffsetUnaligned(const void *P, unsigned int offset)
+{
+#pragma GCC diagnostic push
+#pragma GCC diagnostic ignored "-Wcast-align"
+  return * reinterpret_cast<Type*> ((char *) P + offset);
+#pragma GCC diagnostic pop
+}
+template<typename Type>
+static inline Type& StructAtOffsetUnaligned(void *P, unsigned int offset)
+{
+#pragma GCC diagnostic push
+#pragma GCC diagnostic ignored "-Wcast-align"
+  return * reinterpret_cast<Type*> ((char *) P + offset);
+#pragma GCC diagnostic pop
+}
 
 /* StructAfter<T>(X) returns the struct T& that is placed after X.
  * Works with X of variable size also.  X must implement get_size() */
@@ -97,19 +113,19 @@
 #define DEFINE_SIZE_STATIC(size) \
   DEFINE_INSTANCE_ASSERTION (sizeof (*this) == (size)) \
   unsigned int get_size () const { return (size); } \
-  enum { null_size = (size) }; \
-  enum { min_size = (size) }; \
+  static constexpr unsigned null_size = (size); \
+  static constexpr unsigned min_size = (size); \
   enum { static_size = (size) }
 
 #define DEFINE_SIZE_UNION(size, _member) \
   DEFINE_COMPILES_ASSERTION ((void) this->u._member.static_size) \
   DEFINE_INSTANCE_ASSERTION (sizeof(this->u._member) == (size)) \
-  enum { null_size = (size) }; \
+  static constexpr unsigned null_size = (size); \
   enum { min_size = (size) }
 
 #define DEFINE_SIZE_MIN(size) \
   DEFINE_INSTANCE_ASSERTION (sizeof (*this) >= (size)) \
-  enum { null_size = (size) }; \
+  static constexpr unsigned null_size = (size); \
   enum { min_size = (size) }
 
 #define DEFINE_SIZE_UNBOUNDED(size) \
@@ -119,7 +135,7 @@
 #define DEFINE_SIZE_ARRAY(size, array) \
   DEFINE_COMPILES_ASSERTION ((void) (array)[0].static_size) \
   DEFINE_INSTANCE_ASSERTION (sizeof (*this) == (size) + VAR * sizeof ((array)[0])) \
-  enum { null_size = (size) }; \
+  static constexpr unsigned null_size = (size); \
   enum { min_size = (size) }
 
 #define DEFINE_SIZE_ARRAY_SIZED(size, array) \
@@ -134,7 +150,7 @@
 template <typename Context, typename Return, unsigned int MaxDebugDepth>
 struct hb_dispatch_context_t
 {
-  enum { max_debug_depth = MaxDebugDepth };
+  static constexpr unsigned max_debug_depth = MaxDebugDepth;
   typedef Return return_t;
   template <typename T, typename F>
   bool may_dispatch (const T *obj HB_UNUSED, const F *format HB_UNUSED) { return true; }
diff --git a/src/hb-map.hh b/src/hb-map.hh
index a825de4..8905421 100644
--- a/src/hb-map.hh
+++ b/src/hb-map.hh
@@ -163,7 +163,7 @@
   static constexpr hb_codepoint_t INVALID = HB_MAP_VALUE_INVALID;
 
   /* Map interface. */
-  enum { SENTINEL = INVALID };
+  static constexpr hb_codepoint_t SENTINEL = INVALID;
   typedef hb_codepoint_t value_t;
   value_t operator [] (hb_codepoint_t k) const { return get (k); }
   bool has (hb_codepoint_t k) const { return (*this)[k] != SENTINEL; }
diff --git a/src/hb-open-type.hh b/src/hb-open-type.hh
index 8c623b0..453b4fb 100644
--- a/src/hb-open-type.hh
+++ b/src/hb-open-type.hh
@@ -156,7 +156,7 @@
 
 /* Script/language-system/feature index */
 struct Index : HBUINT16 {
-  enum { NOT_FOUND_INDEX = 0xFFFFu };
+  static constexpr unsigned NOT_FOUND_INDEX = 0xFFFFu;
 };
 DECLARE_NULL_NAMESPACE_BYTES (OT, Index);
 
@@ -353,7 +353,7 @@
 struct UnsizedArrayOf
 {
   typedef Type item_t;
-  enum { item_size = hb_static_size (Type) };
+  static constexpr unsigned item_size = hb_static_size (Type);
 
   HB_NO_CREATE_COPY_ASSIGN_TEMPLATE (UnsizedArrayOf, Type);
 
@@ -509,7 +509,7 @@
 struct ArrayOf
 {
   typedef Type item_t;
-  enum { item_size = hb_static_size (Type) };
+  static constexpr unsigned item_size = hb_static_size (Type);
 
   HB_NO_CREATE_COPY_ASSIGN_TEMPLATE2 (ArrayOf, Type, LenType);
 
@@ -689,7 +689,7 @@
 template <typename Type, typename LenType=HBUINT16>
 struct HeadlessArrayOf
 {
-  enum { item_size = Type::static_size };
+  static constexpr unsigned item_size = Type::static_size;
 
   HB_NO_CREATE_COPY_ASSIGN_TEMPLATE2 (HeadlessArrayOf, Type, LenType);
 
@@ -918,7 +918,7 @@
 template <typename Type>
 struct VarSizedBinSearchArrayOf
 {
-  enum { item_size = Type::static_size };
+  static constexpr unsigned item_size = Type::static_size;
 
   HB_NO_CREATE_COPY_ASSIGN_TEMPLATE (VarSizedBinSearchArrayOf, Type);
 
diff --git a/src/hb-ot-cff1-table.hh b/src/hb-ot-cff1-table.hh
index 073dd7e..1effdf0 100644
--- a/src/hb-ot-cff1-table.hh
+++ b/src/hb-ot-cff1-table.hh
@@ -984,7 +984,7 @@
 
 struct cff1
 {
-  enum { tableTag = HB_OT_TAG_cff1 };
+  static constexpr hb_tag_t tableTag = HB_OT_TAG_cff1;
 
   bool sanitize (hb_sanitize_context_t *c) const
   {
diff --git a/src/hb-ot-cff2-table.hh b/src/hb-ot-cff2-table.hh
index cd37863..a7b0ba9 100644
--- a/src/hb-ot-cff2-table.hh
+++ b/src/hb-ot-cff2-table.hh
@@ -408,7 +408,7 @@
 
 struct cff2
 {
-  enum { tableTag = HB_OT_TAG_cff2 };
+  static constexpr hb_tag_t tableTag = HB_OT_TAG_cff2;
 
   bool sanitize (hb_sanitize_context_t *c) const
   {
diff --git a/src/hb-ot-cmap-table.hh b/src/hb-ot-cmap-table.hh
index 0882dc8..3846d46 100644
--- a/src/hb-ot-cmap-table.hh
+++ b/src/hb-ot-cmap-table.hh
@@ -841,7 +841,7 @@
 
 struct cmap
 {
-  enum { tableTag = HB_OT_TAG_cmap };
+  static constexpr hb_tag_t tableTag = HB_OT_TAG_cmap;
 
   struct subset_plan
   {
@@ -1054,11 +1054,8 @@
 	   done < count && get_glyph_funcZ (get_glyph_data, *first_unicode, first_glyph);
 	   done++)
       {
-#pragma GCC diagnostic push
-#pragma GCC diagnostic ignored "-Wcast-align"
-	first_unicode = &StructAtOffset<hb_codepoint_t> (first_unicode, unicode_stride);
-	first_glyph = &StructAtOffset<hb_codepoint_t> (first_glyph, glyph_stride);
-#pragma GCC diagnostic pop
+	first_unicode = &StructAtOffsetUnaligned<hb_codepoint_t> (first_unicode, unicode_stride);
+	first_glyph = &StructAtOffsetUnaligned<hb_codepoint_t> (first_glyph, glyph_stride);
       }
       return done;
     }
diff --git a/src/hb-ot-color-cbdt-table.hh b/src/hb-ot-color-cbdt-table.hh
index 939aeb1..71c31af 100644
--- a/src/hb-ot-color-cbdt-table.hh
+++ b/src/hb-ot-color-cbdt-table.hh
@@ -332,7 +332,7 @@
 {
   friend struct CBDT;
 
-  enum { tableTag = HB_OT_TAG_CBLC };
+  static constexpr hb_tag_t tableTag = HB_OT_TAG_CBLC;
 
   bool sanitize (hb_sanitize_context_t *c) const
   {
@@ -378,7 +378,7 @@
 
 struct CBDT
 {
-  enum { tableTag = HB_OT_TAG_CBDT };
+  static constexpr hb_tag_t tableTag = HB_OT_TAG_CBDT;
 
   struct accelerator_t
   {
diff --git a/src/hb-ot-color-colr-table.hh b/src/hb-ot-color-colr-table.hh
index cdb986a..a57911a 100644
--- a/src/hb-ot-color-colr-table.hh
+++ b/src/hb-ot-color-colr-table.hh
@@ -87,7 +87,7 @@
 
 struct COLR
 {
-  enum { tableTag = HB_OT_TAG_COLR };
+  static constexpr hb_tag_t tableTag = HB_OT_TAG_COLR;
 
   bool has_data () const { return numBaseGlyphs; }
 
diff --git a/src/hb-ot-color-cpal-table.hh b/src/hb-ot-color-cpal-table.hh
index 81451d3..4070493 100644
--- a/src/hb-ot-color-cpal-table.hh
+++ b/src/hb-ot-color-cpal-table.hh
@@ -107,7 +107,7 @@
 
 struct CPAL
 {
-  enum { tableTag = HB_OT_TAG_CPAL };
+  static constexpr hb_tag_t tableTag = HB_OT_TAG_CPAL;
 
   bool has_data () const { return numPalettes; }
 
diff --git a/src/hb-ot-color-sbix-table.hh b/src/hb-ot-color-sbix-table.hh
index ed93d65..f6bdbb3 100644
--- a/src/hb-ot-color-sbix-table.hh
+++ b/src/hb-ot-color-sbix-table.hh
@@ -130,7 +130,7 @@
 
 struct sbix
 {
-  enum { tableTag = HB_OT_TAG_sbix };
+  static constexpr hb_tag_t tableTag = HB_OT_TAG_sbix;
 
   bool has_data () const { return version; }
 
diff --git a/src/hb-ot-color-svg-table.hh b/src/hb-ot-color-svg-table.hh
index 46f20d7..6e8eddf 100644
--- a/src/hb-ot-color-svg-table.hh
+++ b/src/hb-ot-color-svg-table.hh
@@ -73,7 +73,7 @@
 
 struct SVG
 {
-  enum { tableTag = HB_OT_TAG_SVG };
+  static constexpr hb_tag_t tableTag = HB_OT_TAG_SVG;
 
   bool has_data () const { return svgDocEntries; }
 
diff --git a/src/hb-ot-font.cc b/src/hb-ot-font.cc
index 81bc97f..20b09df 100644
--- a/src/hb-ot-font.cc
+++ b/src/hb-ot-font.cc
@@ -112,11 +112,8 @@
   for (unsigned int i = 0; i < count; i++)
   {
     *first_advance = font->em_scale_x (hmtx.get_advance (*first_glyph, font));
-#pragma GCC diagnostic push
-#pragma GCC diagnostic ignored "-Wcast-align"
-    first_glyph = &StructAtOffset<hb_codepoint_t> (first_glyph, glyph_stride);
-    first_advance = &StructAtOffset<hb_position_t> (first_advance, advance_stride);
-#pragma GCC diagnostic pop
+    first_glyph = &StructAtOffsetUnaligned<hb_codepoint_t> (first_glyph, glyph_stride);
+    first_advance = &StructAtOffsetUnaligned<hb_position_t> (first_advance, advance_stride);
   }
 }
 
@@ -135,11 +132,8 @@
   for (unsigned int i = 0; i < count; i++)
   {
     *first_advance = font->em_scale_y (-(int) vmtx.get_advance (*first_glyph, font));
-#pragma GCC diagnostic push
-#pragma GCC diagnostic ignored "-Wcast-align"
-    first_glyph = &StructAtOffset<hb_codepoint_t> (first_glyph, glyph_stride);
-    first_advance = &StructAtOffset<hb_position_t> (first_advance, advance_stride);
-#pragma GCC diagnostic pop
+    first_glyph = &StructAtOffsetUnaligned<hb_codepoint_t> (first_glyph, glyph_stride);
+    first_advance = &StructAtOffsetUnaligned<hb_position_t> (first_advance, advance_stride);
   }
 }
 
diff --git a/src/hb-ot-gasp-table.hh b/src/hb-ot-gasp-table.hh
index d328fd2..94fff58 100644
--- a/src/hb-ot-gasp-table.hh
+++ b/src/hb-ot-gasp-table.hh
@@ -57,7 +57,7 @@
 
 struct gasp
 {
-  enum { tableTag = HB_OT_TAG_gasp };
+  static constexpr hb_tag_t tableTag = HB_OT_TAG_gasp;
 
   const GaspRange &get_gasp_range (unsigned int i) const
   { return gaspRanges[i]; }
diff --git a/src/hb-ot-glyf-table.hh b/src/hb-ot-glyf-table.hh
index f568cf0..c2b38b0 100644
--- a/src/hb-ot-glyf-table.hh
+++ b/src/hb-ot-glyf-table.hh
@@ -45,7 +45,7 @@
 {
   friend struct glyf;
 
-  enum { tableTag = HB_OT_TAG_loca };
+  static constexpr hb_tag_t tableTag = HB_OT_TAG_loca;
 
   bool sanitize (hb_sanitize_context_t *c HB_UNUSED) const
   {
@@ -71,7 +71,7 @@
 
 struct glyf
 {
-  enum { tableTag = HB_OT_TAG_glyf };
+  static constexpr hb_tag_t tableTag = HB_OT_TAG_glyf;
 
   bool sanitize (hb_sanitize_context_t *c HB_UNUSED) const
   {
diff --git a/src/hb-ot-hdmx-table.hh b/src/hb-ot-hdmx-table.hh
index 02ae8d8..95229c5 100644
--- a/src/hb-ot-hdmx-table.hh
+++ b/src/hb-ot-hdmx-table.hh
@@ -119,7 +119,7 @@
 
 struct hdmx
 {
-  enum { tableTag = HB_OT_TAG_hdmx };
+  static constexpr hb_tag_t tableTag = HB_OT_TAG_hdmx;
 
   unsigned int get_size () const
   { return min_size + numRecords * sizeDeviceRecord; }
diff --git a/src/hb-ot-head-table.hh b/src/hb-ot-head-table.hh
index 41062ca..3c0bb3d 100644
--- a/src/hb-ot-head-table.hh
+++ b/src/hb-ot-head-table.hh
@@ -45,7 +45,7 @@
 {
   friend struct OffsetTable;
 
-  enum { tableTag = HB_OT_TAG_head };
+  static constexpr hb_tag_t tableTag = HB_OT_TAG_head;
 
   unsigned int get_upem () const
   {
diff --git a/src/hb-ot-hhea-table.hh b/src/hb-ot-hhea-table.hh
index 7bc1817..c3155b7 100644
--- a/src/hb-ot-hhea-table.hh
+++ b/src/hb-ot-hhea-table.hh
@@ -86,10 +86,10 @@
 };
 
 struct hhea : _hea<hhea> {
-  enum { tableTag = HB_OT_TAG_hhea };
+  static constexpr hb_tag_t tableTag = HB_OT_TAG_hhea;
 };
 struct vhea : _hea<vhea> {
-  enum { tableTag = HB_OT_TAG_vhea };
+  static constexpr hb_tag_t tableTag = HB_OT_TAG_vhea;
 };
 
 
diff --git a/src/hb-ot-hmtx-table.hh b/src/hb-ot-hmtx-table.hh
index 0a16678..a95a56f 100644
--- a/src/hb-ot-hmtx-table.hh
+++ b/src/hb-ot-hmtx-table.hh
@@ -323,14 +323,14 @@
 };
 
 struct hmtx : hmtxvmtx<hmtx, hhea> {
-  enum { tableTag = HB_OT_TAG_hmtx };
-  enum { variationsTag = HB_OT_TAG_HVAR };
-  enum { os2Tag = HB_OT_TAG_OS2 };
+  static constexpr hb_tag_t tableTag = HB_OT_TAG_hmtx;
+  static constexpr hb_tag_t variationsTag = HB_OT_TAG_HVAR;
+  static constexpr hb_tag_t os2Tag = HB_OT_TAG_OS2;
 };
 struct vmtx : hmtxvmtx<vmtx, vhea> {
-  enum { tableTag = HB_OT_TAG_vmtx };
-  enum { variationsTag = HB_OT_TAG_VVAR };
-  enum { os2Tag = HB_TAG_NONE };
+  static constexpr hb_tag_t tableTag = HB_OT_TAG_vmtx;
+  static constexpr hb_tag_t variationsTag = HB_OT_TAG_VVAR;
+  static constexpr hb_tag_t os2Tag = HB_TAG_NONE;
 };
 
 struct hmtx_accelerator_t : hmtx::accelerator_t {};
diff --git a/src/hb-ot-kern-table.hh b/src/hb-ot-kern-table.hh
index 5e75d08..ec6a3c8 100644
--- a/src/hb-ot-kern-table.hh
+++ b/src/hb-ot-kern-table.hh
@@ -160,7 +160,7 @@
 
 struct KernOTSubTableHeader
 {
-  enum { apple = false };
+  static constexpr bool apple = false;
   typedef AAT::ObsoleteTypes Types;
 
   unsigned int tuple_count () const { return 0; }
@@ -197,8 +197,8 @@
 {
   friend struct AAT::KerxTable<KernOT>;
 
-  enum { tableTag = HB_OT_TAG_kern };
-  enum { minVersion = 0u };
+  static constexpr hb_tag_t tableTag = HB_OT_TAG_kern;
+  static constexpr unsigned minVersion = 0u;
 
   typedef KernOTSubTableHeader SubTableHeader;
   typedef SubTableHeader::Types Types;
@@ -215,7 +215,7 @@
 
 struct KernAATSubTableHeader
 {
-  enum { apple = true };
+  static constexpr bool apple = true;
   typedef AAT::ObsoleteTypes Types;
 
   unsigned int tuple_count () const { return 0; }
@@ -252,8 +252,8 @@
 {
   friend struct AAT::KerxTable<KernAAT>;
 
-  enum { tableTag = HB_OT_TAG_kern };
-  enum { minVersion = 0x00010000u };
+  static constexpr hb_tag_t tableTag = HB_OT_TAG_kern;
+  static constexpr unsigned minVersion = 0x00010000u;
 
   typedef KernAATSubTableHeader SubTableHeader;
   typedef SubTableHeader::Types Types;
@@ -269,7 +269,7 @@
 
 struct kern
 {
-  enum { tableTag = HB_OT_TAG_kern };
+  static constexpr hb_tag_t tableTag = HB_OT_TAG_kern;
 
   bool has_data () const { return u.version32; }
   unsigned int get_type () const { return u.major; }
diff --git a/src/hb-ot-layout-base-table.hh b/src/hb-ot-layout-base-table.hh
index 6c39932..dd0fba1 100644
--- a/src/hb-ot-layout-base-table.hh
+++ b/src/hb-ot-layout-base-table.hh
@@ -464,7 +464,7 @@
 
 struct BASE
 {
-  enum { tableTag = HB_OT_TAG_BASE };
+  static constexpr hb_tag_t tableTag = HB_OT_TAG_BASE;
 
   const Axis &get_axis (hb_direction_t direction) const
   { return HB_DIRECTION_IS_VERTICAL (direction) ? this+vAxis : this+hAxis; }
diff --git a/src/hb-ot-layout-common.hh b/src/hb-ot-layout-common.hh
index ec05694..c163140 100644
--- a/src/hb-ot-layout-common.hh
+++ b/src/hb-ot-layout-common.hh
@@ -1036,7 +1036,7 @@
 struct Coverage
 {
   /* Map interface. */
-  enum { SENTINEL = NOT_COVERED };
+  static constexpr unsigned SENTINEL = NOT_COVERED;
   typedef unsigned int value_t;
   value_t operator [] (hb_codepoint_t k) const { return get (k); }
   bool has (hb_codepoint_t k) const { return (*this)[k] != SENTINEL; }
@@ -1123,7 +1123,7 @@
     hb_iter_t<iter_t, hb_codepoint_t>,
     hb_iter_mixin_t<iter_t, hb_codepoint_t>
   {
-    enum { is_sorted_iterator = true };
+    static constexpr bool is_sorted_iterator = true;
     iter_t (const Coverage &c_ = Null(Coverage))
     {
       memset (this, 0, sizeof (*this));
@@ -1481,7 +1481,7 @@
 struct ClassDef
 {
   /* Map interface. */
-  enum { SENTINEL = 0 };
+  static constexpr unsigned SENTINEL = 0;
   typedef unsigned int value_t;
   value_t operator [] (hb_codepoint_t k) const { return get (k); }
   bool has (hb_codepoint_t k) const { return (*this)[k] != SENTINEL; }
@@ -1969,7 +1969,7 @@
 
 struct FeatureVariations
 {
-  enum { NOT_FOUND_INDEX = 0xFFFFFFFFu };
+  static constexpr unsigned NOT_FOUND_INDEX = 0xFFFFFFFFu;
 
   bool find_index (const int *coords, unsigned int coord_len,
 			  unsigned int *index) const
diff --git a/src/hb-ot-layout-gdef-table.hh b/src/hb-ot-layout-gdef-table.hh
index 58be094..06c26fb 100644
--- a/src/hb-ot-layout-gdef-table.hh
+++ b/src/hb-ot-layout-gdef-table.hh
@@ -341,7 +341,7 @@
 
 struct GDEF
 {
-  enum { tableTag = HB_OT_TAG_GDEF };
+  static constexpr hb_tag_t tableTag = HB_OT_TAG_GDEF;
 
   enum GlyphClasses {
     UnclassifiedGlyph	= 0,
diff --git a/src/hb-ot-layout-gpos-table.hh b/src/hb-ot-layout-gpos-table.hh
index dcb2545..485458a 100644
--- a/src/hb-ot-layout-gpos-table.hh
+++ b/src/hb-ot-layout-gpos-table.hh
@@ -1597,7 +1597,7 @@
 
 struct GPOS : GSUBGPOS
 {
-  enum { tableTag = HB_OT_TAG_GPOS };
+  static constexpr hb_tag_t tableTag = HB_OT_TAG_GPOS;
 
   const PosLookup& get_lookup (unsigned int i) const
   { return CastR<PosLookup> (GSUBGPOS::get_lookup (i)); }
diff --git a/src/hb-ot-layout-gsub-table.hh b/src/hb-ot-layout-gsub-table.hh
index 074c7bb..1b60ce2 100644
--- a/src/hb-ot-layout-gsub-table.hh
+++ b/src/hb-ot-layout-gsub-table.hh
@@ -1363,7 +1363,7 @@
 
 struct GSUB : GSUBGPOS
 {
-  enum { tableTag = HB_OT_TAG_GSUB };
+  static constexpr hb_tag_t tableTag = HB_OT_TAG_GSUB;
 
   const SubstLookup& get_lookup (unsigned int i) const
   { return CastR<SubstLookup> (GSUBGPOS::get_lookup (i)); }
diff --git a/src/hb-ot-layout-gsubgpos.hh b/src/hb-ot-layout-gsubgpos.hh
index f3a59a6..4b10e4d 100644
--- a/src/hb-ot-layout-gsubgpos.hh
+++ b/src/hb-ot-layout-gsubgpos.hh
@@ -2644,7 +2644,7 @@
   { return (version.to_int () >= 0x00010001u ? this+featureVars : Null(FeatureVariations))
 	   .find_index (coords, num_coords, index); }
   const Feature& get_feature_variation (unsigned int feature_index,
-					       unsigned int variations_index) const
+					unsigned int variations_index) const
   {
     if (FeatureVariations::NOT_FOUND_INDEX != variations_index &&
 	version.to_int () >= 0x00010001u)
diff --git a/src/hb-ot-layout-jstf-table.hh b/src/hb-ot-layout-jstf-table.hh
index 3beedc4..1dd31d5 100644
--- a/src/hb-ot-layout-jstf-table.hh
+++ b/src/hb-ot-layout-jstf-table.hh
@@ -195,7 +195,7 @@
 
 struct JSTF
 {
-  enum { tableTag = HB_OT_TAG_JSTF };
+  static constexpr hb_tag_t tableTag = HB_OT_TAG_JSTF;
 
   unsigned int get_script_count () const
   { return scriptList.len; }
diff --git a/src/hb-ot-layout.cc b/src/hb-ot-layout.cc
index 672d4ee..d32be04 100644
--- a/src/hb-ot-layout.cc
+++ b/src/hb-ot-layout.cc
@@ -1299,8 +1299,8 @@
 
 struct GSUBProxy
 {
-  enum { table_index = 0 };
-  enum { inplace = false };
+  static constexpr unsigned table_index = 0u;
+  static constexpr bool inplace = false;
   typedef OT::SubstLookup Lookup;
 
   GSUBProxy (hb_face_t *face) :
@@ -1313,8 +1313,8 @@
 
 struct GPOSProxy
 {
-  enum { table_index = 1 };
-  enum { inplace = true };
+  static constexpr unsigned table_index = 1u;
+  static constexpr bool inplace = true;
   typedef OT::PosLookup Lookup;
 
   GPOSProxy (hb_face_t *face) :
@@ -1387,7 +1387,7 @@
   if (likely (!lookup.is_reverse ()))
   {
     /* in/out forward substitution/positioning */
-    if (Proxy::table_index == 0)
+    if (Proxy::table_index == 0u)
       buffer->clear_output ();
     buffer->idx = 0;
 
@@ -1404,7 +1404,7 @@
   else
   {
     /* in-place backward substitution/positioning */
-    if (Proxy::table_index == 0)
+    if (Proxy::table_index == 0u)
       buffer->remove_output ();
     buffer->idx = buffer->len - 1;
 
diff --git a/src/hb-ot-math-table.hh b/src/hb-ot-math-table.hh
index ae0016f..62bf072 100644
--- a/src/hb-ot-math-table.hh
+++ b/src/hb-ot-math-table.hh
@@ -679,7 +679,7 @@
 
 struct MATH
 {
-  enum { tableTag = HB_OT_TAG_MATH };
+  static constexpr hb_tag_t tableTag = HB_OT_TAG_MATH;
 
   bool has_data () const { return version.to_int (); }
 
diff --git a/src/hb-ot-maxp-table.hh b/src/hb-ot-maxp-table.hh
index 3bbc803..e4b67ab 100644
--- a/src/hb-ot-maxp-table.hh
+++ b/src/hb-ot-maxp-table.hh
@@ -71,7 +71,7 @@
 
 struct maxp
 {
-  enum { tableTag = HB_OT_TAG_maxp };
+  static constexpr hb_tag_t tableTag = HB_OT_TAG_maxp;
 
   unsigned int get_num_glyphs () const { return numGlyphs; }
 
diff --git a/src/hb-ot-name-table.hh b/src/hb-ot-name-table.hh
index 2d5ac63..c8ababd 100644
--- a/src/hb-ot-name-table.hh
+++ b/src/hb-ot-name-table.hh
@@ -151,7 +151,7 @@
 
 struct name
 {
-  enum { tableTag = HB_OT_TAG_name };
+  static constexpr hb_tag_t tableTag = HB_OT_TAG_name;
 
   unsigned int get_size () const
   { return min_size + count * nameRecordZ.item_size; }
diff --git a/src/hb-ot-os2-table.hh b/src/hb-ot-os2-table.hh
index 4c1812c..68dd63e 100644
--- a/src/hb-ot-os2-table.hh
+++ b/src/hb-ot-os2-table.hh
@@ -92,7 +92,7 @@
 
 struct OS2
 {
-  enum { tableTag = HB_OT_TAG_OS2 };
+  static constexpr hb_tag_t tableTag = HB_OT_TAG_OS2;
 
   bool has_data () const { return this != &Null (OS2); }
 
diff --git a/src/hb-ot-post-table.hh b/src/hb-ot-post-table.hh
index a799b86..43c1143 100644
--- a/src/hb-ot-post-table.hh
+++ b/src/hb-ot-post-table.hh
@@ -71,7 +71,7 @@
 
 struct post
 {
-  enum { tableTag = HB_OT_TAG_post };
+  static constexpr hb_tag_t tableTag = HB_OT_TAG_post;
 
   bool subset (hb_subset_plan_t *plan) const
   {
diff --git a/src/hb-ot-shape-fallback.cc b/src/hb-ot-shape-fallback.cc
index d3afdff..f9d4a75 100644
--- a/src/hb-ot-shape-fallback.cc
+++ b/src/hb-ot-shape-fallback.cc
@@ -180,12 +180,18 @@
 static void
 zero_mark_advances (hb_buffer_t *buffer,
 		    unsigned int start,
-		    unsigned int end)
+		    unsigned int end,
+		    bool adjust_offsets_when_zeroing)
 {
   hb_glyph_info_t *info = buffer->info;
   for (unsigned int i = start; i < end; i++)
     if (_hb_glyph_info_get_general_category (&info[i]) == HB_UNICODE_GENERAL_CATEGORY_NON_SPACING_MARK)
     {
+      if (adjust_offsets_when_zeroing)
+      {
+	buffer->pos[i].x_offset -= buffer->pos[i].x_advance;
+	buffer->pos[i].y_offset -= buffer->pos[i].y_advance;
+      }
       buffer->pos[i].x_advance = 0;
       buffer->pos[i].y_advance = 0;
     }
@@ -303,7 +309,8 @@
 		      hb_font_t *font,
 		      hb_buffer_t  *buffer,
 		      unsigned int base,
-		      unsigned int end)
+		      unsigned int end,
+		      bool adjust_offsets_when_zeroing)
 {
   hb_direction_t horiz_dir = HB_DIRECTION_INVALID;
 
@@ -314,11 +321,15 @@
 				&base_extents))
   {
     /* If extents don't work, zero marks and go home. */
-    zero_mark_advances (buffer, base + 1, end);
+    zero_mark_advances (buffer, base + 1, end, adjust_offsets_when_zeroing);
     return;
   }
-  base_extents.x_bearing += buffer->pos[base].x_offset;
   base_extents.y_bearing += buffer->pos[base].y_offset;
+  /* Use horizontal advance for horizontal positioning.
+   * Generally a better idea.  Also works for zero-ink glyphs.  See:
+   * https://github.com/harfbuzz/harfbuzz/issues/1532 */
+  base_extents.x_bearing = 0;
+  base_extents.width = font->get_glyph_h_advance (buffer->info[base].codepoint);
 
   unsigned int lig_id = _hb_glyph_info_get_lig_id (&buffer->info[base]);
   /* Use integer for num_lig_components such that it doesn't convert to unsigned
@@ -394,7 +405,8 @@
 		  hb_font_t *font,
 		  hb_buffer_t  *buffer,
 		  unsigned int start,
-		  unsigned int end)
+		  unsigned int end,
+		  bool adjust_offsets_when_zeroing)
 {
   if (end - start < 2)
     return;
@@ -410,7 +422,7 @@
 	if (!HB_UNICODE_GENERAL_CATEGORY_IS_MARK (_hb_glyph_info_get_general_category (&info[j])))
 	  break;
 
-      position_around_base (plan, font, buffer, i, j);
+      position_around_base (plan, font, buffer, i, j, adjust_offsets_when_zeroing);
 
       i = j - 1;
     }
@@ -419,7 +431,8 @@
 void
 _hb_ot_shape_fallback_mark_position (const hb_ot_shape_plan_t *plan,
 				     hb_font_t *font,
-				     hb_buffer_t  *buffer)
+				     hb_buffer_t  *buffer,
+				     bool adjust_offsets_when_zeroing)
 {
   _hb_buffer_assert_gsubgpos_vars (buffer);
 
@@ -428,10 +441,10 @@
   hb_glyph_info_t *info = buffer->info;
   for (unsigned int i = 1; i < count; i++)
     if (likely (!HB_UNICODE_GENERAL_CATEGORY_IS_MARK (_hb_glyph_info_get_general_category (&info[i])))) {
-      position_cluster (plan, font, buffer, start, i);
+      position_cluster (plan, font, buffer, start, i, adjust_offsets_when_zeroing);
       start = i;
     }
-  position_cluster (plan, font, buffer, start, count);
+  position_cluster (plan, font, buffer, start, count, adjust_offsets_when_zeroing);
 }
 
 
diff --git a/src/hb-ot-shape-fallback.hh b/src/hb-ot-shape-fallback.hh
index 12f18ed..5faf5f2 100644
--- a/src/hb-ot-shape-fallback.hh
+++ b/src/hb-ot-shape-fallback.hh
@@ -34,7 +34,8 @@
 
 HB_INTERNAL void _hb_ot_shape_fallback_mark_position (const hb_ot_shape_plan_t *plan,
 						      hb_font_t *font,
-						      hb_buffer_t  *buffer);
+						      hb_buffer_t  *buffer,
+						      bool adjust_offsets_when_zeroing);
 
 HB_INTERNAL void _hb_ot_shape_fallback_mark_position_recategorize_marks (const hb_ot_shape_plan_t *plan,
 									 hb_font_t *font,
diff --git a/src/hb-ot-shape.cc b/src/hb-ot-shape.cc
index 6e5ce15..e9d97c9 100644
--- a/src/hb-ot-shape.cc
+++ b/src/hb-ot-shape.cc
@@ -428,6 +428,20 @@
 	_hb_glyph_info_set_continuation (&info[i]);
       }
     }
+    /* Or part of the Other_Grapheme_Extend that is not marks.
+     * As of Unicode 11 that is just:
+     *
+     * 200C          ; Other_Grapheme_Extend # Cf       ZERO WIDTH NON-JOINER
+     * FF9E..FF9F    ; Other_Grapheme_Extend # Lm   [2] HALFWIDTH KATAKANA VOICED SOUND MARK..HALFWIDTH KATAKANA SEMI-VOICED SOUND MARK
+     * E0020..E007F  ; Other_Grapheme_Extend # Cf  [96] TAG SPACE..CANCEL TAG
+     *
+     * ZWNJ is special, we don't want to merge it as there's no need, and keeping
+     * it separate results in more granular clusters.  Ignore Katakana for now.
+     * Tags are used for Emoji sub-region flag sequences:
+     * https://github.com/harfbuzz/harfbuzz/issues/1556
+     */
+    else if (unlikely (hb_in_range<hb_codepoint_t> (info[i].codepoint, 0xE0020u, 0xE007Fu)))
+      _hb_glyph_info_set_continuation (&info[i]);
   }
 }
 
@@ -891,7 +905,8 @@
 					&pos[i].y_offset);
 
   if (c->plan->fallback_mark_positioning)
-    _hb_ot_shape_fallback_mark_position (c->plan, c->font, c->buffer);
+    _hb_ot_shape_fallback_mark_position (c->plan, c->font, c->buffer,
+					 adjust_offsets_when_zeroing);
 }
 
 static inline void
diff --git a/src/hb-ot-stat-table.hh b/src/hb-ot-stat-table.hh
index d85958b..04a2ee9 100644
--- a/src/hb-ot-stat-table.hh
+++ b/src/hb-ot-stat-table.hh
@@ -225,7 +225,7 @@
 
 struct STAT
 {
-  enum { tableTag = HB_OT_TAG_STAT };
+  static constexpr hb_tag_t tableTag = HB_OT_TAG_STAT;
 
   bool sanitize (hb_sanitize_context_t *c) const
   {
diff --git a/src/hb-ot-var-avar-table.hh b/src/hb-ot-var-avar-table.hh
index 67a60f5e..c4a192d 100644
--- a/src/hb-ot-var-avar-table.hh
+++ b/src/hb-ot-var-avar-table.hh
@@ -99,7 +99,7 @@
 
 struct avar
 {
-  enum { tableTag = HB_OT_TAG_avar };
+  static constexpr hb_tag_t tableTag = HB_OT_TAG_avar;
 
   bool sanitize (hb_sanitize_context_t *c) const
   {
diff --git a/src/hb-ot-var-fvar-table.hh b/src/hb-ot-var-fvar-table.hh
index 92d164c..78cb3c8 100644
--- a/src/hb-ot-var-fvar-table.hh
+++ b/src/hb-ot-var-fvar-table.hh
@@ -96,7 +96,7 @@
 
 struct fvar
 {
-  enum { tableTag = HB_OT_TAG_fvar };
+  static constexpr hb_tag_t tableTag = HB_OT_TAG_fvar;
 
   bool has_data () const { return version.to_int (); }
 
diff --git a/src/hb-ot-var-hvar-table.hh b/src/hb-ot-var-hvar-table.hh
index 2640f07..a8d9fe3 100644
--- a/src/hb-ot-var-hvar-table.hh
+++ b/src/hb-ot-var-hvar-table.hh
@@ -100,8 +100,8 @@
 
 struct HVARVVAR
 {
-  enum { HVARTag = HB_OT_TAG_HVAR };
-  enum { VVARTag = HB_OT_TAG_VVAR };
+  static constexpr hb_tag_t HVARTag = HB_OT_TAG_HVAR;
+  static constexpr hb_tag_t VVARTag = HB_OT_TAG_VVAR;
 
   bool sanitize (hb_sanitize_context_t *c) const
   {
@@ -140,10 +140,10 @@
 };
 
 struct HVAR : HVARVVAR {
-  enum { tableTag = HB_OT_TAG_HVAR };
+  static constexpr hb_tag_t tableTag = HB_OT_TAG_HVAR;
 };
 struct VVAR : HVARVVAR {
-  enum { tableTag = HB_OT_TAG_VVAR };
+  static constexpr hb_tag_t tableTag = HB_OT_TAG_VVAR;
 
   bool sanitize (hb_sanitize_context_t *c) const
   {
diff --git a/src/hb-ot-var-mvar-table.hh b/src/hb-ot-var-mvar-table.hh
index a5eeddc..0dd63e5 100644
--- a/src/hb-ot-var-mvar-table.hh
+++ b/src/hb-ot-var-mvar-table.hh
@@ -58,7 +58,7 @@
 
 struct MVAR
 {
-  enum { tableTag = HB_OT_TAG_MVAR };
+  static constexpr hb_tag_t tableTag = HB_OT_TAG_MVAR;
 
   bool sanitize (hb_sanitize_context_t *c) const
   {
diff --git a/src/hb-ot-vorg-table.hh b/src/hb-ot-vorg-table.hh
index f11c745..0202fcc 100644
--- a/src/hb-ot-vorg-table.hh
+++ b/src/hb-ot-vorg-table.hh
@@ -57,7 +57,7 @@
 
 struct VORG
 {
-  enum { tableTag = HB_OT_TAG_VORG };
+  static constexpr hb_tag_t tableTag = HB_OT_TAG_VORG;
 
   bool has_data () const { return version.to_int (); }
 
diff --git a/src/hb-set-digest.hh b/src/hb-set-digest.hh
index 9f49af1..7ec275e 100644
--- a/src/hb-set-digest.hh
+++ b/src/hb-set-digest.hh
@@ -48,8 +48,8 @@
 template <typename mask_t, unsigned int shift>
 struct hb_set_digest_lowest_bits_t
 {
-  enum { mask_bytes = sizeof (mask_t) };
-  enum { mask_bits = sizeof (mask_t) * 8 };
+  static constexpr unsigned mask_bytes = sizeof (mask_t);
+  static constexpr unsigned mask_bits = sizeof (mask_t) * 8;
   enum { num_bits = 0
 		  + (mask_bytes >= 1 ? 3 : 0)
 		  + (mask_bytes >= 2 ? 1 : 0)
diff --git a/src/hb-set.hh b/src/hb-set.hh
index c3c981b..c0f6b88 100644
--- a/src/hb-set.hh
+++ b/src/hb-set.hh
@@ -161,7 +161,7 @@
     }
 
     typedef unsigned long long elt_t;
-    enum { PAGE_BITS = 512 };
+    static constexpr unsigned PAGE_BITS = 512;
     static_assert ((PAGE_BITS & ((PAGE_BITS) - 1)) == 0, "");
 
     static unsigned int elt_get_min (const elt_t &elt) { return hb_ctz (elt); }
@@ -169,10 +169,10 @@
 
     typedef hb_vector_size_t<elt_t, PAGE_BITS / 8> vector_t;
 
-    enum { ELT_BITS = sizeof (elt_t) * 8 };
-    enum { ELT_MASK = ELT_BITS - 1 };
-    enum { BITS = sizeof (vector_t) * 8 };
-    enum { MASK = BITS - 1 };
+    static constexpr unsigned ELT_BITS = sizeof (elt_t) * 8;
+    static constexpr unsigned ELT_MASK = ELT_BITS - 1;
+    static constexpr unsigned BITS = sizeof (vector_t) * 8;
+    static constexpr unsigned MASK = BITS - 1;
     static_assert ((unsigned) PAGE_BITS == (unsigned) BITS, "");
 
     elt_t &elt (hb_codepoint_t g) { return v[(g & MASK) / ELT_BITS]; }
@@ -366,7 +366,7 @@
   }
 
   /* Map interface. */
-  enum { SENTINEL = false };
+  static constexpr bool SENTINEL = false;
   typedef bool value_t;
   value_t operator [] (hb_codepoint_t k) const { return get (k); }
   bool has (hb_codepoint_t k) const { return (*this)[k] != SENTINEL; }
@@ -682,7 +682,7 @@
     hb_iter_t<iter_t, hb_codepoint_t>,
     hb_iter_mixin_t<iter_t, hb_codepoint_t>
   {
-    enum { is_sorted_iterator = true };
+    static constexpr bool is_sorted_iterator = true;
     iter_t (const hb_set_t &s_ = Null(hb_set_t)) :
       s (&s_), v (INVALID), l (s->get_population () + 1) { __next__ (); }
 
diff --git a/src/hb-subset-cff1.cc b/src/hb-subset-cff1.cc
index a864540..5133a4d 100644
--- a/src/hb-subset-cff1.cc
+++ b/src/hb-subset-cff1.cc
@@ -882,7 +882,7 @@
 
   /* name INDEX */
   {
-    assert (cff->nameIndex == c.head - c.start);
+    assert (cff->nameIndex == (unsigned) (c.head - c.start));
     CFF1NameIndex *dest = c.start_embed<CFF1NameIndex> ();
     if (unlikely (dest == nullptr)) return false;
     if (unlikely (!dest->serialize (&c, *acc.nameIndex)))
@@ -894,7 +894,7 @@
 
   /* top dict INDEX */
   {
-    assert (plan.offsets.topDictInfo.offset == c.head - c.start);
+    assert (plan.offsets.topDictInfo.offset == (unsigned) (c.head - c.start));
     CFF1IndexOf<TopDict> *dest = c.start_embed< CFF1IndexOf<TopDict> > ();
     if (dest == nullptr) return false;
     cff1_top_dict_op_serializer_t topSzr;
@@ -910,7 +910,7 @@
 
   /* String INDEX */
   {
-    assert (plan.offsets.stringIndexInfo.offset == c.head - c.start);
+    assert (plan.offsets.stringIndexInfo.offset == (unsigned) (c.head - c.start));
     CFF1StringIndex *dest = c.start_embed<CFF1StringIndex> ();
     if (unlikely (dest == nullptr)) return false;
     if (unlikely (!dest->serialize (&c, *acc.stringIndex, plan.offsets.stringIndexInfo.offSize, plan.sidmap)))
@@ -923,7 +923,7 @@
   /* global subrs */
   {
     assert (plan.offsets.globalSubrsInfo.offset != 0);
-    assert (plan.offsets.globalSubrsInfo.offset == c.head - c.start);
+    assert (plan.offsets.globalSubrsInfo.offset == (unsigned) (c.head - c.start));
 
     CFF1Subrs *dest = c.start_embed <CFF1Subrs> ();
     if (unlikely (dest == nullptr)) return false;
@@ -937,7 +937,7 @@
   /* Encoding */
   if (plan.subset_encoding)
   {
-    assert (plan.offsets.encodingOffset == c.head - c.start);
+    assert (plan.offsets.encodingOffset == (unsigned) (c.head - c.start));
     Encoding *dest = c.start_embed<Encoding> ();
     if (unlikely (dest == nullptr)) return false;
     if (unlikely (!dest->serialize (&c,
@@ -954,7 +954,7 @@
   /* Charset */
   if (plan.subset_charset)
   {
-    assert (plan.offsets.charsetInfo.offset == c.head - c.start);
+    assert (plan.offsets.charsetInfo.offset == (unsigned) (c.head - c.start));
     Charset *dest = c.start_embed<Charset> ();
     if (unlikely (dest == nullptr)) return false;
     if (unlikely (!dest->serialize (&c,
@@ -970,7 +970,7 @@
   /* FDSelect */
   if (acc.fdSelect != &Null(CFF1FDSelect))
   {
-    assert (plan.offsets.FDSelectInfo.offset == c.head - c.start);
+    assert (plan.offsets.FDSelectInfo.offset == (unsigned) (c.head - c.start));
 
     if (unlikely (!hb_serialize_cff_fdselect (&c, glyphs.length, *acc.fdSelect, acc.fdCount,
 					      plan.subset_fdselect_format, plan.offsets.FDSelectInfo.size,
@@ -984,7 +984,7 @@
   /* FDArray (FD Index) */
   if (acc.fdArray != &Null(CFF1FDArray))
   {
-    assert (plan.offsets.FDArrayInfo.offset == c.head - c.start);
+    assert (plan.offsets.FDArrayInfo.offset == (unsigned) (c.head - c.start));
     CFF1FDArray  *fda = c.start_embed<CFF1FDArray> ();
     if (unlikely (fda == nullptr)) return false;
     cff1_font_dict_op_serializer_t  fontSzr;
@@ -999,7 +999,7 @@
 
   /* CharStrings */
   {
-    assert (plan.offsets.charStringsInfo.offset == c.head - c.start);
+    assert (plan.offsets.charStringsInfo.offset == (unsigned) (c.head - c.start));
     CFF1CharStrings  *cs = c.start_embed<CFF1CharStrings> ();
     if (unlikely (cs == nullptr)) return false;
     if (unlikely (!cs->serialize (&c, plan.offsets.charStringsInfo.offSize, plan.subset_charstrings)))
@@ -1010,7 +1010,7 @@
   }
 
   /* private dicts & local subrs */
-  assert (plan.offsets.privateDictInfo.offset == c.head - c.start);
+  assert (plan.offsets.privateDictInfo.offset == (unsigned) (c.head - c.start));
   for (unsigned int i = 0; i < acc.privateDicts.length; i++)
   {
     if (plan.fdmap.includes (i))
diff --git a/src/hb-subset-cff2.cc b/src/hb-subset-cff2.cc
index 8d32b7d..73a292d 100644
--- a/src/hb-subset-cff2.cc
+++ b/src/hb-subset-cff2.cc
@@ -453,7 +453,7 @@
 
   /* top dict */
   {
-    assert (cff2->topDict == c.head - c.start);
+    assert (cff2->topDict == (unsigned) (c.head - c.start));
     cff2->topDictSize.set (plan.offsets.topDictInfo.size);
     TopDict &dict = cff2 + cff2->topDict;
     cff2_top_dict_op_serializer_t topSzr;
@@ -466,7 +466,7 @@
 
   /* global subrs */
   {
-    assert (cff2->topDict + plan.offsets.topDictInfo.size == c.head - c.start);
+    assert (cff2->topDict + plan.offsets.topDictInfo.size == (unsigned) (c.head - c.start));
     CFF2Subrs *dest = c.start_embed <CFF2Subrs> ();
     if (unlikely (dest == nullptr)) return false;
     if (unlikely (!dest->serialize (&c, plan.offsets.globalSubrsInfo.offSize, plan.subset_globalsubrs)))
@@ -479,7 +479,7 @@
   /* variation store */
   if (acc.varStore != &Null(CFF2VariationStore))
   {
-    assert (plan.offsets.varStoreOffset == c.head - c.start);
+    assert (plan.offsets.varStoreOffset == (unsigned) (c.head - c.start));
     CFF2VariationStore *dest = c.start_embed<CFF2VariationStore> ();
     if (unlikely (!dest->serialize (&c, acc.varStore)))
     {
@@ -491,7 +491,7 @@
   /* FDSelect */
   if (acc.fdSelect != &Null(CFF2FDSelect))
   {
-    assert (plan.offsets.FDSelectInfo.offset == c.head - c.start);
+    assert (plan.offsets.FDSelectInfo.offset == (unsigned) (c.head - c.start));
 
     if (unlikely (!hb_serialize_cff_fdselect (&c, glyphs.length, *(const FDSelect *)acc.fdSelect, acc.fdArray->count,
 					      plan.subset_fdselect_format, plan.offsets.FDSelectInfo.size,
@@ -504,7 +504,7 @@
 
   /* FDArray (FD Index) */
   {
-    assert (plan.offsets.FDArrayInfo.offset == c.head - c.start);
+    assert (plan.offsets.FDArrayInfo.offset == (unsigned) (c.head - c.start));
     CFF2FDArray  *fda = c.start_embed<CFF2FDArray> ();
     if (unlikely (fda == nullptr)) return false;
     cff_font_dict_op_serializer_t  fontSzr;
@@ -519,7 +519,7 @@
 
   /* CharStrings */
   {
-    assert (plan.offsets.charStringsInfo.offset == c.head - c.start);
+    assert (plan.offsets.charStringsInfo.offset == (unsigned) (c.head - c.start));
     CFF2CharStrings  *cs = c.start_embed<CFF2CharStrings> ();
     if (unlikely (cs == nullptr)) return false;
     if (unlikely (!cs->serialize (&c, plan.offsets.charStringsInfo.offSize, plan.subset_charstrings)))
@@ -530,7 +530,7 @@
   }
 
   /* private dicts & local subrs */
-  assert (plan.offsets.privateDictsOffset == c.head - c.start);
+  assert (plan.offsets.privateDictsOffset == (unsigned) (c.head - c.start));
   for (unsigned int i = 0; i < acc.privateDicts.length; i++)
   {
     if (plan.fdmap.includes (i))
diff --git a/src/hb-vector.hh b/src/hb-vector.hh
index 27f4101..00f4479 100644
--- a/src/hb-vector.hh
+++ b/src/hb-vector.hh
@@ -36,7 +36,7 @@
 struct hb_vector_t
 {
   typedef Type item_t;
-  enum { item_size = hb_static_size (Type) };
+  static constexpr unsigned item_size = hb_static_size (Type);
 
   HB_NO_COPY_ASSIGN_TEMPLATE (hb_vector_t, Type);
   hb_vector_t ()  { init (); }
diff --git a/src/hb.hh b/src/hb.hh
index ffefa62..0b535af 100644
--- a/src/hb.hh
+++ b/src/hb.hh
@@ -29,7 +29,7 @@
 #ifndef HB_HH
 #define HB_HH
 
-#ifndef HB_NO_DIAGNOSTIC_PRAGMAS
+#ifndef HB_NO_PRAGMA_GCC_DIAGNOSTIC
 #if defined(__GNUC__) || defined(__clang__)
 /* Rules:
  *
@@ -43,14 +43,21 @@
  */
 
 /* Setup.  Don't sort order within this category. */
+#ifndef HB_NO_PRAGMA_GCC_DIAGNOSTIC_WARNING
 #pragma GCC diagnostic warning "-Wall"
 #pragma GCC diagnostic warning "-Wextra"
+#endif
+#ifndef HB_NO_PRAGMA_GCC_DIAGNOSTIC_IGNORED
 #pragma GCC diagnostic ignored "-Wpragmas"
 #pragma GCC diagnostic ignored "-Wunknown-pragmas"
 #pragma GCC diagnostic ignored "-Wunknown-warning-option"
+#endif
+#ifndef HB_NO_PRAGMA_GCC_DIAGNOSTIC_WARNING
 //#pragma GCC diagnostic warning "-Weverything"
+#endif
 
 /* Error.  Should never happen. */
+#ifndef HB_NO_PRAGMA_GCC_DIAGNOSTIC_ERROR
 #pragma GCC diagnostic error   "-Wc++11-narrowing"
 #pragma GCC diagnostic error   "-Wcast-align"
 #pragma GCC diagnostic error   "-Wdelete-non-virtual-dtor"
@@ -65,6 +72,7 @@
 #pragma GCC diagnostic error   "-Wpointer-arith"
 #pragma GCC diagnostic error   "-Wredundant-decls"
 #pragma GCC diagnostic error   "-Wreorder"
+#pragma GCC diagnostic error   "-Wsign-compare"
 #pragma GCC diagnostic error   "-Wstrict-prototypes"
 #pragma GCC diagnostic error   "-Wstring-conversion"
 #pragma GCC diagnostic error   "-Wswitch-enum"
@@ -74,9 +82,12 @@
 #pragma GCC diagnostic error   "-Wunused-local-typedefs"
 #pragma GCC diagnostic error   "-Wunused-value"
 #pragma GCC diagnostic error   "-Wunused-variable"
+#pragma GCC diagnostic error   "-Wvla"
 #pragma GCC diagnostic error   "-Wwrite-strings"
+#endif
 
 /* Warning.  To be investigated if happens. */
+#ifndef HB_NO_PRAGMA_GCC_DIAGNOSTIC_WARNING
 #pragma GCC diagnostic warning "-Wbuiltin-macro-redefined"
 #pragma GCC diagnostic warning "-Wdisabled-optimization"
 #pragma GCC diagnostic warning "-Wformat=2"
@@ -84,18 +95,20 @@
 #pragma GCC diagnostic warning "-Wlogical-op"
 #pragma GCC diagnostic warning "-Wmaybe-uninitialized"
 #pragma GCC diagnostic warning "-Wmissing-format-attribute"
-#pragma GCC diagnostic warning "-Wsign-compare"
 #pragma GCC diagnostic warning "-Wundef"
-#pragma GCC diagnostic warning "-Wvla"
+#endif
 
 /* Ignored currently, but should be fixed at some point. */
+#ifndef HB_NO_PRAGMA_GCC_DIAGNOSTIC_IGNORED
 #pragma GCC diagnostic ignored "-Wconversion"			// TODO fix
 #pragma GCC diagnostic ignored "-Wformat-signedness"		// TODO fix
 #pragma GCC diagnostic ignored "-Wshadow"			// TODO fix
 #pragma GCC diagnostic ignored "-Wunsafe-loop-optimizations"	// TODO fix
 #pragma GCC diagnostic ignored "-Wunused-parameter"		// TODO fix
+#endif
 
 /* Ignored intentionally. */
+#ifndef HB_NO_PRAGMA_GCC_DIAGNOSTIC_IGNORED
 #pragma GCC diagnostic ignored "-Wclass-memaccess"
 #pragma GCC diagnostic ignored "-Wformat-nonliteral"
 #pragma GCC diagnostic ignored "-Wformat-zero-length"
@@ -103,6 +116,7 @@
 #pragma GCC diagnostic ignored "-Wpacked" // Erratic impl in clang
 #pragma GCC diagnostic ignored "-Wstrict-aliasing"
 #pragma GCC diagnostic ignored "-Wtype-limits"
+#endif
 
 #endif
 #endif
diff --git a/src/test-iter.cc b/src/test-iter.cc
index e3b258f..2b23901 100644
--- a/src/test-iter.cc
+++ b/src/test-iter.cc
@@ -40,7 +40,7 @@
   array_iter_t (hb_array_t<T> arr_) : arr (arr_) {}
 
   typedef T& __item_t__;
-  enum { is_random_access_iterator = true };
+  static constexpr bool is_random_access_iterator = true;
   T& __item_at__ (unsigned i) const { return arr[i]; }
   void __forward__ (unsigned n) { arr += n; }
   void __rewind__ (unsigned n) { arr -= n; }