Skip to content
Merged
Show file tree
Hide file tree
Changes from 1 commit
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
9 changes: 9 additions & 0 deletions clang/docs/ReleaseNotes.rst
Original file line number Diff line number Diff line change
Expand Up @@ -150,6 +150,15 @@ C Language Changes
- Added ``-Wimplicit-void-ptr-cast``, grouped under ``-Wc++-compat``, which
diagnoses implicit conversion from ``void *`` to another pointer type as
being incompatible with C++. (#GH17792)
- Added ``-Wimplicit-int-enum-cast``, grouped under ``-Wc++-compat``, which
diagnoses implicit conversion from integer types to an enumeration type in C,
which is not compatible with C++. #GH37027
- Split "implicit conversion from enum type to different enum type" diagnostic
from ``-Wenum-conversion`` into its own diagnostic group,
``-Wimplicit-enum-enum-cast``, which is grouped under both
``-Wenum-conversion`` and ``-Wimplicit-int-enum-cast``. This conversion is an
int-to-enum conversion because the enumeration on the right-hand side is
promoted to ``int`` before the assignment.

C2y Feature Support
^^^^^^^^^^^^^^^^^^^
Expand Down
7 changes: 6 additions & 1 deletion clang/include/clang/Basic/DiagnosticGroups.td
Original file line number Diff line number Diff line change
Expand Up @@ -103,10 +103,12 @@ def AnonEnumEnumConversion : DiagGroup<"anon-enum-enum-conversion",
[DeprecatedAnonEnumEnumConversion]>;
def EnumEnumConversion : DiagGroup<"enum-enum-conversion",
[DeprecatedEnumEnumConversion]>;
def ImplicitEnumEnumCast : DiagGroup<"implicit-enum-enum-cast">;
def EnumFloatConversion : DiagGroup<"enum-float-conversion",
[DeprecatedEnumFloatConversion]>;
def EnumConversion : DiagGroup<"enum-conversion",
[EnumEnumConversion,
ImplicitEnumEnumCast,
EnumFloatConversion,
EnumCompareConditional]>;
def DeprecatedOFast : DiagGroup<"deprecated-ofast">;
Expand Down Expand Up @@ -157,7 +159,10 @@ def : DiagGroup<"c2x-compat", [C23Compat]>;
def DefaultConstInitUnsafe : DiagGroup<"default-const-init-unsafe">;
def DefaultConstInit : DiagGroup<"default-const-init", [DefaultConstInitUnsafe]>;
def ImplicitVoidPtrCast : DiagGroup<"implicit-void-ptr-cast">;
def CXXCompat: DiagGroup<"c++-compat", [ImplicitVoidPtrCast, DefaultConstInit]>;
def ImplicitIntToEnumCast : DiagGroup<"implicit-int-enum-cast",
[ImplicitEnumEnumCast]>;
def CXXCompat: DiagGroup<"c++-compat", [ImplicitVoidPtrCast, DefaultConstInit,
ImplicitIntToEnumCast]>;

def ExternCCompat : DiagGroup<"extern-c-compat">;
def KeywordCompat : DiagGroup<"keyword-compat">;
Expand Down
5 changes: 4 additions & 1 deletion clang/include/clang/Basic/DiagnosticSemaKinds.td
Original file line number Diff line number Diff line change
Expand Up @@ -4310,7 +4310,10 @@ def warn_impcast_string_literal_to_bool : Warning<
InGroup<StringConversion>, DefaultIgnore;
def warn_impcast_different_enum_types : Warning<
"implicit conversion from enumeration type %0 to different enumeration type "
"%1">, InGroup<EnumConversion>;
"%1">, InGroup<ImplicitEnumEnumCast>;
def warn_impcast_int_to_enum : Warning<
"implicit conversion from %0 to enumeration type %1 is invalid in C++">,
InGroup<ImplicitIntToEnumCast>, DefaultIgnore;
def warn_impcast_bool_to_null_pointer : Warning<
"initialization of pointer of type %0 to null from a constant boolean "
"expression">, InGroup<BoolConversion>;
Expand Down
8 changes: 7 additions & 1 deletion clang/lib/Sema/SemaChecking.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -12271,10 +12271,16 @@ void Sema::CheckImplicitConversion(Expr *E, QualType T, SourceLocation CC,
return DiagnoseImpCast(*this, E, T, CC, DiagID);
}

// If we're implicitly converting from an integer into an enumeration, that
// is valid in C but invalid in C++.
QualType SourceType = E->getEnumCoercedType(Context);
const BuiltinType *CoercedSourceBT = SourceType->getAs<BuiltinType>();
if (CoercedSourceBT && CoercedSourceBT->isInteger() && isa<EnumType>(Target))
return DiagnoseImpCast(*this, E, T, CC, diag::warn_impcast_int_to_enum);

// Diagnose conversions between different enumeration types.
// In C, we pretend that the type of an EnumConstantDecl is its enumeration
// type, to give us better diagnostics.
QualType SourceType = E->getEnumCoercedType(Context);
Source = Context.getCanonicalType(SourceType).getTypePtr();

if (const EnumType *SourceEnum = Source->getAs<EnumType>())
Expand Down
8 changes: 5 additions & 3 deletions clang/test/Misc/warning-flags-enabled.c
Original file line number Diff line number Diff line change
Expand Up @@ -26,13 +26,15 @@
// CHECK-NO-LEVELS-NOT: {{^F }}
// CHECK-NO-LEVELS: warn_objc_root_class_missing [-Wobjc-root-class]

// Test if EnumConversion is a subgroup of -Wconversion.
// Test if EnumConversion is a subgroup of -Wconversion. Because no diagnostics
// are grouped directly under -Wenum-conversion, we check for
// -Wimplicit-enum-enum-cast instead (which is itself under -Wenum-conversion).
// RUN: diagtool show-enabled --no-levels -Wno-conversion -Wenum-conversion %s | FileCheck --check-prefix CHECK-ENUM-CONVERSION %s
// RUN: diagtool show-enabled --no-levels %s | FileCheck --check-prefix CHECK-ENUM-CONVERSION %s
// RUN: diagtool show-enabled --no-levels -Wno-conversion %s | FileCheck --check-prefix CHECK-NO-ENUM-CONVERSION %s
//
// CHECK-ENUM-CONVERSION: -Wenum-conversion
// CHECK-NO-ENUM-CONVERSION-NOT: -Wenum-conversion
// CHECK-ENUM-CONVERSION: -Wimplicit-enum-enum-cast
// CHECK-NO-ENUM-CONVERSION-NOT: -Wimplicit-enum-enum-cast

// Test if -Wshift-op-parentheses is a subgroup of -Wparentheses
// RUN: diagtool show-enabled --no-levels -Wno-parentheses -Wshift-op-parentheses %s | FileCheck --check-prefix CHECK-SHIFT-OP-PARENTHESES %s
Expand Down
52 changes: 52 additions & 0 deletions clang/test/Sema/implicit-int-enum-conversion.c
Original file line number Diff line number Diff line change
@@ -0,0 +1,52 @@
// RUN: %clang_cc1 -fsyntax-only -verify -Wimplicit-int-enum-cast %s
// RUN: %clang_cc1 -fsyntax-only -verify -Wc++-compat %s
// RUN: %clang_cc1 -fsyntax-only -verify=cxx -x c++ %s
// RUN: %clang_cc1 -fsyntax-only -verify=good -Wno-implicit-enum-enum-cast %s
// RUN: %clang_cc1 -fsyntax-only -verify=good -Wc++-compat -Wno-implicit-enum-enum-cast -Wno-implicit-int-enum-cast %s
// good-no-diagnostics

enum E1 {
E1_Zero,
E1_One
};

enum E2 {
E2_Zero
};

struct S {
enum E1 e;
} s = { 12 }; // expected-warning {{implicit conversion from 'int' to enumeration type 'enum E1' is invalid in C++}} \
cxx-error {{cannot initialize a member subobject of type 'enum E1' with an rvalue of type 'int'}}

enum E1 foo(void) {
int x;
enum E1 e = 12; // expected-warning {{implicit conversion from 'int' to enumeration type 'enum E1' is invalid in C++}} \
cxx-error {{cannot initialize a variable of type 'enum E1' with an rvalue of type 'int'}}

// Enum to integer is fine.
x = e;

// Integer to enum is not fine.
e = x; // expected-warning {{implicit conversion from 'int' to enumeration type 'enum E1' is invalid in C++}} \
cxx-error {{assigning to 'enum E1' from incompatible type 'int'}}
return x; // expected-warning {{implicit conversion from 'int' to enumeration type 'enum E1' is invalid in C++}} \
cxx-error {{cannot initialize return object of type 'enum E1' with an lvalue of type 'int'}}
}

// Returning with the correct types is fine.
enum E1 bar(void) {
return E1_Zero;
}

// Enum to different-enum conversion is also a C++ incompatibility, but is
// handled via a more general diagnostic, -Wimplicit-enum-enum-cast, which is
// on by default.
enum E1 quux(void) {
enum E1 e1 = E2_Zero; // expected-warning {{implicit conversion from enumeration type 'enum E2' to different enumeration type 'enum E1'}} \
cxx-error {{cannot initialize a variable of type 'enum E1' with an rvalue of type 'E2'}}
e1 = E2_Zero; // expected-warning {{implicit conversion from enumeration type 'enum E2' to different enumeration type 'enum E1'}} \
cxx-error {{assigning to 'enum E1' from incompatible type 'E2'}}
return E2_Zero; // expected-warning {{implicit conversion from enumeration type 'enum E2' to different enumeration type 'enum E1'}} \
cxx-error {{cannot initialize return object of type 'enum E1' with an rvalue of type 'E2'}}
}
Loading