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@-1 {{type specifier missing, defaults to 'int'}} +// c99-error@-2 {{type specifier missing, defaults to 'int'}} +// c23-error@-3 {{a type specifier is required for all declarations}} +// c23-error@-4 {{expected ';' after top level declarator}} + +// CHECK: int const imp3; +const imp3; +// c90-warning@-1 {{type specifier missing, defaults to 'int'}} +// c99-error@-2 {{type specifier missing, defaults to 'int'}} +// c23-error@-3 {{a type specifier is required for all declarations}} + +// CHECK: int static imp4; +static imp4; +// c90-warning@-1 {{type specifier missing, defaults to 'int'}} +// c99-error@-2 {{type specifier missing, defaults to 'int'}} +// c23-error@-3 {{a type specifier is required for all declarations}} + +// CHECK: int static const imp5; +static const imp5; +// c90-warning@-1 {{type specifier missing, defaults to 'int'}} +// c99-error@-2 {{type specifier missing, defaults to 'int'}} +// c23-error@-3 {{a type specifier is required for all declarations}} + +// CHECK: int volatile __attribute__ ((aligned (16))) imp6; +volatile __attribute__ ((aligned (16))) imp6; +// c90-warning@-1 {{type specifier missing, defaults to 'int'}} +// c99-error@-2 {{type specifier missing, defaults to 'int'}} +// c23-error@-3 {{a type specifier is required for all declarations}} + +// CHECK-LABEL: int f2(void) +f2(void) +// c90-warning@-1 {{type specifier missing, defaults to 'int'}} +// c99-error@-2 {{type specifier missing, defaults to 'int'}} +// c23-error@-3 {{a type specifier is required for all declarations}} +{ + // CHECK: int register __attribute__ ((uninitialized)) i; + register __attribute__ ((uninitialized)) i; + // c90-warning@-1 {{type specifier missing, defaults to 'int'}} + // c99-error@-2 {{type specifier missing, defaults to 'int'}} + // c23-error@-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@-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}} } _______________________________________________ cfe-commits mailing list [email protected] https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
