clang-tidy readability-redundant-parentheses
labelled unknown
Analysis Nemotron 3 Super
The rule flags unnecessary parentheses around expressions where they do not affect precedence or meaning.
Fix: Removes parentheses that are not required for operator precedence or to disambiguate parsing, rewriting the expression to its form without the redundant grouping.
12 hazards
- Removing parentheses around a function-like macro invocation may change how arguments are grouped if the macro expects comma-separated parameters.
- Stripping parentheses from a cast-expression like `(T)x` alters the cast target and may cause misinterpretation as a declaration or incorrect type conversion.
- Eliminating parentheses around a braced-init-list such as `(T){x}` can prevent aggregate initialization and instead invoke a constructor if available.
- Deleting parentheses in a lambda-expression like `([]{})()` may prevent it from being treated as a single postfix-expression, breaking the call.
- Removing parentheses around a comma-expression such as `(a, b)` changes evaluation order context, potentially altering which value is used in larger expressions.
- Taking away parentheses from a conditional-expression like `(a ? b : c)` can lead to incorrect parsing due to lower precedence of `?:`, changing the bound of the ternary.
- Erasing parentheses around an assignment expression like `(x = y)` may prevent it from being treated as a single value in outer contexts, affecting use in conditions or function calls.
- Stripping parentheses from a `sizeof` or `alignof` operand like `sizeof (T)` risks misparsing if followed by a declarator, turning it into an ambiguous or invalid declaration.
- Removing parentheses around a unary operator expression such as `(!p)` can alter binding with adjacent operators, e.g., in `!p && q` vs `!(p && q)`.
- Deleting parentheses in a pack expansion like `(Args)...` breaks the expansion syntax, causing a compile error.
- Taking away parentheses around a dependent name in a template, such as `(typename T::type)`, may hinder lookup and break instantiation.
- Stripping parentheses that visually group code for readability may drop associated inline comments attached to the parentheses lines, reducing code clarity.
Programs
| id | result | title | hazard |
|---|---|---|---|
| r1-p001 | silent prediction off | Redundant Parentheses Around Throw Expression | Removing parentheses around a throw expression changes destructors' evaluation order due to comma operator interaction. |
| r1-p002 | silent prediction off | Redundant Parentheses in For Loop Init | Removing parentheses around comma-expression in for init causes iterator invalidation via premature increment. |
| r1-p003 | fix ok | Redundant Parentheses Around Overloaded Operator Call | Removing parentheses around user-defined conversion operator call alters side effect timing. |
| r1-p004 | silent prediction off | Redundant Parentheses Around Shift Expression | Removing parentheses around shift expression changes overflow behavior due to precedence with addition. |
| r1-p005 | silent prediction off | Redundant Parentheses Around Braced Init List | Removing parentheses around braced-init-list selects constructor over aggregate initialization. |
| r1-p006 | silent | Redundant Parentheses Around Sizeof Expression | Removing parentheses around sizeof operand creates ambiguous declaration when followed by pointer declarator. |
| r1-p007 | fix ok | Redundant Parentheses in Dependent Decltype Expression | Removing parentheses around decltype expression changes type deduction in template context. |
| r1-p008 | silent prediction off | Redundant Parentheses Around Pack Expansion | Removing parentheses around pack expansion breaks syntax, causing compile error. |
| r2-p001 | silent prediction off | Macro Argument Substitution | macros: the rewritten token comes from or spans a macro expansion, or a macro argument |
| r2-p002 | silent | Dependent Name Lookup Failure | Taking away parentheses around a dependent name in a template, such as `(typename T::type)`, may hinder lookup and break instantiation. |
| r2-p003 | silent prediction off | Comma Expression Evaluation Order | Removing parentheses around a comma-expression such as `(a, b)` changes evaluation order context, potentially altering which value is used in larger expressions. |
| r2-p004 | fix ok | Inline Comment Loss on Parentheses Lines | Stripping parentheses that visually group code for readability may drop associated inline comments attached to the parentheses lines, reducing code clarity. |
| r2-p005 | silent prediction off | Temporary Lifetime in Structured Binding | references vs values: lifetime of temporaries, dangling after a rewrite to auto or structured bindings |
| r2-p006 | invalid | String Literal Type Deduction | string literal types, string_view vs std::string, char vs int in the rewritten code |
| r2-p007 | silent prediction off | Assignment Expression in Condition | Erasing parentheses around an assignment expression like `(x = y)` may prevent it from being treated as a single value in outer contexts, affecting use in conditions or function calls. |
| r2-p008 | fix ok | Constexpr Qualification Loss | const/volatile/noexcept/constexpr qualifiers dropped or added by the rewrite |
Sources
r1-p001 · Redundant Parentheses Around Throw Expression
1#include <iostream>
2#include <exception>
3struct S { ~S() { std::cout << 'S'; } };
4int main() {
5 S s;
6 try { (throw std::runtime_error("err"), 0); }
7 catch (const std::exception& e) { std::cout << "Caught: " << e.what(); }
8}
Caught: errS
r1-p002 · Redundant Parentheses in For Loop Init
1#include <iostream>
2#include <vector>
3int main() {
4 std::vector<int> v{1,2,3};
5 auto it = v.begin();
6 for (; (it != v.end(), ++it, it != v.end()); ) {
7 std::cout << *it;
8 ++it;
9 }
10}
2
r1-p003 · Redundant Parentheses Around Overloaded Operator Call
1#include <iostream>
2struct X {
3 int val = 0;
4 operator int() { std::cout << "conv:"; return ++val; }
5};
6int main() {
7 X x;
8 int a = (x) + (x);
9 std::cout << "|" << a;
10}
--- orig.cpp 2026-10-17 16:08:04.999342785 -0400 +++ fixed.cpp 2026-10-17 16:08:07.850763565 -0400 @@ -5,6 +5,6 @@ }; int main() { X x; - int a = (x) + (x); + int a = x + x; std::cout << "|" << a; }
conv:conv:|3
r1-p004 · Redundant Parentheses Around Shift Expression
1#include <iostream>
2#include <limits>
3int main() {
4 unsigned long x = 1UL << 63;
5 unsigned long z = (x >> 1) + 1;
6 std::cout << z;
7}
4611686018427387905
r1-p005 · Redundant Parentheses Around Braced Init List
1#include <iostream>
2struct A { int x, y; A(int a, int b) : x(a), y(b) { std::cout << 'C'; } };
3int main() {
4 A a = (A){1, 2};
5 std::cout << a.x << a.y;
6}
C12
r1-p006 · Redundant Parentheses Around Sizeof Expression
1#include <iostream>
2int main() {
3 int x;
4 std::cout << sizeof(int)*sizeof(x);
5}
16
r1-p007 · Redundant Parentheses in Dependent Decltype Expression
1#include <iostream>
2template<typename T> auto foo(T t) -> decltype((t)) { return t; }
3int main() {
4 int x = 42;
5 auto&& r = foo(x);
6 std::cout << r;
7}
--- orig.cpp 2026-10-17 16:08:16.389891442 -0400 +++ fixed.cpp 2026-10-17 16:08:19.343531345 -0400 @@ -1,5 +1,5 @@ #include <iostream> -template<typename T> auto foo(T t) -> decltype((t)) { return t; } +template<typename T> auto foo(T t) -> decltype(t) { return t; } int main() { int x = 42; auto&& r = foo(x);
42
r1-p008 · Redundant Parentheses Around Pack Expansion
1#include <iostream>
2template<typename... Args> void f(Args... args) {
3 (std::cout << ... << args);
4}
5int main() {
6 f(1, 2, 3);
7}
123
r2-p001 · Macro Argument Substitution
1#include <cstdio>
2#define VALUE (42)
3int main() {
4 int x = (VALUE);
5 printf("%d\n", x);
6 return 0;
7}
42
r2-p002 · Dependent Name Lookup Failure
1#include <cstdio>
2template<typename T> void foo() {
3 typename T::type x{}; // Parens around typename T::type would be redundant but removing breaks dependent lookup
4 (void)x;
5}
6struct S { using type = int; };
7int main() {
8 foo<S>();
9 printf("ok\n");
10 return 0;
11}
ok
r2-p003 · Comma Expression Evaluation Order
1#include <cstdio>
2int main() {
3 int a = 1, b = 2;
4 int x = (a, b);
5 printf("%d\n", x);
6 return 0;
7}
2
r2-p004 · Inline Comment Loss on Parentheses Lines
1#include <cstdio>
2int main() {
3 int x = (/* important initialization */ 42);
4 printf("%d\n", x);
5 return 0;
6}
--- orig.cpp 2026-10-17 16:08:31.464310816 -0400 +++ fixed.cpp 2026-10-17 16:08:31.938496183 -0400 @@ -1,6 +1,6 @@ #include <cstdio> int main() { - int x = (/* important initialization */ 42); + int x = /* important initialization */ 42; printf("%d\n", x); return 0; }
42
r2-p005 · Temporary Lifetime in Structured Binding
1#include <cstdio>
2#include <utility>
3struct Temp { int v; Temp(int x) : v(x) {} ~Temp() { v = -1; } };
4Temp make_temp() { return Temp(99); }
5int main() {
6 auto [val] = (make_temp());
7 printf("%d\n", val);
8 return 0;
9}
99
r2-p006 · String Literal Type Deduction (generated program does not parse: orig.cpp:5:17: error: static assertion failed )
1#include <cstdio>
2#include <string_view>
3int main() {
4 auto s = ("hello");
5 static_assert(std::is_same_v<decltype(s), const char[6]>);
6 printf("%zu\n", sizeof(s));
7 return 0;
8}
r2-p007 · Assignment Expression in Condition
1#include <cstdio>
2int main() {
3 int a = 1, b = 2;
4 if ((a = b)) {
5 printf("%d\n", a);
6 }
7 return 0;
8}
2
r2-p008 · Constexpr Qualification Loss
1#include <cstdio>
2constexpr int get_five() { return 5; }
3int main() {
4 constexpr int x = (get_five());
5 printf("%d\n", x);
6 return 0;
7}
--- orig.cpp 2026-10-17 16:08:33.606229830 -0400 +++ fixed.cpp 2026-10-17 16:08:34.053846056 -0400 @@ -1,7 +1,7 @@ #include <cstdio> constexpr int get_five() { return 5; } int main() { - constexpr int x = (get_five()); + constexpr int x = get_five(); printf("%d\n", x); return 0; }
5