This is the mail archive of the gcc-patches@gcc.gnu.org mailing list for the GCC project.


Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]
Other format: [Raw text]

[PATCH] Handle OS X deployment targets correctly


As described in PR target/63810, this addresses several problems with
the validation and encoding of deployment target version strings for the
__ENVIRONMENT_MAC_OS_X_VERSION_MIN_REQUIRED__ macro.  There are
currently four testcases exercising inputs to -mmacosx-version-min
(gcc/testsuite/gcc.dg/darwin-minversion-*), but they provide minimal
coverage, and one is incorrect.

* The tiny number is now respected, if present.  Thus "10.9.4"
  correctly becomes "1094" instead of "1090", and "10.10.1" becomes
  "101001" instead of "101000".
* Zero padding is now ignored.  Thus "10.09" correctly becomes "1090"
  instead of "100900", and "10.00010" becomes "101000" instead of being
  treated as invalid.
* Deployment targets that are missing minor and tiny numbers are no
  longer considered invalid.  Thus "10" is treated as "10.0.0", which
  becomes "1000" without causing an error.

With this change, trunk matches the behavior of Apple LLVM Compiler
6.1.0 on 8,451 of 8,464 generated test inputs.  (The discrepancies are
due to a bug in Clang.)  I don't notice any testsuite regressions on
OS X 10.10 Yosemite x86-64.

2015-05-15  Lawrence VelÃzquez  <vq@larryv.me>

	PR target/63810
	* gcc/config/darwin-c.c (version_components): New global enum.
	(parse_version, version_as_legacy_macro)
	(version_as_modern_macro, macosx_version_as_macro): New functions.
	(version_as_macro): Remove.
	(darwin_cpp_builtins): Use new function.
	* gcc/testsuite/gcc.dg/darwin-minversion-3.c: Update testcase.
	* gcc/testsuite/gcc.dg/darwin-minversion-4.c: Ditto.
	* gcc/testsuite/gcc.dg/darwin-minversion-5.c: New testcase.
	* gcc/testsuite/gcc.dg/darwin-minversion-6.c: Ditto.
	* gcc/testsuite/gcc.dg/darwin-minversion-7.c: Ditto.
	* gcc/testsuite/gcc.dg/darwin-minversion-8.c: Ditto.
	* gcc/testsuite/gcc.dg/darwin-minversion-9.c: Ditto.
	* gcc/testsuite/gcc.dg/darwin-minversion-10.c: Ditto.
	* gcc/testsuite/gcc.dg/darwin-minversion-11.c: Ditto.
	* gcc/testsuite/gcc.dg/darwin-minversion-12.c: Ditto.
---
Please Cc me in any replies, as I'm not subscribed to the list.

 gcc/config/darwin-c.c                       | 190 ++++++++++++++++++++++++----
 gcc/testsuite/gcc.dg/darwin-minversion-10.c |  16 +++
 gcc/testsuite/gcc.dg/darwin-minversion-11.c |  16 +++
 gcc/testsuite/gcc.dg/darwin-minversion-12.c |  16 +++
 gcc/testsuite/gcc.dg/darwin-minversion-3.c  |   6 +-
 gcc/testsuite/gcc.dg/darwin-minversion-4.c  |   6 +-
 gcc/testsuite/gcc.dg/darwin-minversion-5.c  |  16 +++
 gcc/testsuite/gcc.dg/darwin-minversion-6.c  |  15 +++
 gcc/testsuite/gcc.dg/darwin-minversion-7.c  |  15 +++
 gcc/testsuite/gcc.dg/darwin-minversion-8.c  |  16 +++
 gcc/testsuite/gcc.dg/darwin-minversion-9.c  |  15 +++
 11 files changed, 295 insertions(+), 32 deletions(-)
 create mode 100644 gcc/testsuite/gcc.dg/darwin-minversion-10.c
 create mode 100644 gcc/testsuite/gcc.dg/darwin-minversion-11.c
 create mode 100644 gcc/testsuite/gcc.dg/darwin-minversion-12.c
 create mode 100644 gcc/testsuite/gcc.dg/darwin-minversion-5.c
 create mode 100644 gcc/testsuite/gcc.dg/darwin-minversion-6.c
 create mode 100644 gcc/testsuite/gcc.dg/darwin-minversion-7.c
 create mode 100644 gcc/testsuite/gcc.dg/darwin-minversion-8.c
 create mode 100644 gcc/testsuite/gcc.dg/darwin-minversion-9.c

diff --git a/gcc/config/darwin-c.c b/gcc/config/darwin-c.c
index 3803e75..cf38416 100644
--- a/gcc/config/darwin-c.c
+++ b/gcc/config/darwin-c.c
@@ -599,42 +599,180 @@ find_subframework_header (cpp_reader *pfile, const char *header, cpp_dir **dirp)
   return 0;
 }
 
-/* Return the value of darwin_macosx_version_min suitable for the
-   __ENVIRONMENT_MAC_OS_X_VERSION_MIN_REQUIRED__ macro, so '10.4.2'
-   becomes 1040 and '10.10.0' becomes 101000.  The lowest digit is
-   always zero, as is the second lowest for '10.10.x' and above.
-   Print a warning if the version number can't be understood.  */
+/* Given an OS X version VERSION_STR, return it as a statically-allocated array
+   of three integers. If VERSION_STR is invalid, return NULL.
+
+   VERSION_STR must consist of one, two, or three tokens, each separated by
+   a single period.  Each token must contain only the characters '0' through
+   '9' and is converted to an equivalent non-negative decimal integer. Omitted
+   tokens become zeros.  For example:
+
+        "10"              becomes       {10,0,0}
+        "10.10"           becomes       {10,10,0}
+        "10.10.1"         becomes       {10,10,1}
+        "10.000010.1"     becomes       {10,10,1}
+        "10.010.001"      becomes       {10,10,1}
+        "000010.10.00001" becomes       {10,10,1}
+        ".9.1"            is invalid
+        "10..9"           is invalid
+        "10.10."          is invalid  */
+
+enum version_components { MAJOR, MINOR, TINY };
+
+static const unsigned long *
+parse_version (const char *version_str)
+{
+  size_t version_len;
+  char *end;
+  static unsigned long version_array[3];
+
+  if (!version_str)
+    return NULL;
+
+  version_len = strlen (version_str);
+  if (version_len < 1)
+    return NULL;
+
+  /* Version string must consist of digits and periods only.  */
+  if (strspn (version_str, "0123456789.") != version_len)
+    return NULL;
+
+  if (!ISDIGIT (version_str[0]) || !ISDIGIT (version_str[version_len - 1]))
+    return NULL;
+
+  version_array[MAJOR] = strtoul (version_str, &end, 10);
+  version_str = end + ((*end == '.') ? 1 : 0);
+
+  /* Version string must not contain adjacent periods.  */
+  if (*version_str == '.')
+    return NULL;
+
+  version_array[MINOR] = strtoul (version_str, &end, 10);
+  version_str = end + ((*end == '.') ? 1 : 0);
+
+  version_array[TINY] = strtoul (version_str, &end, 10);
+
+  /* Version string must contain no more than three tokens.  */
+  if (*end != '\0')
+    return NULL;
+
+  return version_array;
+}
+
+/* Given VERSION -- a three-component OS X version represented as an array of
+   non-negative integers -- return a statically-allocated string suitable for
+   the legacy __ENVIRONMENT_MAC_OS_X_VERSION_MIN_REQUIRED__ macro.  If VERSION
+   is invalid and cannot be coerced into a valid form, return NULL.
+
+   The legacy format is a four-character string -- two chars for the major
+   number and one each for the minor and tiny numbers.  Major numbers are
+   zero-padded if necessary.  Minor and tiny numbers from 10 through 99 are
+   permitted but are clamped to 9 (for example, {10,9,10} produces "1099").  If
+   VERSION contains numbers greater than 99, it is rejected.  */
+
 static const char *
-version_as_macro (void)
+version_as_legacy_macro (const unsigned long *version)
 {
-  static char result[7] = "1000";
-  int minorDigitIdx;
+  unsigned long major, minor, tiny;
+  static char result[sizeof "9999"];
+
+  if (!version)
+    return NULL;
+
+  major = version[MAJOR];
+  minor = version[MINOR];
+  tiny = version[TINY];
+
+  if (major > 99 || minor > 99 || tiny > 99)
+    return NULL;
+
+  minor = ((minor > 9) ? 9 : minor);
+  tiny = ((tiny > 9) ? 9 : tiny);
+
+  /* NOTE: Cast result of sizeof so that result of sprintf is not
+     converted to an unsigned type.  */
+  if (sprintf (result, "%02lu%lu%lu", major, minor, tiny)
+      != (int) sizeof "9999" - 1)
+    return NULL;
+
+  return result;
+}
 
-  if (strncmp (darwin_macosx_version_min, "10.", 3) != 0)
+/* Given VERSION -- a three-component OS X version represented as an array of
+   non-negative integers -- return a statically-allocated string suitable for
+   the modern __ENVIRONMENT_MAC_OS_X_VERSION_MIN_REQUIRED__ macro or the
+   __ENVIRONMENT_IPHONE_OS_VERSION_MIN_REQUIRED__ macro.  If VERSION is
+   invalid, return NULL.
+
+   The modern format is a five- or six-character string -- one or two chars for
+   the major number and two each for the minor and tiny numbers, which are
+   zero-padded if necessary (for example, {8,1,0} produces "80100", and
+   {10,10,1} produces "101001").  If VERSION contains numbers greater than 99,
+   it is rejected.  */
+
+static const char *
+version_as_modern_macro (const unsigned long *version)
+{
+  unsigned long major, minor, tiny;
+  static char result[sizeof "999999"];
+
+  if (!version)
+    return NULL;
+
+  major = version[MAJOR];
+  minor = version[MINOR];
+  tiny = version[TINY];
+
+  if (major > 99 || minor > 99 || tiny > 99)
+    return NULL;
+
+  /* NOTE: Cannot use 'sizeof ((x > y) ? "foo" : "bar")' because that
+     returns the size of a char pointer instead of the size of the
+     chosen char array.  */
+  /* NOTE: Cast result of sizeof so that result of sprintf is not
+     converted to an unsigned type.  */
+  if (sprintf (result, "%lu%02lu%02lu", major, minor, tiny)
+      != (int) ((major > 9) ? sizeof "999999" : sizeof "99999") - 1)
+    return NULL;
+
+  return result;
+}
+
+/* Return the value of darwin_macosx_version_min, suitably formatted for the
+   __ENVIRONMENT_MAC_OS_X_VERSION_MIN_REQUIRED__ macro.  Values representing
+   OS X 10.9 and earlier are encoded using the legacy four-character format,
+   while 10.10 and later use a modern six-character format.  (For example,
+   "10.9" produces "1090", and "10.10.1" produces "101001".)  If
+   darwin_macosx_version_min is invalid and cannot be coerced into a valid
+   form, print a warning and return "1000".  */
+
+static const char *
+macosx_version_as_macro (void)
+{
+  const unsigned long *version_array;
+  const char *version_macro;
+
+  version_array = parse_version (darwin_macosx_version_min);
+  if (!version_array)
     goto fail;
-  if (! ISDIGIT (darwin_macosx_version_min[3]))
+
+  /* Allow for future major numbers greater than 10.  */
+  if (version_array[MAJOR] < 10 || version_array[MAJOR] > 10)
     goto fail;
 
-  minorDigitIdx = 3;
-  result[2] = darwin_macosx_version_min[minorDigitIdx++];
-  if (ISDIGIT (darwin_macosx_version_min[minorDigitIdx]))
-  {
-    /* Starting with OS X 10.10, the macro ends '00' rather than '0',
-       i.e. 10.10.x becomes 101000 rather than 10100.  */
-    result[3] = darwin_macosx_version_min[minorDigitIdx++];
-    result[4] = '0';
-    result[5] = '0';
-    result[6] = '\0';
-  }
-  if (darwin_macosx_version_min[minorDigitIdx] != '\0'
-      && darwin_macosx_version_min[minorDigitIdx] != '.')
+  if (version_array[MAJOR] == 10 && version_array[MINOR] < 10)
+    version_macro = version_as_legacy_macro (version_array);
+  else
+    version_macro = version_as_modern_macro (version_array);
+
+  if (!version_macro)
     goto fail;
 
-  return result;
+  return version_macro;
 
  fail:
   error ("unknown value %qs of -mmacosx-version-min",
-	 darwin_macosx_version_min);
+         darwin_macosx_version_min);
   return "1000";
 }
 
@@ -656,7 +794,7 @@ darwin_cpp_builtins (cpp_reader *pfile)
     builtin_define ("__CONSTANT_CFSTRINGS__");
 
   builtin_define_with_value ("__ENVIRONMENT_MAC_OS_X_VERSION_MIN_REQUIRED__",
-			     version_as_macro(), false);
+			     macosx_version_as_macro(), false);
 
   /* Since we do not (at 4.6) support ObjC gc for the NeXT runtime, the
      following will cause a syntax error if one tries to compile gc attributed
diff --git a/gcc/testsuite/gcc.dg/darwin-minversion-10.c b/gcc/testsuite/gcc.dg/darwin-minversion-10.c
new file mode 100644
index 0000000..bf95d46
--- /dev/null
+++ b/gcc/testsuite/gcc.dg/darwin-minversion-10.c
@@ -0,0 +1,16 @@
+/* PR target/63810: Test that an OS X minimum version with zero-padded
+   minor and tiny numbers less than 10 produces the correct
+   four-character macro.  */
+/* Added by Lawrence VelÃzquez <vq@larryv.me>.  */
+
+/* { dg-options "-mmacosx-version-min=10.07.02" } */
+/* { dg-do compile { target *-*-darwin* } } */
+
+int
+main ()
+{
+#if __ENVIRONMENT_MAC_OS_X_VERSION_MIN_REQUIRED__ != 1072
+  fail me;
+#endif
+  return 0;
+}
diff --git a/gcc/testsuite/gcc.dg/darwin-minversion-11.c b/gcc/testsuite/gcc.dg/darwin-minversion-11.c
new file mode 100644
index 0000000..a03e707
--- /dev/null
+++ b/gcc/testsuite/gcc.dg/darwin-minversion-11.c
@@ -0,0 +1,16 @@
+/* PR target/63810: Test that an OS X minimum version with outrageous
+   zero-padding and a minor number greater than 9 still produces
+   a six-character macro.  */
+/* Added by Lawrence VelÃzquez <vq@larryv.me>.  */
+
+/* { dg-options "-mmacosx-version-min=00010.010.0000098" } */
+/* { dg-do compile { target *-*-darwin* } } */
+
+int
+main ()
+{
+#if __ENVIRONMENT_MAC_OS_X_VERSION_MIN_REQUIRED__ != 101098
+  fail me;
+#endif
+  return 0;
+}
diff --git a/gcc/testsuite/gcc.dg/darwin-minversion-12.c b/gcc/testsuite/gcc.dg/darwin-minversion-12.c
new file mode 100644
index 0000000..4c2ce38
--- /dev/null
+++ b/gcc/testsuite/gcc.dg/darwin-minversion-12.c
@@ -0,0 +1,16 @@
+/* PR target/63810: Test that an OS X minimum version with outrageous
+   zero-padding and a minor number less than 10 still produces
+   a four-character macro.  */
+/* Added by Lawrence VelÃzquez <vq@larryv.me>.  */
+
+/* { dg-options "-mmacosx-version-min=010.008.000031" } */
+/* { dg-do compile { target *-*-darwin* } } */
+
+int
+main ()
+{
+#if __ENVIRONMENT_MAC_OS_X_VERSION_MIN_REQUIRED__ != 1089
+  fail me;
+#endif
+  return 0;
+}
diff --git a/gcc/testsuite/gcc.dg/darwin-minversion-3.c b/gcc/testsuite/gcc.dg/darwin-minversion-3.c
index 4fcb969..d1795e7 100644
--- a/gcc/testsuite/gcc.dg/darwin-minversion-3.c
+++ b/gcc/testsuite/gcc.dg/darwin-minversion-3.c
@@ -1,11 +1,11 @@
-/* Test that most-minor versions greater than 9 work.  */
-/* { dg-options "-mmacosx-version-min=10.4.10" } */
+/* Test that most minor versions less than 10 work.  */
+/* { dg-options "-mmacosx-version-min=10.4.1" } */
 /* { dg-do compile { target *-*-darwin* } } */
 
 int
 main ()
 {
-#if __ENVIRONMENT_MAC_OS_X_VERSION_MIN_REQUIRED__ != 1040
+#if __ENVIRONMENT_MAC_OS_X_VERSION_MIN_REQUIRED__ != 1041
   fail me;
 #endif
   return 0;
diff --git a/gcc/testsuite/gcc.dg/darwin-minversion-4.c b/gcc/testsuite/gcc.dg/darwin-minversion-4.c
index 1cb42eb..1481aa5 100644
--- a/gcc/testsuite/gcc.dg/darwin-minversion-4.c
+++ b/gcc/testsuite/gcc.dg/darwin-minversion-4.c
@@ -1,11 +1,11 @@
-/* Test that major versions greater than 9 work and have the additional 0.  */
-/* { dg-options "-mmacosx-version-min=10.10.0" } */
+/* Test that minor versions greater than 9 produce a six-character macro.  */
+/* { dg-options "-mmacosx-version-min=10.10.1" } */
 /* { dg-do compile { target *-*-darwin* } } */
 
 int
 main ()
 {
-#if __ENVIRONMENT_MAC_OS_X_VERSION_MIN_REQUIRED__ != 101000
+#if __ENVIRONMENT_MAC_OS_X_VERSION_MIN_REQUIRED__ != 101001
   fail me;
 #endif
   return 0;
diff --git a/gcc/testsuite/gcc.dg/darwin-minversion-5.c b/gcc/testsuite/gcc.dg/darwin-minversion-5.c
new file mode 100644
index 0000000..09a9d72
--- /dev/null
+++ b/gcc/testsuite/gcc.dg/darwin-minversion-5.c
@@ -0,0 +1,16 @@
+/* PR target/63810: Test that an OS X minimum version with minor number
+   less than 10 and tiny number greater than 9 produces a four-character
+   macro with the tiny number clamped to 9.  */
+/* Added by Lawrence VelÃzquez <vq@larryv.me>.  */
+
+/* { dg-options "-mmacosx-version-min=10.9.10" } */
+/* { dg-do compile { target *-*-darwin* } } */
+
+int
+main ()
+{
+#if __ENVIRONMENT_MAC_OS_X_VERSION_MIN_REQUIRED__ != 1099
+  fail me;
+#endif
+  return 0;
+}
diff --git a/gcc/testsuite/gcc.dg/darwin-minversion-6.c b/gcc/testsuite/gcc.dg/darwin-minversion-6.c
new file mode 100644
index 0000000..e01fa72
--- /dev/null
+++ b/gcc/testsuite/gcc.dg/darwin-minversion-6.c
@@ -0,0 +1,15 @@
+/* PR target/63810: Test that tiny numbers are preserved in
+   six-character macros.  */
+/* Added by Lawrence VelÃzquez <vq@larryv.me>.  */
+
+/* { dg-options "-mmacosx-version-min=10.10.11" } */
+/* { dg-do compile { target *-*-darwin* } } */
+
+int
+main ()
+{
+#if __ENVIRONMENT_MAC_OS_X_VERSION_MIN_REQUIRED__ != 101011
+  fail me;
+#endif
+  return 0;
+}
diff --git a/gcc/testsuite/gcc.dg/darwin-minversion-7.c b/gcc/testsuite/gcc.dg/darwin-minversion-7.c
new file mode 100644
index 0000000..72f495b
--- /dev/null
+++ b/gcc/testsuite/gcc.dg/darwin-minversion-7.c
@@ -0,0 +1,15 @@
+/* PR target/63810: Test that tiny numbers less than 10 are preserved in
+   four-character macros.  */
+/* Added by Lawrence VelÃzquez <vq@larryv.me>.  */
+
+/* { dg-options "-mmacosx-version-min=10.9.1" } */
+/* { dg-do compile { target *-*-darwin* } } */
+
+int
+main ()
+{
+#if __ENVIRONMENT_MAC_OS_X_VERSION_MIN_REQUIRED__ != 1091
+  fail me;
+#endif
+  return 0;
+}
diff --git a/gcc/testsuite/gcc.dg/darwin-minversion-8.c b/gcc/testsuite/gcc.dg/darwin-minversion-8.c
new file mode 100644
index 0000000..5982df5
--- /dev/null
+++ b/gcc/testsuite/gcc.dg/darwin-minversion-8.c
@@ -0,0 +1,16 @@
+/* PR target/63810: Test that an OS X minimum version with minor number
+   greater than 9 and no tiny number produces a six-character macro
+   ending in "00".  */
+/* Added by Lawrence VelÃzquez <vq@larryv.me>.  */
+
+/* { dg-options "-mmacosx-version-min=10.11" } */
+/* { dg-do compile { target *-*-darwin* } } */
+
+int
+main ()
+{
+#if __ENVIRONMENT_MAC_OS_X_VERSION_MIN_REQUIRED__ != 101100
+  fail me;
+#endif
+  return 0;
+}
diff --git a/gcc/testsuite/gcc.dg/darwin-minversion-9.c b/gcc/testsuite/gcc.dg/darwin-minversion-9.c
new file mode 100644
index 0000000..d781783
--- /dev/null
+++ b/gcc/testsuite/gcc.dg/darwin-minversion-9.c
@@ -0,0 +1,15 @@
+/* PR target/63810: Test that an OS X minimum version with a zero-padded
+   minor number less than 10 produces a four-character macro.  */
+/* Added by Lawrence VelÃzquez <vq@larryv.me>.  */
+
+/* { dg-options "-mmacosx-version-min=10.08.4" } */
+/* { dg-do compile { target *-*-darwin* } } */
+
+int
+main ()
+{
+#if __ENVIRONMENT_MAC_OS_X_VERSION_MIN_REQUIRED__ != 1084
+  fail me;
+#endif
+  return 0;
+}
-- 
2.4.1


Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]