Closed
Description
https://godbolt.org/z/KjEreWf57
With Clang 18.1 and libstdc++, we get different behavior when compared to Clang 17 in the code below.
EDIT: requires at least -O1.
#include <optional>
#include <iostream>
// defined in a separate compilation unit
int takeIntRefAndReturn0(int&);
std::optional<int> shouldReturnEmptyOptional() {
int v = 5;
if (takeIntRefAndReturn0(v))
return v;
return std::nullopt;
}
int main() {
auto opt = shouldReturnEmptyOptional();
if (opt && *opt > 0) {
std::cout << "SHOULD NOT BE PRINTED: *opt = " << *opt << std::endl;
return 1;
}
std::cout << "SHOULD BE PRINTED" << std::endl;
}
With Clang 17, we get SHOULD BE PRINTED
, while with with Clang 18.1 we get SHOULD NOT BE PRINTED: *opt = 5
.
With git-bisect, I found that this is caused by 060de41.
An isomorphic example to reproduce this (https://godbolt.org/z/9PsjY17sT):
int takeIntRefReturn0(int &);
void assertNotReached(int);
static bool logicalAnd(bool a, bool b) { return a && b; }
int main() {
int v4;
bool v3;
{
int v1 = 5;
int v2 = takeIntRefReturn0(v1);
v3 = v2 != 0;
if (v3)
v4 = v1;
}
// Move to a function so that && is not short cutted.
// v4 will be undefined if v2 == 0, but v3 is false, so the branch shouldn't be entered.
if (logicalAnd(v3, v4 > 0))
assertNotReached(v4);
return 0;
}
Note in the generated LLVM IR that
%6 = icmp sgt i32 %5, 0
%7 = and i1 %3, %6
br i1 %7, label %8, label %9
was reduced to only
%6 = icmp sgt i32 %5, 0
br i1 %6, label %7, label %8
Metadata
Metadata
Assignees
Type
Projects
Status
Needs Triage