<table border="1" cellspacing="0" cellpadding="8">
<tr>
<th>Issue</th>
<td>
<a href=https://github.com/llvm/llvm-project/issues/63415>63415</a>
</td>
</tr>
<tr>
<th>Summary</th>
<td>
clang miscompilation with std::optional?
</td>
</tr>
<tr>
<th>Labels</th>
<td>
new issue
</td>
</tr>
<tr>
<th>Assignees</th>
<td>
</td>
</tr>
<tr>
<th>Reporter</th>
<td>
shkoo
</td>
</tr>
</table>
<pre>
I'm encountering a case where constructing a std::optional from std::nullopt behaves differently from using the default constructor, which I don't think should ever happen. Best I can tell, using std::nullopt results in a poison value propagating that ends up causing a register to not be cleared, resulting in miscompilation?
Here's the version of clang I'm using:
> Ubuntu clang version 15.0.7
> Target: x86_64-pc-linux-gnu
> Thread model: posix
> InstalledDir: /usr/bin
> Found candidate GCC installation: /usr/bin/../lib/gcc/x86_64-linux-gnu/10
> Found candidate GCC installation: /usr/bin/../lib/gcc/x86_64-linux-gnu/8
> Found candidate GCC installation: /usr/bin/../lib/gcc/x86_64-linux-gnu/9
> Selected GCC installation: /usr/bin/../lib/gcc/x86_64-linux-gnu/10
> Candidate multilib: .;@ m64
> Selected multilib: .;@ m64
> Found CUDA installation: /usr/local/cuda, version
Though the problem also looks like it occurs on compiler explorer for "clang trunk" with the "x86-64 gcc 10.3" toolchain.
I'm using the following options to generate the miscompile: "-std=c++17 -DMISCOMPILE -O2 --target=x86_64-pc-linux-gnu". Without the -DMISCOMPILE it compiles differently (and I believe correctly).
Compiler explorer shows that the MISCOMPILE version is missing a "xor %eax, %eax":
Compiler explorer link for clang 15.0.0: https://godbolt.org/z/ded5q1f8W
Compiler explorer link for clang trunk: https://godbolt.org/z/rh87KMnje
I've used cvise to try to trim down the test case as much as I can:
```
#include <cassert>
#include <functional>
#include <memory>
#include <optional>
#include <tuple>
namespace llvm {
template <typename To, typename, typename>
struct DefaultDoCastIfPossible {
static To doCastIfPossible(int);
};
template <typename, typename, typename = void>
struct CastInfo;
template <typename To, typename From>
auto dyn_cast(From Val) {
return CastInfo<To, From>::doCastIfPossible(Val);
}
template <typename>
class SmallVectorImpl;
} // namespace llvm
using llvm::dyn_cast;
using llvm::SmallVectorImpl;
namespace llvm {
template <typename T, bool = std::is_class<T>::value>
struct function_traits : function_traits<decltype(&T::operator())> {};
template <typename ClassType, typename ReturnType, typename... Args>
struct function_traits<ReturnType (ClassType::*)(Args...) const, false> {
template <size_t Index>
using arg_t = std::tuple_element_t<Index, std::tuple<Args...>>;
};
} // namespace llvm
namespace mlir {
struct LogicalResult {};
class Type {
public:
operator bool();
};
} // namespace mlir
namespace llvm {
template <typename To, typename From>
struct CastInfo<
To, From,
std::enable_if_t<std::is_same_v<mlir::Type, std::remove_const_t<From>>>>
: DefaultDoCastIfPossible<To, From, CastInfo<To, From>> {};
} // namespace llvm
namespace mlir {
class ModuleOp;
class TypeConverter {
using ConversionCallbackFn = std::function<std::optional<LogicalResult>(
Type, SmallVectorImpl<Type> &, Type)>;
public:
void registerConversion(ConversionCallbackFn);
template <typename FnT, typename T = typename llvm::function_traits<
std::decay_t<FnT>>::template arg_t<0>>
void addConversion(FnT callback) {
registerConversion(wrapCallbackX<T>(callback));
}
template <typename T, typename FnT>
std::enable_if_t<std::is_invocable_v<FnT, T>, ConversionCallbackFn>
wrapCallbackX(FnT callback) {
return wrapCallback<T>(
[callback](T type, SmallVectorImpl<Type> &, Type) {
if (callback(type)) {
}
return std::optional<LogicalResult>();
});
}
template <typename T, typename FnT>
std::enable_if_t<std::is_invocable_v<FnT, T, SmallVectorImpl<Type> &, Type>,
ConversionCallbackFn>
wrapCallback(FnT callback) {
return [callback](Type type, SmallVectorImpl<Type> &results,
Type callStack) -> std::optional<LogicalResult> {
T derivedType = dyn_cast<T>(type);
if (derivedType)
#ifdef MISCOMPILE
return std::nullopt;
#else
return std::optional<LogicalResult>();
#endif
return callback(derivedType, results, callStack);
};
}
};
class Pass {
virtual void runOnOperation();
};
template <typename>
class OperationPass : Pass {};
class ValType : public Type {};
} // namespace mlir
using namespace mlir;
struct SemanticLoweringTypeConverter : TypeConverter {
SemanticLoweringTypeConverter() {
addConversion([](ValType type) {
__assert_fail("", "", 2, __PRETTY_FUNCTION__);
return type;
});
}
};
struct SemanticLoweringPass : OperationPass<ModuleOp> {
void runOnOperation() { SemanticLoweringTypeConverter converter; }
};
std::unique_ptr<OperationPass<ModuleOp>> createSemanticLoweringPass() {
return std::make_unique<SemanticLoweringPass>();
}
```
</pre>
<img width="1px" height="1px" alt="" src="http://email.email.llvm.org/o/eJy0WUtz4zYS_jXwpUsqGdTz4INMWbuuzcRTGWWye1JBYEtCDAIMAMp2fv0WAFIk9fB4JjUulR4E0M-vv27SzFqxU4h3ZHRPRosbVrq9Nnd2_6z1zUZnb3ePhE5yQMV1qRwaoXbAgDOL8LJHg8C1ss6U3MUV6zKSzEky14UTWjEJW6Pz5rIqpdSFgw3u2QEtZGK7RYPKybe4s7RekNsjZLhlpXSNBm0ITeFlL_geHiHTitCJA7cX6hnsXpcyAzyggT0rClR9gHu0Dh6BMwUOpfSno_gzcwzaUjoLQgGDQgurFRyYLBEKowu2Yy5axRygyiyUBXAWZTEwuBPWoQGnQWnvG3CJzGDmNUbRfqdQkAvLdV4IyXx0SLIkgwUZzOP7v9EgoRMbvD-gsUIr0FvgkqkdxEQEnd72eC55gN83pXJltak-dTvqD_qTZtOKmR06kszhdTpej4e9gvekUOVrb6fK1ra9QZZBrjOUfnOhrXhtlh-VdUxKzBbC-GVCl6U1hC43QjW7lrpUmQ96JjLmEP6VpiDiycrrk5N02e8TupRiQ-hyxzmhy8rKxkS6vB38dBXTn65h1mj4ghK5w-xnxCc92p177PmTyRz6JLknwwHk4-EFM765M4Yk_X0xv26u1JxJQpe8zJgHf43HNsxXe13u9gHkhdEbiTkwaTVIrZ8tSPGMIBxozktjQSuIBYMG8LWQ2qCBrTZAKI2Qd6ZUz4RSeBEuSiWUvk7HvfEQdpzD7aCf-GWnteR7JlS_bUyrqsLZrZZSv_hfkcCsL-odKjQ-mn7HsYQxek57gU0WnNB7Qu9vJ9BbfHr8kj59-vz4ywP0nij0eq6qv8Wl8qO0D38It9elCxo654WrA9AlS0KnTGXwCBuUAg-eiI1B7uQbobOOi-lZ_Oxev9jIZl5fS1udL2G9nxW_-XiGiI-Qvfqs1t_okYjOdUjPyj5RMUuBkAY-YnvnCusP0qWHs842Wrq-NjtCl38TuswwG_11u53-8UHJMf8fEGz208l_Pqk_8TT_B4TSYgb8ICz6fDvzFj9EDpl-USFKzjeT0PiYhbzke_8ZmktDx-NB9Yo_aSIUl2WGQJKUM2vROJI8XFrdlorHhnllQ465Nm9XFutme2XZlYVHa7WmWI62YBxBykMOZHIfrzvMC-lR7k-8Fej3wUr7hNc_O99rebE5wyK264VOmXWP28_aWrGR2MgHALCOOcFhpSE72UfoVChH6MxTT_Rhsjh-v2TbNcOAJAs4aJGdWhgUqq1-V-qJx7A0Oj8KYqXTkL2pNWfWETr1i_DVM96s66dBVxrV0phGsbW0MHxcCEGU1QnBdf9rq7hk1sKXnEn5Ff2Y9JgXsi0DINYEdFMf1yP3hd_Rqtq9WsDphmuKvg9XPhobrWXI1nEeE3YdvPEBO8YpDGKnyawLZu0ME86CZ4CTayRJM-TS6yR0Suh4VY-mns39NDn1wfbxfgjmfgNwkHrTVkFcCyG_hVyfXu73-zA3O_sNu0mSNuc9qTc6gq2EzoONUy-r7-eAWRyIva4tkxZr4yP22nZb8TeuHTyqDF-PZnh0VoOr2a1dN_yBKNYoMUfl1o4kaTxM05M9JElrg3yWHi4W7beQ11zLpTCNE1WkftE7wZn8LczPp_mJmI9BaxVeUW6k4EdC9s7W2Q5oq1L-cWu9Zf-YNrskcsZGaWNsiyVoffkYeVRsI3EttiEz7ZqxLMf1wXcJGSZzksxrPB63Gcz1AdcBPEHAkYvqV1TnC-kKl3dpjKbv8NtZQf0oGGKiP-mslPhUXMh_qtUBjb_96jBwxHhc9CNNyqTcMP68VF3I1_XYjmjTTtMOCL1ndNroCBmr4nzGimks4gcgdOw3xI2zTrG8A1vfwI53lo0bniEu-NQGtT99EZRLteqgchUicfzZMPw5R51CMUPO3iKK1KpGUGCHWnFgF5Kkgw64asdYlnV8WqoV8Mqbs2YaG-qFSLwYVtQx-G_dMui0JagTl2M3vRqhbnwq1z5chUIdNA-LhyowPu3BpvQiEhvpXU8-FI8wYLTPNQGo_R3dH2WMFoROV-C-E63nius_sYVOqKeuwvd7hzoZaP9V7ny0Ak_Q3hZ_svSPch4G1h9N-4ejHPBRaXwfJQDdhH8cJ-dQ8J3zQ2ioHo01NoajXtoXV2nt-a0fyd1lZKwgQyMOmMV2niyaEfsI6Rpdl9IeodiS4Tceb4O2GW5bt7gfw1_1XLBhapqgn7Xi4R9Hq5ejMrE9t6KS2SqojkP1c0Sfh07wzyLSbroN_M9np8_-rZOPgzCuZLJqPaV6Uk9hdopk-123Zt1bk6OYqDOZN8rPzPrKZAWDedUWmynvO6a12P5PVpLugPkFc6ac4L_ol_Bg-2SaSOZX54t3T8ZYnUP9tOfFR-7xpq9Vjlfoc72Ozw_WWybiGEvDK4XmW3hbrz__9rBa_W-9_P3XdPX49Ot63YFJBbSg7BJ2rhFoO_pXAnhMbyfhJEmb8e2EAq5CzW_7RoL4MeDJ_TUzqwItlfirxHXhDEnSd4zz9nGDzOEl1y4l9pQKcvaM66iOJOlFKeekcLS9fn50k90l2SyZsRu8ux1PJ3Q2oLPRzf4u2Y75kA0mMxwMhnwyxWRAB8PNLWNbitkUb8QdHdBkMKaD29lwOBr1s_FksNniLBmNaYabKRkOMGdC9v2419dmdyOsLfFunAxvRzeSbVDa8N8gShW-QFj08BotbsydP9PblDtLhgMprLONFCecxLv4SK77X474YPYCWS5vSiPvTh7bCbcvN33u7y-WYSKNH73C6D-RO0KXwSRL6DKY_P8AAAD__5cWMtU">