Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
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
6 changes: 6 additions & 0 deletions clang/include/clang/Analysis/Analyses/UninitializedValues.h
Original file line number Diff line number Diff line change
Expand Up @@ -50,6 +50,9 @@ class UninitUse {
/// Is this use a const reference to this variable?
bool ConstRefUse = false;

/// Is this use a const pointer to this variable?
bool ConstPtrUse = false;

/// This use is always uninitialized if it occurs after any of these branches
/// is taken.
SmallVector<Branch, 2> UninitBranches;
Expand All @@ -65,11 +68,14 @@ class UninitUse {
void setUninitAfterCall() { UninitAfterCall = true; }
void setUninitAfterDecl() { UninitAfterDecl = true; }
void setConstRefUse() { ConstRefUse = true; }
void setConstPtrUse() { ConstPtrUse = true; }

/// Get the expression containing the uninitialized use.
const Expr *getUser() const { return User; }

bool isConstRefUse() const { return ConstRefUse; }
bool isConstPtrUse() const { return ConstPtrUse; }
bool isConstRefOrPtrUse() const { return ConstRefUse || ConstPtrUse; }

/// The kind of uninitialized use.
enum Kind {
Expand Down
4 changes: 3 additions & 1 deletion clang/include/clang/Basic/DiagnosticGroups.td
Original file line number Diff line number Diff line change
Expand Up @@ -952,9 +952,11 @@ def UninitializedMaybe : DiagGroup<"conditional-uninitialized">;
def UninitializedSometimes : DiagGroup<"sometimes-uninitialized">;
def UninitializedStaticSelfInit : DiagGroup<"static-self-init">;
def UninitializedConstReference : DiagGroup<"uninitialized-const-reference">;
def UninitializedConstPointer : DiagGroup<"uninitialized-const-pointer">;
def Uninitialized : DiagGroup<"uninitialized", [UninitializedSometimes,
UninitializedStaticSelfInit,
UninitializedConstReference]>;
UninitializedConstReference,
UninitializedConstPointer]>;
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
Expand Down
4 changes: 4 additions & 0 deletions clang/include/clang/Basic/DiagnosticSemaKinds.td
Original file line number Diff line number Diff line change
Expand Up @@ -2548,6 +2548,10 @@ def warn_uninit_const_reference : Warning<
"variable %0 is uninitialized when passed as a const reference argument "
"here">, InGroup<UninitializedConstReference>, DefaultIgnore;

def warn_uninit_const_pointer : Warning<
"variable %0 is uninitialized when passed as a const pointer argument here">,
InGroup<UninitializedConstPointer>, DefaultIgnore;

def warn_unsequenced_mod_mod : Warning<
"multiple unsequenced modifications to %0">, InGroup<Unsequenced>;
def warn_unsequenced_mod_use : Warning<
Expand Down
26 changes: 17 additions & 9 deletions clang/lib/Analysis/UninitializedValues.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -276,13 +276,7 @@ namespace {
/// escaped the analysis and will be treated as an initialization.
class ClassifyRefs : public StmtVisitor<ClassifyRefs> {
public:
enum Class {
Init,
Use,
SelfInit,
ConstRefUse,
Ignore
};
enum Class { Init, Use, SelfInit, ConstRefUse, ConstPtrUse, Ignore };

private:
const DeclContext *DC;
Expand Down Expand Up @@ -451,8 +445,9 @@ void ClassifyRefs::VisitCallExpr(CallExpr *CE) {
const Expr *Ex = stripCasts(DC->getParentASTContext(), *I);
const auto *UO = dyn_cast<UnaryOperator>(Ex);
if (UO && UO->getOpcode() == UO_AddrOf)
Ex = UO->getSubExpr();
classify(Ex, Ignore);
classify(UO->getSubExpr(), isTrivialBody ? Ignore : ConstPtrUse);
else
classify(Ex, Ignore);
}
}
}
Expand Down Expand Up @@ -496,6 +491,7 @@ class TransferFunctions : public StmtVisitor<TransferFunctions> {

void reportUse(const Expr *ex, const VarDecl *vd);
void reportConstRefUse(const Expr *ex, const VarDecl *vd);
void reportConstPtrUse(const Expr *ex, const VarDecl *vd);

void VisitBinaryOperator(BinaryOperator *bo);
void VisitBlockExpr(BlockExpr *be);
Expand Down Expand Up @@ -682,6 +678,15 @@ void TransferFunctions::reportConstRefUse(const Expr *ex, const VarDecl *vd) {
}
}

void TransferFunctions::reportConstPtrUse(const Expr *ex, const VarDecl *vd) {
Value v = vals[vd];
if (isAlwaysUninit(v)) {
auto use = getUninitUse(ex, vd, v);
use.setConstPtrUse();
handler.handleUseOfUninitVariable(vd, use);
}
}

void TransferFunctions::VisitObjCForCollectionStmt(ObjCForCollectionStmt *FS) {
// This represents an initialization of the 'element' value.
if (const auto *DS = dyn_cast<DeclStmt>(FS->getElement())) {
Expand Down Expand Up @@ -754,6 +759,9 @@ void TransferFunctions::VisitDeclRefExpr(DeclRefExpr *dr) {
case ClassifyRefs::ConstRefUse:
reportConstRefUse(dr, cast<VarDecl>(dr->getDecl()));
break;
case ClassifyRefs::ConstPtrUse:
reportConstPtrUse(dr, cast<VarDecl>(dr->getDecl()));
break;
}
}

Expand Down
20 changes: 16 additions & 4 deletions clang/lib/Sema/AnalysisBasedWarnings.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -994,6 +994,14 @@ static bool DiagnoseUninitializedConstRefUse(Sema &S, const VarDecl *VD,
return !S.getDiagnostics().isLastDiagnosticIgnored();
}

/// Diagnose uninitialized const pointer usages.
static bool DiagnoseUninitializedConstPtrUse(Sema &S, const VarDecl *VD,
const UninitUse &Use) {
S.Diag(Use.getUser()->getBeginLoc(), diag::warn_uninit_const_pointer)
<< VD->getDeclName() << Use.getUser()->getSourceRange();
return !S.getDiagnostics().isLastDiagnosticIgnored();
}

/// 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
Expand Down Expand Up @@ -1599,9 +1607,9 @@ class UninitValsDiagReporter : public UninitVariablesHandler {
// a stable ordering.
llvm::sort(*vec, [](const UninitUse &a, const UninitUse &b) {
// Prefer the direct use of an uninitialized variable over its use via
// constant reference.
if (a.isConstRefUse() != b.isConstRefUse())
return b.isConstRefUse();
// constant reference or pointer.
if (a.isConstRefOrPtrUse() != b.isConstRefOrPtrUse())
return b.isConstRefOrPtrUse();
// Prefer a more confident report over a less confident one.
if (a.getKind() != b.getKind())
return a.getKind() > b.getKind();
Expand All @@ -1612,6 +1620,9 @@ class UninitValsDiagReporter : public UninitVariablesHandler {
if (U.isConstRefUse()) {
if (DiagnoseUninitializedConstRefUse(S, vd, U))
return;
} else if (U.isConstPtrUse()) {
if (DiagnoseUninitializedConstPtrUse(S, vd, U))
return;
} else {
// If we have self-init, downgrade all uses to 'may be uninitialized'.
UninitUse Use = hasSelfInit ? UninitUse(U.getUser(), false) : U;
Expand Down Expand Up @@ -2828,7 +2839,8 @@ void clang::sema::AnalysisBasedWarnings::IssueWarnings(
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_uninit_const_reference, D->getBeginLoc())) {
!Diags.isIgnored(diag::warn_uninit_const_reference, D->getBeginLoc()) ||
!Diags.isIgnored(diag::warn_uninit_const_pointer, D->getBeginLoc())) {
if (CFG *cfg = AC.getCFG()) {
UninitValsDiagReporter reporter(S);
UninitVariablesAnalysisStats stats;
Expand Down
1 change: 1 addition & 0 deletions clang/test/Misc/warning-wall.c
Original file line number Diff line number Diff line change
Expand Up @@ -66,6 +66,7 @@ CHECK-NEXT: -Wuninitialized
CHECK-NEXT: -Wsometimes-uninitialized
CHECK-NEXT: -Wstatic-self-init
CHECK-NEXT: -Wuninitialized-const-reference
CHECK-NEXT: -Wuninitialized-const-pointer
CHECK-NEXT: -Wunknown-pragmas
CHECK-NEXT: -Wunused
CHECK-NEXT: -Wunused-argument
Expand Down
35 changes: 35 additions & 0 deletions clang/test/SemaCXX/warn-uninitialized-const-pointer.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
// RUN: %clang_cc1 -fsyntax-only -fcxx-exceptions -Wuninitialized-const-pointer -verify %s

template <class T>
void ignore_template(const T *) {}
void ignore(const int *) {}
void dont_ignore_non_empty(const int *) { ; }
void dont_ignore_block(const int *) { {} }
void dont_ignore_try_block(const int *) try {
} catch (...) {
}
int const_ptr_use(const int *);

void f(int a) {
int i;
const_ptr_use(&i); // expected-warning {{variable 'i' is uninitialized when passed as a const pointer argument here}}
int j = j + const_ptr_use(&j); // expected-warning {{variable 'j' is uninitialized when used within its own initialization}}
int k = k; // expected-warning {{variable 'k' is uninitialized when used within its own initialization}}
const_ptr_use(&k);

// Only report if a variable is always uninitialized at the point of use
int l;
if (a < 42)
l = 1;
const_ptr_use(&l);

// Don't report if the called function is known to be empty.
int m;
ignore_template(&m);
ignore(&m);
dont_ignore_non_empty(&m); // expected-warning {{variable 'm' is uninitialized when passed as a const pointer argument here}}
int n;
dont_ignore_block(&n); // expected-warning {{variable 'n' is uninitialized when passed as a const pointer argument here}}
int o;
dont_ignore_try_block(&o); // expected-warning {{variable 'o' is uninitialized when passed as a const pointer argument here}}
}
Original file line number Diff line number Diff line change
Expand Up @@ -62,14 +62,14 @@ int main(int, char**)
{
testbuf<char> sb1;
std::ostream os1(&sb1);
int n1;
int n1 = 0;
os1 << &n1;
assert(os1.good());
std::string s1(sb1.str());

testbuf<char> sb2;
std::ostream os2(&sb2);
int n2;
int n2 = 0;
os2 << &n2;
assert(os2.good());
std::string s2(sb2.str());
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -61,7 +61,7 @@ class testbuf : public std::basic_streambuf<CharT> {
int main(int, char**) {
testbuf<char> sb1;
std::ostream os1(&sb1);
int n1;
int n1 = 0;
os1 << &n1;
assert(os1.good());
std::string s1 = sb1.str();
Expand All @@ -74,7 +74,7 @@ int main(int, char**) {

testbuf<char> sb3;
std::ostream os3(&sb3);
volatile int n3;
volatile int n3 = 0;
os3 << &n3;
assert(os3.good());
std::string s3 = sb3.str();
Expand Down
Loading