r213595 - Sema: correct handling for __va_start for WoA

Saleem Abdulrasool compnerd at compnerd.org
Mon Jul 21 19:01:05 PDT 2014


Author: compnerd
Date: Mon Jul 21 21:01:04 2014
New Revision: 213595

URL: http://llvm.org/viewvc/llvm-project?rev=213595&view=rev
Log:
Sema: correct handling for __va_start for WoA

Windows ARM indicates __va_start as a variadic function.  However, the function
itself is treated as having 4 formal arguments:
  - (out) pointer to the va_list
  - (in) address of the last named argument
  - (in) slot size for the type of the last argument
  - address of the last named argument

The last argument does not seem to have any bearing on codegen, and thus is not
explicitly type checked at this point.

Unlike the previous handling for __va_start, it does not currently validate if
the parameter is the last named parameter (it seems that MSVC currently accepts
this).

Added:
    cfe/trunk/test/SemaCXX/microsoft-varargs-diagnostics.cpp
    cfe/trunk/test/SemaCXX/microsoft-varargs.cpp
Modified:
    cfe/trunk/include/clang/Sema/Sema.h
    cfe/trunk/lib/Sema/SemaChecking.cpp

Modified: cfe/trunk/include/clang/Sema/Sema.h
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/Sema/Sema.h?rev=213595&r1=213594&r2=213595&view=diff
==============================================================================
--- cfe/trunk/include/clang/Sema/Sema.h (original)
+++ cfe/trunk/include/clang/Sema/Sema.h Mon Jul 21 21:01:04 2014
@@ -8281,6 +8281,7 @@ private:
   bool CheckX86BuiltinFunctionCall(unsigned BuiltinID, CallExpr *TheCall);
 
   bool SemaBuiltinVAStart(CallExpr *TheCall);
+  bool SemaBuiltinVAStartARM(CallExpr *Call);
   bool SemaBuiltinUnorderedCompare(CallExpr *TheCall);
   bool SemaBuiltinFPClassification(CallExpr *TheCall, unsigned NumArgs);
 

Modified: cfe/trunk/lib/Sema/SemaChecking.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Sema/SemaChecking.cpp?rev=213595&r1=213594&r2=213595&view=diff
==============================================================================
--- cfe/trunk/lib/Sema/SemaChecking.cpp (original)
+++ cfe/trunk/lib/Sema/SemaChecking.cpp Mon Jul 21 21:01:04 2014
@@ -142,10 +142,23 @@ Sema::CheckBuiltinFunctionCall(unsigned
     break;
   case Builtin::BI__builtin_stdarg_start:
   case Builtin::BI__builtin_va_start:
-  case Builtin::BI__va_start:
     if (SemaBuiltinVAStart(TheCall))
       return ExprError();
     break;
+  case Builtin::BI__va_start: {
+    switch (Context.getTargetInfo().getTriple().getArch()) {
+    case llvm::Triple::arm:
+    case llvm::Triple::thumb:
+      if (SemaBuiltinVAStartARM(TheCall))
+        return ExprError();
+      break;
+    default:
+      if (SemaBuiltinVAStart(TheCall))
+        return ExprError();
+      break;
+    }
+    break;
+  }
   case Builtin::BI__builtin_isgreater:
   case Builtin::BI__builtin_isgreaterequal:
   case Builtin::BI__builtin_isless:
@@ -1739,6 +1752,58 @@ bool Sema::SemaBuiltinVAStart(CallExpr *
   return false;
 }
 
+bool Sema::SemaBuiltinVAStartARM(CallExpr *Call) {
+  // void __va_start(va_list *ap, const char *named_addr, size_t slot_size,
+  //                 const char *named_addr);
+
+  Expr *Func = Call->getCallee();
+
+  if (Call->getNumArgs() < 3)
+    return Diag(Call->getLocEnd(),
+                diag::err_typecheck_call_too_few_args_at_least)
+           << 0 /*function call*/ << 3 << Call->getNumArgs();
+
+  // Determine whether the current function is variadic or not.
+  bool IsVariadic;
+  if (BlockScopeInfo *CurBlock = getCurBlock())
+    IsVariadic = CurBlock->TheDecl->isVariadic();
+  else if (FunctionDecl *FD = getCurFunctionDecl())
+    IsVariadic = FD->isVariadic();
+  else if (ObjCMethodDecl *MD = getCurMethodDecl())
+    IsVariadic = MD->isVariadic();
+  else
+    llvm_unreachable("unexpected statement type");
+
+  if (!IsVariadic) {
+    Diag(Func->getLocStart(), diag::err_va_start_used_in_non_variadic_function);
+    return true;
+  }
+
+  // Type-check the first argument normally.
+  if (checkBuiltinArgument(*this, Call, 0))
+    return true;
+
+  static const struct {
+    unsigned ArgNo;
+    QualType Type;
+  } ArgumentTypes[] = {
+    { 1, Context.getPointerType(Context.CharTy.withConst()) },
+    { 2, Context.getSizeType() },
+  };
+
+  for (const auto &AT : ArgumentTypes) {
+    const Expr *Arg = Call->getArg(AT.ArgNo)->IgnoreParens();
+    if (Arg->getType().getCanonicalType() == AT.Type.getCanonicalType())
+      continue;
+    Diag(Arg->getLocStart(), diag::err_typecheck_convert_incompatible)
+      << Arg->getType() << AT.Type << 1 /* different class */
+      << 0 /* qualifier difference */ << 3 /* parameter mismatch */
+      << AT.ArgNo + 1 << Arg->getType() << AT.Type;
+  }
+
+  return false;
+}
+
 /// SemaBuiltinUnorderedCompare - Handle functions like __builtin_isgreater and
 /// friends.  This is declared to take (...), so we have to check everything.
 bool Sema::SemaBuiltinUnorderedCompare(CallExpr *TheCall) {

Added: cfe/trunk/test/SemaCXX/microsoft-varargs-diagnostics.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/SemaCXX/microsoft-varargs-diagnostics.cpp?rev=213595&view=auto
==============================================================================
--- cfe/trunk/test/SemaCXX/microsoft-varargs-diagnostics.cpp (added)
+++ cfe/trunk/test/SemaCXX/microsoft-varargs-diagnostics.cpp Mon Jul 21 21:01:04 2014
@@ -0,0 +1,42 @@
+// RUN: %clang_cc1 -triple thumbv7-windows -fms-compatibility -fsyntax-only %s -verify
+
+extern "C" {
+typedef char * va_list;
+}
+
+void test_no_arguments(int i, ...) {
+  __va_start(); // expected-error{{too few arguments to function call, expected at least 3, have 0}}
+}
+
+void test_one_argument(int i, ...) {
+  va_list ap;
+  __va_start(&ap); // expected-error{{too few arguments to function call, expected at least 3, have 1}}
+}
+
+void test_two_arguments(int i, ...) {
+  va_list ap;
+  __va_start(&ap, &i); // expected-error{{too few arguments to function call, expected at least 3, have 2}}
+}
+
+void test_non_last_argument(int i, int j, ...) {
+  va_list ap;
+  __va_start(&ap, &i, 4);
+  // expected-error at -1{{passing 'int *' to parameter of incompatible type 'const char *': type mismatch at 2nd parameter ('int *' vs 'const char *')}}
+  // expected-error at -2{{passing 'int' to parameter of incompatible type 'unsigned int': type mismatch at 3rd parameter ('int' vs 'unsigned int')}}
+}
+
+void test_stack_allocated(int i, ...) {
+  va_list ap;
+  int j;
+  __va_start(&ap, &j, 4);
+  // expected-error at -1{{passing 'int *' to parameter of incompatible type 'const char *': type mismatch at 2nd parameter ('int *' vs 'const char *')}}
+  // expected-error at -2{{passing 'int' to parameter of incompatible type 'unsigned int': type mismatch at 3rd parameter ('int' vs 'unsigned int')}}
+}
+
+void test_non_pointer_addressof(int i, ...) {
+  va_list ap;
+  __va_start(&ap, 1, 4);
+  // expected-error at -1{{passing 'int' to parameter of incompatible type 'const char *': type mismatch at 2nd parameter ('int' vs 'const char *')}}
+  // expected-error at -2{{passing 'int' to parameter of incompatible type 'unsigned int': type mismatch at 3rd parameter ('int' vs 'unsigned int')}}
+}
+

Added: cfe/trunk/test/SemaCXX/microsoft-varargs.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/SemaCXX/microsoft-varargs.cpp?rev=213595&view=auto
==============================================================================
--- cfe/trunk/test/SemaCXX/microsoft-varargs.cpp (added)
+++ cfe/trunk/test/SemaCXX/microsoft-varargs.cpp Mon Jul 21 21:01:04 2014
@@ -0,0 +1,22 @@
+// RUN: %clang_cc1 -triple thumbv7-windows -fms-compatibility -fsyntax-only %s -verify
+// expected-no-diagnostics
+
+extern "C" {
+typedef char * va_list;
+void __va_start(va_list *, ...);
+}
+
+int test___va_start(int i, ...) {
+  va_list ap;
+  __va_start(&ap, ( &reinterpret_cast<const char &>(i) ),
+             ( (sizeof(i) + 4 - 1) & ~(4 - 1) ),
+             ( &reinterpret_cast<const char &>(i) ));
+  return (*(int *)((ap += ( (sizeof(int) + 4 - 1) & ~(4 - 1) ) + ( ((va_list)0 - (ap)) & (__alignof(int) - 1) )) - ( (sizeof(int) + 4 - 1) & ~(4 - 1) )));
+}
+
+int builtin(int i, ...) {
+  __builtin_va_list ap;
+  __builtin_va_start(ap, i);
+  return __builtin_va_arg(ap, int);
+}
+





More information about the cfe-commits mailing list