]> granicus.if.org Git - clang/commitdiff
[CodeGenObjCXX] Don't rematerialize default arguments of function
authorAkira Hatanaka <ahatanaka@apple.com>
Mon, 2 May 2016 21:52:57 +0000 (21:52 +0000)
committerAkira Hatanaka <ahatanaka@apple.com>
Mon, 2 May 2016 21:52:57 +0000 (21:52 +0000)
parameters in the body of a block.

This fixes a bug where clang would materialize the default argument
inside the body of a block instead of passing the value via the block
descriptor.

For example, in the code below, foo1 would always print 42 regardless
of the value of argument "a" passed to foo1.

void foo1(const int a = 42 ) {
  auto block = ^{
    printf("%d\n", a);
  };
  block();
}

rdar://problem/24449235

git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@268314 91177308-0d34-0410-b5e6-96231b3b80d8

lib/CodeGen/CGBlocks.cpp
test/CodeGenObjCXX/block-default-arg.mm [new file with mode: 0644]

index ea164aad915afea3fd09230721dc331892eb03bc..88786bc9fcf22e7cf4c6b0216cfaf4f2116e943a 100644 (file)
@@ -262,6 +262,11 @@ static bool isSafeForCXXConstantCapture(QualType type) {
 static llvm::Constant *tryCaptureAsConstant(CodeGenModule &CGM,
                                             CodeGenFunction *CGF,
                                             const VarDecl *var) {
+  // Don't rematerialize default arguments of function parameters.
+  if (auto *PD = dyn_cast<ParmVarDecl>(var))
+    if (PD->hasDefaultArg())
+      return nullptr;
+
   QualType type = var->getType();
 
   // We can only do this if the variable is const.
diff --git a/test/CodeGenObjCXX/block-default-arg.mm b/test/CodeGenObjCXX/block-default-arg.mm
new file mode 100644 (file)
index 0000000..167b31d
--- /dev/null
@@ -0,0 +1,16 @@
+// RUN: %clang_cc1 -triple x86_64-apple-darwin10.0.0 -emit-llvm -o - %s -std=c++11 -fblocks -fobjc-arc | FileCheck  %s
+
+// CHECK: define internal void @___Z16test_default_argi_block_invoke(i8* %[[BLOCK_DESCRIPTOR:.*]])
+// CHECK: %[[BLOCK:.*]] = bitcast i8* %[[BLOCK_DESCRIPTOR]] to <{ i8*, i32, i32, i8*, %struct.__block_descriptor*, i32 }>*
+// CHECK: %[[BLOCK_CAPTURE_ADDR:.*]] = getelementptr inbounds <{ i8*, i32, i32, i8*, %struct.__block_descriptor*, i32 }>, <{ i8*, i32, i32, i8*, %struct.__block_descriptor*, i32 }>* %[[BLOCK]], i32 0, i32 5
+// CHECK: %[[V0:.*]] = load i32, i32* %[[BLOCK_CAPTURE_ADDR]]
+// CHECK: call void @_Z4foo1i(i32 %[[V0]])
+
+void foo1(int);
+
+void test_default_arg(const int a = 42) {
+  auto block = ^{
+    foo1(a);
+  };
+  block();
+}