[clang-tools-extra] [clang-tidy] Skip `decltype(auto)` variables in misc-const-correctness (PR #224465)
David Meng via cfe-commits
cfe-commits at lists.llvm.org
Fri Sep 18 06:12:25 PDT 2026
https://github.com/davidmenggx updated https://github.com/llvm/llvm-project/pull/224465
>From 2237065ae201db89573e8d11d71a867a08f92474 Mon Sep 17 00:00:00 2001
From: David Meng <davidmenggx at gmail.com>
Date: Thu, 17 Sep 2026 15:45:57 -0700
Subject: [PATCH 1/3] [clang-tidy] Skip `decltype(auto)` variables in
misc-const-correctness
Since #157319 the check analyzes `auto` variables, which also pulled in
`decltype(auto)`. Its fix-it inserts `const`, but `decltype(auto)` cannot
be combined with other type specifiers, so the fix does not compile:
```cpp
decltype(auto) x = get_ref();
decltype(auto) const x = get_ref(); // error
```
Exclude such variables from the analysis, as no `const` can be added.
Fixes #223940
---
.../clang-tidy/misc/ConstCorrectnessCheck.cpp | 11 ++++++-
clang-tools-extra/docs/ReleaseNotes.md | 3 ++
.../checks/misc/const-correctness.rst | 3 ++
.../misc/const-correctness-decltype-auto.cpp | 32 +++++++++++++++++++
4 files changed, 48 insertions(+), 1 deletion(-)
create mode 100644 clang-tools-extra/test/clang-tidy/checkers/misc/const-correctness-decltype-auto.cpp
diff --git a/clang-tools-extra/clang-tidy/misc/ConstCorrectnessCheck.cpp b/clang-tools-extra/clang-tidy/misc/ConstCorrectnessCheck.cpp
index 1abe4db743a25..b187f68be7ff0 100644
--- a/clang-tools-extra/clang-tidy/misc/ConstCorrectnessCheck.cpp
+++ b/clang-tools-extra/clang-tidy/misc/ConstCorrectnessCheck.cpp
@@ -45,6 +45,11 @@ AST_MATCHER(TypeLoc, hasContainedAutoType) {
return !Node.getContainedAutoTypeLoc().isNull();
}
+AST_MATCHER(TypeLoc, hasContainedDecltypeAutoType) {
+ const AutoTypeLoc Loc = Node.getContainedAutoTypeLoc();
+ return !Loc.isNull() && Loc.isDecltypeAuto();
+}
+
AST_MATCHER(FunctionDecl, isTemplate) {
return Node.getDescribedFunctionTemplate() != nullptr;
}
@@ -142,6 +147,9 @@ void ConstCorrectnessCheck::registerMatchers(MatchFinder *Finder) {
const auto FunctionPointerRef =
hasType(hasCanonicalType(referenceType(pointee(functionType()))));
+ // 'const' cannot be combined with 'decltype(auto)'.
+ const auto DecltypeAutoType = hasTypeLoc(hasContainedDecltypeAutoType());
+
const auto CommonExcludeTypes =
anyOf(ConstType, ConstReference, RValueReference, TemplateType,
FunctionPointerRef, hasType(cxxRecordDecl(isLambda())),
@@ -153,7 +161,8 @@ void ConstCorrectnessCheck::registerMatchers(MatchFinder *Finder) {
isLocal(), hasInitializer(anything()),
unless(anyOf(ConstType, ConstReference, TemplateType,
hasInitializer(isInstantiationDependent()), RValueReference,
- FunctionPointerRef, isImplicit(), AllowedType)),
+ FunctionPointerRef, isImplicit(), AllowedType,
+ DecltypeAutoType)),
AnalyzeLambdas
? Matcher<VarDecl>(anything())
: Matcher<VarDecl>(unless(hasType(cxxRecordDecl(isLambda())))),
diff --git a/clang-tools-extra/docs/ReleaseNotes.md b/clang-tools-extra/docs/ReleaseNotes.md
index 7d34d544a5d99..ad17c23674701 100644
--- a/clang-tools-extra/docs/ReleaseNotes.md
+++ b/clang-tools-extra/docs/ReleaseNotes.md
@@ -209,6 +209,9 @@ infrastructure are described first, followed by tool-specific sections.
- Fixed false positives when the pointee is written through a pointer
assignment, such as `*(p = q) = 0`.
+ - No longer diagnoses variables declared with `decltype(auto)`, where the
+ suggested `const` does not compile.
+
- Improved {doc}`misc-redundant-expression
<clang-tidy/checks/misc/redundant-expression>` by fixing false positives in
nested expressions involving different macros or a mix of macro and
diff --git a/clang-tools-extra/docs/clang-tidy/checks/misc/const-correctness.rst b/clang-tools-extra/docs/clang-tidy/checks/misc/const-correctness.rst
index ce699e06b9276..7f8599b616c4d 100644
--- a/clang-tools-extra/docs/clang-tidy/checks/misc/const-correctness.rst
+++ b/clang-tools-extra/docs/clang-tidy/checks/misc/const-correctness.rst
@@ -60,6 +60,9 @@ Limitations
The check does not run on `C` code.
+Variables declared with ``decltype(auto)`` are not analyzed, because
+``decltype(auto)`` cannot be combined with ``const``.
+
The check will not analyze templated variables, template functions or variables
that are instantiation dependent. Different instantiations can result
in different ``const`` correctness properties and in general it is not
diff --git a/clang-tools-extra/test/clang-tidy/checkers/misc/const-correctness-decltype-auto.cpp b/clang-tools-extra/test/clang-tidy/checkers/misc/const-correctness-decltype-auto.cpp
new file mode 100644
index 0000000000000..8b50caecec75d
--- /dev/null
+++ b/clang-tools-extra/test/clang-tidy/checkers/misc/const-correctness-decltype-auto.cpp
@@ -0,0 +1,32 @@
+// RUN: %check_clang_tidy -std=c++14-or-later %s misc-const-correctness %t \
+// RUN: -config='{CheckOptions: {misc-const-correctness.WarnPointersAsValues: true}}' \
+// RUN: -- -fno-delayed-template-parsing
+
+// 'decltype(auto)' cannot be combined with 'const', so variables declared with
+// it must not be diagnosed, whatever type they deduce to.
+
+int global = 0;
+int &get_ref() { return global; }
+int *get_ptr() { return &global; }
+
+void sink(int);
+
+void decltype_auto_is_ignored() {
+ int i = 42;
+ // CHECK-MESSAGES: [[@LINE-1]]:3: warning: variable 'i' of type 'int' can be declared 'const'
+ // CHECK-FIXES: int const i = 42;
+
+ decltype(auto) value = i;
+ decltype(auto) ref = get_ref();
+ decltype(auto) ptr = get_ptr();
+ sink(value);
+ sink(ref);
+ sink(*ptr);
+}
+
+template <typename T>
+void decltype_auto_in_template(T t) {
+ decltype(auto) value = t;
+ sink(value);
+}
+void instantiate_template() { decltype_auto_in_template(0); }
>From 64564815b8a7e64035874ce7a43fd6fed59cabea Mon Sep 17 00:00:00 2001
From: David Meng <davidmenggx at gmail.com>
Date: Thu, 17 Sep 2026 19:37:21 -0700
Subject: [PATCH 2/3] Address review comments
---
.../clang-tidy/misc/ConstCorrectnessCheck.cpp | 8 ++------
.../docs/clang-tidy/checks/misc/const-correctness.rst | 3 ---
2 files changed, 2 insertions(+), 9 deletions(-)
diff --git a/clang-tools-extra/clang-tidy/misc/ConstCorrectnessCheck.cpp b/clang-tools-extra/clang-tidy/misc/ConstCorrectnessCheck.cpp
index b187f68be7ff0..640385de7258b 100644
--- a/clang-tools-extra/clang-tidy/misc/ConstCorrectnessCheck.cpp
+++ b/clang-tools-extra/clang-tidy/misc/ConstCorrectnessCheck.cpp
@@ -40,16 +40,12 @@ AST_MATCHER(ReferenceType, isSpelledAsLValue) {
return Node.isSpelledAsLValue();
}
AST_MATCHER(Type, isDependentType) { return Node.isDependentType(); }
+AST_MATCHER(AutoType, isDecltypeAuto) { return Node.isDecltypeAuto(); }
AST_MATCHER(TypeLoc, hasContainedAutoType) {
return !Node.getContainedAutoTypeLoc().isNull();
}
-AST_MATCHER(TypeLoc, hasContainedDecltypeAutoType) {
- const AutoTypeLoc Loc = Node.getContainedAutoTypeLoc();
- return !Loc.isNull() && Loc.isDecltypeAuto();
-}
-
AST_MATCHER(FunctionDecl, isTemplate) {
return Node.getDescribedFunctionTemplate() != nullptr;
}
@@ -148,7 +144,7 @@ void ConstCorrectnessCheck::registerMatchers(MatchFinder *Finder) {
hasType(hasCanonicalType(referenceType(pointee(functionType()))));
// 'const' cannot be combined with 'decltype(auto)'.
- const auto DecltypeAutoType = hasTypeLoc(hasContainedDecltypeAutoType());
+ const auto DecltypeAutoType = hasType(autoType(isDecltypeAuto()));
const auto CommonExcludeTypes =
anyOf(ConstType, ConstReference, RValueReference, TemplateType,
diff --git a/clang-tools-extra/docs/clang-tidy/checks/misc/const-correctness.rst b/clang-tools-extra/docs/clang-tidy/checks/misc/const-correctness.rst
index 7f8599b616c4d..ce699e06b9276 100644
--- a/clang-tools-extra/docs/clang-tidy/checks/misc/const-correctness.rst
+++ b/clang-tools-extra/docs/clang-tidy/checks/misc/const-correctness.rst
@@ -60,9 +60,6 @@ Limitations
The check does not run on `C` code.
-Variables declared with ``decltype(auto)`` are not analyzed, because
-``decltype(auto)`` cannot be combined with ``const``.
-
The check will not analyze templated variables, template functions or variables
that are instantiation dependent. Different instantiations can result
in different ``const`` correctness properties and in general it is not
>From 6c5a6ce1f307899836b0f89a068e9308b7ef23b9 Mon Sep 17 00:00:00 2001
From: David Meng <davidmenggx at gmail.com>
Date: Fri, 18 Sep 2026 06:12:10 -0700
Subject: [PATCH 3/3] Address review comments
---
clang-tools-extra/clang-tidy/misc/ConstCorrectnessCheck.cpp | 3 ++-
.../checkers/misc/const-correctness-decltype-auto.cpp | 2 ++
2 files changed, 4 insertions(+), 1 deletion(-)
diff --git a/clang-tools-extra/clang-tidy/misc/ConstCorrectnessCheck.cpp b/clang-tools-extra/clang-tidy/misc/ConstCorrectnessCheck.cpp
index 640385de7258b..57c2bda6c3fd5 100644
--- a/clang-tools-extra/clang-tidy/misc/ConstCorrectnessCheck.cpp
+++ b/clang-tools-extra/clang-tidy/misc/ConstCorrectnessCheck.cpp
@@ -144,7 +144,8 @@ void ConstCorrectnessCheck::registerMatchers(MatchFinder *Finder) {
hasType(hasCanonicalType(referenceType(pointee(functionType()))));
// 'const' cannot be combined with 'decltype(auto)'.
- const auto DecltypeAutoType = hasType(autoType(isDecltypeAuto()));
+ const auto DecltypeAutoType =
+ hasType(ignoringParens(autoType(isDecltypeAuto())));
const auto CommonExcludeTypes =
anyOf(ConstType, ConstReference, RValueReference, TemplateType,
diff --git a/clang-tools-extra/test/clang-tidy/checkers/misc/const-correctness-decltype-auto.cpp b/clang-tools-extra/test/clang-tidy/checkers/misc/const-correctness-decltype-auto.cpp
index 8b50caecec75d..e20bea53cf1d5 100644
--- a/clang-tools-extra/test/clang-tidy/checkers/misc/const-correctness-decltype-auto.cpp
+++ b/clang-tools-extra/test/clang-tidy/checkers/misc/const-correctness-decltype-auto.cpp
@@ -19,9 +19,11 @@ void decltype_auto_is_ignored() {
decltype(auto) value = i;
decltype(auto) ref = get_ref();
decltype(auto) ptr = get_ptr();
+ decltype(auto) (paren) = 42;
sink(value);
sink(ref);
sink(*ptr);
+ sink(paren);
}
template <typename T>
More information about the cfe-commits
mailing list