[CFG]
After discussion with Zhongxing, don't force the initializer of DeclStmts to be
block-level expressions.
This led to some interesting fallout:
[UninitializedValues]
Always visit the initializer of DeclStmts (do not assume they are block-level expressions).
[BasicStore]
With initializers of DeclStmts no longer block-level expressions, this causes self-referencing initializers (e.g. 'int x = x') to no longer cause the initialized variable to be live before the DeclStmt. While this is correct, it caused BasicStore::RemoveDeadBindings() to prune off the values of these variables from the initial store (where they are set to uninitialized). The fix is to back-port some (and only some) of the lazy-binding logic from RegionStore to
BasicStore. Now the default values of local variables are determined lazily as opposed
to explicitly initialized.
llvm-svn: 97591
diff --git a/clang/lib/Analysis/CFG.cpp b/clang/lib/Analysis/CFG.cpp
index d4f64bc..d7072f0 100644
--- a/clang/lib/Analysis/CFG.cpp
+++ b/clang/lib/Analysis/CFG.cpp
@@ -38,13 +38,21 @@
class AddStmtChoice {
public:
- enum Kind { NotAlwaysAdd = 0, AlwaysAdd, AlwaysAddAsLValue };
+ enum Kind { NotAlwaysAdd = 0,
+ AlwaysAdd = 1,
+ AsLValueNotAlwaysAdd = 2,
+ AlwaysAddAsLValue = 3 };
+
public:
- AddStmtChoice(Kind kind) : k(kind) {}
- bool alwaysAdd() const { return k != NotAlwaysAdd; }
- bool asLValue() const { return k == AlwaysAddAsLValue; }
+ AddStmtChoice(Kind k)
+ : AsLValue(k >= AlwaysAddAsLValue), AlwaysAddStmt((unsigned)k & 0x1) {}
+
+ bool alwaysAdd() const { return (bool) AlwaysAddStmt; };
+ bool asLValue() const { return (bool) AsLValue; };
+
private:
- Kind k;
+ unsigned AsLValue : 1;
+ unsigned AlwaysAddStmt : 1;
};
/// CFGBuilder - This class implements CFG construction from an AST.
@@ -771,18 +779,10 @@
Expr *Init = VD->getInit();
if (Init) {
- // Optimization: Don't create separate block-level statements for literals.
- switch (Init->getStmtClass()) {
- case Stmt::IntegerLiteralClass:
- case Stmt::CharacterLiteralClass:
- case Stmt::StringLiteralClass:
- break;
- default:
- Block = addStmt(Init,
- VD->getType()->isReferenceType()
- ? AddStmtChoice::AlwaysAddAsLValue
- : AddStmtChoice::AlwaysAdd);
- }
+ AddStmtChoice::Kind k =
+ VD->getType()->isReferenceType() ? AddStmtChoice::AsLValueNotAlwaysAdd
+ : AddStmtChoice::NotAlwaysAdd;
+ Visit(Init, AddStmtChoice(k));
}
// If the type of VD is a VLA, then we must process its size expressions.
diff --git a/clang/lib/Analysis/UninitializedValues.cpp b/clang/lib/Analysis/UninitializedValues.cpp
index bdc0e7c..7a62864 100644
--- a/clang/lib/Analysis/UninitializedValues.cpp
+++ b/clang/lib/Analysis/UninitializedValues.cpp
@@ -134,8 +134,12 @@
for (DeclStmt::decl_iterator I=S->decl_begin(), E=S->decl_end(); I!=E; ++I) {
VarDecl *VD = dyn_cast<VarDecl>(*I);
if (VD && VD->isBlockVarDecl()) {
- if (Stmt* I = VD->getInit())
- V(VD,AD) = AD.FullUninitTaint ? V(cast<Expr>(I),AD) : Initialized;
+ if (Stmt* I = VD->getInit()) {
+ // Visit the subexpression to check for uses of uninitialized values,
+ // even if we don't propagate that value.
+ bool isSubExprUninit = Visit(I);
+ V(VD,AD) = AD.FullUninitTaint ? isSubExprUninit : Initialized;
+ }
else {
// Special case for declarations of array types. For things like:
//