Index: clang/include/clang/Analysis/Analyses/UninitializedValues.h =================================================================== --- clang/include/clang/Analysis/Analyses/UninitializedValues.h +++ clang/include/clang/Analysis/Analyses/UninitializedValues.h @@ -47,13 +47,16 @@ /// Does this use always see an uninitialized value? bool AlwaysUninit; + /// Is this use a const reference parameter? + bool ConstRef; + /// This use is always uninitialized if it occurs after any of these branches /// is taken. SmallVector UninitBranches; public: - UninitUse(const Expr *User, bool AlwaysUninit) - : User(User), AlwaysUninit(AlwaysUninit) {} + UninitUse(const Expr *User, bool AlwaysUninit, bool ConstRef) + : User(User), AlwaysUninit(AlwaysUninit), ConstRef(ConstRef) {} void addUninitBranch(Branch B) { UninitBranches.push_back(B); @@ -82,12 +85,17 @@ AfterCall, /// The use is always uninitialized. - Always + Always, + + /// The use is uninitialized when passes as const reference parameter to a + /// function + ConstRefUse }; /// Get the kind of uninitialized use. Kind getKind() const { - return AlwaysUninit ? Always : + return ConstRef? ConstRefUse : + AlwaysUninit ? Always : UninitAfterCall ? AfterCall : UninitAfterDecl ? AfterDecl : !branch_empty() ? Sometimes : Maybe; 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/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, DefaultIgnore; + def warn_unsequenced_mod_mod : Warning< "multiple unsequenced modifications to %0">, InGroup; def warn_unsequenced_mod_use : Warning< 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(Ex); @@ -468,7 +471,7 @@ classification(classification), objCNoRet(ac.getASTContext()), handler(handler) {} - void reportUse(const Expr *ex, const VarDecl *vd); + void reportUse(const Expr *ex, const VarDecl *vd, bool ConstRestUse = false); void VisitBinaryOperator(BinaryOperator *bo); void VisitBlockExpr(BlockExpr *be); @@ -488,8 +491,9 @@ return ::findVar(ex, cast(ac.getDecl())); } - UninitUse getUninitUse(const Expr *ex, const VarDecl *vd, Value v) { - UninitUse Use(ex, isAlwaysUninit(v)); + UninitUse getUninitUse(const Expr *ex, const VarDecl *vd, Value v, + bool ConstRefUse) { + UninitUse Use(ex, isAlwaysUninit(v), ConstRefUse); assert(isUninitialized(v)); if (Use.getKind() == UninitUse::Always) @@ -661,10 +665,11 @@ } // namespace -void TransferFunctions::reportUse(const Expr *ex, const VarDecl *vd) { +void TransferFunctions::reportUse(const Expr *ex, const VarDecl *vd, + bool ConstRefUse) { Value v = vals[vd]; if (isUninitialized(v)) - handler.handleUseOfUninitVariable(vd, getUninitUse(ex, vd, v)); + handler.handleUseOfUninitVariable(vd, getUninitUse(ex, vd, v, ConstRefUse)); } void TransferFunctions::VisitObjCForCollectionStmt(ObjCForCollectionStmt *FS) { @@ -736,6 +741,9 @@ case ClassifyRefs::SelfInit: handler.handleSelfInit(cast(dr->getDecl())); break; + case ClassifyRefs::ConstRefUse: + reportUse(dr, cast(dr->getDecl()), true); + break; } } Index: clang/lib/Sema/AnalysisBasedWarnings.cpp =================================================================== --- clang/lib/Sema/AnalysisBasedWarnings.cpp +++ clang/lib/Sema/AnalysisBasedWarnings.cpp @@ -834,6 +834,10 @@ // Carry on to report sometimes-uninitialized branches, if possible, // or a 'may be used uninitialized' diagnostic otherwise. break; + case UninitUse::ConstRefUse: + S.Diag(Use.getUser()->getBeginLoc(), diag::warn_uninit_const_reference) + << VD->getDeclName() << Use.getUser()->getSourceRange(); + break; } // Diagnose each branch which leads to a sometimes-uninitialized use. @@ -1000,8 +1004,11 @@ ContainsReference CR(S.Context, DRE); CR.Visit(Initializer); + unsigned DiagID = Use.getKind() == UninitUse::ConstRefUse + ? diag::warn_uninit_const_reference + : 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; } @@ -1541,7 +1548,7 @@ if (!vec->empty() && hasSelfInit && hasAlwaysUninitializedUse(vec)) DiagnoseUninitializedUse(S, vd, UninitUse(vd->getInit()->IgnoreParenCasts(), - /* isAlwaysUninit */ true), + /* isAlwaysUninit */ true, false), /* alwaysReportSelfInit */ true); else { // Sort the uses by their SourceLocations. While not strictly @@ -1557,7 +1564,7 @@ for (const auto &U : *vec) { // If we have self-init, downgrade all uses to 'may be uninitialized'. - UninitUse Use = hasSelfInit ? UninitUse(U.getUser(), false) : U; + UninitUse Use = hasSelfInit ? UninitUse(U.getUser(), false, false) : U; if (DiagnoseUninitializedUse(S, vd, Use)) // Skip further diagnostics for this variable. We try to warn only @@ -2184,7 +2191,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/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/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 {