if (Result.isInvalid())
return ExprError();
E = Result.take();
+ } else if (VaListType->isRecordType() && getLangOpts().CPlusPlus) {
+ // If va_list is a record type and we are compiling in C++ mode,
+ // check the argument using reference binding.
+ InitializedEntity Entity
+ = InitializedEntity::InitializeParameter(Context,
+ Context.getLValueReferenceType(VaListType), false);
+ ExprResult Init = PerformCopyInitialization(Entity, SourceLocation(), E);
+ if (Init.isInvalid())
+ return ExprError();
+ E = Init.takeAs<Expr>();
} else {
// Otherwise, the va_list argument must be an l-value because
// it is modified by va_arg.
--- /dev/null
+// RUN: %clang_cc1 -triple armv7 -fsyntax-only -verify %s
+
+// va_list on ARM AAPCS is struct { void* __ap }.
+int test1(const __builtin_va_list &ap) {
+ return __builtin_va_arg(ap, int); // expected-error {{binding of reference to type '__builtin_va_list' to a value of type 'const __builtin_va_list' drops qualifiers}}
+}
--- /dev/null
+// RUN: %clang_cc1 %s -ffreestanding
+// RUN: %clang_cc1 %s -ffreestanding -triple i686-unknown-linux
+// RUN: %clang_cc1 %s -ffreestanding -triple x86_64-unknown-linux
+// RUN: %clang_cc1 %s -ffreestanding -triple mips-unknown-linux
+// RUN: %clang_cc1 %s -ffreestanding -triple mipsel-unknown-linux
+// RUN: %clang_cc1 %s -ffreestanding -triple armv7-unknown-linux-gnueabi
+// RUN: %clang_cc1 %s -ffreestanding -triple thumbv7-unknown-linux-gnueabi
+
+#include "stdarg.h"
+
+int int_accumulator = 0;
+double double_accumulator = 0;
+
+int test_vprintf(const char *fmt, va_list ap) {
+ char ch;
+ int result = 0;
+ while (*fmt != '\0') {
+ ch = *fmt++;
+ if (ch != '%') {
+ continue;
+ }
+
+ ch = *fmt++;
+ switch (ch) {
+ case 'd':
+ int_accumulator += va_arg(ap, int);
+ result++;
+ break;
+
+ case 'f':
+ double_accumulator += va_arg(ap, double);
+ result++;
+ break;
+
+ default:
+ break;
+ }
+
+ if (ch == '0') {
+ break;
+ }
+ }
+ return result;
+}
+
+int test_printf(const char *fmt, ...) {
+ va_list ap;
+ va_start(ap, fmt);
+ int result = test_vprintf(fmt, ap);
+ va_end(ap);
+ return result;
+}