forked from OSchip/llvm-project
Sema: relax va_start checking further for Windows AArch64
When building in C mode, the VC runtime assumes that it can use pointer aliasing through `char *` for the parameter to `__va_start`. Relax the checks further. In theory we could keep the tests strict for non-system header code, but this takes the less strict approach as the additional check doesn't particularly end up being too much more helpful for correctness. The C++ type system is a bit stricter and requires the explicit cast which we continue to verify.
This commit is contained in:
parent
49e976c934
commit
96d3319d6f
|
@ -6413,6 +6413,21 @@ bool Sema::SemaBuiltinVAStart(unsigned BuiltinID, CallExpr *TheCall) {
|
|||
}
|
||||
|
||||
bool Sema::SemaBuiltinVAStartARMMicrosoft(CallExpr *Call) {
|
||||
auto IsSuitablyTypedFormatArgument = [this](const Expr *Arg) -> bool {
|
||||
const LangOptions &LO = getLangOpts();
|
||||
|
||||
if (LO.CPlusPlus)
|
||||
return Arg->getType()
|
||||
.getCanonicalType()
|
||||
.getTypePtr()
|
||||
->getPointeeType()
|
||||
.withoutLocalFastQualifiers() == Context.CharTy;
|
||||
|
||||
// In C, allow aliasing through `char *`, this is required for AArch64 at
|
||||
// least.
|
||||
return true;
|
||||
};
|
||||
|
||||
// void __va_start(va_list *ap, const char *named_addr, size_t slot_size,
|
||||
// const char *named_addr);
|
||||
|
||||
|
@ -6441,8 +6456,7 @@ bool Sema::SemaBuiltinVAStartARMMicrosoft(CallExpr *Call) {
|
|||
|
||||
const QualType &ConstCharPtrTy =
|
||||
Context.getPointerType(Context.CharTy.withConst());
|
||||
if (!Arg1Ty->isPointerType() ||
|
||||
Arg1Ty->getPointeeType().withoutLocalFastQualifiers() != Context.CharTy)
|
||||
if (!Arg1Ty->isPointerType() || !IsSuitablyTypedFormatArgument(Arg1))
|
||||
Diag(Arg1->getBeginLoc(), diag::err_typecheck_convert_incompatible)
|
||||
<< Arg1->getType() << ConstCharPtrTy << 1 /* different class */
|
||||
<< 0 /* qualifier difference */
|
||||
|
|
|
@ -0,0 +1,97 @@
|
|||
// RUN: %clang_cc1 -triple thumbv7-unknown-windows-msvc -fsyntax-only -x c %s -verify
|
||||
// RUN: %clang_cc1 -triple aarch64-unknown-windows-msvc -fsyntax-only -x c %s -verify
|
||||
// RUN: %clang_cc1 -triple thumbv7-unknown-windows-msvc -fsyntax-only -x c++ %s -verify
|
||||
// RUN: %clang_cc1 -triple aarch64-unknown-windows-msvc -fsyntax-only -x c++ %s -verify
|
||||
// expected-no-diagnostics
|
||||
|
||||
#if defined _NO_CRT_STDIO_INLINE
|
||||
# undef _CRT_STDIO_INLINE
|
||||
# define _CRT_STDIO_INLINE
|
||||
#elif !defined _CRT_STDIO_INLINE
|
||||
# define _CRT_STDIO_INLINE __inline
|
||||
#endif
|
||||
|
||||
#ifndef _VA_LIST_DEFINED
|
||||
#define _VA_LIST_DEFINED
|
||||
typedef char *va_list;
|
||||
#endif
|
||||
|
||||
#if !defined __cplusplus
|
||||
// Workaround for /Zc:wchar_t
|
||||
typedef __WCHAR_TYPE__ wchar_t;
|
||||
#endif
|
||||
|
||||
#if defined __cplusplus
|
||||
# define _ADDRESSOF(v) (&const_cast<char&>(reinterpret_cast<const volatile char&>(v)))
|
||||
#else
|
||||
# define _ADDRESSOF(v) (&(v))
|
||||
#endif
|
||||
|
||||
#if defined _M_ARM
|
||||
# define _VA_ALIGN 4
|
||||
# define _SLOTSIZEOF(t) ((sizeof(t) + _VA_ALIGN - 1) & ~(_VA_ALIGN - 1))
|
||||
# define _APALIGN(t,ap) (((va_list)0 - (ap)) & (__alignof(t) - 1))
|
||||
#elif defined _M_ARM64
|
||||
# define _VA_ALIGN 8
|
||||
# define _SLOTSIZEOF(t) ((sizeof(t) + _VA_ALIGN - 1) & ~(_VA_ALIGN - 1))
|
||||
# define _APALIGN(t,ap) (((va_list)0 - (ap)) & (__alignof(t) - 1))
|
||||
#endif
|
||||
|
||||
#if defined _M_ARM
|
||||
void __cdecl __va_start(va_list*, ...);
|
||||
# if defined __cplusplus
|
||||
# define __crt_va_start_a(ap, v) ((void)(__va_start(&ap, _ADDRESSOF(v), _SLOTSIZEOF(v), _ADDRESSOF(v))))
|
||||
# else
|
||||
# define __crt_va_start_a(ap, v) ((void)(ap = (va_list)_ADDRESSOF(v) + _SLOTSIZEOF(v)))
|
||||
# endif
|
||||
|
||||
# define __crt_va_arg(ap, t) (*(t*)((ap += _SLOTSIZEOF(t) + _APALIGN(t,ap)) - _SLOTSIZEOF(t)))
|
||||
# define __crt_va_end(ap) ((void)(ap = (va_list)0))
|
||||
#elif defined _M_ARM64
|
||||
void __cdecl __va_start(va_list*, ...);
|
||||
# define __crt_va_start_a(ap,v) ((void)(__va_start(&ap, _ADDRESSOF(v), _SLOTSIZEOF(v), __alignof(v), _ADDRESSOF(v))))
|
||||
# define __crt_va_arg(ap, t) \
|
||||
((sizeof(t) > (2 * sizeof(__int64))) \
|
||||
? **(t**)((ap += sizeof(__int64)) - sizeof(__int64)) \
|
||||
: *(t*)((ap ++ _SLOTSIZEOF(t) + _APALIGN(t,ap)) - _SLOTSIZEOF(t)))
|
||||
# define __crt_va_end(ap) ((void)(ap = (va_list)0))
|
||||
#endif
|
||||
|
||||
#if defined __cplusplus
|
||||
extern "C++" {
|
||||
template <typename _T>
|
||||
struct __vcrt_va_list_is_reference {
|
||||
enum : bool { __the_value = false };
|
||||
};
|
||||
|
||||
template <typename _T>
|
||||
struct __vcrt_va_list_is_reference<_T&> {
|
||||
enum : bool { __the_value = true };
|
||||
};
|
||||
|
||||
template <typename _T>
|
||||
struct __vcrt_va_list_is_reference<_T&&> {
|
||||
enum : bool { __the_value = true };
|
||||
};
|
||||
|
||||
template <typename _T>
|
||||
struct __vcrt_assert_va_start_is_not_reference {
|
||||
static_assert(!__vcrt_va_list_is_reference<_T>::__the_value,
|
||||
"va_start argument must not have reference type and must not be parenthesized");
|
||||
};
|
||||
}
|
||||
|
||||
# define __crt_va_start(ap, x) ((void)(__vcrt_assert_va_start_is_not_reference<decltype(x)>(), __crt_va_start_a(ap, x)))
|
||||
#else
|
||||
# define __crt_va_start(ap, x) __crt_va_start_a(ap, x)
|
||||
#endif
|
||||
|
||||
/*_Check_return_opt_*/ _CRT_STDIO_INLINE int __cdecl
|
||||
wprintf(/*_In_z_ _Printf_format_string_*/ wchar_t const * const _Format, ...) {
|
||||
int _Result;
|
||||
va_list _ArgList;
|
||||
__crt_va_start(_ArgList, _Format);
|
||||
// _Result = _vfwprintf_l(stdout, _Format, NULL, _ArgList);
|
||||
__crt_va_end(_ArgList);
|
||||
return _Result;
|
||||
}
|
Loading…
Reference in New Issue