[cfe-commits] [PATCH] Model C++11 rules for odr-use for variables correctly

Eli Friedman eli.friedman at gmail.com
Tue Jan 31 21:43:11 PST 2012


On Sat, Jan 28, 2012 at 12:35 AM, John McCall <rjmccall at apple.com> wrote:
> On Jan 27, 2012, at 7:56 PM, Eli Friedman wrote:
>> On Fri, Jan 27, 2012 at 3:26 PM, Eli Friedman <eli.friedman at gmail.com> wrote:
>>> On Fri, Jan 27, 2012 at 3:12 PM, John McCall <rjmccall at apple.com> wrote:
>>>> On Jan 27, 2012, at 2:53 PM, Eli Friedman wrote:
>>>>> On Thu, Jan 26, 2012 at 7:29 PM, John McCall <rjmccall at apple.com> wrote:
>>>>>> On Jan 24, 2012, at 9:34 PM, Eli Friedman wrote:
>>>>>>> Patch attached.  Basically, this is implementing the C++11 rules in
>>>>>>> [basic.def.odr]p2 for variables allowed in constant expressions.
>>>>>>> (Those rules don't matter so much for most code given how we do code
>>>>>>> generation, but we have to get the rules exactly right to get implicit
>>>>>>> capture in lambda expressions working correctly.)
>>>>>>>
>>>>>>> I don't really like this patch, but it seems like it is necessary.
>>>>>>
>>>>>> Yeah, I'm really not happy with this.  Obvious alternative:  mark ODR use
>>>>>> at the DRE creation site unless the object is not already marked and it
>>>>>> meets the constant-loading criteria.  If it does, flag that this full-expression
>>>>>> contains a potential reference, then walk back over the completed
>>>>>> full-expression looking for PE DREs not direct operands of L2R casts.
>>>>>
>>>>> Is there any existing hook that actually triggers where I need it to?
>>>>> MaybeCreateExprWithCleanups seems close... but doesn't quite cover
>>>>> everything.
>>>>
>>>> What's missing?
>>>
>>> In essence, things which are constant-expressions in the C++ grammar
>>> are missing.  Not too hard to add them, I guess.
>>
>> New version attached; it doesn't pass regression tests because I still
>> need to add a hook to catch VLA array bounds attached to declarations,
>> but is this the direction you were thinking of?
>
> That's the general idea, although I didn't carefully look at where you added
> the calls.  Two things, though:
>  - The dynamic optimization of not doing this traversal unless we saw
>    a DeclRef of a not-yet-used-but-const-and-whatever-else declaration
>    is going to be quite important.
>  - isDependentContext() is actually both (a) surprisingly expensive and
>    (b) extremely easy for Sema to cache.

New version attached; similar approach, but avoiding the recursive
walk by keeping the relevant expressions in a side-table.  This is
essentially complete except for one issue: I think I need some sort of
stack to prevent incorrect odr-use marking in some edge cases.

-Eli
-------------- next part --------------
Index: include/clang/Sema/Sema.h
===================================================================
--- include/clang/Sema/Sema.h	(revision 149309)
+++ include/clang/Sema/Sema.h	(working copy)
@@ -233,6 +233,8 @@
   /// element type here is ExprWithCleanups::Object.
   SmallVector<BlockDecl*, 8> ExprCleanupObjects;
 
+  llvm::SmallPtrSet<Expr*, 8> MaybeODRUseExprs;
+
   /// \brief Stack containing information about each of the nested
   /// function, block, and method scopes that are currently active.
   ///
@@ -2265,7 +2267,23 @@
   ExprResult TranformToPotentiallyEvaluated(Expr *E);
   ExprResult HandleExprEvaluationContextForTypeof(Expr *E);
 
-  void MarkDeclarationReferenced(SourceLocation Loc, Decl *D);
+  // Functions for marking a declaration referenced.  These functions also
+  // contain the relevant logic for marking if a reference to a function or
+  // variable is an odr-use (in the C++11 sense).  There are separate variants
+  // for expressions referring to a decl; these exist because odr-use marking
+  // needs to be delayed for some constant variables when we build one of the
+  // named expressions.
+  void MarkAnyDeclReferenced(SourceLocation Loc, Decl *D);
+  void MarkFunctionReferenced(SourceLocation Loc, FunctionDecl *Func);
+  void MarkVariableReferenced(SourceLocation Loc, VarDecl *Var);
+  void MarkBlockDeclRefReferenced(BlockDeclRefExpr *E);
+  void MarkDeclRefReferenced(DeclRefExpr *E);
+  void MarkMemberReferenced(MemberExpr *E);
+
+  void UpdateMarkingForLValueToRValue(Expr *E);
+  void CleanupVarDeclMarking();
+
+
   void MarkDeclarationsReferencedInType(SourceLocation Loc, QualType T);
   void MarkDeclarationsReferencedInExpr(Expr *E);
 
Index: lib/Sema/SemaDeclCXX.cpp
===================================================================
--- lib/Sema/SemaDeclCXX.cpp	(revision 149309)
+++ lib/Sema/SemaDeclCXX.cpp	(working copy)
@@ -2382,14 +2382,14 @@
     ParmVarDecl *Param = Constructor->getParamDecl(0);
     QualType ParamType = Param->getType().getNonReferenceType();
 
-    SemaRef.MarkDeclarationReferenced(Constructor->getLocation(), Param);
-
     Expr *CopyCtorArg = 
       DeclRefExpr::Create(SemaRef.Context, NestedNameSpecifierLoc(),
                           SourceLocation(), Param,
                           Constructor->getLocation(), ParamType,
                           VK_LValue, 0);
 
+    SemaRef.MarkDeclRefReferenced(cast<DeclRefExpr>(CopyCtorArg));
+
     // Cast to the base class to avoid ambiguities.
     QualType ArgTy = 
       SemaRef.Context.getQualifiedType(BaseSpec->getType().getUnqualifiedType(), 
@@ -2454,8 +2454,6 @@
     ParmVarDecl *Param = Constructor->getParamDecl(0);
     QualType ParamType = Param->getType().getNonReferenceType();
 
-    SemaRef.MarkDeclarationReferenced(Constructor->getLocation(), Param);
-
     // Suppress copying zero-width bitfields.
     if (Field->isBitField() && Field->getBitWidthValue(SemaRef.Context) == 0)
       return false;
@@ -2465,6 +2463,8 @@
                           SourceLocation(), Param,
                           Loc, ParamType, VK_LValue, 0);
 
+    SemaRef.MarkDeclRefReferenced(cast<DeclRefExpr>(MemberExprBase));
+
     if (Moving) {
       MemberExprBase = CastForMoving(SemaRef, MemberExprBase);
     }
@@ -2796,7 +2796,7 @@
   Constructor->setCtorInitializers(initializer);
 
   if (CXXDestructorDecl *Dtor = LookupDestructor(Constructor->getParent())) {
-    MarkDeclarationReferenced(Initializer->getSourceLocation(), Dtor);
+    MarkFunctionReferenced(Initializer->getSourceLocation(), Dtor);
     DiagnoseUseOfDecl(Dtor, Initializer->getSourceLocation());
   }
 
@@ -3272,7 +3272,7 @@
                             << Field->getDeclName()
                             << FieldType);
 
-    MarkDeclarationReferenced(Location, const_cast<CXXDestructorDecl*>(Dtor));
+    MarkFunctionReferenced(Location, const_cast<CXXDestructorDecl*>(Dtor));
   }
 
   llvm::SmallPtrSet<const RecordType *, 8> DirectVirtualBases;
@@ -3304,7 +3304,7 @@
                             << Base->getType()
                             << Base->getSourceRange());
     
-    MarkDeclarationReferenced(Location, const_cast<CXXDestructorDecl*>(Dtor));
+    MarkFunctionReferenced(Location, const_cast<CXXDestructorDecl*>(Dtor));
   }
   
   // Virtual bases.
@@ -3332,7 +3332,7 @@
                           PDiag(diag::err_access_dtor_vbase)
                             << VBase->getType());
 
-    MarkDeclarationReferenced(Location, const_cast<CXXDestructorDecl*>(Dtor));
+    MarkFunctionReferenced(Location, const_cast<CXXDestructorDecl*>(Dtor));
   }
 }
 
@@ -5306,7 +5306,7 @@
     if (FindDeallocationFunction(Loc, RD, Name, OperatorDelete))
       return true;
 
-    MarkDeclarationReferenced(Loc, OperatorDelete);
+    MarkFunctionReferenced(Loc, OperatorDelete);
     
     Destructor->setOperatorDelete(OperatorDelete);
   }
@@ -9030,7 +9030,7 @@
     CheckNonNullArguments(NonNull, ExprArgs.get(), ConstructLoc);
   }
 
-  MarkDeclarationReferenced(ConstructLoc, Constructor);
+  MarkFunctionReferenced(ConstructLoc, Constructor);
   return Owned(CXXConstructExpr::Create(Context, DeclInitType, ConstructLoc,
                                         Constructor, Elidable, Exprs, NumExprs,
                                         HadMultipleCandidates, RequiresZeroInit,
@@ -9052,7 +9052,7 @@
 
   Expr *Temp = TempResult.takeAs<Expr>();
   CheckImplicitConversions(Temp, VD->getLocation());
-  MarkDeclarationReferenced(VD->getLocation(), Constructor);
+  MarkFunctionReferenced(VD->getLocation(), Constructor);
   Temp = MaybeCreateExprWithCleanups(Temp);
   VD->setInit(Temp);
 
@@ -9068,7 +9068,7 @@
   if (ClassDecl->isDependentContext()) return;
 
   CXXDestructorDecl *Destructor = LookupDestructor(ClassDecl);
-  MarkDeclarationReferenced(VD->getLocation(), Destructor);
+  MarkFunctionReferenced(VD->getLocation(), Destructor);
   CheckDestructorAccess(VD->getLocation(), Destructor,
                         PDiag(diag::err_access_dtor_var)
                         << VD->getDeclName()
@@ -10905,7 +10905,7 @@
     // C++ [basic.def.odr]p2:
     //   [...] A virtual member function is used if it is not pure. [...]
     if (MD->isVirtual() && !MD->isPure())
-      MarkDeclarationReferenced(Loc, MD);
+      MarkFunctionReferenced(Loc, MD);
   }
 
   // Only classes that have virtual bases need a VTT.
@@ -10965,7 +10965,7 @@
                                                         ->getAs<RecordType>()) {
                     CXXRecordDecl *RD = cast<CXXRecordDecl>(RecordTy->getDecl());
         if (CXXDestructorDecl *Destructor = LookupDestructor(RD)) {
-          MarkDeclarationReferenced(Field->getLocation(), Destructor);
+          MarkFunctionReferenced(Field->getLocation(), Destructor);
           CheckDestructorAccess(Field->getLocation(), Destructor,
                             PDiag(diag::err_access_dtor_ivar)
                               << Context.getBaseElementType(Field->getType()));
Index: lib/Sema/TreeTransform.h
===================================================================
--- lib/Sema/TreeTransform.h	(revision 149441)
+++ lib/Sema/TreeTransform.h	(working copy)
@@ -5949,7 +5949,7 @@
 
     // Mark it referenced in the new context regardless.
     // FIXME: this is a bit instantiation-specific.
-    SemaRef.MarkDeclarationReferenced(E->getLocation(), ND);
+    SemaRef.MarkDeclRefReferenced(E);
 
     return SemaRef.Owned(E);
   }
@@ -6293,7 +6293,8 @@
     
     // Mark it referenced in the new context regardless.
     // FIXME: this is a bit instantiation-specific.
-    SemaRef.MarkDeclarationReferenced(E->getMemberLoc(), Member);
+    SemaRef.MarkMemberReferenced(E);
+
     return SemaRef.Owned(E);
   }
 
@@ -7117,11 +7118,11 @@
     // Mark any declarations we need as referenced.
     // FIXME: instantiation-specific.
     if (Constructor)
-      SemaRef.MarkDeclarationReferenced(E->getLocStart(), Constructor);
+      SemaRef.MarkFunctionReferenced(E->getLocStart(), Constructor);
     if (OperatorNew)
-      SemaRef.MarkDeclarationReferenced(E->getLocStart(), OperatorNew);
+      SemaRef.MarkFunctionReferenced(E->getLocStart(), OperatorNew);
     if (OperatorDelete)
-      SemaRef.MarkDeclarationReferenced(E->getLocStart(), OperatorDelete);
+      SemaRef.MarkFunctionReferenced(E->getLocStart(), OperatorDelete);
     
     if (E->isArray() && Constructor && 
         !E->getAllocatedType()->isDependentType()) {
@@ -7130,7 +7131,7 @@
       if (const RecordType *RecordT = ElementType->getAs<RecordType>()) {
         CXXRecordDecl *Record = cast<CXXRecordDecl>(RecordT->getDecl());
         if (CXXDestructorDecl *Destructor = SemaRef.LookupDestructor(Record)) {
-          SemaRef.MarkDeclarationReferenced(E->getLocStart(), Destructor);
+          SemaRef.MarkFunctionReferenced(E->getLocStart(), Destructor);
         }
       }
     }
@@ -7202,15 +7203,15 @@
     // Mark any declarations we need as referenced.
     // FIXME: instantiation-specific.
     if (OperatorDelete)
-      SemaRef.MarkDeclarationReferenced(E->getLocStart(), OperatorDelete);
+      SemaRef.MarkFunctionReferenced(E->getLocStart(), OperatorDelete);
     
     if (!E->getArgument()->isTypeDependent()) {
       QualType Destroyed = SemaRef.Context.getBaseElementType(
                                                          E->getDestroyedType());
       if (const RecordType *DestroyedRec = Destroyed->getAs<RecordType>()) {
         CXXRecordDecl *Record = cast<CXXRecordDecl>(DestroyedRec->getDecl());
-        SemaRef.MarkDeclarationReferenced(E->getLocStart(), 
-                                          SemaRef.LookupDestructor(Record));
+        SemaRef.MarkFunctionReferenced(E->getLocStart(), 
+                                       SemaRef.LookupDestructor(Record));
       }
     }
     
@@ -7540,7 +7541,7 @@
       !ArgumentChanged) {
     // Mark the constructor as referenced.
     // FIXME: Instantiation-specific
-    SemaRef.MarkDeclarationReferenced(E->getLocStart(), Constructor);
+    SemaRef.MarkFunctionReferenced(E->getLocStart(), Constructor);
     return SemaRef.Owned(E);
   }
 
@@ -7601,7 +7602,7 @@
       Constructor == E->getConstructor() &&
       !ArgumentChanged) {
     // FIXME: Instantiation-specific
-    SemaRef.MarkDeclarationReferenced(E->getLocStart(), Constructor);
+    SemaRef.MarkFunctionReferenced(E->getLocStart(), Constructor);
     return SemaRef.MaybeBindToTemporary(E);
   }
   
@@ -8253,7 +8254,7 @@
       ND == E->getDecl()) {
     // Mark it referenced in the new context regardless.
     // FIXME: this is a bit instantiation-specific.
-    SemaRef.MarkDeclarationReferenced(E->getLocation(), ND);
+    SemaRef.MarkBlockDeclRefReferenced(E);
     
     return SemaRef.Owned(E);
   }
Index: lib/Sema/SemaExprCXX.cpp
===================================================================
--- lib/Sema/SemaExprCXX.cpp	(revision 149309)
+++ lib/Sema/SemaExprCXX.cpp	(working copy)
@@ -645,7 +645,7 @@
   if (!Destructor)
     return Owned(E);
 
-  MarkDeclarationReferenced(E->getExprLoc(), Destructor);
+  MarkFunctionReferenced(E->getExprLoc(), Destructor);
   CheckDestructorAccess(E->getExprLoc(), Destructor,
                         PDiag(diag::err_access_dtor_exception) << Ty);
   return Owned(E);
@@ -1185,16 +1185,16 @@
 
   // Mark the new and delete operators as referenced.
   if (OperatorNew)
-    MarkDeclarationReferenced(StartLoc, OperatorNew);
+    MarkFunctionReferenced(StartLoc, OperatorNew);
   if (OperatorDelete)
-    MarkDeclarationReferenced(StartLoc, OperatorDelete);
+    MarkFunctionReferenced(StartLoc, OperatorDelete);
 
   // C++0x [expr.new]p17:
   //   If the new expression creates an array of objects of class type,
   //   access and ambiguity control are done for the destructor.
   if (ArraySize && Constructor) {
     if (CXXDestructorDecl *dtor = LookupDestructor(Constructor->getParent())) {
-      MarkDeclarationReferenced(StartLoc, dtor);
+      MarkFunctionReferenced(StartLoc, dtor);
       CheckDestructorAccess(StartLoc, dtor, 
                             PDiag(diag::err_access_dtor)
                               << Context.getBaseElementType(AllocType));
@@ -1514,7 +1514,7 @@
   case OR_Success: {
     // Got one!
     FunctionDecl *FnDecl = Best->Function;
-    MarkDeclarationReferenced(StartLoc, FnDecl);
+    MarkFunctionReferenced(StartLoc, FnDecl);
     // The first argument is size_t, and the first parameter must be size_t,
     // too. This is checked on declaration and can be assumed. (It can't be
     // asserted on, though, since invalid decls are left in there.)
@@ -1953,7 +1953,7 @@
 
       if (!PointeeRD->hasTrivialDestructor())
         if (CXXDestructorDecl *Dtor = LookupDestructor(PointeeRD)) {
-          MarkDeclarationReferenced(StartLoc,
+          MarkFunctionReferenced(StartLoc,
                                     const_cast<CXXDestructorDecl*>(Dtor));
           DiagnoseUseOfDecl(Dtor, StartLoc);
         }
@@ -2002,7 +2002,7 @@
         return ExprError();
     }
 
-    MarkDeclarationReferenced(StartLoc, OperatorDelete);
+    MarkFunctionReferenced(StartLoc, OperatorDelete);
     
     // Check access and ambiguity of operator delete and destructor.
     if (PointeeRD) {
@@ -2046,7 +2046,7 @@
                               ConditionVar->getType().getNonReferenceType(),
                               VK_LValue));
 
-  MarkDeclarationReferenced(ConditionVar->getLocation(), ConditionVar);
+  MarkDeclRefReferenced(cast<DeclRefExpr>(Condition.get()));
 
   if (ConvertToBoolean) {
     Condition = CheckBooleanCondition(Condition.take(), StmtLoc);
@@ -3606,7 +3606,7 @@
         break;
       RHS = move(RHSRes);
       if (Best->Function)
-        Self.MarkDeclarationReferenced(QuestionLoc, Best->Function);
+        Self.MarkFunctionReferenced(QuestionLoc, Best->Function);
       return false;
     }
     
@@ -4207,7 +4207,7 @@
 
   CXXTemporary *Temp = CXXTemporary::Create(Context, Destructor);
   if (Destructor) {
-    MarkDeclarationReferenced(E->getExprLoc(), Destructor);
+    MarkFunctionReferenced(E->getExprLoc(), Destructor);
     CheckDestructorAccess(E->getExprLoc(), Destructor,
                           PDiag(diag::err_access_dtor_temp)
                             << E->getType());
@@ -4229,6 +4229,8 @@
 Expr *Sema::MaybeCreateExprWithCleanups(Expr *SubExpr) {
   assert(SubExpr && "sub expression can't be null!");
 
+  CleanupVarDeclMarking();
+
   unsigned FirstCleanup = ExprEvalContexts.back().NumCleanupObjects;
   assert(ExprCleanupObjects.size() >= FirstCleanup);
   assert(ExprNeedsCleanups || ExprCleanupObjects.size() == FirstCleanup);
@@ -4248,6 +4250,8 @@
 Stmt *Sema::MaybeCreateStmtWithCleanups(Stmt *SubStmt) {
   assert(SubStmt && "sub statement can't be null!");
 
+  CleanupVarDeclMarking();
+
   if (!ExprNeedsCleanups)
     return SubStmt;
 
@@ -4684,7 +4688,7 @@
   ExprValueKind VK = Expr::getValueKindForType(ResultType);
   ResultType = ResultType.getNonLValueExprType(Context);
 
-  MarkDeclarationReferenced(Exp.get()->getLocStart(), Method);
+  MarkFunctionReferenced(Exp.get()->getLocStart(), Method);
   CXXMemberCallExpr *CE =
     new (Context) CXXMemberCallExpr(Context, ME, 0, 0, ResultType, VK,
                                     Exp.get()->getLocEnd());
Index: lib/Sema/SemaDeclAttr.cpp
===================================================================
--- lib/Sema/SemaDeclAttr.cpp	(revision 149309)
+++ lib/Sema/SemaDeclAttr.cpp	(working copy)
@@ -2160,7 +2160,7 @@
   }
 
   D->addAttr(::new (S.Context) CleanupAttr(Attr.getRange(), S.Context, FD));
-  S.MarkDeclarationReferenced(Attr.getParameterLoc(), FD);
+  S.MarkFunctionReferenced(Attr.getParameterLoc(), FD);
 }
 
 /// Handle __attribute__((format_arg((idx)))) attribute based on
Index: lib/Sema/SemaInit.cpp
===================================================================
--- lib/Sema/SemaInit.cpp	(revision 149309)
+++ lib/Sema/SemaInit.cpp	(working copy)
@@ -3156,7 +3156,7 @@
 
   // This is the overload that will actually be used for the initialization, so
   // mark it as used.
-  S.MarkDeclarationReferenced(DeclLoc, Function);
+  S.MarkFunctionReferenced(DeclLoc, Function);
 
   // Compute the returned type of the conversion.
   if (isa<CXXConversionDecl>(Function))
@@ -3679,7 +3679,7 @@
   }
 
   FunctionDecl *Function = Best->Function;
-  S.MarkDeclarationReferenced(DeclLoc, Function);
+  S.MarkFunctionReferenced(DeclLoc, Function);
   bool HadMultipleCandidates = (CandidateSet.size() > 1);
 
   if (isa<CXXConstructorDecl>(Function)) {
@@ -4388,7 +4388,7 @@
     return S.Owned(CurInitExpr);
   }
 
-  S.MarkDeclarationReferenced(Loc, Constructor);
+  S.MarkFunctionReferenced(Loc, Constructor);
 
   // Determine the arguments required to actually perform the
   // constructor call (we might have derived-to-base conversions, or
@@ -4531,7 +4531,7 @@
     // An explicitly-constructed temporary, e.g., X(1, 2).
     unsigned NumExprs = ConstructorArgs.size();
     Expr **Exprs = (Expr **)ConstructorArgs.take();
-    S.MarkDeclarationReferenced(Loc, Constructor);
+    S.MarkFunctionReferenced(Loc, Constructor);
     S.DiagnoseUseOfDecl(Constructor, Loc);
 
     TypeSourceInfo *TSInfo = Entity.getTypeSourceInfo();
@@ -4899,7 +4899,7 @@
             = S.LookupDestructor(cast<CXXRecordDecl>(Record->getDecl()));
           S.CheckDestructorAccess(CurInit.get()->getLocStart(), Destructor,
                                   S.PDiag(diag::err_access_dtor_temp) << T);
-          S.MarkDeclarationReferenced(CurInit.get()->getLocStart(), Destructor);
+          S.MarkFunctionReferenced(CurInit.get()->getLocStart(), Destructor);
           S.DiagnoseUseOfDecl(Destructor, CurInit.get()->getLocStart());
         }
       }
Index: lib/Sema/SemaDecl.cpp
===================================================================
--- lib/Sema/SemaDecl.cpp	(revision 149309)
+++ lib/Sema/SemaDecl.cpp	(working copy)
@@ -7298,6 +7298,8 @@
 
     assert(ExprCleanupObjects.empty() && "Leftover temporaries in function");
     assert(!ExprNeedsCleanups && "Unaccounted cleanups in function");
+    assert(MaybeODRUseExprs.empty() &&
+           "Leftover expressions for odr-use checking");
   }
   
   if (!IsInstantiation)
Index: lib/Sema/SemaTemplate.cpp
===================================================================
--- lib/Sema/SemaTemplate.cpp	(revision 149309)
+++ lib/Sema/SemaTemplate.cpp	(working copy)
@@ -3630,7 +3630,7 @@
 
   // Create the template argument.
   Converted = TemplateArgument(Entity->getCanonicalDecl());
-  S.MarkDeclarationReferenced(Arg->getLocStart(), Entity);
+  S.MarkAnyDeclReferenced(Arg->getLocStart(), Entity);
   return false;
 }
 
Index: lib/Sema/SemaOverload.cpp
===================================================================
--- lib/Sema/SemaOverload.cpp	(revision 149309)
+++ lib/Sema/SemaOverload.cpp	(working copy)
@@ -2893,7 +2893,7 @@
     // Record the standard conversion we used and the conversion function.
     if (CXXConstructorDecl *Constructor
           = dyn_cast<CXXConstructorDecl>(Best->Function)) {
-      S.MarkDeclarationReferenced(From->getLocStart(), Constructor);
+      S.MarkFunctionReferenced(From->getLocStart(), Constructor);
 
       // C++ [over.ics.user]p1:
       //   If the user-defined conversion is specified by a
@@ -2923,7 +2923,7 @@
     }
     if (CXXConversionDecl *Conversion
                  = dyn_cast<CXXConversionDecl>(Best->Function)) {
-      S.MarkDeclarationReferenced(From->getLocStart(), Conversion);
+      S.MarkFunctionReferenced(From->getLocStart(), Conversion);
 
       // C++ [over.ics.user]p1:
       //
@@ -3793,7 +3793,7 @@
       return false;
 
     if (Best->Function)
-      S.MarkDeclarationReferenced(DeclLoc, Best->Function);
+      S.MarkFunctionReferenced(DeclLoc, Best->Function);
     ICS.setUserDefined();
     ICS.UserDefined.Before = Best->Conversions[0].Standard;
     ICS.UserDefined.After = Best->FinalConversion;
@@ -8817,7 +8817,7 @@
     Fn = Resolver.getMatchingFunctionDecl();
     assert(Fn);
     FoundResult = *Resolver.getMatchingFunctionAccessPair();
-    MarkDeclarationReferenced(AddressOfExpr->getLocStart(), Fn);
+    MarkFunctionReferenced(AddressOfExpr->getLocStart(), Fn);
     if (Complain)
       CheckAddressOfMemberAccess(AddressOfExpr, FoundResult);
   }
@@ -9380,7 +9380,7 @@
   switch (CandidateSet.BestViableFunction(*this, Fn->getLocStart(), Best)) {
   case OR_Success: {
     FunctionDecl *FDecl = Best->Function;
-    MarkDeclarationReferenced(Fn->getExprLoc(), FDecl);
+    MarkFunctionReferenced(Fn->getExprLoc(), FDecl);
     CheckUnresolvedLookupAccess(ULE, Best->FoundDecl);
     DiagnoseUseOfDecl(FDecl, ULE->getNameLoc());
     Fn = FixOverloadedFunctionReference(Fn, Best->FoundDecl, FDecl);
@@ -9534,7 +9534,7 @@
       // We matched an overloaded operator. Build a call to that
       // operator.
 
-      MarkDeclarationReferenced(OpLoc, FnDecl);
+      MarkFunctionReferenced(OpLoc, FnDecl);
 
       // Convert the arguments.
       if (CXXMethodDecl *Method = dyn_cast<CXXMethodDecl>(FnDecl)) {
@@ -9755,7 +9755,7 @@
         // We matched an overloaded operator. Build a call to that
         // operator.
 
-        MarkDeclarationReferenced(OpLoc, FnDecl);
+        MarkFunctionReferenced(OpLoc, FnDecl);
 
         // Convert the arguments.
         if (CXXMethodDecl *Method = dyn_cast<CXXMethodDecl>(FnDecl)) {
@@ -9962,7 +9962,7 @@
         // We matched an overloaded operator. Build a call to that
         // operator.
 
-        MarkDeclarationReferenced(LLoc, FnDecl);
+        MarkFunctionReferenced(LLoc, FnDecl);
 
         CheckMemberOperatorAccess(LLoc, Args[0], Args[1], Best->FoundDecl);
         DiagnoseUseOfDecl(Best->FoundDecl, LLoc);
@@ -10211,7 +10211,7 @@
                                             Best)) {
     case OR_Success:
       Method = cast<CXXMethodDecl>(Best->Function);
-      MarkDeclarationReferenced(UnresExpr->getMemberLoc(), Method);
+      MarkFunctionReferenced(UnresExpr->getMemberLoc(), Method);
       FoundDecl = Best->FoundDecl;
       CheckUnresolvedMemberAccess(UnresExpr, Best->FoundDecl);
       DiagnoseUseOfDecl(Best->FoundDecl, UnresExpr->getNameLoc());
@@ -10476,7 +10476,7 @@
                          RParenLoc);
   }
 
-  MarkDeclarationReferenced(LParenLoc, Best->Function);
+  MarkFunctionReferenced(LParenLoc, Best->Function);
   CheckMemberOperatorAccess(LParenLoc, Object.get(), 0, Best->FoundDecl);
   DiagnoseUseOfDecl(Best->FoundDecl, LParenLoc);
 
@@ -10666,7 +10666,7 @@
     return ExprError();
   }
 
-  MarkDeclarationReferenced(OpLoc, Best->Function);
+  MarkFunctionReferenced(OpLoc, Best->Function);
   CheckMemberOperatorAccess(OpLoc, Base, 0, Best->FoundDecl);
   DiagnoseUseOfDecl(Best->FoundDecl, OpLoc);
 
Index: lib/Sema/SemaExprMember.cpp
===================================================================
--- lib/Sema/SemaExprMember.cpp	(revision 149309)
+++ lib/Sema/SemaExprMember.cpp	(working copy)
@@ -776,7 +776,8 @@
 }
 
 /// \brief Build a MemberExpr AST node.
-static MemberExpr *BuildMemberExpr(ASTContext &C, Expr *Base, bool isArrow,
+static MemberExpr *BuildMemberExpr(Sema &SemaRef,
+                                   ASTContext &C, Expr *Base, bool isArrow,
                                    const CXXScopeSpec &SS,
                                    SourceLocation TemplateKWLoc,
                                    ValueDecl *Member,
@@ -786,9 +787,12 @@
                                    ExprValueKind VK, ExprObjectKind OK,
                                    const TemplateArgumentListInfo *TemplateArgs = 0) {
   assert((!isArrow || Base->isRValue()) && "-> base must be a pointer rvalue");
-  return MemberExpr::Create(C, Base, isArrow, SS.getWithLocInContext(C),
-                            TemplateKWLoc, Member, FoundDecl, MemberNameInfo,
-                            TemplateArgs, Ty, VK, OK);
+  MemberExpr *E =
+      MemberExpr::Create(C, Base, isArrow, SS.getWithLocInContext(C),
+                         TemplateKWLoc, Member, FoundDecl, MemberNameInfo,
+                         TemplateArgs, Ty, VK, OK);
+  SemaRef.MarkMemberReferenced(E);
+  return E;
 }
 
 ExprResult
@@ -908,9 +912,8 @@
                                                     BaseExpr, OpLoc);
 
   if (VarDecl *Var = dyn_cast<VarDecl>(MemberDecl)) {
-    MarkDeclarationReferenced(MemberLoc, Var);
-    return Owned(BuildMemberExpr(Context, BaseExpr, IsArrow, SS, TemplateKWLoc,
-                                 Var, FoundDecl, MemberNameInfo,
+    return Owned(BuildMemberExpr(*this, Context, BaseExpr, IsArrow, SS,
+                                 TemplateKWLoc, Var, FoundDecl, MemberNameInfo,
                                  Var->getType().getNonReferenceType(),
                                  VK_LValue, OK_Ordinary));
   }
@@ -926,17 +929,16 @@
       type = MemberFn->getType();
     }
 
-    MarkDeclarationReferenced(MemberLoc, MemberDecl);
-    return Owned(BuildMemberExpr(Context, BaseExpr, IsArrow, SS, TemplateKWLoc,
-                                 MemberFn, FoundDecl, MemberNameInfo,
-                                 type, valueKind, OK_Ordinary));
+    return Owned(BuildMemberExpr(*this, Context, BaseExpr, IsArrow, SS, 
+                                 TemplateKWLoc, MemberFn, FoundDecl, 
+                                 MemberNameInfo, type, valueKind,
+                                 OK_Ordinary));
   }
   assert(!isa<FunctionDecl>(MemberDecl) && "member function not C++ method?");
 
   if (EnumConstantDecl *Enum = dyn_cast<EnumConstantDecl>(MemberDecl)) {
-    MarkDeclarationReferenced(MemberLoc, MemberDecl);
-    return Owned(BuildMemberExpr(Context, BaseExpr, IsArrow, SS, TemplateKWLoc,
-                                 Enum, FoundDecl, MemberNameInfo,
+    return Owned(BuildMemberExpr(*this, Context, BaseExpr, IsArrow, SS,
+                                 TemplateKWLoc, Enum, FoundDecl, MemberNameInfo,
                                  Enum->getType(), VK_RValue, OK_Ordinary));
   }
 
@@ -1540,13 +1542,12 @@
       MemberType = S.Context.getQualifiedType(MemberType, Combined);
   }
   
-  S.MarkDeclarationReferenced(MemberNameInfo.getLoc(), Field);
   ExprResult Base =
   S.PerformObjectMemberConversion(BaseExpr, SS.getScopeRep(),
                                   FoundDecl, Field);
   if (Base.isInvalid())
     return ExprError();
-  return S.Owned(BuildMemberExpr(S.Context, Base.take(), IsArrow, SS,
+  return S.Owned(BuildMemberExpr(S, S.Context, Base.take(), IsArrow, SS,
                                  /*TemplateKWLoc=*/SourceLocation(),
                                  Field, FoundDecl, MemberNameInfo,
                                  MemberType, VK, OK));
Index: lib/Sema/SemaExpr.cpp
===================================================================
--- lib/Sema/SemaExpr.cpp	(revision 149309)
+++ lib/Sema/SemaExpr.cpp	(working copy)
@@ -404,6 +404,8 @@
   if (T.hasQualifiers())
     T = T.getUnqualifiedType();
 
+  UpdateMarkingForLValueToRValue(E);
+
   ExprResult Res = Owned(ImplicitCastExpr::Create(Context, T, CK_LValueToRValue,
                                                   E, 0, VK_RValue));
 
@@ -1330,8 +1332,6 @@
     return CR_Error;
   }
 
-  S.MarkDeclarationReferenced(loc, var);
-
   // The BlocksAttr indicates the variable is bound by-reference.
   bool byRef = var->hasAttr<BlocksAttr>();
 
@@ -1410,6 +1410,8 @@
                                             NameInfo.getLoc(), true);
   }
 
+  S.MarkBlockDeclRefReferenced(BDRE);
+
   return S.Owned(BDRE);
 }
 
@@ -1441,13 +1443,13 @@
         }
       }
 
-  MarkDeclarationReferenced(NameInfo.getLoc(), D);
+  DeclRefExpr *E = DeclRefExpr::Create(Context,
+                                       SS ? SS->getWithLocInContext(Context)
+                                              : NestedNameSpecifierLoc(),
+                                           SourceLocation(),
+                                           D, NameInfo, Ty, VK);
 
-  Expr *E = DeclRefExpr::Create(Context,
-                                SS ? SS->getWithLocInContext(Context)
-                                   : NestedNameSpecifierLoc(),
-                                SourceLocation(),
-                                D, NameInfo, Ty, VK);
+  MarkDeclRefReferenced(E);
 
   // Just in case we're building an illegal pointer-to-member.
   FieldDecl *FD = dyn_cast<FieldDecl>(D);
@@ -2003,7 +2005,7 @@
       if (SelfExpr.isInvalid())
         return ExprError();
 
-      MarkDeclarationReferenced(Loc, IV);
+      MarkAnyDeclReferenced(Loc, IV);
       return Owned(new (Context)
                    ObjCIvarRefExpr(IV, IV->getType(), Loc,
                                    SelfExpr.take(), true, true));
@@ -3741,7 +3743,7 @@
 
   DeclRefExpr *ConfigDR = new (Context) DeclRefExpr(
       ConfigDecl, ConfigQTy, VK_LValue, LLLLoc);
-  MarkDeclarationReferenced(LLLLoc, ConfigDecl);
+  MarkFunctionReferenced(LLLLoc, ConfigDecl);
 
   return ActOnCallExpr(S, ConfigDR, LLLLoc, ExecConfig, GGGLoc, 0,
                        /*IsExecConfig=*/true);
@@ -9447,6 +9449,7 @@
     ExprCleanupObjects.erase(ExprCleanupObjects.begin() + Rec.NumCleanupObjects,
                              ExprCleanupObjects.end());
     ExprNeedsCleanups = Rec.ParentNeedsCleanups;
+    CleanupVarDeclMarking();
 
   // Otherwise, merge the contexts together.
   } else {
@@ -9467,55 +9470,47 @@
   return TranformToPotentiallyEvaluated(E);
 }
 
-/// \brief Note that the given declaration was referenced in the source code.
-///
-/// This routine should be invoke whenever a given declaration is referenced
-/// in the source code, and where that reference occurred. If this declaration
-/// reference means that the the declaration is used (C++ [basic.def.odr]p2,
-/// C99 6.9p3), then the declaration will be marked as used.
-///
-/// \param Loc the location where the declaration was referenced.
-///
-/// \param D the declaration that has been referenced by the source code.
-void Sema::MarkDeclarationReferenced(SourceLocation Loc, Decl *D) {
-  assert(D && "No declaration?");
-
-  D->setReferenced();
-
-  if (D->isUsed(false))
-    return;
-
-  if (!isa<VarDecl>(D) && !isa<FunctionDecl>(D))
-    return;
-
+bool IsPotentiallyEvaluatedContext(Sema &SemaRef) {
   // Do not mark anything as "used" within a dependent context; wait for
   // an instantiation.
-  if (CurContext->isDependentContext())
-    return;
+  if (SemaRef.CurContext->isDependentContext())
+    return false;
 
-  switch (ExprEvalContexts.back().Context) {
-    case Unevaluated:
+  switch (SemaRef.ExprEvalContexts.back().Context) {
+    case Sema::Unevaluated:
       // We are in an expression that is not potentially evaluated; do nothing.
       // (Depending on how you read the standard, we actually do need to do
       // something here for null pointer constants, but the standard's
       // definition of a null pointer constant is completely crazy.)
-      return;
+      return false;
 
-    case ConstantEvaluated:
-    case PotentiallyEvaluated:
+    case Sema::ConstantEvaluated:
+    case Sema::PotentiallyEvaluated:
       // We are in a potentially evaluated expression (or a constant-expression
       // in C++03); we need to do implicit template instantiation, implicitly
       // define class members, and mark most declarations as used.
-      break;
+      return true;
 
-    case PotentiallyEvaluatedIfUsed:
+    case Sema::PotentiallyEvaluatedIfUsed:
       // Referenced declarations will only be used if the construct in the
       // containing expression is used.
-      return;
+      return false;
   }
+}
 
+void Sema::MarkFunctionReferenced(SourceLocation Loc, FunctionDecl *Func) {
+  assert(Func && "No function?");
+
+  Func->setReferenced();
+
+  if (Func->isUsed(false))
+    return;
+
+  if (!IsPotentiallyEvaluatedContext(*this))
+    return;
+
   // Note that this declaration has been used.
-  if (CXXConstructorDecl *Constructor = dyn_cast<CXXConstructorDecl>(D)) {
+  if (CXXConstructorDecl *Constructor = dyn_cast<CXXConstructorDecl>(Func)) {
     if (Constructor->isDefaulted()) {
       if (Constructor->isDefaultConstructor()) {
         if (Constructor->isTrivial())
@@ -9532,12 +9527,13 @@
     }
 
     MarkVTableUsed(Loc, Constructor->getParent());
-  } else if (CXXDestructorDecl *Destructor = dyn_cast<CXXDestructorDecl>(D)) {
+  } else if (CXXDestructorDecl *Destructor =
+                 dyn_cast<CXXDestructorDecl>(Func)) {
     if (Destructor->isDefaulted() && !Destructor->isUsed(false))
       DefineImplicitDestructor(Loc, Destructor);
     if (Destructor->isVirtual())
       MarkVTableUsed(Loc, Destructor->getParent());
-  } else if (CXXMethodDecl *MethodDecl = dyn_cast<CXXMethodDecl>(D)) {
+  } else if (CXXMethodDecl *MethodDecl = dyn_cast<CXXMethodDecl>(Func)) {
     if (MethodDecl->isDefaulted() && MethodDecl->isOverloadedOperator() &&
         MethodDecl->getOverloadedOperator() == OO_Equal) {
       if (!MethodDecl->isUsed(false)) {
@@ -9549,101 +9545,183 @@
     } else if (MethodDecl->isVirtual())
       MarkVTableUsed(Loc, MethodDecl->getParent());
   }
-  if (FunctionDecl *Function = dyn_cast<FunctionDecl>(D)) {
-    // Recursive functions should be marked when used from another function.
-    if (CurContext == Function) return;
 
-    // Implicit instantiation of function templates and member functions of
-    // class templates.
-    if (Function->isImplicitlyInstantiable()) {
-      bool AlreadyInstantiated = false;
-      if (FunctionTemplateSpecializationInfo *SpecInfo
-                                = Function->getTemplateSpecializationInfo()) {
-        if (SpecInfo->getPointOfInstantiation().isInvalid())
-          SpecInfo->setPointOfInstantiation(Loc);
-        else if (SpecInfo->getTemplateSpecializationKind()
-                   == TSK_ImplicitInstantiation)
-          AlreadyInstantiated = true;
-      } else if (MemberSpecializationInfo *MSInfo
-                                  = Function->getMemberSpecializationInfo()) {
-        if (MSInfo->getPointOfInstantiation().isInvalid())
-          MSInfo->setPointOfInstantiation(Loc);
-        else if (MSInfo->getTemplateSpecializationKind()
-                   == TSK_ImplicitInstantiation)
-          AlreadyInstantiated = true;
-      }
+  // Recursive functions should be marked when used from another function.
+  // FIXME: Is this really right?
+  if (CurContext == Func) return;
 
-      if (!AlreadyInstantiated) {
-        if (isa<CXXRecordDecl>(Function->getDeclContext()) &&
-            cast<CXXRecordDecl>(Function->getDeclContext())->isLocalClass())
-          PendingLocalImplicitInstantiations.push_back(std::make_pair(Function,
-                                                                      Loc));
-        else if (Function->getTemplateInstantiationPattern()->isConstexpr())
-          // Do not defer instantiations of constexpr functions, to avoid the
-          // expression evaluator needing to call back into Sema if it sees a
-          // call to such a function.
-          InstantiateFunctionDefinition(Loc, Function);
-        else
-          PendingInstantiations.push_back(std::make_pair(Function, Loc));
-      }
-    } else {
-      // Walk redefinitions, as some of them may be instantiable.
-      for (FunctionDecl::redecl_iterator i(Function->redecls_begin()),
-           e(Function->redecls_end()); i != e; ++i) {
-        if (!i->isUsed(false) && i->isImplicitlyInstantiable())
-          MarkDeclarationReferenced(Loc, *i);
-      }
+  // Implicit instantiation of function templates and member functions of
+  // class templates.
+  if (Func->isImplicitlyInstantiable()) {
+    bool AlreadyInstantiated = false;
+    if (FunctionTemplateSpecializationInfo *SpecInfo
+                              = Func->getTemplateSpecializationInfo()) {
+      if (SpecInfo->getPointOfInstantiation().isInvalid())
+        SpecInfo->setPointOfInstantiation(Loc);
+      else if (SpecInfo->getTemplateSpecializationKind()
+                 == TSK_ImplicitInstantiation)
+        AlreadyInstantiated = true;
+    } else if (MemberSpecializationInfo *MSInfo
+                                = Func->getMemberSpecializationInfo()) {
+      if (MSInfo->getPointOfInstantiation().isInvalid())
+        MSInfo->setPointOfInstantiation(Loc);
+      else if (MSInfo->getTemplateSpecializationKind()
+                 == TSK_ImplicitInstantiation)
+        AlreadyInstantiated = true;
     }
 
-    // Keep track of used but undefined functions.
-    if (!Function->isPure() && !Function->hasBody() &&
-        Function->getLinkage() != ExternalLinkage) {
-      SourceLocation &old = UndefinedInternals[Function->getCanonicalDecl()];
-      if (old.isInvalid()) old = Loc;
+    if (!AlreadyInstantiated) {
+      if (isa<CXXRecordDecl>(Func->getDeclContext()) &&
+          cast<CXXRecordDecl>(Func->getDeclContext())->isLocalClass())
+        PendingLocalImplicitInstantiations.push_back(std::make_pair(Func,
+                                                                    Loc));
+      else if (Func->getTemplateInstantiationPattern()->isConstexpr())
+        // Do not defer instantiations of constexpr functions, to avoid the
+        // expression evaluator needing to call back into Sema if it sees a
+        // call to such a function.
+        InstantiateFunctionDefinition(Loc, Func);
+      else
+        PendingInstantiations.push_back(std::make_pair(Func, Loc));
     }
+  } else {
+    // Walk redefinitions, as some of them may be instantiable.
+    for (FunctionDecl::redecl_iterator i(Func->redecls_begin()),
+         e(Func->redecls_end()); i != e; ++i) {
+      if (!i->isUsed(false) && i->isImplicitlyInstantiable())
+        MarkFunctionReferenced(Loc, *i);
+    }
+  }
 
-    Function->setUsed(true);
-    return;
+  // Keep track of used but undefined functions.
+  if (!Func->isPure() && !Func->hasBody() &&
+      Func->getLinkage() != ExternalLinkage) {
+    SourceLocation &old = UndefinedInternals[Func->getCanonicalDecl()];
+    if (old.isInvalid()) old = Loc;
   }
 
-  if (VarDecl *Var = dyn_cast<VarDecl>(D)) {
-    // Implicit instantiation of static data members of class templates.
-    if (Var->isStaticDataMember() &&
-        Var->getInstantiatedFromStaticDataMember()) {
-      MemberSpecializationInfo *MSInfo = Var->getMemberSpecializationInfo();
-      assert(MSInfo && "Missing member specialization information?");
-      if (MSInfo->getPointOfInstantiation().isInvalid() &&
-          MSInfo->getTemplateSpecializationKind()== TSK_ImplicitInstantiation) {
-        MSInfo->setPointOfInstantiation(Loc);
-        // This is a modification of an existing AST node. Notify listeners.
-        if (ASTMutationListener *L = getASTMutationListener())
-          L->StaticDataMemberInstantiated(Var);
-        if (Var->isUsableInConstantExpressions())
-          // Do not defer instantiations of variables which could be used in a
-          // constant expression.
-          InstantiateStaticDataMemberDefinition(Loc, Var);
-        else
-          PendingInstantiations.push_back(std::make_pair(Var, Loc));
-      }
+  Func->setUsed(true);
+}
+
+static void InstantiateVarDecl(Sema &SemaRef, VarDecl *Var,
+                               SourceLocation Loc) {
+  // Implicit instantiation of static data members of class templates.
+  if (Var->isStaticDataMember() &&
+      Var->getInstantiatedFromStaticDataMember()) {
+    MemberSpecializationInfo *MSInfo = Var->getMemberSpecializationInfo();
+    assert(MSInfo && "Missing member specialization information?");
+    if (MSInfo->getPointOfInstantiation().isInvalid() &&
+        MSInfo->getTemplateSpecializationKind()== TSK_ImplicitInstantiation) {
+      MSInfo->setPointOfInstantiation(Loc);
+      // This is a modification of an existing AST node. Notify listeners.
+      if (ASTMutationListener *L = SemaRef.getASTMutationListener())
+        L->StaticDataMemberInstantiated(Var);
+      if (Var->isUsableInConstantExpressions())
+        // Do not defer instantiations of variables which could be used in a
+        // constant expression.
+        SemaRef.InstantiateStaticDataMemberDefinition(Loc, Var);
+      else
+        SemaRef.PendingInstantiations.push_back(std::make_pair(Var, Loc));
     }
+  }
+}
 
-    // Keep track of used but undefined variables.  We make a hole in
-    // the warning for static const data members with in-line
-    // initializers.
-    // FIXME: The hole we make for static const data members is too wide!
-    // We need to implement the C++11 rules for odr-used.
-    if (Var->hasDefinition() == VarDecl::DeclarationOnly
-        && Var->getLinkage() != ExternalLinkage
-        && !(Var->isStaticDataMember() && Var->hasInit())) {
-      SourceLocation &old = UndefinedInternals[Var->getCanonicalDecl()];
-      if (old.isInvalid()) old = Loc;
+static void MarkVarDeclODRUsed(Sema &SemaRef, VarDecl *Var,
+                               SourceLocation Loc) {
+  // Keep track of used but undefined variables.
+  if (Var->hasDefinition() == VarDecl::DeclarationOnly &&
+      Var->getLinkage() != ExternalLinkage) {
+    SourceLocation &old = SemaRef.UndefinedInternals[Var->getCanonicalDecl()];
+    if (old.isInvalid()) old = Loc;
+  }
+
+  Var->setUsed(true);
+}
+
+void Sema::UpdateMarkingForLValueToRValue(Expr *E) {
+  MaybeODRUseExprs.erase(E->IgnoreParens());
+}
+
+void Sema::CleanupVarDeclMarking() {
+  for (llvm::SmallPtrSetIterator<Expr*> i = MaybeODRUseExprs.begin(),
+                                        e = MaybeODRUseExprs.end();
+       i != e; ++i) {
+    VarDecl *Var;
+    SourceLocation Loc;
+    if (BlockDeclRefExpr *BDRE = dyn_cast<BlockDeclRefExpr>(*i)) {
+      Var = BDRE->getDecl();
+      Loc = BDRE->getLocation();
+    } else if (DeclRefExpr *DRE = dyn_cast<DeclRefExpr>(*i)) {
+      Var = cast<VarDecl>(DRE->getDecl());
+      Loc = DRE->getLocation();
+    } else if (MemberExpr *ME = dyn_cast<MemberExpr>(*i)) {
+      Var = cast<VarDecl>(ME->getMemberDecl());
+      Loc = ME->getMemberLoc();
+    } else {
+      llvm_unreachable("Unexpcted expression");
     }
 
-    D->setUsed(true);
+    MarkVarDeclODRUsed(*this, Var, Loc);
+  }
+
+  MaybeODRUseExprs.clear();
+}
+
+void DoMarkVarDeclReferenced(Sema &SemaRef, SourceLocation Loc,
+                             VarDecl *Var, Expr *E) {
+  Var->setReferenced();
+
+  if (Var->isUsed(false))
     return;
+
+  if (!IsPotentiallyEvaluatedContext(SemaRef))
+    return;
+
+  InstantiateVarDecl(SemaRef, Var, Loc);
+
+  const VarDecl *DefVD;
+  if (E && !isa<ParmVarDecl>(Var) &&
+      Var->isUsableInConstantExpressions() &&
+      Var->getAnyInitializer(DefVD) && DefVD->checkInitIsICE())
+    SemaRef.MaybeODRUseExprs.insert(E);
+  else
+    MarkVarDeclODRUsed(SemaRef, Var, Loc);
+}
+
+void Sema::MarkVariableReferenced(SourceLocation Loc, VarDecl *Var) {
+  DoMarkVarDeclReferenced(*this, Loc, Var, 0);
+}
+
+static void MarkExprReferenced(Sema &SemaRef, SourceLocation Loc,
+                               Decl *D, Expr *E) {
+  if (VarDecl *Var = dyn_cast<VarDecl>(D)) {
+    DoMarkVarDeclReferenced(SemaRef, Loc, Var, E);
+    return;
   }
+
+  SemaRef.MarkAnyDeclReferenced(Loc, D);
 }
 
+void Sema::MarkBlockDeclRefReferenced(BlockDeclRefExpr *E) {
+  MarkExprReferenced(*this, E->getLocation(), E->getDecl(), E);
+}
+
+void Sema::MarkDeclRefReferenced(DeclRefExpr *E) {
+  MarkExprReferenced(*this, E->getLocation(), E->getDecl(), E);
+}
+
+void Sema::MarkMemberReferenced(MemberExpr *E) {
+  MarkExprReferenced(*this, E->getMemberLoc(), E->getMemberDecl(), E);
+}
+
+void Sema::MarkAnyDeclReferenced(SourceLocation Loc, Decl *D) {
+  if (VarDecl *VD = dyn_cast<VarDecl>(D))
+    MarkVariableReferenced(Loc, VD);
+  else if (FunctionDecl *FD = dyn_cast<FunctionDecl>(D))
+    MarkFunctionReferenced(Loc, FD);
+  else
+    D->setReferenced();
+}
+
 namespace {
   // Mark all of the declarations referenced
   // FIXME: Not fully implemented yet! We need to have a better understanding
@@ -9665,7 +9743,7 @@
 bool MarkReferencedDecls::TraverseTemplateArgument(
   const TemplateArgument &Arg) {
   if (Arg.getKind() == TemplateArgument::Declaration) {
-    S.MarkDeclarationReferenced(Loc, Arg.getAsDecl());
+    S.MarkAnyDeclReferenced(Loc, Arg.getAsDecl());
   }
 
   return Inherited::TraverseTemplateArgument(Arg);
@@ -9698,37 +9776,37 @@
     explicit EvaluatedExprMarker(Sema &S) : Inherited(S.Context), S(S) { }
     
     void VisitDeclRefExpr(DeclRefExpr *E) {
-      S.MarkDeclarationReferenced(E->getLocation(), E->getDecl());
+      S.MarkDeclRefReferenced(E);
     }
     
     void VisitMemberExpr(MemberExpr *E) {
-      S.MarkDeclarationReferenced(E->getMemberLoc(), E->getMemberDecl());
+      S.MarkMemberReferenced(E);
       Inherited::VisitMemberExpr(E);
     }
     
     void VisitCXXBindTemporaryExpr(CXXBindTemporaryExpr *E) {
-      S.MarkDeclarationReferenced(E->getLocStart(),
+      S.MarkFunctionReferenced(E->getLocStart(),
             const_cast<CXXDestructorDecl*>(E->getTemporary()->getDestructor()));
       Visit(E->getSubExpr());
     }
     
     void VisitCXXNewExpr(CXXNewExpr *E) {
       if (E->getConstructor())
-        S.MarkDeclarationReferenced(E->getLocStart(), E->getConstructor());
+        S.MarkFunctionReferenced(E->getLocStart(), E->getConstructor());
       if (E->getOperatorNew())
-        S.MarkDeclarationReferenced(E->getLocStart(), E->getOperatorNew());
+        S.MarkFunctionReferenced(E->getLocStart(), E->getOperatorNew());
       if (E->getOperatorDelete())
-        S.MarkDeclarationReferenced(E->getLocStart(), E->getOperatorDelete());
+        S.MarkFunctionReferenced(E->getLocStart(), E->getOperatorDelete());
       Inherited::VisitCXXNewExpr(E);
     }
     
     void VisitCXXDeleteExpr(CXXDeleteExpr *E) {
       if (E->getOperatorDelete())
-        S.MarkDeclarationReferenced(E->getLocStart(), E->getOperatorDelete());
+        S.MarkFunctionReferenced(E->getLocStart(), E->getOperatorDelete());
       QualType Destroyed = S.Context.getBaseElementType(E->getDestroyedType());
       if (const RecordType *DestroyedRec = Destroyed->getAs<RecordType>()) {
         CXXRecordDecl *Record = cast<CXXRecordDecl>(DestroyedRec->getDecl());
-        S.MarkDeclarationReferenced(E->getLocStart(), 
+        S.MarkFunctionReferenced(E->getLocStart(), 
                                     S.LookupDestructor(Record));
       }
       
@@ -9736,12 +9814,12 @@
     }
     
     void VisitCXXConstructExpr(CXXConstructExpr *E) {
-      S.MarkDeclarationReferenced(E->getLocStart(), E->getConstructor());
+      S.MarkFunctionReferenced(E->getLocStart(), E->getConstructor());
       Inherited::VisitCXXConstructExpr(E);
     }
     
     void VisitBlockDeclRefExpr(BlockDeclRefExpr *E) {
-      S.MarkDeclarationReferenced(E->getLocation(), E->getDecl());
+      //S.MarkFunctionReferenced(E->getLocation(), E->getDecl());
     }
     
     void VisitCXXDefaultArgExpr(CXXDefaultArgExpr *E) {


More information about the cfe-commits mailing list