Add support for the OpenCL vec_step operator, by generalising and
extending the existing support for sizeof and alignof.  Original
patch by Guy Benyei.

git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@127475 91177308-0d34-0410-b5e6-96231b3b80d8
diff --git a/lib/Sema/SemaExpr.cpp b/lib/Sema/SemaExpr.cpp
index 9cff0f5..7dee502 100644
--- a/lib/Sema/SemaExpr.cpp
+++ b/lib/Sema/SemaExpr.cpp
@@ -2711,10 +2711,10 @@
 
 /// The UsualUnaryConversions() function is *not* called by this routine.
 /// See C99 6.3.2.1p[2-4] for more details.
-bool Sema::CheckSizeOfAlignOfOperand(QualType exprType,
-                                     SourceLocation OpLoc,
-                                     SourceRange ExprRange,
-                                     bool isSizeof) {
+bool Sema::CheckUnaryExprOrTypeTraitOperand(QualType exprType,
+                                            SourceLocation OpLoc,
+                                            SourceRange ExprRange,
+                                            UnaryExprOrTypeTrait ExprKind) {
   if (exprType->isDependentType())
     return false;
 
@@ -2725,30 +2725,47 @@
   if (const ReferenceType *Ref = exprType->getAs<ReferenceType>())
     exprType = Ref->getPointeeType();
 
+  // [OpenCL 1.1 6.11.12] "The vec_step built-in function takes a built-in
+  // scalar or vector data type argument..."
+  // Every built-in scalar type (OpenCL 1.1 6.1.1) is either an arithmetic
+  // type (C99 6.2.5p18) or void.
+  if (ExprKind == UETT_VecStep) {
+    if (!(exprType->isArithmeticType() || exprType->isVoidType() ||
+          exprType->isVectorType())) {
+      Diag(OpLoc, diag::err_vecstep_non_scalar_vector_type)
+        << exprType << ExprRange;
+      return true;
+    }
+  }
+
   // C99 6.5.3.4p1:
   if (exprType->isFunctionType()) {
     // alignof(function) is allowed as an extension.
-    if (isSizeof)
-      Diag(OpLoc, diag::ext_sizeof_function_type) << ExprRange;
+    if (ExprKind == UETT_SizeOf)
+      Diag(OpLoc, diag::ext_sizeof_function_type) 
+        << ExprRange;
     return false;
   }
 
-  // Allow sizeof(void)/alignof(void) as an extension.
+  // Allow sizeof(void)/alignof(void) as an extension.  vec_step(void) is not
+  // an extension, as void is a built-in scalar type (OpenCL 1.1 6.1.1).
   if (exprType->isVoidType()) {
-    Diag(OpLoc, diag::ext_sizeof_void_type)
-      << (isSizeof ? "sizeof" : "__alignof") << ExprRange;
+    if (ExprKind != UETT_VecStep)
+      Diag(OpLoc, diag::ext_sizeof_void_type)
+        << ExprKind << ExprRange;
     return false;
   }
 
   if (RequireCompleteType(OpLoc, exprType,
                           PDiag(diag::err_sizeof_alignof_incomplete_type)
-                          << int(!isSizeof) << ExprRange))
+                          << ExprKind << ExprRange))
     return true;
 
   // Reject sizeof(interface) and sizeof(interface<proto>) in 64-bit mode.
   if (LangOpts.ObjCNonFragileABI && exprType->isObjCObjectType()) {
     Diag(OpLoc, diag::err_sizeof_nonfragile_interface)
-      << exprType << isSizeof << ExprRange;
+      << exprType << (ExprKind == UETT_SizeOf)
+      << ExprRange;
     return true;
   }
 
@@ -2778,78 +2795,98 @@
     if (isa<FieldDecl>(ME->getMemberDecl()))
       return false;
 
-  return S.CheckSizeOfAlignOfOperand(E->getType(), OpLoc, ExprRange, false);
+  return S.CheckUnaryExprOrTypeTraitOperand(E->getType(), OpLoc, ExprRange,
+                                            UETT_AlignOf);
+}
+
+bool Sema::CheckVecStepExpr(Expr *E, SourceLocation OpLoc,
+                            SourceRange ExprRange) {
+  E = E->IgnoreParens();
+
+  // Cannot know anything else if the expression is dependent.
+  if (E->isTypeDependent())
+    return false;
+
+  return CheckUnaryExprOrTypeTraitOperand(E->getType(), OpLoc, ExprRange,
+                                          UETT_VecStep);
 }
 
 /// \brief Build a sizeof or alignof expression given a type operand.
 ExprResult
-Sema::CreateSizeOfAlignOfExpr(TypeSourceInfo *TInfo,
-                              SourceLocation OpLoc,
-                              bool isSizeOf, SourceRange R) {
+Sema::CreateUnaryExprOrTypeTraitExpr(TypeSourceInfo *TInfo,
+                                     SourceLocation OpLoc,
+                                     UnaryExprOrTypeTrait ExprKind,
+                                     SourceRange R) {
   if (!TInfo)
     return ExprError();
 
   QualType T = TInfo->getType();
 
   if (!T->isDependentType() &&
-      CheckSizeOfAlignOfOperand(T, OpLoc, R, isSizeOf))
+      CheckUnaryExprOrTypeTraitOperand(T, OpLoc, R, ExprKind))
     return ExprError();
 
   // C99 6.5.3.4p4: the type (an unsigned integer type) is size_t.
-  return Owned(new (Context) SizeOfAlignOfExpr(isSizeOf, TInfo,
-                                               Context.getSizeType(), OpLoc,
-                                               R.getEnd()));
+  return Owned(new (Context) UnaryExprOrTypeTraitExpr(ExprKind, TInfo,
+                                                      Context.getSizeType(),
+                                                      OpLoc, R.getEnd()));
 }
 
 /// \brief Build a sizeof or alignof expression given an expression
 /// operand.
 ExprResult
-Sema::CreateSizeOfAlignOfExpr(Expr *E, SourceLocation OpLoc,
-                              bool isSizeOf, SourceRange R) {
+Sema::CreateUnaryExprOrTypeTraitExpr(Expr *E, SourceLocation OpLoc,
+                                     UnaryExprOrTypeTrait ExprKind,
+                                     SourceRange R) {
   // Verify that the operand is valid.
   bool isInvalid = false;
   if (E->isTypeDependent()) {
     // Delay type-checking for type-dependent expressions.
-  } else if (!isSizeOf) {
+  } else if (ExprKind == UETT_AlignOf) {
     isInvalid = CheckAlignOfExpr(*this, E, OpLoc, R);
+  } else if (ExprKind == UETT_VecStep) {
+    isInvalid = CheckVecStepExpr(E, OpLoc, R);
   } else if (E->getBitField()) {  // C99 6.5.3.4p1.
     Diag(OpLoc, diag::err_sizeof_alignof_bitfield) << 0;
     isInvalid = true;
   } else if (E->getType()->isPlaceholderType()) {
     ExprResult PE = CheckPlaceholderExpr(E, OpLoc);
     if (PE.isInvalid()) return ExprError();
-    return CreateSizeOfAlignOfExpr(PE.take(), OpLoc, isSizeOf, R);
+    return CreateUnaryExprOrTypeTraitExpr(PE.take(), OpLoc, ExprKind, R);
   } else {
-    isInvalid = CheckSizeOfAlignOfOperand(E->getType(), OpLoc, R, true);
+    isInvalid = CheckUnaryExprOrTypeTraitOperand(E->getType(), OpLoc, R,
+                                                 UETT_SizeOf);
   }
 
   if (isInvalid)
     return ExprError();
 
   // C99 6.5.3.4p4: the type (an unsigned integer type) is size_t.
-  return Owned(new (Context) SizeOfAlignOfExpr(isSizeOf, E,
-                                               Context.getSizeType(), OpLoc,
-                                               R.getEnd()));
+  return Owned(new (Context) UnaryExprOrTypeTraitExpr(ExprKind, E,
+                                                      Context.getSizeType(),
+                                                      OpLoc, R.getEnd()));
 }
 
-/// ActOnSizeOfAlignOfExpr - Handle @c sizeof(type) and @c sizeof @c expr and
-/// the same for @c alignof and @c __alignof
+/// ActOnUnaryExprOrTypeTraitExpr - Handle @c sizeof(type) and @c sizeof @c
+/// expr and the same for @c alignof and @c __alignof
 /// Note that the ArgRange is invalid if isType is false.
 ExprResult
-Sema::ActOnSizeOfAlignOfExpr(SourceLocation OpLoc, bool isSizeof, bool isType,
-                             void *TyOrEx, const SourceRange &ArgRange) {
+Sema::ActOnUnaryExprOrTypeTraitExpr(SourceLocation OpLoc,
+                                    UnaryExprOrTypeTrait ExprKind, bool isType,
+                                    void *TyOrEx, const SourceRange &ArgRange) {
   // If error parsing type, ignore.
   if (TyOrEx == 0) return ExprError();
 
   if (isType) {
     TypeSourceInfo *TInfo;
     (void) GetTypeFromParser(ParsedType::getFromOpaquePtr(TyOrEx), &TInfo);
-    return CreateSizeOfAlignOfExpr(TInfo, OpLoc, isSizeof, ArgRange);
+    return CreateUnaryExprOrTypeTraitExpr(TInfo, OpLoc, ExprKind, ArgRange);
   }
 
   Expr *ArgEx = (Expr *)TyOrEx;
   ExprResult Result
-    = CreateSizeOfAlignOfExpr(ArgEx, OpLoc, isSizeof, ArgEx->getSourceRange());
+    = CreateUnaryExprOrTypeTraitExpr(ArgEx, OpLoc, ExprKind,
+                                     ArgEx->getSourceRange());
 
   return move(Result);
 }