Author: Balázs Kéri Date: 2025-07-31T09:00:34+02:00 New Revision: 6f2cf6b0acf206626cb69cda6e428d1091a4e783
URL: https://github.com/llvm/llvm-project/commit/6f2cf6b0acf206626cb69cda6e428d1091a4e783 DIFF: https://github.com/llvm/llvm-project/commit/6f2cf6b0acf206626cb69cda6e428d1091a4e783.diff LOG: [clang-tidy] Add check 'bugprone-invalid-enum-default-initialization' (#136823) Added: clang-tools-extra/clang-tidy/bugprone/InvalidEnumDefaultInitializationCheck.cpp clang-tools-extra/clang-tidy/bugprone/InvalidEnumDefaultInitializationCheck.h clang-tools-extra/docs/clang-tidy/checks/bugprone/invalid-enum-default-initialization.rst clang-tools-extra/test/clang-tidy/checkers/bugprone/invalid-enum-default-initialization.c clang-tools-extra/test/clang-tidy/checkers/bugprone/invalid-enum-default-initialization.cpp Modified: clang-tools-extra/clang-tidy/bugprone/BugproneTidyModule.cpp clang-tools-extra/clang-tidy/bugprone/CMakeLists.txt clang-tools-extra/docs/ReleaseNotes.rst clang-tools-extra/docs/clang-tidy/checks/list.rst Removed: ################################################################################ diff --git a/clang-tools-extra/clang-tidy/bugprone/BugproneTidyModule.cpp b/clang-tools-extra/clang-tidy/bugprone/BugproneTidyModule.cpp index ed1fd138d8f1b..824ebdfbd00dc 100644 --- a/clang-tools-extra/clang-tidy/bugprone/BugproneTidyModule.cpp +++ b/clang-tools-extra/clang-tidy/bugprone/BugproneTidyModule.cpp @@ -38,6 +38,7 @@ #include "IncorrectRoundingsCheck.h" #include "InfiniteLoopCheck.h" #include "IntegerDivisionCheck.h" +#include "InvalidEnumDefaultInitializationCheck.h" #include "LambdaFunctionNameCheck.h" #include "MacroParenthesesCheck.h" #include "MacroRepeatedSideEffectsCheck.h" @@ -165,6 +166,8 @@ class BugproneModule : public ClangTidyModule { CheckFactories.registerCheck<InfiniteLoopCheck>("bugprone-infinite-loop"); CheckFactories.registerCheck<IntegerDivisionCheck>( "bugprone-integer-division"); + CheckFactories.registerCheck<InvalidEnumDefaultInitializationCheck>( + "bugprone-invalid-enum-default-initialization"); CheckFactories.registerCheck<LambdaFunctionNameCheck>( "bugprone-lambda-function-name"); CheckFactories.registerCheck<MacroParenthesesCheck>( diff --git a/clang-tools-extra/clang-tidy/bugprone/CMakeLists.txt b/clang-tools-extra/clang-tidy/bugprone/CMakeLists.txt index d862794cde323..59928e5e47a09 100644 --- a/clang-tools-extra/clang-tidy/bugprone/CMakeLists.txt +++ b/clang-tools-extra/clang-tidy/bugprone/CMakeLists.txt @@ -30,6 +30,7 @@ add_clang_library(clangTidyBugproneModule STATIC InaccurateEraseCheck.cpp IncorrectEnableIfCheck.cpp IncorrectEnableSharedFromThisCheck.cpp + InvalidEnumDefaultInitializationCheck.cpp UnintendedCharOstreamOutputCheck.cpp ReturnConstRefFromParameterCheck.cpp SuspiciousStringviewDataUsageCheck.cpp diff --git a/clang-tools-extra/clang-tidy/bugprone/InvalidEnumDefaultInitializationCheck.cpp b/clang-tools-extra/clang-tidy/bugprone/InvalidEnumDefaultInitializationCheck.cpp new file mode 100644 index 0000000000000..33fcf45788277 --- /dev/null +++ b/clang-tools-extra/clang-tidy/bugprone/InvalidEnumDefaultInitializationCheck.cpp @@ -0,0 +1,180 @@ +//===--- InvalidEnumDefaultInitializationCheck.cpp - clang-tidy -----------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +#include "InvalidEnumDefaultInitializationCheck.h" +#include "clang/AST/ASTContext.h" +#include "clang/AST/TypeVisitor.h" +#include "clang/ASTMatchers/ASTMatchFinder.h" +#include <algorithm> + +using namespace clang::ast_matchers; + +namespace clang::tidy::bugprone { + +namespace { + +bool isCompleteAndHasNoZeroValue(const EnumDecl *D) { + const EnumDecl *Definition = D->getDefinition(); + return Definition && Definition->isComplete() && + !Definition->enumerators().empty() && + std::none_of(Definition->enumerator_begin(), + Definition->enumerator_end(), + [](const EnumConstantDecl *Value) { + return Value->getInitVal().isZero(); + }); +} + +AST_MATCHER(EnumDecl, isCompleteAndHasNoZeroValue) { + return isCompleteAndHasNoZeroValue(&Node); +} + +// Find an initialization which initializes the value (if it has enum type) to a +// default zero value. +AST_MATCHER(Expr, isEmptyInit) { + if (isa<CXXScalarValueInitExpr, ImplicitValueInitExpr>(&Node)) + return true; + if (const auto *Init = dyn_cast<InitListExpr>(&Node)) { + if (Init->getNumInits() == 0) + return true; + } + return false; +} + +AST_MATCHER(InitListExpr, hasArrayFiller) { return Node.hasArrayFiller(); } + +// Check if any type has a "child" type that is an enum without zero value. +// The "child" type can be an array element type or member type of a record +// type (or a recursive combination of these). In this case, if the "root" type +// is statically initialized, the enum component is initialized to zero. +class FindEnumMember : public TypeVisitor<FindEnumMember, bool> { +public: + const EnumType *FoundEnum = nullptr; + + bool VisitType(const Type *T) { + const Type *DesT = T->getUnqualifiedDesugaredType(); + if (DesT != T) + return Visit(DesT); + return false; + } + bool VisitArrayType(const ArrayType *T) { + return Visit(T->getElementType().getTypePtr()); + } + bool VisitConstantArrayType(const ConstantArrayType *T) { + return Visit(T->getElementType().getTypePtr()); + } + bool VisitEnumType(const EnumType *T) { + if (isCompleteAndHasNoZeroValue(T->getDecl())) { + FoundEnum = T; + return true; + } + return false; + } + bool VisitRecordType(const RecordType *T) { + const RecordDecl *RD = T->getDecl(); + if (RD->isUnion()) + return false; + auto VisitField = [this](const FieldDecl *F) { + return Visit(F->getType().getTypePtr()); + }; + return llvm::any_of(RD->fields(), VisitField); + } +}; + +} // namespace + +InvalidEnumDefaultInitializationCheck::InvalidEnumDefaultInitializationCheck( + StringRef Name, ClangTidyContext *Context) + : ClangTidyCheck(Name, Context) {} + +void InvalidEnumDefaultInitializationCheck::registerMatchers( + MatchFinder *Finder) { + auto EnumWithoutZeroValue = enumType( + hasDeclaration(enumDecl(isCompleteAndHasNoZeroValue()).bind("enum"))); + auto EnumOrArrayOfEnum = qualType(hasUnqualifiedDesugaredType( + anyOf(EnumWithoutZeroValue, + arrayType(hasElementType(qualType( + hasUnqualifiedDesugaredType(EnumWithoutZeroValue))))))); + Finder->addMatcher( + expr(isEmptyInit(), hasType(EnumOrArrayOfEnum)).bind("expr"), this); + + // Array initialization can contain an "array filler" for the (syntactically) + // unspecified elements. This expression is not found by AST matchers and can + // have any type (the array's element type). This is an implicitly generated + // initialization, so if the type contains somewhere an enum without zero + // enumerator, the zero initialization applies here. We search this array + // element type for the specific enum type manually when this matcher matches. + Finder->addMatcher(initListExpr(hasArrayFiller()).bind("array_filler_expr"), + this); +} + +void InvalidEnumDefaultInitializationCheck::check( + const MatchFinder::MatchResult &Result) { + const auto *InitExpr = Result.Nodes.getNodeAs<Expr>("expr"); + const auto *Enum = Result.Nodes.getNodeAs<EnumDecl>("enum"); + if (!InitExpr) { + const auto *InitList = + Result.Nodes.getNodeAs<InitListExpr>("array_filler_expr"); + // Initialization of omitted array elements with array filler was found. + // Check the type for enum without zero value. + // FIXME: In this way only one enum-typed value is found, not all of these. + FindEnumMember Finder; + if (!Finder.Visit(InitList->getArrayFiller()->getType().getTypePtr())) + return; + InitExpr = InitList; + Enum = Finder.FoundEnum->getDecl(); + } + + if (!InitExpr || !Enum) + return; + + ASTContext &ACtx = Enum->getASTContext(); + SourceLocation Loc = InitExpr->getExprLoc(); + if (Loc.isInvalid()) { + if (isa<ImplicitValueInitExpr, InitListExpr>(InitExpr)) { + DynTypedNodeList Parents = ACtx.getParents(*InitExpr); + if (Parents.empty()) + return; + + if (const auto *Ctor = Parents[0].get<CXXConstructorDecl>()) { + // Try to find member initializer with the found expression and get the + // source location from it. + CXXCtorInitializer *const *CtorInit = std::find_if( + Ctor->init_begin(), Ctor->init_end(), + [InitExpr](const CXXCtorInitializer *Init) { + return Init->isMemberInitializer() && Init->getInit() == InitExpr; + }); + if (!CtorInit) + return; + Loc = (*CtorInit)->getLParenLoc(); + } else if (const auto *InitList = Parents[0].get<InitListExpr>()) { + // The expression may be implicitly generated for an initialization. + // Search for a parent initialization list with valid source location. + while (InitList->getExprLoc().isInvalid()) { + DynTypedNodeList Parents = ACtx.getParents(*InitList); + if (Parents.empty()) + return; + InitList = Parents[0].get<InitListExpr>(); + if (!InitList) + return; + } + Loc = InitList->getExprLoc(); + } + } + // If still not found a source location, omit the warning. + // Ideally all such cases (if they exist) should be handled to make the + // check more precise. + if (Loc.isInvalid()) + return; + } + diag(Loc, "enum value of type %0 initialized with invalid value of 0, " + "enum doesn't have a zero-value enumerator") + << Enum; + diag(Enum->getLocation(), "enum is defined here", DiagnosticIDs::Note); +} + +} // namespace clang::tidy::bugprone diff --git a/clang-tools-extra/clang-tidy/bugprone/InvalidEnumDefaultInitializationCheck.h b/clang-tools-extra/clang-tidy/bugprone/InvalidEnumDefaultInitializationCheck.h new file mode 100644 index 0000000000000..0746c4d025d1f --- /dev/null +++ b/clang-tools-extra/clang-tidy/bugprone/InvalidEnumDefaultInitializationCheck.h @@ -0,0 +1,31 @@ +//===--- InvalidEnumDefaultInitializationCheck.h - clang-tidy -*- C++ -*---===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_CLANG_TOOLS_EXTRA_CLANG_TIDY_BUGPRONE_INVALIDENUMDEFAULTINITIALIZATIONCHECK_H +#define LLVM_CLANG_TOOLS_EXTRA_CLANG_TIDY_BUGPRONE_INVALIDENUMDEFAULTINITIALIZATIONCHECK_H + +#include "../ClangTidyCheck.h" + +namespace clang::tidy::bugprone { + +/// Detects default initialization (to 0) of variables with `enum` type where +/// the enum has no enumerator with value of 0. +/// +/// For the user-facing documentation see: +/// http://clang.llvm.org/extra/clang-tidy/checks/bugprone/invalid-enum-default-initialization.html +class InvalidEnumDefaultInitializationCheck : public ClangTidyCheck { +public: + InvalidEnumDefaultInitializationCheck(StringRef Name, + ClangTidyContext *Context); + void registerMatchers(ast_matchers::MatchFinder *Finder) override; + void check(const ast_matchers::MatchFinder::MatchResult &Result) override; +}; + +} // namespace clang::tidy::bugprone + +#endif // LLVM_CLANG_TOOLS_EXTRA_CLANG_TIDY_BUGPRONE_INVALIDENUMDEFAULTINITIALIZATIONCHECK_H diff --git a/clang-tools-extra/docs/ReleaseNotes.rst b/clang-tools-extra/docs/ReleaseNotes.rst index 2de2818172850..e45f870fd4330 100644 --- a/clang-tools-extra/docs/ReleaseNotes.rst +++ b/clang-tools-extra/docs/ReleaseNotes.rst @@ -108,6 +108,12 @@ Improvements to clang-tidy New checks ^^^^^^^^^^ +- New :doc:`bugprone-invalid-enum-default-initialization + <clang-tidy/checks/bugprone/invalid-enum-default-initialization>` check. + + Detects default initialization (to 0) of variables with ``enum`` type where + the enum has no enumerator with value of 0. + - New :doc:`llvm-mlir-op-builder <clang-tidy/checks/llvm/use-new-mlir-op-builder>` check. diff --git a/clang-tools-extra/docs/clang-tidy/checks/bugprone/invalid-enum-default-initialization.rst b/clang-tools-extra/docs/clang-tidy/checks/bugprone/invalid-enum-default-initialization.rst new file mode 100644 index 0000000000000..a3bd2b6d85c37 --- /dev/null +++ b/clang-tools-extra/docs/clang-tidy/checks/bugprone/invalid-enum-default-initialization.rst @@ -0,0 +1,72 @@ +.. title:: clang-tidy - bugprone-invalid-enum-default-initialization + +bugprone-invalid-enum-default-initialization +============================================ + +Detects default initialization (to 0) of variables with ``enum`` type where +the enum has no enumerator with value of 0. + +In C++ a default initialization is performed if a variable is initialized with +initializer list or in other implicit ways, and no value is specified at the +initialization. In such cases the value 0 is used for the initialization. +This also applies to enumerations even if it does not have an enumerator with +value 0. In this way a variable with the ``enum`` type may contain initially an +invalid value (if the program expects that it contains only the listed +enumerator values). + +The check emits a warning only if an ``enum`` variable is default-initialized +(contrary to not initialized) and the ``enum`` does not have an enumerator with +value of 0. The type can be a scoped or non-scoped ``enum``. Unions are not +handled by the check (if it contains a member of enumeration type). + +.. code-block:: c++ + + enum class Enum1: int { + A = 1, + B + }; + + enum class Enum0: int { + A = 0, + B + }; + + void f() { + Enum1 X1{}; // warn: 'X1' is initialized to 0 + Enum1 X2 = Enum1(); // warn: 'X2' is initialized to 0 + Enum1 X3; // no warning: 'X3' is not initialized + Enum0 X4{}; // no warning: type has an enumerator with value of 0 + } + + struct S1 { + Enum1 A; + S(): A() {} // warn: 'A' is initialized to 0 + }; + + struct S2 { + int A; + Enum1 B; + }; + + S2 VarS2{}; // warn: member 'B' is initialized to 0 + +The check applies to initialization of arrays or structures with initialization +lists in C code too. In these cases elements not specified in the list (and have +enum type) are set to 0. + +.. code-block:: c + + enum Enum1 { + Enum1_A = 1, + Enum1_B + }; + struct Struct1 { + int a; + enum Enum1 b; + }; + + enum Enum1 Array1[2] = {Enum1_A}; // warn: omitted elements are initialized to 0 + enum Enum1 Array2[2][2] = {{Enum1_A}, {Enum1_A}}; // warn: last element of both nested arrays is initialized to 0 + enum Enum1 Array3[2][2] = {{Enum1_A, Enum1_A}}; // warn: elements of second array are initialized to 0 + + struct Struct1 S1 = {1}; // warn: element 'b' is initialized to 0 diff --git a/clang-tools-extra/docs/clang-tidy/checks/list.rst b/clang-tools-extra/docs/clang-tidy/checks/list.rst index 20a43274f9788..b6444eb3c9aec 100644 --- a/clang-tools-extra/docs/clang-tidy/checks/list.rst +++ b/clang-tools-extra/docs/clang-tidy/checks/list.rst @@ -106,6 +106,7 @@ Clang-Tidy Checks :doc:`bugprone-incorrect-roundings <bugprone/incorrect-roundings>`, :doc:`bugprone-infinite-loop <bugprone/infinite-loop>`, :doc:`bugprone-integer-division <bugprone/integer-division>`, + :doc:`bugprone-invalid-enum-default-initialization <bugprone/invalid-enum-default-initialization>`, :doc:`bugprone-lambda-function-name <bugprone/lambda-function-name>`, :doc:`bugprone-macro-parentheses <bugprone/macro-parentheses>`, "Yes" :doc:`bugprone-macro-repeated-side-effects <bugprone/macro-repeated-side-effects>`, diff --git a/clang-tools-extra/test/clang-tidy/checkers/bugprone/invalid-enum-default-initialization.c b/clang-tools-extra/test/clang-tidy/checkers/bugprone/invalid-enum-default-initialization.c new file mode 100644 index 0000000000000..55f588477a65e --- /dev/null +++ b/clang-tools-extra/test/clang-tidy/checkers/bugprone/invalid-enum-default-initialization.c @@ -0,0 +1,54 @@ +// RUN: %check_clang_tidy %s bugprone-invalid-enum-default-initialization %t + +enum Enum1 { + Enum1_A = 1, + Enum1_B +}; + +struct Struct1 { + int a; + enum Enum1 b; +}; + +struct Struct2 { + struct Struct1 a; + char b; +}; + +enum Enum1 E1 = {}; +// CHECK-NOTES: :[[@LINE-1]]:17: warning: enum value of type 'Enum1' initialized with invalid value of 0, enum doesn't have a zero-value enumerator +// CHECK-NOTES: :3:6: note: enum is defined here +enum Enum1 E2[10] = {}; +// CHECK-NOTES: :[[@LINE-1]]:21: warning: enum value of type 'Enum1' initialized with invalid value of 0, enum doesn't have a zero-value enumerator +// CHECK-NOTES: :3:6: note: enum is defined here +enum Enum1 E3[10] = {Enum1_A}; +// CHECK-NOTES: :[[@LINE-1]]:21: warning: enum value of type 'Enum1' initialized with invalid value of 0, enum doesn't have a zero-value enumerator +// CHECK-NOTES: :3:6: note: enum is defined here +enum Enum1 E4[2][2] = {{Enum1_A}, {Enum1_A}}; +// CHECK-NOTES: :[[@LINE-1]]:24: warning: enum value of type 'Enum1' initialized with invalid value of 0, enum doesn't have a zero-value enumerator +// CHECK-NOTES: :3:6: note: enum is defined here +// CHECK-NOTES: :[[@LINE-3]]:35: warning: enum value of type 'Enum1' initialized with invalid value of 0, enum doesn't have a zero-value enumerator +// CHECK-NOTES: :3:6: note: enum is defined here +enum Enum1 E5[2][2] = {{Enum1_A, Enum1_A}}; +// CHECK-NOTES: :[[@LINE-1]]:23: warning: enum value of type 'Enum1' initialized with invalid value of 0, enum doesn't have a zero-value enumerator +// CHECK-NOTES: :3:6: note: enum is defined here + + +struct Struct1 S1[2][2] = {{{1, Enum1_A}, {2, Enum1_A}}}; +// CHECK-NOTES: :[[@LINE-1]]:27: warning: enum value of type 'Enum1' initialized with invalid value of 0, enum doesn't have a zero-value enumerator +// CHECK-NOTES: :3:6: note: enum is defined here + +struct Struct2 S2[3] = {{1}}; +// CHECK-NOTES: :[[@LINE-1]]:24: warning: enum value of type 'Enum1' initialized with invalid value of 0, enum doesn't have a zero-value enumerator +// CHECK-NOTES: :3:6: note: enum is defined here +// CHECK-NOTES: :[[@LINE-3]]:26: warning: enum value of type 'Enum1' initialized with invalid value of 0, enum doesn't have a zero-value enumerator +// CHECK-NOTES: :3:6: note: enum is defined here + +union Union1 { + enum Enum1 a; + int b; +}; + +// no warnings for union +union Union1 U1 = {}; +union Union1 U2[3] = {}; diff --git a/clang-tools-extra/test/clang-tidy/checkers/bugprone/invalid-enum-default-initialization.cpp b/clang-tools-extra/test/clang-tidy/checkers/bugprone/invalid-enum-default-initialization.cpp new file mode 100644 index 0000000000000..eb3d5632eaef7 --- /dev/null +++ b/clang-tools-extra/test/clang-tidy/checkers/bugprone/invalid-enum-default-initialization.cpp @@ -0,0 +1,145 @@ +// RUN: %check_clang_tidy -std=c++17 %s bugprone-invalid-enum-default-initialization %t + +enum class Enum0: int { + A = 0, + B +}; + +enum class Enum1: int { + A = 1, + B +}; + +enum Enum2 { + Enum_A = 4, + Enum_B +}; + +Enum0 E0_1{}; +Enum0 E0_2 = Enum0(); +Enum0 E0_3; +Enum0 E0_4{0}; +Enum0 E0_5{Enum0::A}; +Enum0 E0_6{Enum0::B}; + +Enum1 E1_1{}; +// CHECK-NOTES: :[[@LINE-1]]:11: warning: enum value of type 'Enum1' initialized with invalid value of 0, enum doesn't have a zero-value enumerator +// CHECK-NOTES: :8:12: note: enum is defined here +Enum1 E1_2 = Enum1(); +// CHECK-NOTES: :[[@LINE-1]]:14: warning: enum value of type 'Enum1' initialized with invalid value of 0, enum doesn't have a zero-value enumerator +// CHECK-NOTES: :8:12: note: enum is defined here +Enum1 E1_3; +Enum1 E1_4{0}; +Enum1 E1_5{Enum1::A}; +Enum1 E1_6{Enum1::B}; + +Enum2 E2_1{}; +// CHECK-NOTES: :[[@LINE-1]]:11: warning: enum value of type 'Enum2' initialized with invalid value of 0, enum doesn't have a zero-value enumerator +// CHECK-NOTES: :13:6: note: enum is defined here +Enum2 E2_2 = Enum2(); +// CHECK-NOTES: :[[@LINE-1]]:14: warning: enum value of type 'Enum2' initialized with invalid value of 0, enum doesn't have a zero-value enumerator +// CHECK-NOTES: :13:6: note: enum is defined here + +void f1() { + static Enum1 S; // FIMXE: warn for this? + Enum1 A; + Enum1 B = Enum1(); + // CHECK-NOTES: :[[@LINE-1]]:13: warning: enum value of type 'Enum1' initialized with invalid value of 0, enum doesn't have a zero-value enumerator + // CHECK-NOTES: :8:12: note: enum is defined here + int C = int(); +} + +void f2() { + Enum1 A{}; + // CHECK-NOTES: :[[@LINE-1]]:10: warning: enum value of type 'Enum1' initialized with invalid value of 0, enum doesn't have a zero-value enumerator + // CHECK-NOTES: :8:12: note: enum is defined here + Enum1 B = Enum1(); + // CHECK-NOTES: :[[@LINE-1]]:13: warning: enum value of type 'Enum1' initialized with invalid value of 0, enum doesn't have a zero-value enumerator + // CHECK-NOTES: :8:12: note: enum is defined here + Enum1 C[5] = {{}}; + // CHECK-NOTES: :[[@LINE-1]]:16: warning: enum value of type 'Enum1' initialized with invalid value of 0, enum doesn't have a zero-value enumerator + // CHECK-NOTES: :8:12: note: enum is defined here + // CHECK-NOTES: :[[@LINE-3]]:17: warning: enum value of type 'Enum1' initialized with invalid value of 0, enum doesn't have a zero-value enumerator + // CHECK-NOTES: :8:12: note: enum is defined here + Enum1 D[5] = {}; // FIMXE: warn for this? + // CHECK-NOTES: :[[@LINE-1]]:16: warning: enum value of type 'Enum1' initialized with invalid value of 0, enum doesn't have a zero-value enumerator + // CHECK-NOTES: :8:12: note: enum is defined here +} + +struct S1 { + Enum1 E_1{}; + // CHECK-NOTES: :[[@LINE-1]]:12: warning: enum value of type 'Enum1' initialized with invalid value of 0, enum doesn't have a zero-value enumerator + // CHECK-NOTES: :8:12: note: enum is defined here + Enum1 E_2 = Enum1(); + // CHECK-NOTES: :[[@LINE-1]]:15: warning: enum value of type 'Enum1' initialized with invalid value of 0, enum doesn't have a zero-value enumerator + // CHECK-NOTES: :8:12: note: enum is defined here + Enum1 E_3; + Enum1 E_4; + Enum1 E_5; + + S1() : + E_3{}, + // CHECK-NOTES: :[[@LINE-1]]:8: warning: enum value of type 'Enum1' initialized with invalid value of 0, enum doesn't have a zero-value enumerator + // CHECK-NOTES: :8:12: note: enum is defined here + E_4(), + // CHECK-NOTES: :[[@LINE-1]]:8: warning: enum value of type 'Enum1' initialized with invalid value of 0, enum doesn't have a zero-value enumerator + // CHECK-NOTES: :8:12: note: enum is defined here + E_5{Enum1::B} + {} +}; + +struct S2 { + Enum0 X; + Enum1 Y; + Enum2 Z; +}; + +struct S3 { + S2 X; + int Y; +}; + +struct S4 : public S3 { + int Z; +}; + +struct S5 { + S2 X[3]; + int Y; +}; + +S2 VarS2{}; +// CHECK-NOTES: :[[@LINE-1]]:9: warning: enum value of type 'Enum1' initialized with invalid value of 0 +// CHECK-NOTES: :8:12: note: enum is defined here +// CHECK-NOTES: :[[@LINE-3]]:9: warning: enum value of type 'Enum2' initialized with invalid value of 0 +// CHECK-NOTES: :13:6: note: enum is defined here +S3 VarS3{}; +// CHECK-NOTES: :[[@LINE-1]]:10: warning: enum value of type 'Enum1' initialized with invalid value of 0 +// CHECK-NOTES: :8:12: note: enum is defined here +// CHECK-NOTES: :[[@LINE-3]]:10: warning: enum value of type 'Enum2' initialized with invalid value of 0 +// CHECK-NOTES: :13:6: note: enum is defined here +S4 VarS4{}; +// CHECK-NOTES: :[[@LINE-1]]:10: warning: enum value of type 'Enum1' initialized with invalid value of 0 +// CHECK-NOTES: :8:12: note: enum is defined here +// CHECK-NOTES: :[[@LINE-3]]:10: warning: enum value of type 'Enum2' initialized with invalid value of 0 +// CHECK-NOTES: :13:6: note: enum is defined here +S5 VarS5{}; +// CHECK-NOTES: :[[@LINE-1]]:10: warning: enum value of type 'Enum1' initialized with invalid value of 0 +// CHECK-NOTES: :8:12: note: enum is defined here + +enum class EnumFwd; + +EnumFwd Fwd{}; + +enum class EnumEmpty {}; + +EnumEmpty Empty{}; + +template<typename T> +struct Templ { + T Mem1{}; + // CHECK-NOTES: :[[@LINE-1]]:9: warning: enum value of type 'Enum1' initialized with invalid value of 0 + // CHECK-NOTES: :8:12: note: enum is defined here +}; + +Templ<Enum1> TemplVar; _______________________________________________ cfe-commits mailing list cfe-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits