zequanwu updated this revision to Diff 264300. zequanwu added a comment. Since the new warning is controlled by `-Wuninitialized`, I disabled it in existing test case and added a separate test case for `-Wuninitialized-const-reference`.
CHANGES SINCE LAST ACTION https://reviews.llvm.org/D79895/new/ https://reviews.llvm.org/D79895 Files: clang/include/clang/Analysis/Analyses/UninitializedValues.h clang/include/clang/Basic/DiagnosticGroups.td clang/include/clang/Basic/DiagnosticSemaKinds.td clang/lib/Analysis/UninitializedValues.cpp clang/lib/Sema/AnalysisBasedWarnings.cpp clang/test/Misc/warning-wall.c clang/test/SemaCXX/uninit-variables.cpp clang/test/SemaCXX/uninitialized.cpp clang/test/SemaCXX/warn-uninitialized-const-reference.cpp
Index: clang/test/SemaCXX/warn-uninitialized-const-reference.cpp =================================================================== --- /dev/null +++ clang/test/SemaCXX/warn-uninitialized-const-reference.cpp @@ -0,0 +1,29 @@ +// RUN: %clang_cc1 -fsyntax-only -Wuninitialized-const-reference -verify %s + +class A { +public: + int i; + A() {}; + A(const A& a) {}; + A(int i) {} + bool operator!=(const A&); +}; + +A const_ref_use_A(const A& a); +int const_ref_use(const int& i); +A const_use_A(const A a); +int const_use(const int i); + +void f() { + int i; + const_ref_use(i); // expected-warning {{variable 'i' is uninitialized when passes as a const reference parameter here}} + int j = j + const_ref_use(j); // expected-warning {{variable 'j' is uninitialized when used within its own initialization}} expected-warning {{variable 'j' is uninitialized when passes as a const reference parameter here}} + A a1 = const_ref_use_A(a1); // expected-warning {{variable 'a1' is uninitialized when passes as a const reference parameter here}} + int k = const_use(k); // expected-warning {{variable 'k' is uninitialized when used within its own initialization}} + A a2 = const_use_A(a2); // expected-warning {{variable 'a2' is uninitialized when used within its own initialization}} + A a3(const_ref_use_A(a3)); // expected-warning {{variable 'a3' is uninitialized when passes as a const reference parameter here}} + A a4 = a3 != a4; // expected-warning {{variable 'a4' is uninitialized when used within its own initialization}} expected-warning {{variable 'a4' is uninitialized when passes as a const reference parameter here}} + + A a5; + const_ref_use_A(a5); +} Index: clang/test/SemaCXX/uninitialized.cpp =================================================================== --- clang/test/SemaCXX/uninitialized.cpp +++ clang/test/SemaCXX/uninitialized.cpp @@ -1,4 +1,4 @@ -// RUN: %clang_cc1 -fsyntax-only -Wall -Wuninitialized -Wno-unused-value -Wno-unused-lambda-capture -std=c++1z -verify %s +// RUN: %clang_cc1 -fsyntax-only -Wall -Wuninitialized -Wno-unused-value -Wno-unused-lambda-capture -Wno-uninitialized-const-reference -std=c++1z -verify %s // definitions for std::move namespace std { Index: clang/test/SemaCXX/uninit-variables.cpp =================================================================== --- clang/test/SemaCXX/uninit-variables.cpp +++ clang/test/SemaCXX/uninit-variables.cpp @@ -1,4 +1,4 @@ -// RUN: %clang_cc1 -fsyntax-only -Wuninitialized -fsyntax-only -fcxx-exceptions %s -verify -std=c++1y +// RUN: %clang_cc1 -fsyntax-only -Wuninitialized -Wno-uninitialized-const-reference -fsyntax-only -fcxx-exceptions %s -verify -std=c++1y // Stub out types for 'typeid' to work. namespace std { class type_info {}; } Index: clang/test/Misc/warning-wall.c =================================================================== --- clang/test/Misc/warning-wall.c +++ clang/test/Misc/warning-wall.c @@ -55,6 +55,7 @@ CHECK-NEXT: -Wuninitialized CHECK-NEXT: -Wsometimes-uninitialized CHECK-NEXT: -Wstatic-self-init +CHECK-NEXT: -Wuninitialized-const-reference CHECK-NEXT: -Wunknown-pragmas CHECK-NEXT: -Wunused CHECK-NEXT: -Wunused-argument Index: clang/lib/Sema/AnalysisBasedWarnings.cpp =================================================================== --- clang/lib/Sema/AnalysisBasedWarnings.cpp +++ clang/lib/Sema/AnalysisBasedWarnings.cpp @@ -974,6 +974,14 @@ << Use.getUser()->getSourceRange(); } +/// Diagnose uninitialized const reference usages. +static bool DiagnoseUninitializedConstRefUse(Sema &S, const VarDecl *VD, + const UninitUse &Use) { + S.Diag(Use.getUser()->getBeginLoc(), diag::warn_uninit_const_reference) + << VD->getDeclName() << Use.getUser()->getSourceRange(); + return true; +} + /// DiagnoseUninitializedUse -- Helper function for diagnosing uses of an /// uninitialized variable. This manages the different forms of diagnostic /// emitted for particular types of uses. Returns true if the use was diagnosed @@ -1000,8 +1008,9 @@ ContainsReference CR(S.Context, DRE); CR.Visit(Initializer); + unsigned DiagID = diag::warn_uninit_self_reference_in_init; if (CR.doesContainReference()) { - S.Diag(DRE->getBeginLoc(), diag::warn_uninit_self_reference_in_init) + S.Diag(DRE->getBeginLoc(), DiagID) << VD->getDeclName() << VD->getLocation() << DRE->getSourceRange(); return true; } @@ -1506,12 +1515,13 @@ // order of diagnostics when calling flushDiagnostics(). typedef llvm::MapVector<const VarDecl *, MappedType> UsesMap; UsesMap uses; + UsesMap constRefUses; public: UninitValsDiagReporter(Sema &S) : S(S) {} ~UninitValsDiagReporter() override { flushDiagnostics(); } - MappedType &getUses(const VarDecl *vd) { + MappedType &getUses(UsesMap &uses, const VarDecl *vd) { MappedType &V = uses[vd]; if (!V.getPointer()) V.setPointer(new UsesVec()); @@ -1520,11 +1530,16 @@ void handleUseOfUninitVariable(const VarDecl *vd, const UninitUse &use) override { - getUses(vd).getPointer()->push_back(use); + getUses(uses, vd).getPointer()->push_back(use); } void handleSelfInit(const VarDecl *vd) override { - getUses(vd).setInt(true); + getUses(uses, vd).setInt(true); + } + + void handleConstRefUseOfUninitVariable(const VarDecl *vd, + const UninitUse &use) override { + getUses(constRefUses, vd).getPointer()->push_back(use); } void flushDiagnostics() { @@ -1571,6 +1586,20 @@ } uses.clear(); + + // flush all const reference uses diags + for (const auto &P : constRefUses) { + const VarDecl *vd = P.first; + const MappedType &V = P.second; + + UsesVec *vec = V.getPointer(); + for (const auto &U : *vec) { + if (DiagnoseUninitializedConstRefUse(S, vd, U)) + break; + } + } + + constRefUses.clear(); } private: @@ -2184,7 +2213,8 @@ if (!Diags.isIgnored(diag::warn_uninit_var, D->getBeginLoc()) || !Diags.isIgnored(diag::warn_sometimes_uninit_var, D->getBeginLoc()) || - !Diags.isIgnored(diag::warn_maybe_uninit_var, D->getBeginLoc())) { + !Diags.isIgnored(diag::warn_maybe_uninit_var, D->getBeginLoc()) || + !Diags.isIgnored(diag::warn_uninit_const_reference, D->getBeginLoc())) { if (CFG *cfg = AC.getCFG()) { UninitValsDiagReporter reporter(S); UninitVariablesAnalysisStats stats; Index: clang/lib/Analysis/UninitializedValues.cpp =================================================================== --- clang/lib/Analysis/UninitializedValues.cpp +++ clang/lib/Analysis/UninitializedValues.cpp @@ -268,6 +268,7 @@ Init, Use, SelfInit, + ConstRefUse, Ignore }; @@ -413,14 +414,16 @@ return; } - // If a value is passed by const pointer or by const reference to a function, + // If a value is passed by const pointer to a function, // we should not assume that it is initialized by the call, and we // conservatively do not assume that it is used. + // If a value is passed by const reference to a function, + // it should already be initialized. for (CallExpr::arg_iterator I = CE->arg_begin(), E = CE->arg_end(); I != E; ++I) { if ((*I)->isGLValue()) { if ((*I)->getType().isConstQualified()) - classify((*I), Ignore); + classify((*I), ConstRefUse); } else if (isPointerToConst((*I)->getType())) { const Expr *Ex = stripCasts(DC->getParentASTContext(), *I); const auto *UO = dyn_cast<UnaryOperator>(Ex); @@ -469,6 +472,7 @@ handler(handler) {} void reportUse(const Expr *ex, const VarDecl *vd); + void reportConstRefUse(const Expr *ex, const VarDecl *vd); void VisitBinaryOperator(BinaryOperator *bo); void VisitBlockExpr(BlockExpr *be); @@ -667,6 +671,12 @@ handler.handleUseOfUninitVariable(vd, getUninitUse(ex, vd, v)); } +void TransferFunctions::reportConstRefUse(const Expr *ex, const VarDecl *vd) { + Value v = vals[vd]; + if (isUninitialized(v)) + handler.handleConstRefUseOfUninitVariable(vd, getUninitUse(ex, vd, v)); +} + void TransferFunctions::VisitObjCForCollectionStmt(ObjCForCollectionStmt *FS) { // This represents an initialization of the 'element' value. if (const auto *DS = dyn_cast<DeclStmt>(FS->getElement())) { @@ -734,7 +744,10 @@ vals[cast<VarDecl>(dr->getDecl())] = Initialized; break; case ClassifyRefs::SelfInit: - handler.handleSelfInit(cast<VarDecl>(dr->getDecl())); + handler.handleSelfInit(cast<VarDecl>(dr->getDecl())); + break; + case ClassifyRefs::ConstRefUse: + reportConstRefUse(dr, cast<VarDecl>(dr->getDecl())); break; } } @@ -874,6 +887,12 @@ hadUse[currentBlock] = true; hadAnyUse = true; } + + void handleConstRefUseOfUninitVariable(const VarDecl *vd, + const UninitUse &use) override { + hadUse[currentBlock] = true; + hadAnyUse = true; + } }; } // namespace Index: clang/include/clang/Basic/DiagnosticSemaKinds.td =================================================================== --- clang/include/clang/Basic/DiagnosticSemaKinds.td +++ clang/include/clang/Basic/DiagnosticSemaKinds.td @@ -2106,6 +2106,10 @@ "cannot initialize %select{non-class|reference}0 type %1 with a " "parenthesized initializer list">; +def warn_uninit_const_reference : Warning< + "variable %0 is uninitialized when passes as a const reference parameter " + "here">, InGroup<UninitializedConstReference>, DefaultIgnore; + def warn_unsequenced_mod_mod : Warning< "multiple unsequenced modifications to %0">, InGroup<Unsequenced>; def warn_unsequenced_mod_use : Warning< Index: clang/include/clang/Basic/DiagnosticGroups.td =================================================================== --- clang/include/clang/Basic/DiagnosticGroups.td +++ clang/include/clang/Basic/DiagnosticGroups.td @@ -624,8 +624,10 @@ def UninitializedMaybe : DiagGroup<"conditional-uninitialized">; def UninitializedSometimes : DiagGroup<"sometimes-uninitialized">; def UninitializedStaticSelfInit : DiagGroup<"static-self-init">; +def UninitializedConstReference : DiagGroup<"uninitialized-const-reference">; def Uninitialized : DiagGroup<"uninitialized", [UninitializedSometimes, - UninitializedStaticSelfInit]>; + UninitializedStaticSelfInit, + UninitializedConstReference]>; def IgnoredPragmaIntrinsic : DiagGroup<"ignored-pragma-intrinsic">; // #pragma optimize is often used to avoid to work around MSVC codegen bugs or // to disable inlining. It's not completely clear what alternative to suggest Index: clang/include/clang/Analysis/Analyses/UninitializedValues.h =================================================================== --- clang/include/clang/Analysis/Analyses/UninitializedValues.h +++ clang/include/clang/Analysis/Analyses/UninitializedValues.h @@ -114,6 +114,9 @@ /// idiom 'int x = x'. All other uses of 'x' within the initializer /// are handled by handleUseOfUninitVariable. virtual void handleSelfInit(const VarDecl *vd) {} + + virtual void handleConstRefUseOfUninitVariable(const VarDecl *vd, + const UninitUse &use) {} }; struct UninitVariablesAnalysisStats {
_______________________________________________ cfe-commits mailing list cfe-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits