Skip to content

Commit 4579272

Browse files
committed
[clang][RISCV] Introduce command line options for Zicfilp-backed forward-edge CFI
This patch enables the following command line flags for RISC-V targets: + `-fcf-protection=branch` turns on forward-edge control-flow integrity conditioning on RISC-V targets with Zicfilp extension + `-mcf-branch-label-scheme=unlabeled|func-sig` selects the label scheme used in the forward-edge CFI conditioning
1 parent ea902d1 commit 4579272

File tree

14 files changed

+249
-0
lines changed

14 files changed

+249
-0
lines changed
Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,15 @@
1+
//===-- CFProtectionOptions.def - cf-protection options ---------*- C++ -*-===//
2+
//
3+
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4+
// See https://llvm.org/LICENSE.txt for license information.
5+
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6+
//
7+
//===----------------------------------------------------------------------===//
8+
9+
10+
#ifdef CF_BRANCH_LABEL_SCHEME
11+
CF_BRANCH_LABEL_SCHEME(Unlabeled, unlabeled)
12+
CF_BRANCH_LABEL_SCHEME(FuncSig, func-sig)
13+
14+
#undef CF_BRANCH_LABEL_SCHEME
15+
#endif // #ifdef CF_BRANCH_LABEL_SCHEME
Lines changed: 38 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,38 @@
1+
//===--- CFProtectionOptions.h ----------------------------------*- C++ -*-===//
2+
//
3+
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4+
// See https://llvm.org/LICENSE.txt for license information.
5+
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6+
//
7+
//===----------------------------------------------------------------------===//
8+
//
9+
// This file defines constants for -fcf-protection and other related flags.
10+
//
11+
//===----------------------------------------------------------------------===//
12+
13+
#ifndef LLVM_CLANG_BASIC_CFPROTECTIONOPTIONS_H
14+
#define LLVM_CLANG_BASIC_CFPROTECTIONOPTIONS_H
15+
16+
#include "llvm/Support/ErrorHandling.h"
17+
18+
namespace clang {
19+
20+
enum class CFBranchLabelSchemeKind {
21+
Default,
22+
#define CF_BRANCH_LABEL_SCHEME(Kind, FlagVal) Kind,
23+
#include "clang/Basic/CFProtectionOptions.def"
24+
};
25+
26+
static inline const char *
27+
getCFBranchLabelSchemeFlagVal(const CFBranchLabelSchemeKind Scheme) {
28+
#define CF_BRANCH_LABEL_SCHEME(Kind, FlagVal) \
29+
if (Scheme == CFBranchLabelSchemeKind::Kind) \
30+
return #FlagVal;
31+
#include "clang/Basic/CFProtectionOptions.def"
32+
33+
llvm::report_fatal_error("invalid scheme");
34+
}
35+
36+
} // namespace clang
37+
38+
#endif // #ifndef LLVM_CLANG_BASIC_CFPROTECTIONOPTIONS_H

clang/include/clang/Basic/CodeGenOptions.def

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -110,6 +110,8 @@ CODEGENOPT(CFProtectionReturn , 1, 0) ///< if -fcf-protection is
110110
///< set to full or return.
111111
CODEGENOPT(CFProtectionBranch , 1, 0) ///< if -fcf-protection is
112112
///< set to full or branch.
113+
ENUM_CODEGENOPT(CFBranchLabelScheme, CFBranchLabelSchemeKind, 2,
114+
CFBranchLabelSchemeKind::Default) ///< if -mcf-branch-label-scheme is set.
113115
CODEGENOPT(FunctionReturnThunks, 1, 0) ///< -mfunction-return={keep|thunk-extern}
114116
CODEGENOPT(IndirectBranchCSPrefix, 1, 0) ///< if -mindirect-branch-cs-prefix
115117
///< is set.

clang/include/clang/Basic/CodeGenOptions.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,7 @@
1313
#ifndef LLVM_CLANG_BASIC_CODEGENOPTIONS_H
1414
#define LLVM_CLANG_BASIC_CODEGENOPTIONS_H
1515

16+
#include "clang/Basic/CFProtectionOptions.h"
1617
#include "clang/Basic/PointerAuthOptions.h"
1718
#include "clang/Basic/Sanitizers.h"
1819
#include "clang/Basic/XRayInstr.h"

clang/include/clang/Basic/LangOptions.def

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -364,6 +364,8 @@ BENIGN_LANGOPT(CompatibilityQualifiedIdBlockParamTypeChecking, 1, 0,
364364
LANGOPT(ObjCDisableDirectMethodsForTesting, 1, 0,
365365
"Disable recognition of objc_direct methods")
366366
LANGOPT(CFProtectionBranch , 1, 0, "Control-Flow Branch Protection enabled")
367+
ENUM_LANGOPT(CFBranchLabelScheme, CFBranchLabelSchemeKind, 2, CFBranchLabelSchemeKind::Default,
368+
"Control-Flow Branch Protection Label Scheme")
367369
LANGOPT(FakeAddressSpaceMap , 1, 0, "OpenCL fake address space map")
368370
ENUM_LANGOPT(AddressSpaceMapMangling , AddrSpaceMapMangling, 2, ASMM_Target, "OpenCL address space map mangling mode")
369371
LANGOPT(IncludeDefaultHeader, 1, 0, "Include default header file for OpenCL")

clang/include/clang/Basic/LangOptions.h

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,7 @@
1414
#ifndef LLVM_CLANG_BASIC_LANGOPTIONS_H
1515
#define LLVM_CLANG_BASIC_LANGOPTIONS_H
1616

17+
#include "clang/Basic/CFProtectionOptions.h"
1718
#include "clang/Basic/CommentOptions.h"
1819
#include "clang/Basic/LLVM.h"
1920
#include "clang/Basic/LangStandard.h"
@@ -73,6 +74,7 @@ class LangOptionsBase {
7374
public:
7475
using Visibility = clang::Visibility;
7576
using RoundingMode = llvm::RoundingMode;
77+
using CFBranchLabelSchemeKind = clang::CFBranchLabelSchemeKind;
7678

7779
enum GCMode { NonGC, GCOnly, HybridGC };
7880
enum StackProtectorMode { SSPOff, SSPOn, SSPStrong, SSPReq };

clang/include/clang/Basic/TargetInfo.h

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,7 @@
1616

1717
#include "clang/Basic/AddressSpaces.h"
1818
#include "clang/Basic/BitmaskEnum.h"
19+
#include "clang/Basic/CFProtectionOptions.h"
1920
#include "clang/Basic/CodeGenOptions.h"
2021
#include "clang/Basic/LLVM.h"
2122
#include "clang/Basic/LangOptions.h"
@@ -1727,6 +1728,13 @@ class TargetInfo : public TransferrableTargetInfo,
17271728
virtual bool
17281729
checkCFProtectionBranchSupported(DiagnosticsEngine &Diags) const;
17291730

1731+
/// Get the target default CFBranchLabelScheme scheme
1732+
virtual CFBranchLabelSchemeKind getDefaultCFBranchLabelScheme() const;
1733+
1734+
virtual bool
1735+
checkCFBranchLabelSchemeSupported(const CFBranchLabelSchemeKind Scheme,
1736+
DiagnosticsEngine &Diags) const;
1737+
17301738
/// Check if the target supports CFProtection return.
17311739
virtual bool
17321740
checkCFProtectionReturnSupported(DiagnosticsEngine &Diags) const;

clang/include/clang/Driver/Options.td

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2841,6 +2841,10 @@ def fcf_protection : Flag<["-"], "fcf-protection">, Group<f_Group>,
28412841
Visibility<[ClangOption, CLOption, CC1Option]>,
28422842
Alias<fcf_protection_EQ>, AliasArgs<["full"]>,
28432843
HelpText<"Enable cf-protection in 'full' mode">;
2844+
def mcf_branch_label_scheme_EQ : Joined<["-"], "mcf-branch-label-scheme=">,
2845+
Visibility<[ClangOption, CC1Option]>, Group<m_Group>,
2846+
HelpText<"Select label scheme for branch control-flow architecture protection">,
2847+
Values<"unlabeled,func-sig">;
28442848
def mfunction_return_EQ : Joined<["-"], "mfunction-return=">,
28452849
Group<m_Group>, Visibility<[ClangOption, CLOption, CC1Option]>,
28462850
HelpText<"Replace returns with jumps to ``__x86_return_thunk`` (x86 only, error otherwise)">,

clang/lib/Basic/TargetInfo.cpp

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -198,6 +198,21 @@ TargetInfo::checkCFProtectionBranchSupported(DiagnosticsEngine &Diags) const {
198198
return false;
199199
}
200200

201+
CFBranchLabelSchemeKind TargetInfo::getDefaultCFBranchLabelScheme() const {
202+
// if this hook is called, the target should override it to return a
203+
// non-default scheme
204+
llvm::report_fatal_error("not implemented");
205+
}
206+
207+
bool TargetInfo::checkCFBranchLabelSchemeSupported(
208+
const CFBranchLabelSchemeKind Scheme, DiagnosticsEngine &Diags) const {
209+
Diags.Report(diag::err_opt_not_valid_on_target)
210+
<< (Twine("mcf-branch-label-scheme=") +
211+
getCFBranchLabelSchemeFlagVal(Scheme))
212+
.str();
213+
return false;
214+
}
215+
201216
bool
202217
TargetInfo::checkCFProtectionReturnSupported(DiagnosticsEngine &Diags) const {
203218
Diags.Report(diag::err_opt_not_valid_on_target) << "cf-protection=return";

clang/lib/Basic/Targets/RISCV.h

Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -134,6 +134,28 @@ class RISCVTargetInfo : public TargetInfo {
134134

135135
bool validateGlobalRegisterVariable(StringRef RegName, unsigned RegSize,
136136
bool &HasSizeMismatch) const override;
137+
138+
bool checkCFProtectionBranchSupported(DiagnosticsEngine &) const override {
139+
// Always generate Zicfilp lpad insns
140+
// Non-zicfilp CPUs would read them as NOP
141+
return true;
142+
}
143+
144+
CFBranchLabelSchemeKind getDefaultCFBranchLabelScheme() const override {
145+
return CFBranchLabelSchemeKind::FuncSig;
146+
}
147+
148+
bool
149+
checkCFBranchLabelSchemeSupported(const CFBranchLabelSchemeKind Scheme,
150+
DiagnosticsEngine &Diags) const override {
151+
switch (Scheme) {
152+
case CFBranchLabelSchemeKind::Default:
153+
case CFBranchLabelSchemeKind::Unlabeled:
154+
case CFBranchLabelSchemeKind::FuncSig:
155+
return true;
156+
}
157+
return TargetInfo::checkCFBranchLabelSchemeSupported(Scheme, Diags);
158+
}
137159
};
138160
class LLVM_LIBRARY_VISIBILITY RISCV32TargetInfo : public RISCVTargetInfo {
139161
public:

clang/lib/CodeGen/CodeGenModule.cpp

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1164,6 +1164,16 @@ void CodeGenModule::Release() {
11641164
// Indicate that we want to instrument branch control flow protection.
11651165
getModule().addModuleFlag(llvm::Module::Min, "cf-protection-branch",
11661166
1);
1167+
1168+
auto Scheme = CodeGenOpts.getCFBranchLabelScheme();
1169+
if (Target.checkCFBranchLabelSchemeSupported(Scheme, getDiags())) {
1170+
if (Scheme == CFBranchLabelSchemeKind::Default)
1171+
Scheme = Target.getDefaultCFBranchLabelScheme();
1172+
getModule().addModuleFlag(
1173+
llvm::Module::Error, "cf-branch-label-scheme",
1174+
llvm::MDString::get(getLLVMContext(),
1175+
getCFBranchLabelSchemeFlagVal(Scheme)));
1176+
}
11671177
}
11681178

11691179
if (CodeGenOpts.FunctionReturnThunks)

clang/lib/Driver/ToolChains/Clang.cpp

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7012,6 +7012,10 @@ void Clang::ConstructJob(Compilation &C, const JobAction &JA,
70127012
if (Arg *A = Args.getLastArg(options::OPT_fcf_protection_EQ)) {
70137013
CmdArgs.push_back(
70147014
Args.MakeArgString(Twine("-fcf-protection=") + A->getValue()));
7015+
7016+
if (Arg *SA = Args.getLastArg(options::OPT_mcf_branch_label_scheme_EQ))
7017+
CmdArgs.push_back(Args.MakeArgString(Twine("-mcf-branch-label-scheme=") +
7018+
SA->getValue()));
70157019
}
70167020

70177021
if (Arg *A = Args.getLastArg(options::OPT_mfunction_return_EQ))

clang/lib/Frontend/CompilerInvocation.cpp

Lines changed: 40 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1688,6 +1688,18 @@ void CompilerInvocationBase::GenerateCodeGenArgs(const CodeGenOptions &Opts,
16881688
else if (Opts.CFProtectionBranch)
16891689
GenerateArg(Consumer, OPT_fcf_protection_EQ, "branch");
16901690

1691+
if (Opts.CFProtectionBranch) {
1692+
switch (Opts.getCFBranchLabelScheme()) {
1693+
case CFBranchLabelSchemeKind::Default:
1694+
break;
1695+
#define CF_BRANCH_LABEL_SCHEME(Kind, FlagVal) \
1696+
case CFBranchLabelSchemeKind::Kind: \
1697+
GenerateArg(Consumer, OPT_mcf_branch_label_scheme_EQ, #FlagVal); \
1698+
break;
1699+
#include "clang/Basic/CFProtectionOptions.def"
1700+
}
1701+
}
1702+
16911703
if (Opts.FunctionReturnThunks)
16921704
GenerateArg(Consumer, OPT_mfunction_return_EQ, "thunk-extern");
16931705

@@ -2022,6 +2034,22 @@ bool CompilerInvocation::ParseCodeGenArgs(CodeGenOptions &Opts, ArgList &Args,
20222034
Diags.Report(diag::err_drv_invalid_value) << A->getAsString(Args) << Name;
20232035
}
20242036

2037+
if (Opts.CFProtectionBranch && T.isRISCV()) {
2038+
if (const Arg *A = Args.getLastArg(OPT_mcf_branch_label_scheme_EQ)) {
2039+
const auto Scheme =
2040+
llvm::StringSwitch<CFBranchLabelSchemeKind>(A->getValue())
2041+
#define CF_BRANCH_LABEL_SCHEME(Kind, FlagVal) \
2042+
.Case(#FlagVal, CFBranchLabelSchemeKind::Kind)
2043+
#include "clang/Basic/CFProtectionOptions.def"
2044+
.Default(CFBranchLabelSchemeKind::Default);
2045+
if (Scheme != CFBranchLabelSchemeKind::Default)
2046+
Opts.setCFBranchLabelScheme(Scheme);
2047+
else
2048+
Diags.Report(diag::err_drv_invalid_value)
2049+
<< A->getAsString(Args) << A->getValue();
2050+
}
2051+
}
2052+
20252053
if (const Arg *A = Args.getLastArg(OPT_mfunction_return_EQ)) {
20262054
auto Val = llvm::StringSwitch<llvm::FunctionReturnThunksKind>(A->getValue())
20272055
.Case("keep", llvm::FunctionReturnThunksKind::Keep)
@@ -3952,6 +3980,18 @@ bool CompilerInvocation::ParseLangArgs(LangOptions &Opts, ArgList &Args,
39523980
}
39533981
}
39543982

3983+
if (Opts.CFProtectionBranch) {
3984+
if (const Arg *A = Args.getLastArg(OPT_mcf_branch_label_scheme_EQ)) {
3985+
const auto Scheme =
3986+
llvm::StringSwitch<CFBranchLabelSchemeKind>(A->getValue())
3987+
#define CF_BRANCH_LABEL_SCHEME(Kind, FlagVal) \
3988+
.Case(#FlagVal, CFBranchLabelSchemeKind::Kind)
3989+
#include "clang/Basic/CFProtectionOptions.def"
3990+
.Default(CFBranchLabelSchemeKind::Default);
3991+
Opts.setCFBranchLabelScheme(Scheme);
3992+
}
3993+
}
3994+
39553995
if ((Args.hasArg(OPT_fsycl_is_device) || Args.hasArg(OPT_fsycl_is_host)) &&
39563996
!Args.hasArg(OPT_sycl_std_EQ)) {
39573997
// If the user supplied -fsycl-is-device or -fsycl-is-host, but failed to
Lines changed: 86 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,86 @@
1+
// RUN: %clang --target=riscv32 -menable-experimental-extensions \
2+
// RUN: -march=rv32i_zicfilp1p0 -fcf-protection=branch \
3+
// RUN: -mcf-branch-label-scheme=unlabeled -S -emit-llvm %s -o - | FileCheck \
4+
// RUN: --check-prefixes=BRANCH-PROT-FLAG,UNLABELED-FLAG %s
5+
6+
// RUN: %clang --target=riscv32 -menable-experimental-extensions \
7+
// RUN: -march=rv32i_zicfilp1p0 -fcf-protection=branch \
8+
// RUN: -mcf-branch-label-scheme=func-sig -S -emit-llvm %s -o - | FileCheck \
9+
// RUN: --check-prefixes=BRANCH-PROT-FLAG,FUNC-SIG-FLAG %s
10+
11+
// RUN: %clang --target=riscv32 -menable-experimental-extensions \
12+
// RUN: -march=rv32i_zicfilp1p0 -mcf-branch-label-scheme=unlabeled -S \
13+
// RUN: -emit-llvm %s -o - 2>&1 | FileCheck \
14+
// RUN: --check-prefixes=NO-FLAG,UNLABELED-SCHEME-UNUSED %s
15+
16+
// RUN: %clang --target=riscv32 -menable-experimental-extensions \
17+
// RUN: -march=rv32i_zicfilp1p0 -mcf-branch-label-scheme=func-sig -S \
18+
// RUN: -emit-llvm %s -o - 2>&1 | FileCheck \
19+
// RUN: --check-prefixes=NO-FLAG,FUNC-SIG-SCHEME-UNUSED %s
20+
21+
// RUN: %clang --target=riscv32 -fcf-protection=branch \
22+
// RUN: -mcf-branch-label-scheme=unlabeled -S -emit-llvm %s -o - | FileCheck \
23+
// RUN: --check-prefixes=BRANCH-PROT-FLAG,UNLABELED-FLAG %s
24+
25+
// RUN: %clang --target=riscv32 -fcf-protection=branch \
26+
// RUN: -mcf-branch-label-scheme=func-sig -S -emit-llvm %s -o - | FileCheck \
27+
// RUN: --check-prefixes=BRANCH-PROT-FLAG,FUNC-SIG-FLAG %s
28+
29+
// RUN: %clang --target=riscv32 -mcf-branch-label-scheme=unlabeled -S \
30+
// RUN: -emit-llvm %s -o - 2>&1 | FileCheck \
31+
// RUN: --check-prefixes=NO-FLAG,UNLABELED-SCHEME-UNUSED %s
32+
33+
// RUN: %clang --target=riscv32 -mcf-branch-label-scheme=func-sig -S \
34+
// RUN: -emit-llvm %s -o - 2>&1 | FileCheck \
35+
// RUN: --check-prefixes=NO-FLAG,FUNC-SIG-SCHEME-UNUSED %s
36+
37+
// RUN: %clang --target=riscv64 -menable-experimental-extensions \
38+
// RUN: -march=rv64i_zicfilp1p0 -fcf-protection=branch \
39+
// RUN: -mcf-branch-label-scheme=unlabeled -S -emit-llvm %s -o - | FileCheck \
40+
// RUN: --check-prefixes=BRANCH-PROT-FLAG,UNLABELED-FLAG %s
41+
42+
// RUN: %clang --target=riscv64 -menable-experimental-extensions \
43+
// RUN: -march=rv64i_zicfilp1p0 -fcf-protection=branch \
44+
// RUN: -mcf-branch-label-scheme=func-sig -S -emit-llvm %s -o - | FileCheck \
45+
// RUN: --check-prefixes=BRANCH-PROT-FLAG,FUNC-SIG-FLAG %s
46+
47+
// RUN: %clang --target=riscv64 -menable-experimental-extensions \
48+
// RUN: -march=rv64i_zicfilp1p0 -mcf-branch-label-scheme=unlabeled -S \
49+
// RUN: -emit-llvm %s -o - 2>&1 | FileCheck \
50+
// RUN: --check-prefixes=NO-FLAG,UNLABELED-SCHEME-UNUSED %s
51+
52+
// RUN: %clang --target=riscv64 -menable-experimental-extensions \
53+
// RUN: -march=rv64i_zicfilp1p0 -mcf-branch-label-scheme=func-sig -S \
54+
// RUN: -emit-llvm %s -o - 2>&1 | FileCheck \
55+
// RUN: --check-prefixes=NO-FLAG,FUNC-SIG-SCHEME-UNUSED %s
56+
57+
// RUN: %clang --target=riscv64 -fcf-protection=branch \
58+
// RUN: -mcf-branch-label-scheme=unlabeled -S -emit-llvm %s -o - | FileCheck \
59+
// RUN: --check-prefixes=BRANCH-PROT-FLAG,UNLABELED-FLAG %s
60+
61+
// RUN: %clang --target=riscv64 -fcf-protection=branch \
62+
// RUN: -mcf-branch-label-scheme=func-sig -S -emit-llvm %s -o - | FileCheck \
63+
// RUN: --check-prefixes=BRANCH-PROT-FLAG,FUNC-SIG-FLAG %s
64+
65+
// RUN: %clang --target=riscv64 -mcf-branch-label-scheme=unlabeled -S \
66+
// RUN: -emit-llvm %s -o - 2>&1 | FileCheck \
67+
// RUN: --check-prefixes=NO-FLAG,UNLABELED-SCHEME-UNUSED %s
68+
69+
// RUN: %clang --target=riscv64 -mcf-branch-label-scheme=func-sig -S \
70+
// RUN: -emit-llvm %s -o - 2>&1 | FileCheck \
71+
// RUN: --check-prefixes=NO-FLAG,FUNC-SIG-SCHEME-UNUSED %s
72+
73+
// UNLABELED-SCHEME-UNUSED: warning: argument unused during compilation:
74+
// UNLABELED-SCHEME-UNUSED-SAME: '-mcf-branch-label-scheme=unlabeled'
75+
// FUNC-SIG-SCHEME-UNUSED: warning: argument unused during compilation:
76+
// FUNC-SIG-SCHEME-UNUSED-SAME: '-mcf-branch-label-scheme=func-sig'
77+
78+
// BRANCH-PROT-FLAG-DAG: [[P_FLAG:![0-9]+]] = !{i32 8, !"cf-protection-branch", i32 1}
79+
// UNLABELED-FLAG-DAG: [[S_FLAG:![0-9]+]] = !{i32 1, !"cf-branch-label-scheme", !"unlabeled"}
80+
// FUNC-SIG-FLAG-DAG: [[S_FLAG:![0-9]+]] = !{i32 1, !"cf-branch-label-scheme", !"func-sig"}
81+
// BRANCH-PROT-FLAG-DAG: !llvm.module.flags = !{{[{].*}}[[P_FLAG]]{{.*, }}[[S_FLAG]]{{(,.+)?[}]}}
82+
// NO-FLAG-NOT: !{i32 8, !"cf-protection-branch", i32 1}
83+
// NO-FLAG-NOT: !{i32 8, !"cf-branch-label-scheme", !"unlabeled"}
84+
// NO-FLAG-NOT: !{i32 8, !"cf-branch-label-scheme", !"func-sig"}
85+
86+
int main() { return 0; }

0 commit comments

Comments
 (0)