ICU-20814 new tool for checking API tags vs. ifdef guards; add FORCE guards, and move some guards, to make this work
diff --git a/.travis.yml b/.travis.yml
index 289f9cc..21370d6 100644
--- a/.travis.yml
+++ b/.travis.yml
@@ -66,6 +66,11 @@
         - PATH="${PREFIX}/bin:$PATH" make -C test/hdrtst check
 
     # clang release build with some options to enforce useful constraints.
+    # Includes dependency checker on an in-source, optimized build.
+    # Includes checking @draft etc. API tags vs. ifndef guards like
+    # U_HIDE_DRAFT_API and U_FORCE_HIDE_DRAFT_API.
+    # (FORCE guards make this tool pass but won't compile to working code.
+    # See the testtagsguards.sh script for details.)
     - name: "c: linux clang"
       dist:     xenial
       language: cpp
@@ -81,6 +86,7 @@
       script:
         - make -j2 check
         - ( cd test/depstest && python3 depstest.py ../../../source/ )
+        - ( cd .. && source/test/hdrtst/testtagsguards.sh )
 
     - name: "c: osx clang"
       language: cpp
diff --git a/icu4c/source/common/unicode/brkiter.h b/icu4c/source/common/unicode/brkiter.h
index 7448198..b944497 100644
--- a/icu4c/source/common/unicode/brkiter.h
+++ b/icu4c/source/common/unicode/brkiter.h
@@ -497,6 +497,7 @@
     static UnicodeString& U_EXPORT2 getDisplayName(const Locale& objectLocale,
                                          UnicodeString& name);
 
+#ifndef U_FORCE_HIDE_DEPRECATED_API
     /**
      * Deprecated functionality. Use clone() instead.
      *
@@ -519,6 +520,7 @@
     virtual BreakIterator *  createBufferClone(void *stackBuffer,
                                                int32_t &BufferSize,
                                                UErrorCode &status) = 0;
+#endif  // U_FORCE_HIDE_DEPRECATED_API
 
 #ifndef U_HIDE_DEPRECATED_API
 
diff --git a/icu4c/source/common/unicode/filteredbrk.h b/icu4c/source/common/unicode/filteredbrk.h
index a084556..4293676 100644
--- a/icu4c/source/common/unicode/filteredbrk.h
+++ b/icu4c/source/common/unicode/filteredbrk.h
@@ -104,6 +104,7 @@
    */
   virtual UBool unsuppressBreakAfter(const UnicodeString& string, UErrorCode& status) = 0;
 
+#ifndef U_FORCE_HIDE_DEPRECATED_API
   /**
    * This function has been deprecated in favor of wrapIteratorWithFilter()
    * The behavior is identical.
@@ -114,6 +115,7 @@
    * @see wrapBreakIteratorWithFilter()
    */
   virtual BreakIterator *build(BreakIterator* adoptBreakIterator, UErrorCode& status) = 0;
+#endif  // U_FORCE_HIDE_DEPRECATED_API
 
   /**
    * Wrap (adopt) an existing break iterator in a new filtered instance.
diff --git a/icu4c/source/common/unicode/normlzr.h b/icu4c/source/common/unicode/normlzr.h
index 05bc9df..07a596b 100644
--- a/icu4c/source/common/unicode/normlzr.h
+++ b/icu4c/source/common/unicode/normlzr.h
@@ -185,6 +185,7 @@
   Normalizer(const CharacterIterator& iter, UNormalizationMode mode);
 #endif  /* U_HIDE_DEPRECATED_API */
 
+#ifndef U_FORCE_HIDE_DEPRECATED_API
   /**
    * Copy constructor.
    * @param copy The object to be copied.
@@ -197,7 +198,7 @@
    * @deprecated ICU 56 Use Normalizer2 instead.
    */
   virtual ~Normalizer();
-
+#endif  // U_FORCE_HIDE_DEPRECATED_API
 
   //-------------------------------------------------------------------------
   // Static utility methods
@@ -725,12 +726,14 @@
   static UClassID U_EXPORT2 getStaticClassID();
 #endif  /* U_HIDE_DEPRECATED_API */
 
+#ifndef U_FORCE_HIDE_DEPRECATED_API
   /**
    * ICU "poor man's RTTI", returns a UClassID for the actual class.
    * @return a UClassID for the actual class.
    * @deprecated ICU 56 Use Normalizer2 instead.
    */
   virtual UClassID getDynamicClassID() const;
+#endif  // U_FORCE_HIDE_DEPRECATED_API
 
 private:
   //-------------------------------------------------------------------------
diff --git a/icu4c/source/common/unicode/platform.h b/icu4c/source/common/unicode/platform.h
index 9180a8d..ad75b29 100644
--- a/icu4c/source/common/unicode/platform.h
+++ b/icu4c/source/common/unicode/platform.h
@@ -882,4 +882,4 @@
 #endif
 /* @} */
 
-#endif
+#endif  // _PLATFORM_H
diff --git a/icu4c/source/common/unicode/rbbi.h b/icu4c/source/common/unicode/rbbi.h
index 90dee20..7825f60 100644
--- a/icu4c/source/common/unicode/rbbi.h
+++ b/icu4c/source/common/unicode/rbbi.h
@@ -538,6 +538,7 @@
      */
     static UClassID U_EXPORT2 getStaticClassID(void);
 
+#ifndef U_FORCE_HIDE_DEPRECATED_API
     /**
      * Deprecated functionality. Use clone() instead.
      *
@@ -567,7 +568,7 @@
     virtual RuleBasedBreakIterator *createBufferClone(void *stackBuffer,
                                                       int32_t &BufferSize,
                                                       UErrorCode &status);
-
+#endif  // U_FORCE_HIDE_DEPRECATED_API
 
     /**
      * Return the binary form of compiled break rules,
diff --git a/icu4c/source/common/unicode/uconfig.h b/icu4c/source/common/unicode/uconfig.h
index e61eb57..bbc232d 100644
--- a/icu4c/source/common/unicode/uconfig.h
+++ b/icu4c/source/common/unicode/uconfig.h
@@ -453,4 +453,4 @@
 #   define UCONFIG_NO_FILTERED_BREAK_ITERATION 0
 #endif
 
-#endif
+#endif  // __UCONFIG_H__
diff --git a/icu4c/source/common/unicode/unorm.h b/icu4c/source/common/unicode/unorm.h
index 3839de1..09dd366 100644
--- a/icu4c/source/common/unicode/unorm.h
+++ b/icu4c/source/common/unicode/unorm.h
@@ -131,6 +131,8 @@
 
 // Do not conditionalize the following enum with #ifndef U_HIDE_DEPRECATED_API,
 // it is needed for layout of Normalizer object.
+#ifndef U_FORCE_HIDE_DEPRECATED_API
+
 /**
  * Constants for normalization modes.
  * @deprecated ICU 56 Use unorm2.h instead.
@@ -155,6 +157,8 @@
   UNORM_MODE_COUNT
 } UNormalizationMode;
 
+#endif  // U_FORCE_HIDE_DEPRECATED_API
+
 #ifndef U_HIDE_DEPRECATED_API
 
 /**
diff --git a/icu4c/source/common/unicode/utf_old.h b/icu4c/source/common/unicode/utf_old.h
index b18b824..b2428e6 100644
--- a/icu4c/source/common/unicode/utf_old.h
+++ b/icu4c/source/common/unicode/utf_old.h
@@ -19,9 +19,6 @@
 /**
  * \file
  * \brief C API: Deprecated macros for Unicode string handling
- */
-
-/**
  *
  * The macros in utf_old.h are all deprecated and their use discouraged.
  * Some of the design principles behind the set of UTF macros
@@ -139,12 +136,16 @@
  *
  * <hr>
  *
- * @deprecated ICU 2.4. Use the macros in utf.h, utf16.h, utf8.h instead.
+ * Deprecated ICU 2.4. Use the macros in utf.h, utf16.h, utf8.h instead.
  */
 
 #ifndef __UTF_OLD_H__
 #define __UTF_OLD_H__
 
+#include "unicode/utf.h"
+#include "unicode/utf8.h"
+#include "unicode/utf16.h"
+
 /**
  * \def U_HIDE_OBSOLETE_UTF_OLD_H
  *
@@ -162,10 +163,6 @@
 
 #if !defined(U_HIDE_DEPRECATED_API) && !U_HIDE_OBSOLETE_UTF_OLD_H
 
-#include "unicode/utf.h"
-#include "unicode/utf8.h"
-#include "unicode/utf16.h"
-
 /* Formerly utf.h, part 1 --------------------------------------------------- */
 
 #ifdef U_USE_UTF_DEPRECATES
diff --git a/icu4c/source/i18n/unicode/calendar.h b/icu4c/source/i18n/unicode/calendar.h
index 4716711..2a8c293 100644
--- a/icu4c/source/i18n/unicode/calendar.h
+++ b/icu4c/source/i18n/unicode/calendar.h
@@ -186,7 +186,7 @@
  */
 class U_I18N_API Calendar : public UObject {
 public:
-
+#ifndef U_FORCE_HIDE_DEPRECATED_API
     /**
      * Field IDs for date and time. Used to specify date/time fields. ERA is calendar
      * specific. Example ranges given are for illustration only; see specific Calendar
@@ -229,6 +229,7 @@
         FIELD_COUNT = UCAL_FIELD_COUNT // See ucal.h for other fields.
 #endif /* U_HIDE_DEPRECATED_API */
     };
+#endif  // U_FORCE_HIDE_DEPRECATED_API
 
 #ifndef U_HIDE_DEPRECATED_API
     /**
@@ -520,6 +521,7 @@
      */
     UBool after(const Calendar& when, UErrorCode& status) const;
 
+#ifndef U_FORCE_HIDE_DEPRECATED_API
     /**
      * UDate Arithmetic function. Adds the specified (signed) amount of time to the given
      * time field, based on the calendar's rules. For example, to subtract 5 days from
@@ -541,6 +543,7 @@
      * @deprecated ICU 2.6. use add(UCalendarDateFields field, int32_t amount, UErrorCode& status) instead.
      */
     virtual void add(EDateFields field, int32_t amount, UErrorCode& status);
+#endif  // U_FORCE_HIDE_DEPRECATED_API
 
     /**
      * UDate Arithmetic function. Adds the specified (signed) amount of time to the given
@@ -634,6 +637,7 @@
      */
     inline void roll(UCalendarDateFields field, UBool up, UErrorCode& status);
 
+#ifndef U_FORCE_HIDE_DEPRECATED_API
     /**
      * Time Field Rolling function. Rolls by the given amount on the given
      * time field. For example, to roll the current date up by one day, call
@@ -666,6 +670,7 @@
      * @deprecated ICU 2.6. Use roll(UCalendarDateFields field, int32_t amount, UErrorCode& status) instead.
      */
     virtual void roll(EDateFields field, int32_t amount, UErrorCode& status);
+#endif  // U_FORCE_HIDE_DEPRECATED_API
 
     /**
      * Time Field Rolling function. Rolls by the given amount on the given
@@ -700,6 +705,7 @@
      */
     virtual void roll(UCalendarDateFields field, int32_t amount, UErrorCode& status);
 
+#ifndef U_FORCE_HIDE_DEPRECATED_API
     /**
      * Return the difference between the given time and the time this
      * calendar object is set to.  If this calendar is set
@@ -756,6 +762,7 @@
      * @deprecated ICU 2.6. Use fieldDifference(UDate when, UCalendarDateFields field, UErrorCode& status).
      */
     virtual int32_t fieldDifference(UDate when, EDateFields field, UErrorCode& status);
+#endif  // U_FORCE_HIDE_DEPRECATED_API
 
     /**
      * Return the difference between the given time and the time this
@@ -1012,6 +1019,7 @@
      */
     uint8_t getMinimalDaysInFirstWeek(void) const;
 
+#ifndef U_FORCE_HIDE_DEPRECATED_API
     /**
      * Gets the minimum value for the given time field. e.g., for Gregorian
      * DAY_OF_MONTH, 1.
@@ -1021,6 +1029,7 @@
      * @deprecated ICU 2.6. Use getMinimum(UCalendarDateFields field) instead.
      */
     virtual int32_t getMinimum(EDateFields field) const;
+#endif  // U_FORCE_HIDE_DEPRECATED_API
 
     /**
      * Gets the minimum value for the given time field. e.g., for Gregorian
@@ -1032,6 +1041,7 @@
      */
     virtual int32_t getMinimum(UCalendarDateFields field) const;
 
+#ifndef U_FORCE_HIDE_DEPRECATED_API
     /**
      * Gets the maximum value for the given time field. e.g. for Gregorian DAY_OF_MONTH,
      * 31.
@@ -1041,6 +1051,7 @@
      * @deprecated ICU 2.6. Use getMaximum(UCalendarDateFields field) instead.
      */
     virtual int32_t getMaximum(EDateFields field) const;
+#endif  // U_FORCE_HIDE_DEPRECATED_API
 
     /**
      * Gets the maximum value for the given time field. e.g. for Gregorian DAY_OF_MONTH,
@@ -1052,6 +1063,7 @@
      */
     virtual int32_t getMaximum(UCalendarDateFields field) const;
 
+#ifndef U_FORCE_HIDE_DEPRECATED_API
     /**
      * Gets the highest minimum value for the given field if varies. Otherwise same as
      * getMinimum(). For Gregorian, no difference.
@@ -1061,6 +1073,7 @@
      * @deprecated ICU 2.6. Use getGreatestMinimum(UCalendarDateFields field) instead.
      */
     virtual int32_t getGreatestMinimum(EDateFields field) const;
+#endif  // U_FORCE_HIDE_DEPRECATED_API
 
     /**
      * Gets the highest minimum value for the given field if varies. Otherwise same as
@@ -1072,6 +1085,7 @@
      */
     virtual int32_t getGreatestMinimum(UCalendarDateFields field) const;
 
+#ifndef U_FORCE_HIDE_DEPRECATED_API
     /**
      * Gets the lowest maximum value for the given field if varies. Otherwise same as
      * getMaximum(). e.g., for Gregorian DAY_OF_MONTH, 28.
@@ -1081,6 +1095,7 @@
      * @deprecated ICU 2.6. Use getLeastMaximum(UCalendarDateFields field) instead.
      */
     virtual int32_t getLeastMaximum(EDateFields field) const;
+#endif  // U_FORCE_HIDE_DEPRECATED_API
 
     /**
      * Gets the lowest maximum value for the given field if varies. Otherwise same as
@@ -1897,11 +1912,13 @@
      */
     int32_t     fFields[UCAL_FIELD_COUNT];
 
+#ifndef U_FORCE_HIDE_DEPRECATED_API
     /**
      * The flags which tell if a specified time field for the calendar is set.
      * @deprecated ICU 2.8 use (fStamp[n]!=kUnset)
      */
     UBool      fIsSet[UCAL_FIELD_COUNT];
+#endif  // U_FORCE_HIDE_DEPRECATED_API
 
     /** Special values of stamp[]
      * @stable ICU 2.0
diff --git a/icu4c/source/i18n/unicode/choicfmt.h b/icu4c/source/i18n/unicode/choicfmt.h
index 54c2e13..3b2f48c 100644
--- a/icu4c/source/i18n/unicode/choicfmt.h
+++ b/icu4c/source/i18n/unicode/choicfmt.h
@@ -34,7 +34,6 @@
  */
 
 #if !UCONFIG_NO_FORMATTING
-#ifndef U_HIDE_DEPRECATED_API
 
 #include "unicode/fieldpos.h"
 #include "unicode/format.h"
@@ -42,6 +41,8 @@
 #include "unicode/numfmt.h"
 #include "unicode/unistr.h"
 
+#ifndef U_HIDE_DEPRECATED_API
+
 U_NAMESPACE_BEGIN
 
 class MessageFormat;
diff --git a/icu4c/source/i18n/unicode/coll.h b/icu4c/source/i18n/unicode/coll.h
index 861bd5c..f5564c7 100644
--- a/icu4c/source/i18n/unicode/coll.h
+++ b/icu4c/source/i18n/unicode/coll.h
@@ -206,6 +206,7 @@
 
     // Cannot use #ifndef U_HIDE_DEPRECATED_API for the following, it is
     // used by virtual methods that cannot have that conditional.
+#ifndef U_FORCE_HIDE_DEPRECATED_API
     /**
      * LESS is returned if source string is compared to be less than target
      * string in the compare() method.
@@ -222,6 +223,7 @@
         EQUAL = UCOL_EQUAL,  // 0
         GREATER = UCOL_GREATER  // 1
     };
+#endif  // U_FORCE_HIDE_DEPRECATED_API
 
     // Collator public destructor -----------------------------------------
 
@@ -325,6 +327,7 @@
      */
     static Collator* U_EXPORT2 createInstance(const Locale& loc, UErrorCode& err);
 
+#ifndef U_FORCE_HIDE_DEPRECATED_API
     /**
      * The comparison function compares the character data stored in two
      * different strings. Returns information about whether a string is less
@@ -338,6 +341,7 @@
      */
     virtual EComparisonResult compare(const UnicodeString& source,
                                       const UnicodeString& target) const;
+#endif  // U_FORCE_HIDE_DEPRECATED_API
 
     /**
      * The comparison function compares the character data stored in two
@@ -355,6 +359,7 @@
                                       const UnicodeString& target,
                                       UErrorCode &status) const = 0;
 
+#ifndef U_FORCE_HIDE_DEPRECATED_API
     /**
      * Does the same thing as compare but limits the comparison to a specified
      * length
@@ -370,6 +375,7 @@
     virtual EComparisonResult compare(const UnicodeString& source,
                                       const UnicodeString& target,
                                       int32_t length) const;
+#endif  // U_FORCE_HIDE_DEPRECATED_API
 
     /**
      * Does the same thing as compare but limits the comparison to a specified
@@ -389,6 +395,7 @@
                                       int32_t length,
                                       UErrorCode &status) const = 0;
 
+#ifndef U_FORCE_HIDE_DEPRECATED_API
     /**
      * The comparison function compares the character data stored in two
      * different string arrays. Returns information about whether a string array
@@ -425,6 +432,7 @@
     virtual EComparisonResult compare(const char16_t* source, int32_t sourceLength,
                                       const char16_t* target, int32_t targetLength)
                                       const;
+#endif  // U_FORCE_HIDE_DEPRECATED_API
 
     /**
      * The comparison function compares the character data stored in two
@@ -529,6 +537,7 @@
      */
     virtual int32_t hashCode(void) const = 0;
 
+#ifndef U_FORCE_HIDE_DEPRECATED_API
     /**
      * Gets the locale of the Collator
      *
@@ -542,6 +551,7 @@
      * in ICU 3.0.
      */
     virtual Locale getLocale(ULocDataLocaleType type, UErrorCode& status) const = 0;
+#endif  // U_FORCE_HIDE_DEPRECATED_API
 
     /**
      * Convenience method for comparing two strings based on the collation rules.
@@ -578,6 +588,7 @@
      */
     UBool equals(const UnicodeString& source, const UnicodeString& target) const;
 
+#ifndef U_FORCE_HIDE_DEPRECATED_API
     /**
      * Determines the minimum strength that will be used in comparison or
      * transformation.
@@ -609,6 +620,7 @@
      * @deprecated ICU 2.6 Use setAttribute(UCOL_STRENGTH...) instead
      */
     virtual void setStrength(ECollationStrength newStrength);
+#endif  // U_FORCE_HIDE_DEPRECATED_API
 
     /**
      * Retrieves the reordering codes for this collator.
@@ -906,6 +918,7 @@
      */
     virtual UColReorderCode getMaxVariable() const;
 
+#ifndef U_FORCE_HIDE_DEPRECATED_API
     /**
      * Sets the variable top to the primary weight of the specified string.
      *
@@ -953,6 +966,7 @@
      * @deprecated ICU 53 Call setMaxVariable() instead.
      */
     virtual void setVariableTop(uint32_t varTop, UErrorCode &status) = 0;
+#endif  // U_FORCE_HIDE_DEPRECATED_API
 
     /**
      * Gets the variable top value of a Collator.
@@ -974,6 +988,7 @@
      */
     virtual UnicodeSet *getTailoredSet(UErrorCode &status) const;
 
+#ifndef U_FORCE_HIDE_DEPRECATED_API
     /**
      * Same as clone().
      * The base class implementation simply calls clone().
@@ -982,6 +997,7 @@
      * @deprecated ICU 50 no need to have two methods for cloning
      */
     virtual Collator* safeClone() const;
+#endif  // U_FORCE_HIDE_DEPRECATED_API
 
     /**
      * Get the sort key as an array of bytes from a UnicodeString.
diff --git a/icu4c/source/i18n/unicode/decimfmt.h b/icu4c/source/i18n/unicode/decimfmt.h
index 0e93c17..c33ec80 100644
--- a/icu4c/source/i18n/unicode/decimfmt.h
+++ b/icu4c/source/i18n/unicode/decimfmt.h
@@ -2021,12 +2021,14 @@
      */
     void setCurrency(const char16_t* theCurrency, UErrorCode& ec) U_OVERRIDE;
 
+#ifndef U_FORCE_HIDE_DEPRECATED_API
     /**
      * Sets the currency used to display currency amounts.  See
      * setCurrency(const char16_t*, UErrorCode&).
      * @deprecated ICU 3.0. Use setCurrency(const char16_t*, UErrorCode&).
      */
     virtual void setCurrency(const char16_t* theCurrency);
+#endif  // U_FORCE_HIDE_DEPRECATED_API
 
     /**
      * Sets the `Currency Usage` object used to display currency.
diff --git a/icu4c/source/i18n/unicode/formattedvalue.h b/icu4c/source/i18n/unicode/formattedvalue.h
index 61fdb8e..5c47264 100644
--- a/icu4c/source/i18n/unicode/formattedvalue.h
+++ b/icu4c/source/i18n/unicode/formattedvalue.h
@@ -29,6 +29,7 @@
 // The following cannot have #ifndef U_HIDE_DRAFT_API because
 // class FormattedValue depends on it, and FormattedValue cannot be
 // hidden becauseclass FormattedNumber (stable ICU 60) depends on it.
+#ifndef U_FORCE_HIDE_DRAFT_API
 /**
  * Represents a span of a string containing a given field.
  *
@@ -320,7 +321,7 @@
      */
     virtual UBool nextPosition(ConstrainedFieldPosition& cfpos, UErrorCode& status) const = 0;
 };
-
+#endif  // U_FORCE_HIDE_DRAFT_API
 
 U_NAMESPACE_END
 
diff --git a/icu4c/source/i18n/unicode/gregocal.h b/icu4c/source/i18n/unicode/gregocal.h
index 9249b59..4ce40da 100644
--- a/icu4c/source/i18n/unicode/gregocal.h
+++ b/icu4c/source/i18n/unicode/gregocal.h
@@ -352,6 +352,7 @@
      */
     virtual UBool isEquivalentTo(const Calendar& other) const;
 
+#ifndef U_FORCE_HIDE_DEPRECATED_API
     /**
      * (Overrides Calendar) Rolls up or down by the given amount in the specified field.
      * For more information, see the documentation for Calendar::roll().
@@ -364,6 +365,7 @@
      * @deprecated ICU 2.6. Use roll(UCalendarDateFields field, int32_t amount, UErrorCode& status) instead.
      */
     virtual void roll(EDateFields field, int32_t amount, UErrorCode& status);
+#endif  // U_FORCE_HIDE_DEPRECATED_API
 
     /**
      * (Overrides Calendar) Rolls up or down by the given amount in the specified field.
diff --git a/icu4c/source/i18n/unicode/measfmt.h b/icu4c/source/i18n/unicode/measfmt.h
index df79c0f..b4f9048 100644
--- a/icu4c/source/i18n/unicode/measfmt.h
+++ b/icu4c/source/i18n/unicode/measfmt.h
@@ -165,6 +165,7 @@
             FieldPosition &pos,
             UErrorCode &status) const;
 
+#ifndef U_FORCE_HIDE_DRAFT_API
     /**
      * Parse a string to produce an object. This implementation sets
      * status to U_UNSUPPORTED_ERROR.
@@ -175,6 +176,7 @@
             const UnicodeString &source,
             Formattable &reslt,
             ParsePosition &pos) const;
+#endif  // U_FORCE_HIDE_DRAFT_API
 
     /**
      * Formats measure objects to produce a string. An example of such a
diff --git a/icu4c/source/i18n/unicode/nounit.h b/icu4c/source/i18n/unicode/nounit.h
index e1da7c5..61b5c16 100644
--- a/icu4c/source/i18n/unicode/nounit.h
+++ b/icu4c/source/i18n/unicode/nounit.h
@@ -15,10 +15,11 @@
 #if U_SHOW_CPLUSPLUS_API
 
 #if !UCONFIG_NO_FORMATTING
-#ifndef U_HIDE_DRAFT_API
 
 #include "unicode/measunit.h"
 
+#ifndef U_HIDE_DRAFT_API
+
 /**
  * \file
  * \brief C++ API: units for percent and permille
diff --git a/icu4c/source/i18n/unicode/numberformatter.h b/icu4c/source/i18n/unicode/numberformatter.h
index 82d2e3c..6d48f18 100644
--- a/icu4c/source/i18n/unicode/numberformatter.h
+++ b/icu4c/source/i18n/unicode/numberformatter.h
@@ -2411,12 +2411,14 @@
   public:
 
     // Default constructor cannot have #ifndef U_HIDE_DRAFT_API
+#ifndef U_FORCE_HIDE_DRAFT_API
     /**
      * Default constructor; makes an empty FormattedNumber.
      * @draft ICU 64
      */
     FormattedNumber()
         : fData(nullptr), fErrorCode(U_INVALID_STATE_ERROR) {}
+#endif  // U_FORCE_HIDE_DRAFT_API
 
     /**
      * Move constructor: Leaves the source FormattedNumber in an undefined state.
diff --git a/icu4c/source/i18n/unicode/rbtz.h b/icu4c/source/i18n/unicode/rbtz.h
index 56d6f1c..d66e1f0 100644
--- a/icu4c/source/i18n/unicode/rbtz.h
+++ b/icu4c/source/i18n/unicode/rbtz.h
@@ -226,6 +226,7 @@
      */
     virtual UBool useDaylightTime(void) const;
 
+#ifndef U_FORCE_HIDE_DEPRECATED_API
     /**
      * Queries if the given date is in daylight savings time in
      * this time zone.
@@ -240,6 +241,7 @@
      * @deprecated ICU 2.4. Use Calendar::inDaylightTime() instead.
      */
     virtual UBool inDaylightTime(UDate date, UErrorCode& status) const;
+#endif  // U_FORCE_HIDE_DEPRECATED_API
 
     /**
      * Returns true if this zone has the same rule and offset as another zone.
diff --git a/icu4c/source/i18n/unicode/simpletz.h b/icu4c/source/i18n/unicode/simpletz.h
index f8e2a74..980a1b8 100644
--- a/icu4c/source/i18n/unicode/simpletz.h
+++ b/icu4c/source/i18n/unicode/simpletz.h
@@ -674,6 +674,7 @@
      */
     virtual UBool useDaylightTime(void) const;
 
+#ifndef U_FORCE_HIDE_DEPRECATED_API
     /**
      * Returns true if the given date is within the period when daylight savings time
      * is in effect; false otherwise.  If the TimeZone doesn't observe daylight savings
@@ -689,6 +690,7 @@
      * @deprecated ICU 2.4. Use Calendar::inDaylightTime() instead.
      */
     virtual UBool inDaylightTime(UDate date, UErrorCode& status) const;
+#endif  // U_FORCE_HIDE_DEPRECATED_API
 
     /**
      * Return true if this zone has the same rules and offset as another zone.
diff --git a/icu4c/source/i18n/unicode/tblcoll.h b/icu4c/source/i18n/unicode/tblcoll.h
index c4471b0..f5dc135 100644
--- a/icu4c/source/i18n/unicode/tblcoll.h
+++ b/icu4c/source/i18n/unicode/tblcoll.h
@@ -391,6 +391,7 @@
      */
     virtual int32_t hashCode() const;
 
+#ifndef U_FORCE_HIDE_DEPRECATED_API
     /**
     * Gets the locale of the Collator
     * @param type can be either requested, valid or actual locale. For more
@@ -402,6 +403,7 @@
     * @deprecated ICU 2.8 likely to change in ICU 3.0, based on feedback
     */
     virtual Locale getLocale(ULocDataLocaleType type, UErrorCode& status) const;
+#endif  // U_FORCE_HIDE_DEPRECATED_API
 
     /**
      * Gets the tailoring rules for this collator.
@@ -547,6 +549,7 @@
      */
     virtual UColReorderCode getMaxVariable() const;
 
+#ifndef U_FORCE_HIDE_DEPRECATED_API
     /**
      * Sets the variable top to the primary weight of the specified string.
      *
@@ -594,6 +597,7 @@
      * @deprecated ICU 53 Call setMaxVariable() instead.
      */
     virtual void setVariableTop(uint32_t varTop, UErrorCode &status);
+#endif  // U_FORCE_HIDE_DEPRECATED_API
 
     /**
      * Gets the variable top value of a Collator.
diff --git a/icu4c/source/i18n/unicode/timezone.h b/icu4c/source/i18n/unicode/timezone.h
index 5c361e7..433e3b5 100644
--- a/icu4c/source/i18n/unicode/timezone.h
+++ b/icu4c/source/i18n/unicode/timezone.h
@@ -722,6 +722,7 @@
      */
     virtual UBool useDaylightTime(void) const = 0;
 
+#ifndef U_FORCE_HIDE_DEPRECATED_API
     /**
      * Queries if the given date is in daylight savings time in
      * this time zone.
@@ -736,6 +737,7 @@
      * @deprecated ICU 2.4. Use Calendar::inDaylightTime() instead.
      */
     virtual UBool inDaylightTime(UDate date, UErrorCode& status) const = 0;
+#endif  // U_FORCE_HIDE_DEPRECATED_API
 
     /**
      * Returns true if this zone has the same rule and offset as another zone.
diff --git a/icu4c/source/i18n/unicode/tmutfmt.h b/icu4c/source/i18n/unicode/tmutfmt.h
index 82be597..ad871f7 100644
--- a/icu4c/source/i18n/unicode/tmutfmt.h
+++ b/icu4c/source/i18n/unicode/tmutfmt.h
@@ -21,7 +21,6 @@
 #if U_SHOW_CPLUSPLUS_API
 
 #if !UCONFIG_NO_FORMATTING
-#ifndef U_HIDE_DEPRECATED_API
 
 #include "unicode/unistr.h"
 #include "unicode/tmunit.h"
@@ -30,6 +29,7 @@
 #include "unicode/numfmt.h"
 #include "unicode/plurrule.h"
 
+#ifndef U_HIDE_DEPRECATED_API
 
 /**
  * Constants for various styles.
diff --git a/icu4c/source/i18n/unicode/ucal.h b/icu4c/source/i18n/unicode/ucal.h
index 4466223..c198450 100644
--- a/icu4c/source/i18n/unicode/ucal.h
+++ b/icu4c/source/i18n/unicode/ucal.h
@@ -441,11 +441,13 @@
 
     /* Do not conditionalize the following with #ifndef U_HIDE_DEPRECATED_API,
      * it is needed for layout of Calendar, DateFormat, and other objects */
+#ifndef U_FORCE_HIDE_DEPRECATED_API
     /**
      * One more than the highest normal UCalendarDateFields value.
      * @deprecated ICU 58 The numeric value may change over time, see ICU ticket #12420.
      */
-  UCAL_FIELD_COUNT,
+    UCAL_FIELD_COUNT,
+#endif  // U_FORCE_HIDE_DEPRECATED_API
 
  /**
    * Field number indicating the
diff --git a/icu4c/source/i18n/unicode/ucol.h b/icu4c/source/i18n/unicode/ucol.h
index dbac48e..673af1c 100644
--- a/icu4c/source/i18n/unicode/ucol.h
+++ b/icu4c/source/i18n/unicode/ucol.h
@@ -344,11 +344,13 @@
 
     /* Do not conditionalize the following with #ifndef U_HIDE_DEPRECATED_API,
      * it is needed for layout of RuleBasedCollator object. */
+#ifndef U_FORCE_HIDE_DEPRECATED_API
     /**
      * One more than the highest normal UColAttribute value.
      * @deprecated ICU 58 The numeric value may change over time, see ICU ticket #12420.
      */
      UCOL_ATTRIBUTE_COUNT
+#endif  // U_FORCE_HIDE_DEPRECATED_API
 } UColAttribute;
 
 /** Options for retrieving the rule string 
diff --git a/icu4c/source/i18n/unicode/udat.h b/icu4c/source/i18n/unicode/udat.h
index c67a6d6..bdbd080 100644
--- a/icu4c/source/i18n/unicode/udat.h
+++ b/icu4c/source/i18n/unicode/udat.h
@@ -923,11 +923,13 @@
 
     /* Do not conditionalize the following with #ifndef U_HIDE_DEPRECATED_API,
      * it is needed for layout of DateFormat object. */
+#ifndef U_FORCE_HIDE_DEPRECATED_API
     /**
      * One more than the highest normal UDateFormatBooleanAttribute value.
      * @deprecated ICU 58 The numeric value may change over time, see ICU ticket #12420.
      */
     UDAT_BOOLEAN_ATTRIBUTE_COUNT = 4
+#endif  // U_FORCE_HIDE_DEPRECATED_API
 } UDateFormatBooleanAttribute;
 
 /**
diff --git a/icu4c/source/i18n/unicode/udatpg.h b/icu4c/source/i18n/unicode/udatpg.h
index fc25d57..7f28b5a 100644
--- a/icu4c/source/i18n/unicode/udatpg.h
+++ b/icu4c/source/i18n/unicode/udatpg.h
@@ -88,11 +88,13 @@
 
     /* Do not conditionalize the following with #ifndef U_HIDE_DEPRECATED_API,
      * it is needed for layout of DateTimePatternGenerator object. */
+#ifndef U_FORCE_HIDE_DEPRECATED_API
     /**
      * One more than the highest normal UDateTimePatternField value.
      * @deprecated ICU 58 The numeric value may change over time, see ICU ticket #12420.
      */
     UDATPG_FIELD_COUNT
+#endif  // U_FORCE_HIDE_DEPRECATED_API
 } UDateTimePatternField;
 
 /**
diff --git a/icu4c/source/i18n/unicode/uformattedvalue.h b/icu4c/source/i18n/unicode/uformattedvalue.h
index eaa4f288..0b289e3 100644
--- a/icu4c/source/i18n/unicode/uformattedvalue.h
+++ b/icu4c/source/i18n/unicode/uformattedvalue.h
@@ -7,10 +7,11 @@
 #include "unicode/utypes.h"
 
 #if !UCONFIG_NO_FORMATTING
-#ifndef U_HIDE_DRAFT_API
 
 #include "unicode/ufieldpositer.h"
 
+#ifndef U_HIDE_DRAFT_API
+
 /**
  * \file
  * \brief C API: Abstract operations for localized strings.
diff --git a/icu4c/source/i18n/unicode/unum.h b/icu4c/source/i18n/unicode/unum.h
index 3d55cc8..4304538 100644
--- a/icu4c/source/i18n/unicode/unum.h
+++ b/icu4c/source/i18n/unicode/unum.h
@@ -338,11 +338,13 @@
 
     /* Do not conditionalize the following with #ifndef U_HIDE_DEPRECATED_API,
      * it is needed for layout of DecimalFormatSymbols object. */
+#ifndef U_FORCE_HIDE_DEPRECATED_API
     /**
      * One more than the highest normal UCurrencySpacing value.
      * @deprecated ICU 58 The numeric value may change over time, see ICU ticket #12420.
      */
     UNUM_CURRENCY_SPACING_COUNT
+#endif  // U_FORCE_HIDE_DEPRECATED_API
 };
 typedef enum UCurrencySpacing UCurrencySpacing; /**< @stable ICU 4.8 */
 
diff --git a/icu4c/source/i18n/unicode/vtzone.h b/icu4c/source/i18n/unicode/vtzone.h
index 32e22b2..2743b6c 100644
--- a/icu4c/source/i18n/unicode/vtzone.h
+++ b/icu4c/source/i18n/unicode/vtzone.h
@@ -290,6 +290,7 @@
      */
     virtual UBool useDaylightTime(void) const;
 
+#ifndef U_FORCE_HIDE_DEPRECATED_API
     /**
      * Queries if the given date is in daylight savings time in
      * this time zone.
@@ -304,6 +305,7 @@
      * @deprecated ICU 2.4. Use Calendar::inDaylightTime() instead.
      */
     virtual UBool inDaylightTime(UDate date, UErrorCode& status) const;
+#endif  // U_FORCE_HIDE_DEPRECATED_API
 
     /**
      * Returns true if this zone has the same rule and offset as another zone.
diff --git a/icu4c/source/test/hdrtst/testtagsguards.sh b/icu4c/source/test/hdrtst/testtagsguards.sh
new file mode 100755
index 0000000..928707c
--- /dev/null
+++ b/icu4c/source/test/hdrtst/testtagsguards.sh
@@ -0,0 +1,94 @@
+# Copyright © 2019 and later: Unicode, Inc. and others.
+# License & terms of use: http://www.unicode.org/copyright.html
+
+# Run this script from $ICU_ROOT/icu4c.
+# ~/icu/mine/src/icu4c$ source/test/hdrtest/testtagsguards.sh
+
+# set -x # echo on
+
+DEF=-DU_NO_DEFAULT_INCLUDE_UTF_HEADERS=1
+INCL="-Isource/common -Isource/i18n -Isource/io"
+TMPDIR=`mktemp -d`
+DIFF="diff -u --minimal"
+
+echo "*** testtagsguards.sh TMPDIR=$TMPDIR"
+
+for file in source/common/unicode/*.h source/i18n/unicode/*.h source/io/unicode/*.h ; do
+    base=`basename $file`
+    echo $file
+    echo '#include "unicode/'$base'"' > $TMPDIR/ht-$base.cpp
+    # Preprocess only.
+    clang++ $INCL -C -E $DEF -o $TMPDIR/ht-$base-normal.i $TMPDIR/ht-$base.cpp
+
+    # When hiding @draft, none should be in the output.
+    TAG=draft
+    GUARD=DRAFT
+    echo "    @$TAG"
+    clang++ $INCL -C -E -DU_HIDE_${GUARD}_API=1 -DU_FORCE_HIDE_${GUARD}_API=1 $DEF -o $TMPDIR/ht-$base-$TAG.i $TMPDIR/ht-$base.cpp
+    if grep "@$TAG" -C 5 $TMPDIR/ht-$base-$TAG.i; then
+        echo "*** error: @$TAG not hidden in $TMPDIR/ht-$base-$TAG.i"
+        exit 1
+    fi
+    # Only @draft should be hidden.
+    # Except: Ok to hide nested @internal/@system/@obsolete.
+    $DIFF $TMPDIR/ht-$base-normal.i $TMPDIR/ht-$base-$TAG.i > $TMPDIR/ht-$base-normal-$TAG.txt
+    if egrep '^-.*@(stable|deprecated)' -C 5 $TMPDIR/ht-$base-normal-$TAG.txt; then
+        echo "*** error: Non-@$TAG hidden in $TMPDIR/ht-$base-$TAG.i see $TMPDIR/ht-$base-normal-$TAG.txt"
+        cat $TMPDIR/ht-$base-normal-$TAG.txt
+        exit 1
+    fi
+
+    # @deprecated
+    TAG=deprecated
+    GUARD=DEPRECATED
+    echo "    @$TAG"
+    clang++ $INCL -C -E -DU_HIDE_${GUARD}_API=1 -DU_FORCE_HIDE_${GUARD}_API=1 $DEF -o $TMPDIR/ht-$base-$TAG.i $TMPDIR/ht-$base.cpp
+    if grep "@$TAG" -C 5 $TMPDIR/ht-$base-$TAG.i; then
+        echo "*** error: @$TAG not hidden in $TMPDIR/ht-$base-$TAG.i"
+        exit 1
+    fi
+    # In the egrep: All tags except $TAG and @internal & similar.
+    $DIFF $TMPDIR/ht-$base-normal.i $TMPDIR/ht-$base-$TAG.i > $TMPDIR/ht-$base-normal-$TAG.txt
+    if egrep '^-.*@(stable|draft)' -C 5 $TMPDIR/ht-$base-normal-$TAG.txt; then
+        echo "*** error: Non-@$TAG hidden in $TMPDIR/ht-$base-$TAG.i see $TMPDIR/ht-$base-normal-$TAG.txt"
+        cat $TMPDIR/ht-$base-normal-$TAG.txt
+        exit 1
+    fi
+
+    # TODO: @internal
+    # Hiding some @internal definitions, in particular in platform.h and similar,
+    # tends to break even preprocessing of other headers.
+
+    # @system
+    TAG=system
+    GUARD=SYSTEM
+    echo "    @$TAG"
+    clang++ $INCL -C -E -DU_HIDE_${GUARD}_API=1 -DU_FORCE_HIDE_${GUARD}_API=1 $DEF -o $TMPDIR/ht-$base-$TAG.i $TMPDIR/ht-$base.cpp
+    if grep "@$TAG" -C 5 $TMPDIR/ht-$base-$TAG.i; then
+        echo "*** error: @$TAG not hidden in $TMPDIR/ht-$base-$TAG.i"
+        exit 1
+    fi
+    # @system is orthogonal to @stable / @deprecated etc.,
+    # so we don't check that none of those are hidden.
+
+    # @obsolete
+    TAG=obsolete
+    GUARD=OBSOLETE
+    echo "    @$TAG"
+    clang++ $INCL -C -E -DU_HIDE_${GUARD}_API=1 -DU_FORCE_HIDE_${GUARD}_API=1 $DEF -o $TMPDIR/ht-$base-$TAG.i $TMPDIR/ht-$base.cpp
+    if grep "@$TAG" -C 5 $TMPDIR/ht-$base-$TAG.i; then
+        echo "*** error: @$TAG not hidden in $TMPDIR/ht-$base-$TAG.i"
+        exit 1
+    fi
+    # In the egrep: All tags except $TAG and @internal & similar.
+    $DIFF $TMPDIR/ht-$base-normal.i $TMPDIR/ht-$base-$TAG.i > $TMPDIR/ht-$base-normal-$TAG.txt
+    if egrep '^-.*@(stable|draft|deprecated)' -C 5 $TMPDIR/ht-$base-normal-$TAG.txt; then
+        echo "*** error: Non-@$TAG hidden in $TMPDIR/ht-$base-$TAG.i see $TMPDIR/ht-$base-normal-$TAG.txt"
+        cat $TMPDIR/ht-$base-normal-$TAG.txt
+        exit 1
+    fi
+done
+
+echo "pass"
+rm -rf $TMPDIR
+