objective-c - llvm 从不同范围内定义的两个本地结构定义中选择第一个(错误的)本地结构定义 : is that llvm's bug?

标签 objective-c llvm objective-c++

我有以下示例代码:

@interface S1 : NSObject
{
    void(*fn_)();
}
@end
@implementation S1
- (void) set:(BOOL)f
{
    if (f)
    {
        struct A { static void f() { std::cout << "1" << std::endl; } };
        fn_ = A::f;
    }
    else
    {
        struct A { static void f() { std::cout << "2" << std::endl; } };
        fn_ = A::f;
    }
}
- (void) test { fn_(); }
@end

struct S2
{
    void set(BOOL f)
    {
        if (f)
        {
            struct A { static void f() { std::cout << "1" << std::endl; } };
            fn_ = A::f;
        }
        else
        {
            struct A { static void f() { std::cout << "2" << std::endl; } };
            fn_ = A::f;
        }
    }
    void test() { fn_(); }
    void(*fn_)();
};

int main(int argc, const char * argv[])
{
    auto s1 = [[S1 alloc] init];
    [s1 set:TRUE];
    [s1 test];
    [s1 set:FALSE];
    [s1 test];

    S2 s2;
    s2.set(TRUE);
    s2.test();
    s2.set(FALSE);
    s2.test();

    return 0;
}

打印

1
1
1
2

但我期待

1
2
1
2

如果我将第二个结构的名称更改为不同的名称(例如“B”),则始终按预期工作。

没有出现任何警告,因此很难找到程序无法正常运行的原因。

这是我的无知还是llvm的bug?

最佳答案

这确实看起来是一个 clang bug。 (需要注意的是,没有指定 Objective-C++ 语言的标准,所以什么是“正确”还有些悬而未决)

如果我不编译为可执行代码,而是使用这样的命令生成 LLVM IR

clang -g -std=c++11  -Wall -Wextra localstruct.mm  -emit-llvm -S

-set: 方法编译如下,突出显示两个函数指针赋值行:

define internal void @"\01-[S1 set:]"(%0* %self, i8* %_cmd, i8 signext %f) uwtable ssp {
  %1 = alloca %0*, align 8
  %2 = alloca i8*, align 8
  %3 = alloca i8, align 1
  store %0* %self, %0** %1, align 8
  call void @llvm.dbg.declare(metadata !{%0** %1}, metadata !1490), !dbg !1491
  store i8* %_cmd, i8** %2, align 8
  call void @llvm.dbg.declare(metadata !{i8** %2}, metadata !1492), !dbg !1491
  store i8 %f, i8* %3, align 1
  call void @llvm.dbg.declare(metadata !{i8* %3}, metadata !1493), !dbg !1494
  %4 = load i8* %3, align 1, !dbg !1495
  %5 = icmp ne i8 %4, 0, !dbg !1495
  br i1 %5, label %6, label %12, !dbg !1495

; <label>:6                                       ; preds = %0
  %7 = load %0** %1, align 8, !dbg !1497
  %8 = load i64* @"OBJC_IVAR_$_S1.fn_", !dbg !1497, !invariant.load !1499
  %9 = bitcast %0* %7 to i8*, !dbg !1497
  %10 = getelementptr inbounds i8* %9, i64 %8, !dbg !1497
  %11 = bitcast i8* %10 to void ()**, !dbg !1497

store void ()* @"_ZN10-[S1 set:]1A1fEv", void ()** %11,对齐 8,!dbg !1497

  br label %18, !dbg !1500

; <label>:12                                      ; preds = %0
  %13 = load %0** %1, align 8, !dbg !1501
  %14 = load i64* @"OBJC_IVAR_$_S1.fn_", !dbg !1501, !invariant.load !1499
  %15 = bitcast %0* %13 to i8*, !dbg !1501
  %16 = getelementptr inbounds i8* %15, i64 %14, !dbg !1501
  %17 = bitcast i8* %16 to void ()**, !dbg !1501

store void ()* @"_ZN10-[S1 set:]1A1fEv", void ()** %17,对齐 8,!dbg !1501

  br label %18

; <label>:18                                      ; preds = %12, %6
  ret void, !dbg !1503
}

这两种情况似乎都引用了相同的函数符号_ZN10-[S1 set:]1A1fEv。如果您查看结构中该方法的相应代码,它会引用两个:_ZZN2S23setEaEN1A1fEv_ZZN2S23setEaEN1A1fE_0v

FWIW,GCC 的 Objective-C++ 编译器产生了所需的结果。请务必向 clang 项目报告该错误,而不要只是解决代码中的问题。

关于objective-c - llvm 从不同范围内定义的两个本地结构定义中选择第一个(错误的)本地结构定义 : is that llvm's bug?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/12628892/

相关文章:

从另一个文件定义的 LLVM 插入函数调用

c++ - 通过命令行编译和链接 Swift/Objective-C++ 应用程序

c++ - 如何在 C++ 类中接收来自 Objective-C 的 NSNotifications?

iphone - 如何像 JetBlue iPhone 应用程序一样从屏幕外轻轻拖动面板

objective-c - 将 Reactive Cocoa doNext^ 转换为 Swift

objective-c - 我们可以将标签栏放在顶部>吗?

ios - Xcode:表达式不可分配

c++ - 如何在LLVM中删除无条件分支?

objective-c - 为什么具有负值的枚举会导致 Objective-C/C 出现问题?

c++ - stringstream sgetn 在 iOS 5.1 上返回 NULL