assert(E->getObjectKind() == OK_Ordinary);
// Rebuild the function type, replacing the result type with DestType.
- if (const FunctionProtoType *Proto = dyn_cast<FunctionProtoType>(FnType))
- DestType = S.Context.getFunctionType(DestType, Proto->getArgTypes(),
+ const FunctionProtoType *Proto = dyn_cast<FunctionProtoType>(FnType);
+ if (Proto) {
+ // __unknown_anytype(...) is a special case used by the debugger when
+ // it has no idea what a function's signature is.
+ //
+ // We want to build this call essentially under the K&R
+ // unprototyped rules, but making a FunctionNoProtoType in C++
+ // would foul up all sorts of assumptions. However, we cannot
+ // simply pass all arguments as variadic arguments, nor can we
+ // portably just call the function under a non-variadic type; see
+ // the comment on IR-gen's TargetInfo::isNoProtoCallVariadic.
+ // However, it turns out that in practice it is generally safe to
+ // call a function declared as "A foo(B,C,D);" under the prototype
+ // "A foo(B,C,D,...);". The only known exception is with the
+ // Windows ABI, where any variadic function is implicitly cdecl
+ // regardless of its normal CC. Therefore we change the parameter
+ // types to match the types of the arguments.
+ //
+ // This is a hack, but it is far superior to moving the
+ // corresponding target-specific code from IR-gen to Sema/AST.
+
+ ArrayRef<QualType> ParamTypes = Proto->getArgTypes();
+ SmallVector<QualType, 8> ArgTypes;
+ if (ParamTypes.empty() && Proto->isVariadic()) { // the special case
+ ArgTypes.reserve(E->getNumArgs());
+ for (unsigned i = 0, e = E->getNumArgs(); i != e; ++i) {
+ Expr *Arg = E->getArg(i);
+ QualType ArgType = Arg->getType();
+ if (E->isLValue()) {
+ ArgType = S.Context.getLValueReferenceType(ArgType);
+ } else if (E->isXValue()) {
+ ArgType = S.Context.getRValueReferenceType(ArgType);
+ }
+ ArgTypes.push_back(ArgType);
+ }
+ ParamTypes = ArgTypes;
+ }
+ DestType = S.Context.getFunctionType(DestType, ParamTypes,
Proto->getExtProtoInfo());
- else
+ } else {
DestType = S.Context.getFunctionNoProtoType(DestType,
FnType->getExtInfo());
+ }
// Rebuild the appropriate pointer-to-function type.
switch (Kind) {
return ExprError();
}
+ // Modifying the declaration like this is friendly to IR-gen but
+ // also really dangerous.
VD->setType(DestType);
E->setType(Type);
E->setValueKind(ValueKind);
-// RUN: %clang_cc1 -triple x86_64-apple-darwin10 -funknown-anytype -emit-llvm -o - %s | FileCheck %s
+// RUN: %clang_cc1 -triple x86_64-apple-darwin10 -funknown-anytype -emit-llvm -o %t %s
+// RUN: FileCheck -check-prefix COMMON %s < %t
+// RUN: FileCheck -check-prefix X86_64 %s < %t
+// RUN: %clang_cc1 -triple i386-apple-darwin10 -funknown-anytype -emit-llvm -o %t %s
+// RUN: FileCheck -check-prefix COMMON %s < %t
+// RUN: FileCheck -check-prefix I386 %s < %t
+
+// x86-64 is the special case here because of its variadic convention.
+// We want to ensure that it always uses a variadic convention even if
+// other platforms do not.
+// rdar://13731520
int test0() {
extern __unknown_anytype test0_any;
- // CHECK: load i32* @test0_any
+ // COMMON: load i32* @test0_any
return (int) test0_any;
}
int test1() {
extern __unknown_anytype test1_any();
- // CHECK: call i32 @_Z9test1_anyv()
+ // COMMON: call i32 @_Z9test1_anyv()
return (int) test1_any();
}
extern "C" __unknown_anytype test2_any(...);
float test2() {
- // CHECK: call float (...)* @test2_any(double {{[^,]+}})
+ // X86_64: call float (double, ...)* @test2_any(double {{[^,]+}})
+ // I386: call float (double, ...)* @test2_any(double {{[^,]+}})
return (float) test2_any(0.5f);
}
extern "C" __unknown_anytype test2a_any(...);
float test2a() {
- // CHECK: call float (...)* @test2a_any(float {{[^,]+}})
+ // X86_64: call float (float, ...)* @test2a_any(float {{[^,]+}})
+ // I386: call float (float, ...)* @test2a_any(float {{[^,]+}})
return (float) test2a_any((float) 0.5f);
}
float test3() {
extern __unknown_anytype test3_any;
- // CHECK: [[FN:%.*]] = load float (i32)** @test3_any,
- // CHECK: call float [[FN]](i32 5)
+ // COMMON: [[FN:%.*]] = load float (i32)** @test3_any,
+ // COMMON: call float [[FN]](i32 5)
return ((float(*)(int)) test3_any)(5);
}
extern __unknown_anytype test4_any2;
int test() {
- // CHECK: load i32* @_ZN5test410test4_any1E
- // CHECK: load i8* @_ZN5test410test4_any2E
+ // COMMON: load i32* @_ZN5test410test4_any1E
+ // COMMON: load i8* @_ZN5test410test4_any2E
return (int) test4_any1 + (char) test4_any2;
}
}
extern "C" __unknown_anytype test5_any();
void test5() {
- // CHECK: call void @test5_any()
+ // COMMON: call void @test5_any()
return (void) test5_any();
}
extern "C" __unknown_anytype test6_any(float *);
long test6() {
- // CHECK: call i64 @test6_any(float* null)
- return (long) test6_any(0);
+ // COMMON: call i64 @test6_any(float* null)
+ return (long long) test6_any(0);
}
struct Test7 {
};
extern "C" __unknown_anytype test7_any(int);
Test7 test7() {
- // CHECK: call void @test7_any({{%.*}}* sret {{%.*}}, i32 5)
+ // COMMON: call void @test7_any({{%.*}}* sret {{%.*}}, i32 5)
return (Test7) test7_any(5);
}
};
void Test8::test() {
float f;
- // CHECK: call i32 @_ZN5Test83fooEv(
+ // COMMON: call i32 @_ZN5Test83fooEv(
f = (int) foo();
- // CHECK: call i32 @_ZN5Test83fooEi(
+ // COMMON: call i32 @_ZN5Test83fooEi(
f = (int) foo(5);
- // CHECK: call i32 @_ZN5Test83fooEv(
+ // COMMON: call i32 @_ZN5Test83fooEv(
f = (float) this->foo();
- // CHECK: call i32 @_ZN5Test83fooEi(
+ // COMMON: call i32 @_ZN5Test83fooEi(
f = (float) this->foo(5);
}
void test8(Test8 *p) {
double d;
- // CHECK: call i32 @_ZN5Test83fooEv(
+ // COMMON: call i32 @_ZN5Test83fooEv(
d = (double) p->foo();
- // CHECK: call i32 @_ZN5Test83fooEi(
+ // COMMON: call i32 @_ZN5Test83fooEi(
d = (double) p->foo(5);
- // CHECK: call i32 @_ZN5Test83fooEv(
+ // COMMON: call i32 @_ZN5Test83fooEv(
d = (bool) (*p).foo();
- // CHECK: call i32 @_ZN5Test83fooEi(
+ // COMMON: call i32 @_ZN5Test83fooEi(
d = (bool) (*p).foo(5);
}
extern "C" __unknown_anytype test9_foo;
void *test9() {
- // CHECK: ret i8* bitcast (i32* @test9_foo to i8*)
+ // COMMON: ret i8* bitcast (i32* @test9_foo to i8*)
return (int*) &test9_foo;
}
+
+// Don't explode on this.
+extern "C" __unknown_anytype test10_any(...);
+void test10() {
+ (void) test10_any(), (void) test10_any();
+}