[llvm] [IR] Make succ_iterator compliant with C++20 (PR #188601)
Daniel Hoekwater via llvm-commits
llvm-commits at lists.llvm.org
Wed Mar 25 13:50:02 PDT 2026
https://github.com/dhoekwater created https://github.com/llvm/llvm-project/pull/188601
GCC 15.2 enforces the `DefaultConstructible` requirement for
`std::reverse_iterator<llvm::succ_iterator>` causing LLVM to fail to
build with C++20 (see
https://discourse.llvm.org/t/suspicious-usages-of-std-reverse-iterator-and-associated-llvm-build-failures-with-gcc-15-2-1/89426,
issue #182417).
```
$ cmake -G Ninja -S llvm -B llvm/build \
-DCMAKE_INSTALL_PREFIX=$(mktemp -d) \
-DCMAKE_BUILD_TYPE=Release \
-DCMAKE_C_COMPILER=gcc \
-DCMAKE_CXX_COMPILER=g++ \
-DLLVM_ENABLE_PROJECTS="clang;" \
-DLLVM_ENABLE_ASSERTIONS=ON \
-DLLVM_USE_LINKER=lld \
-DCMAKE_CXX_STANDARD=20 \
-DLLVM_OPTIMIZED_TABLEGEN=ON \
-DLLVM_PARALLEL_LINK_JOBS=4
$ ninja -C llvm/build bin/llvm-lib
...
/usr/include/c++/15/bits/stl_iterator.h:182:7: error: no matching function for call to ‘llvm::Instruction::succ_iterator::succ_iterator()’
182 | _GLIBCXX_NOEXCEPT_IF(noexcept(_Iterator()))
...
```
Adding a default constructor fixes this error.
Fixes #182417.
>From 3465df89057ae2a8479ac010c170c01e506fa82d Mon Sep 17 00:00:00 2001
From: Daniel Hoekwater <hoekwater at google.com>
Date: Wed, 25 Mar 2026 20:11:57 +0000
Subject: [PATCH] [IR] Make succ_iterator compliant with C++20
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
GCC 15.2 enforces the `DefaultConstructible` requirement for
`std::reverse_iterator<llvm::succ_iterator>` causing LLVM to fail to
build with C++20 (see
https://discourse.llvm.org/t/suspicious-usages-of-std-reverse-iterator-and-associated-llvm-build-failures-with-gcc-15-2-1/89426,
issue #182417).
```
$ cmake -G Ninja -S llvm -B llvm/build \
-DCMAKE_INSTALL_PREFIX=$(mktemp -d) \
-DCMAKE_BUILD_TYPE=Release \
-DCMAKE_C_COMPILER=gcc \
-DCMAKE_CXX_COMPILER=g++ \
-DLLVM_ENABLE_PROJECTS="clang;" \
-DLLVM_ENABLE_ASSERTIONS=ON \
-DLLVM_USE_LINKER=lld \
-DCMAKE_CXX_STANDARD=20 \
-DLLVM_OPTIMIZED_TABLEGEN=ON \
-DLLVM_PARALLEL_LINK_JOBS=4
$ ninja -C llvm/build bin/llvm-lib
...
/usr/include/c++/15/bits/stl_iterator.h:182:7: error: no matching function for call to ‘llvm::Instruction::succ_iterator::succ_iterator()’
182 | _GLIBCXX_NOEXCEPT_IF(noexcept(_Iterator()))
...
```
Adding a default constructor fixes this error.
Fixes #182417.
---
llvm/include/llvm/IR/Instruction.h | 75 ++++++++++++++++--------------
1 file changed, 39 insertions(+), 36 deletions(-)
diff --git a/llvm/include/llvm/IR/Instruction.h b/llvm/include/llvm/IR/Instruction.h
index 00b63f1e1b060..ed54ee118f833 100644
--- a/llvm/include/llvm/IR/Instruction.h
+++ b/llvm/include/llvm/IR/Instruction.h
@@ -78,6 +78,7 @@ class Instruction : public User,
: iterator_adaptor_base<succ_iterator, op_iterator,
std::random_access_iterator_tag, BasicBlock *,
ptrdiff_t, BasicBlock *, BasicBlock *> {
+ succ_iterator() = default;
explicit succ_iterator(op_iterator I) : iterator_adaptor_base(I) {}
BasicBlock *operator*() const { return cast<BasicBlock>(*I); }
@@ -92,6 +93,7 @@ class Instruction : public User,
std::random_access_iterator_tag,
const BasicBlock *, ptrdiff_t, const BasicBlock *,
const BasicBlock *> {
+ const_succ_iterator() = default;
explicit const_succ_iterator(const_op_iterator I)
: iterator_adaptor_base(I) {}
@@ -102,7 +104,7 @@ class Instruction : public User,
};
private:
- DebugLoc DbgLoc; // 'dbg' Metadata cache.
+ DebugLoc DbgLoc; // 'dbg' Metadata cache.
/// Relative order of this instruction in its parent basic block. Used for
/// O(1) local dominance checks between instructions.
@@ -198,8 +200,10 @@ class Instruction : public User,
/// Specialize the methods defined in Value, as we know that an instruction
/// can only be used by other instructions.
- Instruction *user_back() { return cast<Instruction>(*user_begin());}
- const Instruction *user_back() const { return cast<Instruction>(*user_begin());}
+ Instruction *user_back() { return cast<Instruction>(*user_begin()); }
+ const Instruction *user_back() const {
+ return cast<Instruction>(*user_begin());
+ }
/// Return the module owning the function this instruction belongs to
/// or nullptr it the function does not have a module.
@@ -209,7 +213,7 @@ class Instruction : public User,
LLVM_ABI const Module *getModule() const;
Module *getModule() {
return const_cast<Module *>(
- static_cast<const Instruction *>(this)->getModule());
+ static_cast<const Instruction *>(this)->getModule());
}
/// Return the function this instruction belongs to.
@@ -219,7 +223,7 @@ class Instruction : public User,
LLVM_ABI const Function *getFunction() const;
Function *getFunction() {
return const_cast<Function *>(
- static_cast<const Instruction *>(this)->getFunction());
+ static_cast<const Instruction *>(this)->getFunction());
}
/// Get the data layout of the module this instruction belongs to.
@@ -388,9 +392,7 @@ class Instruction : public User,
}
/// Return true if this is an arithmetic shift right.
- inline bool isArithmeticShift() const {
- return getOpcode() == AShr;
- }
+ inline bool isArithmeticShift() const { return getOpcode() == AShr; }
/// Determine if the Opcode is and/or/xor.
static inline bool isBitwiseLogicOp(unsigned Opcode) {
@@ -398,9 +400,7 @@ class Instruction : public User,
}
/// Return true if this is and/or/xor.
- inline bool isBitwiseLogicOp() const {
- return isBitwiseLogicOp(getOpcode());
- }
+ inline bool isBitwiseLogicOp() const { return isBitwiseLogicOp(getOpcode()); }
/// Determine if the Opcode is one of the CastInst instructions.
static inline bool isCast(unsigned Opcode) {
@@ -465,7 +465,8 @@ class Instruction : public User,
/// Get the metadata of given kind attached to this Instruction.
/// If the metadata is not found then return null.
MDNode *getMetadata(StringRef Kind) const {
- if (!hasMetadata()) return nullptr;
+ if (!hasMetadata())
+ return nullptr;
return getMetadataImpl(Kind);
}
@@ -780,8 +781,8 @@ class Instruction : public User,
///
LLVM_ABI bool isAssociative() const LLVM_READONLY;
static bool isAssociative(unsigned Opcode) {
- return Opcode == And || Opcode == Or || Opcode == Xor ||
- Opcode == Add || Opcode == Mul;
+ return Opcode == And || Opcode == Or || Opcode == Xor || Opcode == Add ||
+ Opcode == Mul;
}
/// Return true if the instruction is commutative:
@@ -800,13 +801,17 @@ class Instruction : public User,
static bool isCommutative(unsigned Opcode) {
switch (Opcode) {
- case Add: case FAdd:
- case Mul: case FMul:
- case And: case Or: case Xor:
+ case Add:
+ case FAdd:
+ case Mul:
+ case FMul:
+ case And:
+ case Or:
+ case Xor:
return true;
default:
return false;
- }
+ }
}
/// Return true if the instruction is idempotent:
@@ -830,9 +835,7 @@ class Instruction : public User,
/// In LLVM, the Xor operator is nilpotent.
///
bool isNilpotent() const { return isNilpotent(getOpcode()); }
- static bool isNilpotent(unsigned Opcode) {
- return Opcode == Xor;
- }
+ static bool isNilpotent(unsigned Opcode) { return Opcode == Xor; }
/// Return true if this instruction may modify memory.
LLVM_ABI bool mayWriteToMemory() const LLVM_READONLY;
@@ -1025,52 +1028,52 @@ class Instruction : public User,
//----------------------------------------------------------------------
// Exported enumerations.
//
- enum TermOps { // These terminate basic blocks
-#define FIRST_TERM_INST(N) TermOpsBegin = N,
+ enum TermOps { // These terminate basic blocks
+#define FIRST_TERM_INST(N) TermOpsBegin = N,
#define HANDLE_TERM_INST(N, OPC, CLASS) OPC = N,
-#define LAST_TERM_INST(N) TermOpsEnd = N+1
+#define LAST_TERM_INST(N) TermOpsEnd = N + 1
#include "llvm/IR/Instruction.def"
};
enum UnaryOps {
-#define FIRST_UNARY_INST(N) UnaryOpsBegin = N,
+#define FIRST_UNARY_INST(N) UnaryOpsBegin = N,
#define HANDLE_UNARY_INST(N, OPC, CLASS) OPC = N,
-#define LAST_UNARY_INST(N) UnaryOpsEnd = N+1
+#define LAST_UNARY_INST(N) UnaryOpsEnd = N + 1
#include "llvm/IR/Instruction.def"
};
enum BinaryOps {
-#define FIRST_BINARY_INST(N) BinaryOpsBegin = N,
+#define FIRST_BINARY_INST(N) BinaryOpsBegin = N,
#define HANDLE_BINARY_INST(N, OPC, CLASS) OPC = N,
-#define LAST_BINARY_INST(N) BinaryOpsEnd = N+1
+#define LAST_BINARY_INST(N) BinaryOpsEnd = N + 1
#include "llvm/IR/Instruction.def"
};
enum MemoryOps {
-#define FIRST_MEMORY_INST(N) MemoryOpsBegin = N,
+#define FIRST_MEMORY_INST(N) MemoryOpsBegin = N,
#define HANDLE_MEMORY_INST(N, OPC, CLASS) OPC = N,
-#define LAST_MEMORY_INST(N) MemoryOpsEnd = N+1
+#define LAST_MEMORY_INST(N) MemoryOpsEnd = N + 1
#include "llvm/IR/Instruction.def"
};
enum CastOps {
-#define FIRST_CAST_INST(N) CastOpsBegin = N,
+#define FIRST_CAST_INST(N) CastOpsBegin = N,
#define HANDLE_CAST_INST(N, OPC, CLASS) OPC = N,
-#define LAST_CAST_INST(N) CastOpsEnd = N+1
+#define LAST_CAST_INST(N) CastOpsEnd = N + 1
#include "llvm/IR/Instruction.def"
};
enum FuncletPadOps {
-#define FIRST_FUNCLETPAD_INST(N) FuncletPadOpsBegin = N,
+#define FIRST_FUNCLETPAD_INST(N) FuncletPadOpsBegin = N,
#define HANDLE_FUNCLETPAD_INST(N, OPC, CLASS) OPC = N,
-#define LAST_FUNCLETPAD_INST(N) FuncletPadOpsEnd = N+1
+#define LAST_FUNCLETPAD_INST(N) FuncletPadOpsEnd = N + 1
#include "llvm/IR/Instruction.def"
};
enum OtherOps {
-#define FIRST_OTHER_INST(N) OtherOpsBegin = N,
+#define FIRST_OTHER_INST(N) OtherOpsBegin = N,
#define HANDLE_OTHER_INST(N, OPC, CLASS) OPC = N,
-#define LAST_OTHER_INST(N) OtherOpsEnd = N+1
+#define LAST_OTHER_INST(N) OtherOpsEnd = N + 1
#include "llvm/IR/Instruction.def"
};
More information about the llvm-commits
mailing list