@@ -705,6 +705,21 @@ namespace {
705
705
// user when diagnosing unknown bounds errors.
706
706
llvm::DenseMap<const VarDecl *, SmallVector<Expr *, 4 >> UnknownSrcBounds;
707
707
708
+ // BlameAssignments maps a variable declaration V to an expression in a
709
+ // top-level CFG statement that last updates any variable used in the
710
+ // declared bounds of V.
711
+ //
712
+ // BlameAssignments is used to provide more context for two types of
713
+ // diagnostic messages:
714
+ // 1. The compiler cannot prove or can disprove the declared bounds for
715
+ // V are valid after an assignment to a variable in the bounds of V; and
716
+ // 2. The inferred bounds of V become unknown after an assignment to a
717
+ // variable in the bounds of V.
718
+ //
719
+ // BlameAssignments is updated in UpdateAfterAssignments and reset after
720
+ // checking each top-level CFG statement.
721
+ llvm::DenseMap<const VarDecl *, Expr *> BlameAssignments;
722
+
708
723
// TargetSrcEquality maps a target expression V to the most recent
709
724
// expression Src that has been assigned to V within the current
710
725
// top-level CFG statement. When validating the bounds context,
@@ -718,6 +733,7 @@ namespace {
718
733
SameValue.clear ();
719
734
LostVariables.clear ();
720
735
UnknownSrcBounds.clear ();
736
+ BlameAssignments.clear ();
721
737
TargetSrcEquality.clear ();
722
738
}
723
739
};
@@ -2819,8 +2835,8 @@ namespace {
2819
2835
// Update the checking state and result bounds for assignments to `e1`
2820
2836
// where `e1` is a variable.
2821
2837
if (LHSVar)
2822
- ResultBounds = UpdateAfterAssignment (LHSVar, Target, Src, ResultBounds ,
2823
- CSS, State, State);
2838
+ ResultBounds = UpdateAfterAssignment (LHSVar, E, Target, Src ,
2839
+ ResultBounds, CSS, State, State);
2824
2840
// Update EquivExprs and SameValue for assignments where `e1` is not
2825
2841
// a variable.
2826
2842
else
@@ -3265,8 +3281,8 @@ namespace {
3265
3281
BoundsExpr *RHSBounds = RValueCastBounds (Target, SubExprTargetBounds,
3266
3282
SubExprLValueBounds,
3267
3283
SubExprBounds, State);
3268
- IncDecResultBounds = UpdateAfterAssignment (V, Target, RHS, RHSBounds,
3269
- CSS, State, State);
3284
+ IncDecResultBounds = UpdateAfterAssignment (
3285
+ V, E, Target, RHS, RHSBounds, CSS, State, State);
3270
3286
}
3271
3287
3272
3288
// Update the set SameValue of expressions that produce the same
@@ -3927,13 +3943,13 @@ namespace {
3927
3943
// whose observed bounds are unknown after checking the top-level CFG
3928
3944
// statement St.
3929
3945
//
3930
- // State contians information that is used to provide more context in
3946
+ // State contains information that is used to provide more context in
3931
3947
// the diagnostic messages.
3932
3948
void DiagnoseUnknownObservedBounds (Stmt *St, const VarDecl *V,
3933
3949
BoundsExpr *DeclaredBounds,
3934
3950
CheckingState State) {
3935
- S. Diag (St-> getBeginLoc (), diag::err_unknown_inferred_bounds)
3936
- << V << St-> getSourceRange ( );
3951
+ BlameAssignmentWithinStmt (St, V, State,
3952
+ diag::err_unknown_inferred_bounds );
3937
3953
S.Diag (V->getLocation (), diag::note_declared_bounds)
3938
3954
<< DeclaredBounds << DeclaredBounds->getSourceRange ();
3939
3955
@@ -4000,22 +4016,12 @@ namespace {
4000
4016
return ;
4001
4017
}
4002
4018
4003
- // For a declaration, the diagnostic message should start at the
4004
- // location of v rather than the beginning of St. If the message
4005
- // starts at the beginning of a declaration T v = e, then extra
4006
- // diagnostics may be emitted for T.
4007
- SourceLocation Loc = St->getBeginLoc ();
4008
- if (isa<DeclStmt>(St))
4009
- Loc = V->getLocation ();
4010
-
4011
4019
unsigned DiagId = (Result == ProofResult::False) ?
4012
4020
diag::error_bounds_declaration_invalid :
4013
4021
(CSS != CheckedScopeSpecifier::CSS_Unchecked?
4014
4022
diag::warn_checked_scope_bounds_declaration_invalid :
4015
4023
diag::warn_bounds_declaration_invalid);
4016
- S.Diag (Loc, DiagId)
4017
- << Sema::BoundsDeclarationCheck::BDC_Statement << V
4018
- << St->getSourceRange () << St->getSourceRange ();
4024
+ SourceLocation Loc = BlameAssignmentWithinStmt (St, V, State, DiagId);
4019
4025
if (Result == ProofResult::False)
4020
4026
ExplainProofFailure (Loc, Cause, ProofStmtKind::BoundsDeclaration);
4021
4027
S.Diag (V->getLocation (), diag::note_declared_bounds)
@@ -4024,11 +4030,62 @@ namespace {
4024
4030
<< ObservedBounds << ObservedBounds->getSourceRange ();
4025
4031
}
4026
4032
4033
+ // BlameAssignmentWithinStmt prints a diagnostic message that highlights the
4034
+ // assignment expression in St that causes V's observed bounds to be unknown
4035
+ // or not provably valid. If St is a DeclStmt, St itself and V are
4036
+ // highlighted. BlameAssignmentWithinStmt returns the source location of
4037
+ // the blamed assignment.
4038
+ SourceLocation BlameAssignmentWithinStmt (Stmt *St, const VarDecl *V,
4039
+ CheckingState State,
4040
+ unsigned DiagId) const {
4041
+ assert (St);
4042
+ SourceRange SrcRange = St->getSourceRange ();
4043
+ auto BDCType = Sema::BoundsDeclarationCheck::BDC_Statement;
4044
+
4045
+ // For a declaration, show the diagnostic message that starts at the
4046
+ // location of v rather than the beginning of St and return. If the
4047
+ // message starts at the beginning of a declaration T v = e, then extra
4048
+ // diagnostics may be emitted for T.
4049
+ SourceLocation Loc = St->getBeginLoc ();
4050
+ if (isa<DeclStmt>(St)) {
4051
+ Loc = V->getLocation ();
4052
+ BDCType = Sema::BoundsDeclarationCheck::BDC_Initialization;
4053
+ S.Diag (Loc, DiagId) << BDCType << V << SrcRange << SrcRange;
4054
+ return Loc;
4055
+ }
4056
+
4057
+ // If not a declaration, find the assignment (if it exists) in St to blame
4058
+ // for the error or warning.
4059
+ auto It = State.BlameAssignments .find (V);
4060
+ if (It != State.BlameAssignments .end ()) {
4061
+ Expr *BlameExpr = It->second ;
4062
+ Loc = BlameExpr->getBeginLoc ();
4063
+ SrcRange = BlameExpr->getSourceRange ();
4064
+
4065
+ // Choose the type of assignment E to show in the diagnostic messages
4066
+ // from: assignment (=), decrement (--) or increment (++). If none of
4067
+ // these cases match, the diagnostic message reports that the error is
4068
+ // for a statement.
4069
+ if (UnaryOperator *UO = dyn_cast<UnaryOperator>(BlameExpr)) {
4070
+ if (UO->isIncrementOp ())
4071
+ BDCType = Sema::BoundsDeclarationCheck::BDC_Increment;
4072
+ else if (UO->isDecrementOp ())
4073
+ BDCType = Sema::BoundsDeclarationCheck::BDC_Decrement;
4074
+ } else if (isa<BinaryOperator>(BlameExpr)) {
4075
+ // Must be an assignment or a compound assignment, because E is
4076
+ // modifying.
4077
+ BDCType = Sema::BoundsDeclarationCheck::BDC_Assignment;
4078
+ }
4079
+ }
4080
+ S.Diag (Loc, DiagId) << BDCType << V << SrcRange << SrcRange;
4081
+ return Loc;
4082
+ }
4083
+
4027
4084
// Methods to update the checking state.
4028
4085
4029
4086
// UpdateAfterAssignment updates the checking state after a variable V
4030
- // is updated in an assignment Target = Src, based on the state before
4031
- // the assignment. It also returns updated bounds for Src.
4087
+ // is updated in an assignment E of the form Target = Src, based on the
4088
+ // state before the assignment. It also returns updated bounds for Src.
4032
4089
//
4033
4090
// If V has an original value, the original value is substituted for
4034
4091
// any uses of the value of V in the bounds in ObservedBounds and the
@@ -4041,8 +4098,8 @@ namespace {
4041
4098
// SrcBounds are the original bounds for the source of the assignment.
4042
4099
//
4043
4100
// PrevState is the checking state that was true before the assignment.
4044
- BoundsExpr *UpdateAfterAssignment (DeclRefExpr *V, Expr *Target , Expr *Src ,
4045
- BoundsExpr *SrcBounds,
4101
+ BoundsExpr *UpdateAfterAssignment (DeclRefExpr *V, Expr *E , Expr *Target ,
4102
+ Expr *Src, BoundsExpr *SrcBounds,
4046
4103
CheckedScopeSpecifier CSS,
4047
4104
const CheckingState PrevState,
4048
4105
CheckingState &State) {
@@ -4078,6 +4135,13 @@ namespace {
4078
4135
BoundsExpr *AdjustedBounds = ReplaceVariableInBounds (Bounds, V, OriginalValue, CSS);
4079
4136
if (!Pair.second ->isUnknown () && AdjustedBounds->isUnknown ())
4080
4137
State.LostVariables [W] = std::make_pair (Bounds, V);
4138
+
4139
+ // If E modifies the bounds of W, add the pair to BlameAssignments. We
4140
+ // can check this cheaply by comparing the pointer values of
4141
+ // AdjustedBounds and Bounds because ReplaceVariableInBounds returns
4142
+ // Bounds as AdjustedBounds if Bounds is not adjusted.
4143
+ if (AdjustedBounds != Bounds)
4144
+ State.BlameAssignments [W] = E;
4081
4145
State.ObservedBounds [W] = AdjustedBounds;
4082
4146
}
4083
4147
@@ -4087,6 +4151,10 @@ namespace {
4087
4151
if (DeclaredBounds)
4088
4152
State.ObservedBounds [VariableDecl] = AdjustedSrcBounds;
4089
4153
4154
+ // Record that E updates the observed bounds of VariableDecl.
4155
+ if (DeclaredBounds)
4156
+ State.BlameAssignments [VariableDecl] = E;
4157
+
4090
4158
// If the initial source bounds were not unknown, but they are unknown
4091
4159
// after replacing uses of V, then the assignment to V caused the
4092
4160
// source bounds (which are the observed bounds for V) to be unknown.
0 commit comments