Index: include/clang/AST/Decl.h =================================================================== --- include/clang/AST/Decl.h +++ include/clang/AST/Decl.h @@ -840,6 +840,8 @@ /// It is illegal to call this function with SC == None. static const char *getStorageClassSpecifierString(StorageClass SC); + mutable bool ValChanged = false; + protected: // A pointer union of Stmt * and EvaluatedStmt *. When an EvaluatedStmt, we // have allocated the auxiliary struct of information there. @@ -1477,6 +1479,14 @@ /// Do we need to emit an exit-time destructor for this variable? bool isNoDestroy(const ASTContext &) const; + bool getIsValChanged() const { + return ValChanged; + } + + void setValChanged() const { + ValChanged = true; + } + // Implement isa/cast/dyncast/etc. static bool classof(const Decl *D) { return classofKind(D->getKind()); } static bool classofKind(Kind K) { return K >= firstVar && K <= lastVar; } Index: lib/CodeGen/CGDebugInfo.cpp =================================================================== --- lib/CodeGen/CGDebugInfo.cpp +++ lib/CodeGen/CGDebugInfo.cpp @@ -3778,6 +3778,11 @@ if (VD->isImplicit()) Flags |= llvm::DINode::FlagArtificial; + auto &CGOpts = CGM.getCodeGenOpts(); + if (CGOpts.EnableParamEntryValues && !VD->getIsValChanged()) + Flags |= llvm::DINode::FlagVariableNotChanged; + + auto Align = getDeclAlignIfRequired(VD, CGM.getContext()); unsigned AddressSpace = CGM.getContext().getTargetAddressSpace(VD->getType()); Index: lib/Sema/SemaExpr.cpp =================================================================== --- lib/Sema/SemaExpr.cpp +++ lib/Sema/SemaExpr.cpp @@ -16,6 +16,7 @@ #include "clang/AST/ASTLambda.h" #include "clang/AST/ASTMutationListener.h" #include "clang/AST/CXXInheritance.h" +#include "clang/AST/Decl.h" #include "clang/AST/DeclObjC.h" #include "clang/AST/DeclTemplate.h" #include "clang/AST/EvaluatedExprVisitor.h" @@ -11276,6 +11277,20 @@ DiagnoseConstAssignment(S, E, Loc); } +/// Variable's value might be changed, so update the info. +static void EmitVriablesValueChangeInfo(Expr *E) { + if (const DeclRefExpr *LHSDeclRef = + dyn_cast(E->IgnoreParenCasts())) + if (const ValueDecl *Decl = LHSDeclRef->getDecl()) + if (const VarDecl *VD = dyn_cast(Decl)) { + // For now, we are supporting just parameters. + if (!isa(VD)) + return; + if (!VD->getIsValChanged()) + VD->setValChanged(); + } +} + /// CheckForModifiableLvalue - Verify that E is a modifiable lvalue. If not, /// emit an error and return true. If so, return false. static bool CheckForModifiableLvalue(Expr *E, SourceLocation Loc, Sema &S) { @@ -11283,6 +11298,12 @@ S.CheckShadowingDeclModification(E, Loc); + if (MemberExpr *ME = dyn_cast(E)) { + if (Expr *BaseExpr = ME->getBase()) + EmitVriablesValueChangeInfo(BaseExpr); + } else + EmitVriablesValueChangeInfo(E); + SourceLocation OrigLoc = Loc; Expr::isModifiableLvalueResult IsLV = E->isModifiableLvalue(S.Context, &Loc); Index: test/CodeGen/debug-info-varchange.c =================================================================== --- /dev/null +++ test/CodeGen/debug-info-varchange.c @@ -0,0 +1,35 @@ +// RUN: %clang -femit-param-entry-values -emit-llvm -S -g %s -o - | FileCheck %s + +// CHECK: !DILocalVariable(name: "a", arg: 1, scope: {{.*}}, file: {{.*}}, line: {{.*}}, type: {{.*}}, flags: DIFlagVariableNotChanged) +// CHECK: !DILocalVariable(name: "b", arg: 2, scope: {{.*}}, file: {{.*}}, line: {{.*}}, type: {{.*}}) +// CHECK: !DILocalVariable(name: "test_s", arg: 3, scope: {{.*}}, file: {{.*}}, line: {{.*}}, type: {{.*}}, flags: DIFlagVariableNotChanged) +// CHECK: !DILocalVariable(name: "test_s2", arg: 4, scope: {{.*}}, file: {{.*}}, line: {{.*}}, type: {{.*}}) +// CHECK: !DILocalVariable(name: "x", scope: {{.*}}, file: {{.*}}, line: {{.*}}, type: {{.*}}) +// CHECK: !DILocalVariable(name: "y", scope: {{.*}}, file: {{.*}}, line: {{.*}}, type: {{.*}}) + +typedef struct s { + int m; + int n; +}S; + +void foo (int a, int b, + S test_s, S test_s2) +{ + b++; + b = a + 1; + if (b>4) + test_s2.m = 434; +} + +int main() +{ + S test_s = {4, 5}; + + int x = 5; + int y = 6; + + foo(x , y, test_s, test_s); + + return 0; +} +