Hi!

The recent changes to move strchr folding from builtins.c to gimple-fold.c
broke constexpr handling with __builtin_strchr etc. (which the libstdc++
folks want to use).

Fixed by handling it also in fold-const-call.c.  Bootstrapped/regtested on
x86_64-linux and i686-linux, ok for trunk?

2016-12-05  Jakub Jelinek  <ja...@redhat.com>

        PR c++/71537
        * fold-const-call.c (fold_const_call): Handle
        CFN_BUILT_IN_{INDEX,STRCHR,RINDEX,STRRCHR}.

        * g++.dg/cpp0x/constexpr-strchr.C: New test.

--- gcc/fold-const-call.c.jj    2016-11-09 18:54:03.000000000 +0100
+++ gcc/fold-const-call.c       2016-12-05 12:53:38.597090946 +0100
@@ -1383,6 +1383,7 @@ tree
 fold_const_call (combined_fn fn, tree type, tree arg0, tree arg1)
 {
   const char *p0, *p1;
+  char c;
   switch (fn)
     {
     case CFN_BUILT_IN_STRSPN:
@@ -1409,6 +1410,30 @@ fold_const_call (combined_fn fn, tree ty
        }
       return NULL_TREE;
 
+    case CFN_BUILT_IN_INDEX:
+    case CFN_BUILT_IN_STRCHR:
+      if ((p0 = c_getstr (arg0)) && target_char_cst_p (arg1, &c))
+       {
+         const char *r = strchr (p0, c);
+         if (r == NULL)
+           return build_int_cst (type, 0);
+         return fold_convert (type,
+                              fold_build_pointer_plus_hwi (arg0, r - p0));
+       }
+      return NULL_TREE;
+
+    case CFN_BUILT_IN_RINDEX:
+    case CFN_BUILT_IN_STRRCHR:
+      if ((p0 = c_getstr (arg0)) && target_char_cst_p (arg1, &c))
+       {
+         const char *r = strrchr (p0, c);
+         if (r == NULL)
+           return build_int_cst (type, 0);
+         return fold_convert (type,
+                              fold_build_pointer_plus_hwi (arg0, r - p0));
+       }
+      return NULL_TREE;
+
     default:
       return fold_const_call_1 (fn, type, arg0, arg1);
     }
--- gcc/testsuite/g++.dg/cpp0x/constexpr-strchr.C.jj    2016-12-05 
13:00:19.448101292 +0100
+++ gcc/testsuite/g++.dg/cpp0x/constexpr-strchr.C       2016-12-05 
13:00:36.270888812 +0100
@@ -0,0 +1,27 @@
+// { dg-do compile { target c++11 } }
+
+constexpr const char *f1 (const char *p, int q) { return __builtin_strchr (p, 
q); }
+constexpr const char *f2 (const char *p, int q) { return __builtin_index (p, 
q); }
+constexpr const char *f3 (const char *p, int q) { return __builtin_strrchr (p, 
q); }
+constexpr const char *f4 (const char *p, int q) { return __builtin_rindex (p, 
q); }
+constexpr const char a[] = "abcdefedcba";
+static_assert (f1 ("abcde", 'f') == nullptr, "");
+static_assert (f1 (a, 'g') == nullptr, "");
+static_assert (f1 (a, 'f') == a + 5, "");
+static_assert (f1 (a, 'c') == a + 2, "");
+static_assert (f1 (a, '\0') == a + 11, "");
+static_assert (f2 ("abcde", 'f') == nullptr, "");
+static_assert (f2 (a, 'g') == nullptr, "");
+static_assert (f2 (a, 'f') == a + 5, "");
+static_assert (f2 (a, 'c') == a + 2, "");
+static_assert (f2 (a, '\0') == a + 11, "");
+static_assert (f3 ("abcde", 'f') == nullptr, "");
+static_assert (f3 (a, 'g') == nullptr, "");
+static_assert (f3 (a, 'f') == a + 5, "");
+static_assert (f3 (a, 'c') == a + 8, "");
+static_assert (f3 (a, '\0') == a + 11, "");
+static_assert (f4 ("abcde", 'f') == nullptr, "");
+static_assert (f4 (a, 'g') == nullptr, "");
+static_assert (f4 (a, 'f') == a + 5, "");
+static_assert (f4 (a, 'c') == a + 8, "");
+static_assert (f4 (a, '\0') == a + 11, "");

        Jakub

Reply via email to