Support constant expression evaluation for wchar_t versions of simple string
functions, in order to support constexpr std::char_traits<wchar_t>.

llvm-svn: 288193
diff --git a/clang/lib/AST/ExprConstant.cpp b/clang/lib/AST/ExprConstant.cpp
index 7fd8177..e212928 100644
--- a/clang/lib/AST/ExprConstant.cpp
+++ b/clang/lib/AST/ExprConstant.cpp
@@ -5346,16 +5346,20 @@
   }
 
   case Builtin::BIstrchr:
+  case Builtin::BIwcschr:
   case Builtin::BImemchr:
+  case Builtin::BIwmemchr:
     if (Info.getLangOpts().CPlusPlus11)
       Info.CCEDiag(E, diag::note_constexpr_invalid_function)
         << /*isConstexpr*/0 << /*isConstructor*/0
-        << (BuiltinOp == Builtin::BIstrchr ? "'strchr'" : "'memchr'");
+        << (std::string("'") + Info.Ctx.BuiltinInfo.getName(BuiltinOp) + "'");
     else
       Info.CCEDiag(E, diag::note_invalid_subexpr_in_const_expr);
     // Fall through.
   case Builtin::BI__builtin_strchr:
-  case Builtin::BI__builtin_memchr: {
+  case Builtin::BI__builtin_wcschr:
+  case Builtin::BI__builtin_memchr:
+  case Builtin::BI__builtin_wmemchr: {
     if (!Visit(E->getArg(0)))
       return false;
     APSInt Desired;
@@ -5363,29 +5367,51 @@
       return false;
     uint64_t MaxLength = uint64_t(-1);
     if (BuiltinOp != Builtin::BIstrchr &&
-        BuiltinOp != Builtin::BI__builtin_strchr) {
+        BuiltinOp != Builtin::BIwcschr &&
+        BuiltinOp != Builtin::BI__builtin_strchr &&
+        BuiltinOp != Builtin::BI__builtin_wcschr) {
       APSInt N;
       if (!EvaluateInteger(E->getArg(2), N, Info))
         return false;
       MaxLength = N.getExtValue();
     }
 
-    QualType CharTy = Info.Ctx.CharTy;
-    bool IsStrchr = (BuiltinOp != Builtin::BImemchr &&
-                     BuiltinOp != Builtin::BI__builtin_memchr);
+    QualType CharTy = E->getArg(0)->getType()->getPointeeType();
 
-    // strchr compares directly to the passed integer, and therefore
-    // always fails if given an int that is not a char.
-    if (IsStrchr &&
-        !APSInt::isSameValue(HandleIntToIntCast(Info, E, CharTy,
-                                                E->getArg(1)->getType(),
-                                                Desired),
-                             Desired))
-      return ZeroInitialization(E);
+    // Figure out what value we're actually looking for (after converting to
+    // the corresponding unsigned type if necessary).
+    uint64_t DesiredVal;
+    bool StopAtNull = false;
+    switch (BuiltinOp) {
+    case Builtin::BIstrchr:
+    case Builtin::BI__builtin_strchr:
+      // strchr compares directly to the passed integer, and therefore
+      // always fails if given an int that is not a char.
+      if (!APSInt::isSameValue(HandleIntToIntCast(Info, E, CharTy,
+                                                  E->getArg(1)->getType(),
+                                                  Desired),
+                               Desired))
+        return ZeroInitialization(E);
+      StopAtNull = true;
+      // Fall through.
+    case Builtin::BImemchr:
+    case Builtin::BI__builtin_memchr:
+      // memchr compares by converting both sides to unsigned char. That's also
+      // correct for strchr if we get this far (to cope with plain char being
+      // unsigned in the strchr case).
+      DesiredVal = Desired.trunc(Info.Ctx.getCharWidth()).getZExtValue();
+      break;
 
-    // memchr compares by converting both sides to unsigned char. That's also
-    // correct for strchr if we get this far.
-    uint64_t DesiredVal = Desired.trunc(Info.Ctx.getCharWidth()).getZExtValue();
+    case Builtin::BIwcschr:
+    case Builtin::BI__builtin_wcschr:
+      StopAtNull = true;
+      // Fall through.
+    case Builtin::BIwmemchr:
+    case Builtin::BI__builtin_wmemchr:
+      // wcschr and wmemchr are given a wchar_t to look for. Just use it.
+      DesiredVal = Desired.getZExtValue();
+      break;
+    }
 
     for (; MaxLength; --MaxLength) {
       APValue Char;
@@ -5394,7 +5420,7 @@
         return false;
       if (Char.getInt().getZExtValue() == DesiredVal)
         return true;
-      if (IsStrchr && !Char.getInt())
+      if (StopAtNull && !Char.getInt())
         break;
       if (!HandleLValueArrayAdjustment(Info, E, Result, CharTy, 1))
         return false;
@@ -7117,20 +7143,25 @@
   }
 
   case Builtin::BIstrlen:
+  case Builtin::BIwcslen:
     // A call to strlen is not a constant expression.
     if (Info.getLangOpts().CPlusPlus11)
       Info.CCEDiag(E, diag::note_constexpr_invalid_function)
-        << /*isConstexpr*/0 << /*isConstructor*/0 << "'strlen'";
+        << /*isConstexpr*/0 << /*isConstructor*/0
+        << (std::string("'") + Info.Ctx.BuiltinInfo.getName(BuiltinOp) + "'");
     else
       Info.CCEDiag(E, diag::note_invalid_subexpr_in_const_expr);
     // Fall through.
-  case Builtin::BI__builtin_strlen: {
+  case Builtin::BI__builtin_strlen:
+  case Builtin::BI__builtin_wcslen: {
     // As an extension, we support __builtin_strlen() as a constant expression,
     // and support folding strlen() to a constant.
     LValue String;
     if (!EvaluatePointer(E->getArg(0), String, Info))
       return false;
 
+    QualType CharTy = E->getArg(0)->getType()->getPointeeType();
+
     // Fast path: if it's a string literal, search the string value.
     if (const StringLiteral *S = dyn_cast_or_null<StringLiteral>(
             String.getLValueBase().dyn_cast<const Expr *>())) {
@@ -7139,7 +7170,9 @@
       StringRef Str = S->getBytes();
       int64_t Off = String.Offset.getQuantity();
       if (Off >= 0 && (uint64_t)Off <= (uint64_t)Str.size() &&
-          S->getCharByteWidth() == 1) {
+          S->getCharByteWidth() == 1 &&
+          // FIXME: Add fast-path for wchar_t too.
+          Info.Ctx.hasSameUnqualifiedType(CharTy, Info.Ctx.CharTy)) {
         Str = Str.substr(Off);
 
         StringRef::size_type Pos = Str.find(0);
@@ -7153,7 +7186,6 @@
     }
 
     // Slow path: scan the bytes of the string looking for the terminating 0.
-    QualType CharTy = Info.Ctx.CharTy;
     for (uint64_t Strlen = 0; /**/; ++Strlen) {
       APValue Char;
       if (!handleLValueToRValueConversion(Info, E, CharTy, String, Char) ||
@@ -7167,36 +7199,46 @@
   }
 
   case Builtin::BIstrcmp:
+  case Builtin::BIwcscmp:
   case Builtin::BIstrncmp:
+  case Builtin::BIwcsncmp:
   case Builtin::BImemcmp:
+  case Builtin::BIwmemcmp:
     // A call to strlen is not a constant expression.
     if (Info.getLangOpts().CPlusPlus11)
       Info.CCEDiag(E, diag::note_constexpr_invalid_function)
         << /*isConstexpr*/0 << /*isConstructor*/0
-        << (BuiltinOp == Builtin::BIstrncmp ? "'strncmp'" :
-            BuiltinOp == Builtin::BImemcmp ? "'memcmp'" :
-            "'strcmp'");
+        << (std::string("'") + Info.Ctx.BuiltinInfo.getName(BuiltinOp) + "'");
     else
       Info.CCEDiag(E, diag::note_invalid_subexpr_in_const_expr);
     // Fall through.
   case Builtin::BI__builtin_strcmp:
+  case Builtin::BI__builtin_wcscmp:
   case Builtin::BI__builtin_strncmp:
-  case Builtin::BI__builtin_memcmp: {
+  case Builtin::BI__builtin_wcsncmp:
+  case Builtin::BI__builtin_memcmp:
+  case Builtin::BI__builtin_wmemcmp: {
     LValue String1, String2;
     if (!EvaluatePointer(E->getArg(0), String1, Info) ||
         !EvaluatePointer(E->getArg(1), String2, Info))
       return false;
+
+    QualType CharTy = E->getArg(0)->getType()->getPointeeType();
+
     uint64_t MaxLength = uint64_t(-1);
     if (BuiltinOp != Builtin::BIstrcmp &&
-        BuiltinOp != Builtin::BI__builtin_strcmp) {
+        BuiltinOp != Builtin::BIwcscmp &&
+        BuiltinOp != Builtin::BI__builtin_strcmp &&
+        BuiltinOp != Builtin::BI__builtin_wcscmp) {
       APSInt N;
       if (!EvaluateInteger(E->getArg(2), N, Info))
         return false;
       MaxLength = N.getExtValue();
     }
     bool StopAtNull = (BuiltinOp != Builtin::BImemcmp &&
-                       BuiltinOp != Builtin::BI__builtin_memcmp);
-    QualType CharTy = Info.Ctx.CharTy;
+                       BuiltinOp != Builtin::BIwmemcmp &&
+                       BuiltinOp != Builtin::BI__builtin_memcmp &&
+                       BuiltinOp != Builtin::BI__builtin_wmemcmp);
     for (; MaxLength; --MaxLength) {
       APValue Char1, Char2;
       if (!handleLValueToRValueConversion(Info, E, CharTy, String1, Char1) ||