[clang] 0776af1 - [Clang] [Sema] Fix FixIt for implicit-int diagnostics. (#179356)
via cfe-commits
cfe-commits at lists.llvm.org
Wed Feb 11 07:47:42 PST 2026
Author: Karl Friebel
Date: 2026-02-11T15:47:36Z
New Revision: 0776af16c57cecca98472888f1bfc6f83151c427
URL: https://github.com/llvm/llvm-project/commit/0776af16c57cecca98472888f1bfc6f83151c427
DIFF: https://github.com/llvm/llvm-project/commit/0776af16c57cecca98472888f1bfc6f83151c427.diff
LOG: [Clang] [Sema] Fix FixIt for implicit-int diagnostics. (#179356)
When encountering a declaration without a type specifier, in contexts
where they could reasonably be assumed to default to int, clang emits a
diagnostic with FixIt. This FixIt does not produce working code.
This patch updates `SemaType` to correctly insert a single int type
specifier per group of declarations, and adds coverage in the FixIt lit test suite.
Fixes #179354
Added:
clang/test/FixIt/fixit-missing-type-spec.c
Modified:
clang/docs/ReleaseNotes.rst
clang/lib/Parse/Parser.cpp
clang/lib/Sema/SemaType.cpp
clang/test/SemaOpenCL/invalid-pipes-cl2.0.cl
Removed:
################################################################################
diff --git a/clang/docs/ReleaseNotes.rst b/clang/docs/ReleaseNotes.rst
index 59fdbc80e8bed..982f866e228b6 100644
--- a/clang/docs/ReleaseNotes.rst
+++ b/clang/docs/ReleaseNotes.rst
@@ -228,6 +228,9 @@ Improvements to Clang's diagnostics
when accessing a member function on a past-the-end array element.
(#GH179128)
+- Added a missing space to the FixIt for the ``implicit-int`` group of diagnostics and
+ made sure that only one such diagnostic and FixIt is emitted per declaration group. (#GH179354)
+
Improvements to Clang's time-trace
----------------------------------
diff --git a/clang/lib/Parse/Parser.cpp b/clang/lib/Parse/Parser.cpp
index be9e0a39a3781..5d18414b1a746 100644
--- a/clang/lib/Parse/Parser.cpp
+++ b/clang/lib/Parse/Parser.cpp
@@ -1188,7 +1188,8 @@ Decl *Parser::ParseFunctionDefinition(ParsingDeclarator &D,
// declaration-specifiers are completely optional in the grammar.
if (getLangOpts().isImplicitIntRequired() && D.getDeclSpec().isEmpty()) {
Diag(D.getIdentifierLoc(), diag::warn_missing_type_specifier)
- << D.getDeclSpec().getSourceRange();
+ << D.getDeclSpec().getSourceRange()
+ << FixItHint::CreateInsertion(D.getDeclSpec().getBeginLoc(), "int ");
const char *PrevSpec;
unsigned DiagID;
const PrintingPolicy &Policy = Actions.getASTContext().getPrintingPolicy();
diff --git a/clang/lib/Sema/SemaType.cpp b/clang/lib/Sema/SemaType.cpp
index 348823ab2e9ca..a6d4b989cae3d 100644
--- a/clang/lib/Sema/SemaType.cpp
+++ b/clang/lib/Sema/SemaType.cpp
@@ -978,17 +978,24 @@ static QualType ConvertDeclSpecToType(TypeProcessingState &state) {
// parser already though by it pretending to have seen an 'int' in this
// case.
if (S.getLangOpts().isImplicitIntRequired()) {
- S.Diag(DeclLoc, diag::warn_missing_type_specifier)
- << DS.getSourceRange()
- << FixItHint::CreateInsertion(DS.getBeginLoc(), "int");
+ // Only emit the diagnostic for the first declarator in a DeclGroup, as
+ // the warning is always implied for all subsequent declarators, and the
+ // fix must only be applied exactly once as well.
+ if (declarator.isFirstDeclarator()) {
+ S.Diag(DeclLoc, diag::warn_missing_type_specifier)
+ << DS.getSourceRange()
+ << FixItHint::CreateInsertion(DS.getBeginLoc(), "int ");
+ }
} else if (!DS.hasTypeSpecifier()) {
// C99 and C++ require a type specifier. For example, C99 6.7.2p2 says:
// "At least one type specifier shall be given in the declaration
- // specifiers in each declaration, and in the specifier-qualifier list in
- // each struct declaration and type name."
+ // specifiers in each declaration, and in the specifier-qualifier list
+ // in each struct declaration and type name."
if (!S.getLangOpts().isImplicitIntAllowed() && !DS.isTypeSpecPipe()) {
- S.Diag(DeclLoc, diag::err_missing_type_specifier)
- << DS.getSourceRange();
+ if (declarator.isFirstDeclarator()) {
+ S.Diag(DeclLoc, diag::err_missing_type_specifier)
+ << DS.getSourceRange();
+ }
// When this occurs, often something is very broken with the value
// being declared, poison it as invalid so we don't get chains of
@@ -996,15 +1003,17 @@ static QualType ConvertDeclSpecToType(TypeProcessingState &state) {
declarator.setInvalidType(true);
} else if (S.getLangOpts().getOpenCLCompatibleVersion() >= 200 &&
DS.isTypeSpecPipe()) {
- S.Diag(DeclLoc, diag::err_missing_actual_pipe_type)
- << DS.getSourceRange();
+ if (declarator.isFirstDeclarator()) {
+ S.Diag(DeclLoc, diag::err_missing_actual_pipe_type)
+ << DS.getSourceRange();
+ }
declarator.setInvalidType(true);
- } else {
+ } else if (declarator.isFirstDeclarator()) {
assert(S.getLangOpts().isImplicitIntAllowed() &&
"implicit int is disabled?");
S.Diag(DeclLoc, diag::ext_missing_type_specifier)
<< DS.getSourceRange()
- << FixItHint::CreateInsertion(DS.getBeginLoc(), "int");
+ << FixItHint::CreateInsertion(DS.getBeginLoc(), "int ");
}
}
diff --git a/clang/test/FixIt/fixit-missing-type-spec.c b/clang/test/FixIt/fixit-missing-type-spec.c
new file mode 100644
index 0000000000000..a8804593bc496
--- /dev/null
+++ b/clang/test/FixIt/fixit-missing-type-spec.c
@@ -0,0 +1,61 @@
+// RUN: %clang_cc1 -std=c90 -pedantic -Wno-comment -Wno-deprecated-non-prototype -Wimplicit-int -fsyntax-only -verify=c90 -x c %s
+// RUN: cp %s %t
+// RUN: not %clang_cc1 -std=c90 -pedantic -Wno-comment -Wno-deprecated-non-prototype -Wimplicit-int -Werror -fixit %t
+// RUN: %clang_cc1 -std=c90 -pedantic -Wno-comment -Wno-deprecated-non-prototype -Wimplicit-int -fsyntax-only -verify -x c %t
+// RUN: cat %t | FileCheck %s
+//
+// RUN: %clang_cc1 -std=c99 -pedantic -Wno-deprecated-non-prototype -fsyntax-only -verify=c99 -x c %s
+// RUN: cp %s %t
+// RUN: not %clang_cc1 -std=c99 -pedantic -Wno-deprecated-non-prototype -fixit %t
+// RUN: %clang_cc1 -std=c99 -pedantic -Wno-deprecated-non-prototype -fsyntax-only -verify -x c %t
+// RUN: cat %t | FileCheck %s
+//
+// RUN: %clang_cc1 -std=c23 -pedantic -fsyntax-only -verify=c23 -x c %s
+
+// expected-no-diagnostics
+
+// CHECK: int imp0[4],imp1,imp2=5;
+imp0[4],imp1,imp2=5;
+// c90-warning at -1 {{type specifier missing, defaults to 'int'}}
+// c99-error at -2 {{type specifier missing, defaults to 'int'}}
+// c23-error at -3 {{a type specifier is required for all declarations}}
+// c23-error at -4 {{expected ';' after top level declarator}}
+
+// CHECK: int const imp3;
+const imp3;
+// c90-warning at -1 {{type specifier missing, defaults to 'int'}}
+// c99-error at -2 {{type specifier missing, defaults to 'int'}}
+// c23-error at -3 {{a type specifier is required for all declarations}}
+
+// CHECK: int static imp4;
+static imp4;
+// c90-warning at -1 {{type specifier missing, defaults to 'int'}}
+// c99-error at -2 {{type specifier missing, defaults to 'int'}}
+// c23-error at -3 {{a type specifier is required for all declarations}}
+
+// CHECK: int static const imp5;
+static const imp5;
+// c90-warning at -1 {{type specifier missing, defaults to 'int'}}
+// c99-error at -2 {{type specifier missing, defaults to 'int'}}
+// c23-error at -3 {{a type specifier is required for all declarations}}
+
+// CHECK: int volatile __attribute__ ((aligned (16))) imp6;
+volatile __attribute__ ((aligned (16))) imp6;
+// c90-warning at -1 {{type specifier missing, defaults to 'int'}}
+// c99-error at -2 {{type specifier missing, defaults to 'int'}}
+// c23-error at -3 {{a type specifier is required for all declarations}}
+
+// CHECK-LABEL: int f2(void)
+f2(void)
+// c90-warning at -1 {{type specifier missing, defaults to 'int'}}
+// c99-error at -2 {{type specifier missing, defaults to 'int'}}
+// c23-error at -3 {{a type specifier is required for all declarations}}
+{
+ // CHECK: int register __attribute__ ((uninitialized)) i;
+ register __attribute__ ((uninitialized)) i;
+ // c90-warning at -1 {{type specifier missing, defaults to 'int'}}
+ // c99-error at -2 {{type specifier missing, defaults to 'int'}}
+ // c23-error at -3 {{a type specifier is required for all declarations}}
+
+ return 0;
+}
diff --git a/clang/test/SemaOpenCL/invalid-pipes-cl2.0.cl b/clang/test/SemaOpenCL/invalid-pipes-cl2.0.cl
index edfce02f2ea25..089b2f16765fd 100644
--- a/clang/test/SemaOpenCL/invalid-pipes-cl2.0.cl
+++ b/clang/test/SemaOpenCL/invalid-pipes-cl2.0.cl
@@ -16,6 +16,8 @@ extern pipe write_only int get_pipe(void); // expected-error {{'write_only' attr
// expected-error-re at -5{{type '__private write_only pipe int ({{(void)?}})' can only be used as a function parameter in OpenCL}}
#endif
+global pipe notype1, notype2; // expected-error {{missing actual type specifier for pipe}}
+
kernel void test_invalid_reserved_id(reserve_id_t ID) { // expected-error {{'__private reserve_id_t' cannot be used as the type of a kernel parameter}}
}
More information about the cfe-commits
mailing list