Skip to content

Commit bc9aa0f

Browse files
authored
[C] Add -Wtentative-definition-compat (#137967)
This adds a new diagnostic to warn about redeclaration of a tentative definition in C. This is incompatible with C++, so the new diagnostic group is under -Wc++-compat.
1 parent 75d1cce commit bc9aa0f

File tree

6 files changed

+41
-1
lines changed

6 files changed

+41
-1
lines changed

clang/docs/ReleaseNotes.rst

+9
Original file line numberDiff line numberDiff line change
@@ -175,6 +175,15 @@ C Language Changes
175175
``-Wenum-conversion`` and ``-Wimplicit-int-enum-cast``. This conversion is an
176176
int-to-enum conversion because the enumeration on the right-hand side is
177177
promoted to ``int`` before the assignment.
178+
- Added ``-Wtentative-definition-compat``, grouped under ``-Wc++-compat``,
179+
which diagnoses tentative definitions in C with multiple declarations as
180+
being incompatible with C++. e.g.,
181+
182+
.. code-block:: c
183+
184+
// File scope
185+
int i;
186+
int i; // Vaild C, invalid C++, now diagnosed
178187
- Added ``-Wunterminated-string-initialization``, grouped under ``-Wextra``,
179188
which diagnoses an initialization from a string literal where only the null
180189
terminator cannot be stored. e.g.,

clang/include/clang/Basic/DiagnosticGroups.td

+2
Original file line numberDiff line numberDiff line change
@@ -176,9 +176,11 @@ def DefaultConstInit : DiagGroup<"default-const-init",
176176
def ImplicitVoidPtrCast : DiagGroup<"implicit-void-ptr-cast">;
177177
def ImplicitIntToEnumCast : DiagGroup<"implicit-int-enum-cast",
178178
[ImplicitEnumEnumCast]>;
179+
def TentativeDefnCompat : DiagGroup<"tentative-definition-compat">;
179180
def CXXCompat: DiagGroup<"c++-compat", [ImplicitVoidPtrCast, DefaultConstInit,
180181
ImplicitIntToEnumCast, HiddenCppDecl,
181182
InitStringTooLongForCpp,
183+
TentativeDefnCompat,
182184
DuplicateDeclSpecifier]>;
183185

184186
def ExternCCompat : DiagGroup<"extern-c-compat">;

clang/include/clang/Basic/DiagnosticSemaKinds.td

+3
Original file line numberDiff line numberDiff line change
@@ -7455,6 +7455,9 @@ def err_tentative_def_incomplete_type : Error<
74557455
def warn_tentative_incomplete_array : Warning<
74567456
"tentative array definition assumed to have one element">,
74577457
InGroup<DiagGroup<"tentative-definition-array">>;
7458+
def warn_cxx_compat_tentative_definition : Warning<
7459+
"duplicate declaration of %0 is invalid in C++">,
7460+
InGroup<TentativeDefnCompat>, DefaultIgnore;
74587461
def err_typecheck_incomplete_array_needs_initializer : Error<
74597462
"definition of variable with array type needs an explicit size "
74607463
"or an initializer">;

clang/lib/Sema/SemaDecl.cpp

+3
Original file line numberDiff line numberDiff line change
@@ -4750,6 +4750,9 @@ void Sema::MergeVarDecl(VarDecl *New, LookupResult &Previous) {
47504750
if (Def && checkVarDeclRedefinition(Def, New))
47514751
return;
47524752
}
4753+
} else {
4754+
Diag(New->getLocation(), diag::warn_cxx_compat_tentative_definition) << New;
4755+
Diag(Old->getLocation(), diag::note_previous_declaration);
47534756
}
47544757

47554758
if (haveIncompatibleLanguageLinkages(Old, New)) {

clang/test/Sema/warn-default-const-init.c

+1-1
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
// Both of these should enable everything.
2-
// RUN: %clang_cc1 -fsyntax-only -verify=unsafe-var,unsafe-field,zero-init-var,zero-init-field -Wc++-compat %s
2+
// RUN: %clang_cc1 -fsyntax-only -verify=unsafe-var,unsafe-field,zero-init-var,zero-init-field -Wc++-compat -Wno-tentative-definition-compat %s
33
// RUN: %clang_cc1 -fsyntax-only -verify=unsafe-var,unsafe-field,zero-init-var,zero-init-field -Wdefault-const-init %s
44

55
// This should enable nothing.
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,23 @@
1+
// RUN: %clang_cc1 -fsyntax-only -verify -Wtentative-definition-compat %s
2+
// RUN: %clang_cc1 -fsyntax-only -verify -Wc++-compat %s
3+
// RUN: %clang_cc1 -fsyntax-only -verify=good %s
4+
// RUN: %clang_cc1 -fsyntax-only -verify=cxx -x c++ %s
5+
// good-no-diagnostics
6+
7+
int i; // expected-note {{previous declaration is here}} \
8+
cxx-note {{previous definition is here}}
9+
int i; // expected-warning {{duplicate declaration of 'i' is invalid in C++}} \
10+
cxx-error {{redefinition of 'i'}}
11+
12+
int j = 12; // expected-note {{previous declaration is here}} \
13+
cxx-note {{previous definition is here}}
14+
int j; // expected-warning {{duplicate declaration of 'j' is invalid in C++}} \
15+
cxx-error {{redefinition of 'j'}}
16+
17+
int k; // expected-note {{previous declaration is here}} \
18+
cxx-note {{previous definition is here}}
19+
int k = 12; // expected-warning {{duplicate declaration of 'k' is invalid in C++}} \
20+
cxx-error {{redefinition of 'k'}}
21+
22+
// Cannot have two declarations with initializers, that is a redefinition in
23+
// both C and C++.

0 commit comments

Comments
 (0)