r185112 - Ensure that debugger calls to signature-less functions default to

John McCall rjmccall at apple.com
Thu Jun 27 15:43:24 PDT 2013


Author: rjmccall
Date: Thu Jun 27 17:43:24 2013
New Revision: 185112

URL: http://llvm.org/viewvc/llvm-project?rev=185112&view=rev
Log:
Ensure that debugger calls to signature-less functions default to
passing arguments in the fixed style.

We have an abstraction for deciding this, but it's (1) deep in
IR-generation, (2) necessarily tied to exact argument lists, and
(3) triggered by unprototyped function types, which we can't
legitimately make in C++ mode.  So this solution, wherein Sema
rewrites the function type to an exact prototype but leaves the
variadic bit enabled so as to request x86-64-like platforms to
pass the extra variadic info, is very much a hack, but it's one
that works in practice on the platforms that LLDB will support
in the medium term --- the only place we know of where it's a
problem is instance methods in Windows, where variadic functions
are implicitly cdecl.  We may have a more abstracted base on which
to build a solution by then.

rdar://13731520

Modified:
    cfe/trunk/lib/CodeGen/TargetInfo.h
    cfe/trunk/lib/Sema/SemaExpr.cpp
    cfe/trunk/test/CodeGenCXX/unknown-anytype.cpp

Modified: cfe/trunk/lib/CodeGen/TargetInfo.h
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/CodeGen/TargetInfo.h?rev=185112&r1=185111&r2=185112&view=diff
==============================================================================
--- cfe/trunk/lib/CodeGen/TargetInfo.h (original)
+++ cfe/trunk/lib/CodeGen/TargetInfo.h Thu Jun 27 17:43:24 2013
@@ -171,6 +171,13 @@ namespace clang {
     /// arguments in %al.  On these platforms, it is desireable to
     /// call unprototyped functions using the variadic convention so
     /// that unprototyped calls to varargs functions still succeed.
+    ///
+    /// Relatedly, platforms which pass the fixed arguments to this:
+    ///   A foo(B, C, D);
+    /// differently than they would pass them to this:
+    ///   A foo(B, C, D, ...);
+    /// may need to adjust the debugger-support code in Sema to do the
+    /// right thing when calling a function with no know signature.
     virtual bool isNoProtoCallVariadic(const CodeGen::CallArgList &args,
                                        const FunctionNoProtoType *fnType) const;
 

Modified: cfe/trunk/lib/Sema/SemaExpr.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Sema/SemaExpr.cpp?rev=185112&r1=185111&r2=185112&view=diff
==============================================================================
--- cfe/trunk/lib/Sema/SemaExpr.cpp (original)
+++ cfe/trunk/lib/Sema/SemaExpr.cpp Thu Jun 27 17:43:24 2013
@@ -12200,12 +12200,49 @@ ExprResult RebuildUnknownAnyExpr::VisitC
   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) { 
@@ -12338,6 +12375,8 @@ ExprResult RebuildUnknownAnyExpr::resolv
     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);

Modified: cfe/trunk/test/CodeGenCXX/unknown-anytype.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/CodeGenCXX/unknown-anytype.cpp?rev=185112&r1=185111&r2=185112&view=diff
==============================================================================
--- cfe/trunk/test/CodeGenCXX/unknown-anytype.cpp (original)
+++ cfe/trunk/test/CodeGenCXX/unknown-anytype.cpp Thu Jun 27 17:43:24 2013
@@ -1,33 +1,45 @@
-// 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);
 }
 
@@ -36,22 +48,22 @@ namespace test4 {
   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 {
@@ -59,7 +71,7 @@ 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);
 }
 
@@ -71,29 +83,35 @@ struct Test8 {
 };
 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();
+}





More information about the cfe-commits mailing list