<div dir="ltr"><div dir="ltr">On Thu, 13 Jun 2019 at 21:02, Nico Weber <<a href="mailto:thakis@chromium.org">thakis@chromium.org</a>> wrote:<br></div><div class="gmail_quote"><blockquote class="gmail_quote" style="margin:0px 0px 0px 0.8ex;border-left:1px solid rgb(204,204,204);padding-left:1ex"><div dir="ltr">Hi,<div><br></div><div>this made clang segfault on some inputs seen in ANGLE. I filed PR42276 with a reduced repro and reverted this (and the two dependent changes) in r363352 for now.</div></div></blockquote><div><br></div><div>Thanks for the revert and the reduced testcase. Fixed and recommitted as r363428-r363430.</div><div> </div><blockquote class="gmail_quote" style="margin:0px 0px 0px 0.8ex;border-left:1px solid rgb(204,204,204);padding-left:1ex"><div dir="ltr"><div>Nico</div></div><br><div class="gmail_quote"><div dir="ltr" class="gmail_attr">On Thu, Jun 13, 2019 at 2:56 PM Richard Smith via cfe-commits <<a href="mailto:cfe-commits@lists.llvm.org" target="_blank">cfe-commits@lists.llvm.org</a>> wrote:<br></div><blockquote class="gmail_quote" style="margin:0px 0px 0px 0.8ex;border-left:1px solid rgb(204,204,204);padding-left:1ex">Author: rsmith<br>
Date: Thu Jun 13 12:00:16 2019<br>
New Revision: 363295<br>
<br>
URL: <a href="http://llvm.org/viewvc/llvm-project?rev=363295&view=rev" rel="noreferrer" target="_blank">http://llvm.org/viewvc/llvm-project?rev=363295&view=rev</a><br>
Log:<br>
C++ DR712 and others: handle non-odr-use resulting from an lvalue-to-rvalue conversion applied to a member access or similar not-quite-trivial lvalue expression.<br>
<br>
Summary:<br>
When a variable is named in a context where we can't directly emit a<br>
reference to it (because we don't know for sure that it's going to be<br>
defined, or it's from an enclosing function and not captured, or the<br>
reference might not "work" for some reason), we emit a copy of the<br>
variable as a global and use that for the known-to-be-read-only access.<br>
<br>
Reviewers: rjmccall<br>
<br>
Subscribers: jdoerfert, cfe-commits<br>
<br>
Tags: #clang<br>
<br>
Differential Revision: <a href="https://reviews.llvm.org/D63157" rel="noreferrer" target="_blank">https://reviews.llvm.org/D63157</a><br>
<br>
Added:<br>
    cfe/trunk/test/CXX/basic/basic.def.odr/p2.cpp<br>
    cfe/trunk/test/CodeGenCXX/no-odr-use.cpp<br>
Modified:<br>
    cfe/trunk/lib/CodeGen/CGDecl.cpp<br>
    cfe/trunk/lib/CodeGen/CGExpr.cpp<br>
    cfe/trunk/lib/CodeGen/CodeGenModule.h<br>
    cfe/trunk/lib/Sema/SemaExpr.cpp<br>
    cfe/trunk/test/CXX/drs/dr20xx.cpp<br>
    cfe/trunk/test/CXX/drs/dr21xx.cpp<br>
    cfe/trunk/test/CXX/drs/dr23xx.cpp<br>
    cfe/trunk/test/CXX/drs/dr6xx.cpp<br>
    cfe/trunk/test/CXX/drs/dr7xx.cpp<br>
    cfe/trunk/www/cxx_dr_status.html<br>
<br>
Modified: cfe/trunk/lib/CodeGen/CGDecl.cpp<br>
URL: <a href="http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/CodeGen/CGDecl.cpp?rev=363295&r1=363294&r2=363295&view=diff" rel="noreferrer" target="_blank">http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/CodeGen/CGDecl.cpp?rev=363295&r1=363294&r2=363295&view=diff</a><br>
==============================================================================<br>
--- cfe/trunk/lib/CodeGen/CGDecl.cpp (original)<br>
+++ cfe/trunk/lib/CodeGen/CGDecl.cpp Thu Jun 13 12:00:16 2019<br>
@@ -1077,17 +1077,16 @@ static llvm::Constant *constWithPadding(<br>
   return constant;<br>
 }<br>
<br>
-static Address createUnnamedGlobalFrom(CodeGenModule &CGM, const VarDecl &D,<br>
-                                       CGBuilderTy &Builder,<br>
-                                       llvm::Constant *Constant,<br>
-                                       CharUnits Align) {<br>
+Address CodeGenModule::createUnnamedGlobalFrom(const VarDecl &D,<br>
+                                               llvm::Constant *Constant,<br>
+                                               CharUnits Align) {<br>
   auto FunctionName = [&](const DeclContext *DC) -> std::string {<br>
     if (const auto *FD = dyn_cast<FunctionDecl>(DC)) {<br>
       if (const auto *CC = dyn_cast<CXXConstructorDecl>(FD))<br>
         return CC->getNameAsString();<br>
       if (const auto *CD = dyn_cast<CXXDestructorDecl>(FD))<br>
         return CD->getNameAsString();<br>
-      return CGM.getMangledName(FD);<br>
+      return getMangledName(FD);<br>
     } else if (const auto *OM = dyn_cast<ObjCMethodDecl>(DC)) {<br>
       return OM->getNameAsString();<br>
     } else if (isa<BlockDecl>(DC)) {<br>
@@ -1099,22 +1098,39 @@ static Address createUnnamedGlobalFrom(C<br>
     }<br>
   };<br>
<br>
-  auto *Ty = Constant->getType();<br>
-  bool isConstant = true;<br>
-  llvm::GlobalVariable *InsertBefore = nullptr;<br>
-  unsigned AS = CGM.getContext().getTargetAddressSpace(<br>
-      CGM.getStringLiteralAddressSpace());<br>
-  llvm::GlobalVariable *GV = new llvm::GlobalVariable(<br>
-      CGM.getModule(), Ty, isConstant, llvm::GlobalValue::PrivateLinkage,<br>
-      Constant,<br>
-      "__const." + FunctionName(D.getParentFunctionOrMethod()) + "." +<br>
-          D.getName(),<br>
-      InsertBefore, llvm::GlobalValue::NotThreadLocal, AS);<br>
-  GV->setAlignment(Align.getQuantity());<br>
-  GV->setUnnamedAddr(llvm::GlobalValue::UnnamedAddr::Global);<br>
-<br>
-  Address SrcPtr = Address(GV, Align);<br>
-  llvm::Type *BP = llvm::PointerType::getInt8PtrTy(CGM.getLLVMContext(), AS);<br>
+  // Form a simple per-variable cache of these values in case we find we<br>
+  // want to reuse them.<br>
+  llvm::GlobalVariable *&CacheEntry = InitializerConstants[&D];<br>
+  if (!CacheEntry || CacheEntry->getInitializer() != Constant) {<br>
+    auto *Ty = Constant->getType();<br>
+    bool isConstant = true;<br>
+    llvm::GlobalVariable *InsertBefore = nullptr;<br>
+    unsigned AS =<br>
+        getContext().getTargetAddressSpace(getStringLiteralAddressSpace());<br>
+    llvm::GlobalVariable *GV = new llvm::GlobalVariable(<br>
+        getModule(), Ty, isConstant, llvm::GlobalValue::PrivateLinkage,<br>
+        Constant,<br>
+        "__const." + FunctionName(D.getParentFunctionOrMethod()) + "." +<br>
+            D.getName(),<br>
+        InsertBefore, llvm::GlobalValue::NotThreadLocal, AS);<br>
+    GV->setAlignment(Align.getQuantity());<br>
+    GV->setUnnamedAddr(llvm::GlobalValue::UnnamedAddr::Global);<br>
+    CacheEntry = GV;<br>
+  } else if (CacheEntry->getAlignment() < Align.getQuantity()) {<br>
+    CacheEntry->setAlignment(Align.getQuantity());<br>
+  }<br>
+<br>
+  return Address(CacheEntry, Align);<br>
+}<br>
+<br>
+static Address createUnnamedGlobalForMemcpyFrom(CodeGenModule &CGM,<br>
+                                                const VarDecl &D,<br>
+                                                CGBuilderTy &Builder,<br>
+                                                llvm::Constant *Constant,<br>
+                                                CharUnits Align) {<br>
+  Address SrcPtr = CGM.createUnnamedGlobalFrom(D, Constant, Align);<br>
+  llvm::Type *BP = llvm::PointerType::getInt8PtrTy(CGM.getLLVMContext(),<br>
+                                                   SrcPtr.getAddressSpace());<br>
   if (SrcPtr.getType() != BP)<br>
     SrcPtr = Builder.CreateBitCast(SrcPtr, BP);<br>
   return SrcPtr;<br>
@@ -1197,10 +1213,10 @@ static void emitStoresForConstant(CodeGe<br>
   }<br>
<br>
   // Copy from a global.<br>
-  Builder.CreateMemCpy(<br>
-      Loc,<br>
-      createUnnamedGlobalFrom(CGM, D, Builder, constant, Loc.getAlignment()),<br>
-      SizeVal, isVolatile);<br>
+  Builder.CreateMemCpy(Loc,<br>
+                       createUnnamedGlobalForMemcpyFrom(<br>
+                           CGM, D, Builder, constant, Loc.getAlignment()),<br>
+                       SizeVal, isVolatile);<br>
 }<br>
<br>
 static void emitStoresForZeroInit(CodeGenModule &CGM, const VarDecl &D,<br>
@@ -1763,10 +1779,10 @@ void CodeGenFunction::EmitAutoVarInit(co<br>
       llvm::PHINode *Cur = Builder.CreatePHI(Begin.getType(), 2, "vla.cur");<br>
       Cur->addIncoming(Begin.getPointer(), OriginBB);<br>
       CharUnits CurAlign = Loc.getAlignment().alignmentOfArrayElement(EltSize);<br>
-      Builder.CreateMemCpy(<br>
-          Address(Cur, CurAlign),<br>
-          createUnnamedGlobalFrom(CGM, D, Builder, Constant, ConstantAlign),<br>
-          BaseSizeInChars, isVolatile);<br>
+      Builder.CreateMemCpy(Address(Cur, CurAlign),<br>
+                           createUnnamedGlobalForMemcpyFrom(<br>
+                               CGM, D, Builder, Constant, ConstantAlign),<br>
+                           BaseSizeInChars, isVolatile);<br>
       llvm::Value *Next =<br>
           Builder.CreateInBoundsGEP(Int8Ty, Cur, BaseSizeInChars, "vla.next");<br>
       llvm::Value *Done = Builder.CreateICmpEQ(Next, End, "vla-init.isdone");<br>
<br>
Modified: cfe/trunk/lib/CodeGen/CGExpr.cpp<br>
URL: <a href="http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/CodeGen/CGExpr.cpp?rev=363295&r1=363294&r2=363295&view=diff" rel="noreferrer" target="_blank">http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/CodeGen/CGExpr.cpp?rev=363295&r1=363294&r2=363295&view=diff</a><br>
==============================================================================<br>
--- cfe/trunk/lib/CodeGen/CGExpr.cpp (original)<br>
+++ cfe/trunk/lib/CodeGen/CGExpr.cpp Thu Jun 13 12:00:16 2019<br>
@@ -1422,10 +1422,11 @@ static ConstantEmissionKind checkVarType<br>
 }<br>
<br>
 /// Try to emit a reference to the given value without producing it as<br>
-/// an l-value.  This is actually more than an optimization: we can't<br>
-/// produce an l-value for variables that we never actually captured<br>
-/// in a block or lambda, which means const int variables or constexpr<br>
-/// literals or similar.<br>
+/// an l-value.  This is just an optimization, but it avoids us needing<br>
+/// to emit global copies of variables if they're named without triggering<br>
+/// a formal use in a context where we can't emit a direct reference to them,<br>
+/// for instance if a block or lambda or a member of a local class uses a<br>
+/// const int variable or constexpr variable from an enclosing function.<br>
 CodeGenFunction::ConstantEmission<br>
 CodeGenFunction::tryEmitAsConstant(DeclRefExpr *refExpr) {<br>
   ValueDecl *value = refExpr->getDecl();<br>
@@ -2450,33 +2451,97 @@ static LValue EmitGlobalNamedRegister(co<br>
   return LValue::MakeGlobalReg(Address(Ptr, Alignment), VD->getType());<br>
 }<br>
<br>
+/// Determine whether we can emit a reference to \p VD from the current<br>
+/// context, despite not necessarily having seen an odr-use of the variable in<br>
+/// this context.<br>
+static bool canEmitSpuriousReferenceToVariable(CodeGenFunction &CGF,<br>
+                                               const DeclRefExpr *E,<br>
+                                               const VarDecl *VD,<br>
+                                               bool IsConstant) {<br>
+  // For a variable declared in an enclosing scope, do not emit a spurious<br>
+  // reference even if we have a capture, as that will emit an unwarranted<br>
+  // reference to our capture state, and will likely generate worse code than<br>
+  // emitting a local copy.<br>
+  if (E->refersToEnclosingVariableOrCapture())<br>
+    return false;<br>
+<br>
+  // For a local declaration declared in this function, we can always reference<br>
+  // it even if we don't have an odr-use.<br>
+  if (VD->hasLocalStorage()) {<br>
+    return VD->getDeclContext() ==<br>
+           dyn_cast_or_null<DeclContext>(CGF.CurCodeDecl);<br>
+  }<br>
+<br>
+  // For a global declaration, we can emit a reference to it if we know<br>
+  // for sure that we are able to emit a definition of it.<br>
+  VD = VD->getDefinition(CGF.getContext());<br>
+  if (!VD)<br>
+    return false;<br>
+<br>
+  // Don't emit a spurious reference if it might be to a variable that only<br>
+  // exists on a different device / target.<br>
+  // FIXME: This is unnecessarily broad. Check whether this would actually be a<br>
+  // cross-target reference.<br>
+  if (CGF.getLangOpts().OpenMP || CGF.getLangOpts().CUDA ||<br>
+      CGF.getLangOpts().OpenCL) {<br>
+    return false;<br>
+  }<br>
+<br>
+  // We can emit a spurious reference only if the linkage implies that we'll<br>
+  // be emitting a non-interposable symbol that will be retained until link<br>
+  // time.<br>
+  switch (CGF.CGM.getLLVMLinkageVarDefinition(VD, IsConstant)) {<br>
+  case llvm::GlobalValue::ExternalLinkage:<br>
+  case llvm::GlobalValue::LinkOnceODRLinkage:<br>
+  case llvm::GlobalValue::WeakODRLinkage:<br>
+  case llvm::GlobalValue::InternalLinkage:<br>
+  case llvm::GlobalValue::PrivateLinkage:<br>
+    return true;<br>
+  default:<br>
+    return false;<br>
+  }<br>
+}<br>
+<br>
 LValue CodeGenFunction::EmitDeclRefLValue(const DeclRefExpr *E) {<br>
   const NamedDecl *ND = E->getDecl();<br>
   QualType T = E->getType();<br>
<br>
+  assert(E->isNonOdrUse() != NOUR_Unevaluated &&<br>
+         "should not emit an unevaluated operand");<br>
+<br>
   if (const auto *VD = dyn_cast<VarDecl>(ND)) {<br>
     // Global Named registers access via intrinsics only<br>
     if (VD->getStorageClass() == SC_Register &&<br>
         VD->hasAttr<AsmLabelAttr>() && !VD->isLocalVarDecl())<br>
       return EmitGlobalNamedRegister(VD, CGM);<br>
<br>
-    // A DeclRefExpr for a reference initialized by a constant expression can<br>
-    // appear without being odr-used. Directly emit the constant initializer.<br>
-    VD->getAnyInitializer(VD);<br>
-    if (E->isNonOdrUse() == NOUR_Constant && VD->getType()->isReferenceType()) {<br>
-      llvm::Constant *Val =<br>
-        ConstantEmitter(*this).emitAbstract(E->getLocation(),<br>
-                                            *VD->evaluateValue(),<br>
-                                            VD->getType());<br>
-      assert(Val && "failed to emit reference constant expression");<br>
-      // FIXME: Eventually we will want to emit vector element references.<br>
-<br>
-      // Should we be using the alignment of the constant pointer we emitted?<br>
-      CharUnits Alignment = getNaturalTypeAlignment(E->getType(),<br>
-                                                    /* BaseInfo= */ nullptr,<br>
-                                                    /* TBAAInfo= */ nullptr,<br>
-                                                    /* forPointeeType= */ true);<br>
-      return MakeAddrLValue(Address(Val, Alignment), T, AlignmentSource::Decl);<br>
+    // If this DeclRefExpr does not constitute an odr-use of the variable,<br>
+    // we're not permitted to emit a reference to it in general, and it might<br>
+    // not be captured if capture would be necessary for a use. Emit the<br>
+    // constant value directly instead.<br>
+    if (E->isNonOdrUse() == NOUR_Constant &&<br>
+        (VD->getType()->isReferenceType() ||<br>
+         !canEmitSpuriousReferenceToVariable(*this, E, VD, true))) {<br>
+      VD->getAnyInitializer(VD);<br>
+      llvm::Constant *Val = ConstantEmitter(*this).emitAbstract(<br>
+          E->getLocation(), *VD->evaluateValue(), VD->getType());<br>
+      assert(Val && "failed to emit constant expression");<br>
+<br>
+      Address Addr = Address::invalid();<br>
+      if (!VD->getType()->isReferenceType()) {<br>
+        // Spill the constant value to a global.<br>
+        Addr = CGM.createUnnamedGlobalFrom(*VD, Val,<br>
+                                           getContext().getDeclAlign(VD));<br>
+      } else {<br>
+        // Should we be using the alignment of the constant pointer we emitted?<br>
+        CharUnits Alignment =<br>
+            getNaturalTypeAlignment(E->getType(),<br>
+                                    /* BaseInfo= */ nullptr,<br>
+                                    /* TBAAInfo= */ nullptr,<br>
+                                    /* forPointeeType= */ true);<br>
+        Addr = Address(Val, Alignment);<br>
+      }<br>
+      return MakeAddrLValue(Addr, T, AlignmentSource::Decl);<br>
     }<br>
<br>
     // FIXME: Handle other kinds of non-odr-use DeclRefExprs.<br>
@@ -2512,7 +2577,7 @@ LValue CodeGenFunction::EmitDeclRefLValu<br>
   // FIXME: We should be able to assert this for FunctionDecls as well!<br>
   // FIXME: We should be able to assert this for all DeclRefExprs, not just<br>
   // those with a valid source location.<br>
-  assert((ND->isUsed(false) || !isa<VarDecl>(ND) ||<br>
+  assert((ND->isUsed(false) || !isa<VarDecl>(ND) || E->isNonOdrUse() ||<br>
           !E->getLocation().isValid()) &&<br>
          "Should not use decl without marking it used!");<br>
<br>
<br>
Modified: cfe/trunk/lib/CodeGen/CodeGenModule.h<br>
URL: <a href="http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/CodeGen/CodeGenModule.h?rev=363295&r1=363294&r2=363295&view=diff" rel="noreferrer" target="_blank">http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/CodeGen/CodeGenModule.h?rev=363295&r1=363294&r2=363295&view=diff</a><br>
==============================================================================<br>
--- cfe/trunk/lib/CodeGen/CodeGenModule.h (original)<br>
+++ cfe/trunk/lib/CodeGen/CodeGenModule.h Thu Jun 13 12:00:16 2019<br>
@@ -362,6 +362,10 @@ private:<br>
   llvm::SmallVector<std::pair<llvm::GlobalValue *, llvm::Constant *>, 8><br>
     GlobalValReplacements;<br>
<br>
+  /// Variables for which we've emitted globals containing their constant<br>
+  /// values along with the corresponding globals, for opportunistic reuse.<br>
+  llvm::DenseMap<const VarDecl*, llvm::GlobalVariable*> InitializerConstants;<br>
+<br>
   /// Set of global decls for which we already diagnosed mangled name conflict.<br>
   /// Required to not issue a warning (on a mangling conflict) multiple times<br>
   /// for the same decl.<br>
@@ -623,6 +627,9 @@ public:<br>
     StaticLocalDeclGuardMap[D] = C;<br>
   }<br>
<br>
+  Address createUnnamedGlobalFrom(const VarDecl &D, llvm::Constant *Constant,<br>
+                                  CharUnits Align);<br>
+<br>
   bool lookupRepresentativeDecl(StringRef MangledName,<br>
                                 GlobalDecl &Result) const;<br>
<br>
<br>
Modified: cfe/trunk/lib/Sema/SemaExpr.cpp<br>
URL: <a href="http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Sema/SemaExpr.cpp?rev=363295&r1=363294&r2=363295&view=diff" rel="noreferrer" target="_blank">http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Sema/SemaExpr.cpp?rev=363295&r1=363294&r2=363295&view=diff</a><br>
==============================================================================<br>
--- cfe/trunk/lib/Sema/SemaExpr.cpp (original)<br>
+++ cfe/trunk/lib/Sema/SemaExpr.cpp Thu Jun 13 12:00:16 2019<br>
@@ -15806,6 +15806,32 @@ QualType Sema::getCapturedDeclRefType(Va<br>
   return DeclRefType;<br>
 }<br>
<br>
+namespace {<br>
+// Helper to copy the template arguments from a DeclRefExpr or MemberExpr.<br>
+// The produced TemplateArgumentListInfo* points to data stored within this<br>
+// object, so should only be used in contexts where the pointer will not be<br>
+// used after the CopiedTemplateArgs object is destroyed.<br>
+class CopiedTemplateArgs {<br>
+  bool HasArgs;<br>
+  TemplateArgumentListInfo TemplateArgStorage;<br>
+public:<br>
+  template<typename RefExpr><br>
+  CopiedTemplateArgs(RefExpr *E) : HasArgs(E->hasExplicitTemplateArgs()) {<br>
+    if (HasArgs)<br>
+      E->copyTemplateArgumentsInto(TemplateArgStorage);<br>
+  }<br>
+  operator TemplateArgumentListInfo*()<br>
+#ifdef __has_cpp_attribute<br>
+#if __has_cpp_attribute(clang::lifetimebound)<br>
+  [[clang::lifetimebound]]<br>
+#endif<br>
+#endif<br>
+  {<br>
+    return HasArgs ? &TemplateArgStorage : nullptr;<br>
+  }<br>
+};<br>
+}<br>
+<br>
 /// Walk the set of potential results of an expression and mark them all as<br>
 /// non-odr-uses if they satisfy the side-conditions of the NonOdrUseReason.<br>
 ///<br>
@@ -15897,16 +15923,11 @@ static ExprResult rebuildPotentialResult<br>
<br>
     // Rebuild as a non-odr-use DeclRefExpr.<br>
     MarkNotOdrUsed();<br>
-    TemplateArgumentListInfo TemplateArgStorage, *TemplateArgs = nullptr;<br>
-    if (DRE->hasExplicitTemplateArgs()) {<br>
-      DRE->copyTemplateArgumentsInto(TemplateArgStorage);<br>
-      TemplateArgs = &TemplateArgStorage;<br>
-    }<br>
     return DeclRefExpr::Create(<br>
         S.Context, DRE->getQualifierLoc(), DRE->getTemplateKeywordLoc(),<br>
         DRE->getDecl(), DRE->refersToEnclosingVariableOrCapture(),<br>
         DRE->getNameInfo(), DRE->getType(), DRE->getValueKind(),<br>
-        DRE->getFoundDecl(), TemplateArgs, NOUR);<br>
+        DRE->getFoundDecl(), CopiedTemplateArgs(DRE), NOUR);<br>
   }<br>
<br>
   case Expr::FunctionParmPackExprClass: {<br>
@@ -15924,52 +15945,107 @@ static ExprResult rebuildPotentialResult<br>
     break;<br>
   }<br>
<br>
-  // FIXME: Implement these.<br>
   //   -- If e is a subscripting operation with an array operand...<br>
-  //   -- If e is a class member access expression [...] naming a non-static<br>
-  //      data member...<br>
+  case Expr::ArraySubscriptExprClass: {<br>
+    auto *ASE = cast<ArraySubscriptExpr>(E);<br>
+    Expr *OldBase = ASE->getBase()->IgnoreImplicit();<br>
+    if (!OldBase->getType()->isArrayType())<br>
+      break;<br>
+    ExprResult Base = Rebuild(OldBase);<br>
+    if (!Base.isUsable())<br>
+      return Base;<br>
+    Expr *LHS = ASE->getBase() == ASE->getLHS() ? Base.get() : ASE->getLHS();<br>
+    Expr *RHS = ASE->getBase() == ASE->getRHS() ? Base.get() : ASE->getRHS();<br>
+    SourceLocation LBracketLoc = ASE->getBeginLoc(); // FIXME: Not stored.<br>
+    return S.ActOnArraySubscriptExpr(nullptr, LHS, LBracketLoc, RHS,<br>
+                                     ASE->getRBracketLoc());<br>
+  }<br>
<br>
-  //   -- If e is a class member access expression naming a static data member,<br>
-  //      ...<br>
   case Expr::MemberExprClass: {<br>
     auto *ME = cast<MemberExpr>(E);<br>
+    // -- If e is a class member access expression [...] naming a non-static<br>
+    //    data member...<br>
+    if (isa<FieldDecl>(ME->getMemberDecl())) {<br>
+      ExprResult Base = Rebuild(ME->getBase());<br>
+      if (!Base.isUsable())<br>
+        return Base;<br>
+      return MemberExpr::Create(<br>
+          S.Context, Base.get(), ME->isArrow(), ME->getOperatorLoc(),<br>
+          ME->getQualifierLoc(), ME->getTemplateKeywordLoc(),<br>
+          ME->getMemberDecl(), ME->getFoundDecl(), ME->getMemberNameInfo(),<br>
+          CopiedTemplateArgs(ME), ME->getType(), ME->getValueKind(),<br>
+          ME->getObjectKind(), ME->isNonOdrUse());<br>
+    }<br>
+<br>
     if (ME->getMemberDecl()->isCXXInstanceMember())<br>
-      // FIXME: Recurse to the left-hand side.<br>
       break;<br>
<br>
+    // -- If e is a class member access expression naming a static data member,<br>
+    //    ...<br>
     if (ME->isNonOdrUse() || IsPotentialResultOdrUsed(ME->getMemberDecl()))<br>
       break;<br>
<br>
     // Rebuild as a non-odr-use MemberExpr.<br>
     MarkNotOdrUsed();<br>
-    TemplateArgumentListInfo TemplateArgStorage, *TemplateArgs = nullptr;<br>
-    if (ME->hasExplicitTemplateArgs()) {<br>
-      ME->copyTemplateArgumentsInto(TemplateArgStorage);<br>
-      TemplateArgs = &TemplateArgStorage;<br>
-    }<br>
     return MemberExpr::Create(<br>
         S.Context, ME->getBase(), ME->isArrow(), ME->getOperatorLoc(),<br>
         ME->getQualifierLoc(), ME->getTemplateKeywordLoc(), ME->getMemberDecl(),<br>
-        ME->getFoundDecl(), ME->getMemberNameInfo(), TemplateArgs,<br>
+        ME->getFoundDecl(), ME->getMemberNameInfo(), CopiedTemplateArgs(ME),<br>
         ME->getType(), ME->getValueKind(), ME->getObjectKind(), NOUR);<br>
     return ExprEmpty();<br>
   }<br>
<br>
-  // FIXME: Implement this.<br>
-  //   -- If e is a pointer-to-member expression of the form e1 .* e2 ...<br>
+  case Expr::BinaryOperatorClass: {<br>
+    auto *BO = cast<BinaryOperator>(E);<br>
+    Expr *LHS = BO->getLHS();<br>
+    Expr *RHS = BO->getRHS();<br>
+    // -- If e is a pointer-to-member expression of the form e1 .* e2 ...<br>
+    if (BO->getOpcode() == BO_PtrMemD) {<br>
+      ExprResult Sub = Rebuild(LHS);<br>
+      if (!Sub.isUsable())<br>
+        return Sub;<br>
+      LHS = Sub.get();<br>
+    //   -- If e is a comma expression, ...<br>
+    } else if (BO->getOpcode() == BO_Comma) {<br>
+      ExprResult Sub = Rebuild(RHS);<br>
+      if (!Sub.isUsable())<br>
+        return Sub;<br>
+      RHS = Sub.get();<br>
+    } else {<br>
+      break;<br>
+    }<br>
+    return S.BuildBinOp(nullptr, BO->getOperatorLoc(), BO->getOpcode(),<br>
+                        LHS, RHS);<br>
+  }<br>
<br>
   //   -- If e has the form (e1)...<br>
   case Expr::ParenExprClass: {<br>
-    auto *PE = dyn_cast<ParenExpr>(E);<br>
+    auto *PE = cast<ParenExpr>(E);<br>
     ExprResult Sub = Rebuild(PE->getSubExpr());<br>
     if (!Sub.isUsable())<br>
       return Sub;<br>
     return S.ActOnParenExpr(PE->getLParen(), PE->getRParen(), Sub.get());<br>
   }<br>
<br>
-  // FIXME: Implement these.<br>
   //   -- If e is a glvalue conditional expression, ...<br>
-  //   -- If e is a comma expression, ...<br>
+  // We don't apply this to a binary conditional operator. FIXME: Should we?<br>
+  case Expr::ConditionalOperatorClass: {<br>
+    auto *CO = cast<ConditionalOperator>(E);<br>
+    ExprResult LHS = Rebuild(CO->getLHS());<br>
+    if (LHS.isInvalid())<br>
+      return ExprError();<br>
+    ExprResult RHS = Rebuild(CO->getRHS());<br>
+    if (RHS.isInvalid())<br>
+      return ExprError();<br>
+    if (!LHS.isUsable() && !RHS.isUsable())<br>
+      return ExprEmpty();<br>
+    if (!LHS.isUsable())<br>
+      LHS = CO->getLHS();<br>
+    if (!RHS.isUsable())<br>
+      RHS = CO->getRHS();<br>
+    return S.ActOnConditionalOp(CO->getQuestionLoc(), CO->getColonLoc(),<br>
+                                CO->getCond(), LHS.get(), RHS.get());<br>
+  }<br>
<br>
   // [Clang extension]<br>
   //   -- If e has the form __extension__ e1...<br>
@@ -15988,7 +16064,7 @@ static ExprResult rebuildPotentialResult<br>
   //   -- If e has the form _Generic(...), the set of potential results is the<br>
   //      union of the sets of potential results of the associated expressions.<br>
   case Expr::GenericSelectionExprClass: {<br>
-    auto *GSE = dyn_cast<GenericSelectionExpr>(E);<br>
+    auto *GSE = cast<GenericSelectionExpr>(E);<br>
<br>
     SmallVector<Expr *, 4> AssocExprs;<br>
     bool AnyChanged = false;<br>
@@ -16016,7 +16092,7 @@ static ExprResult rebuildPotentialResult<br>
   //      results is the union of the sets of potential results of the<br>
   //      second and third subexpressions.<br>
   case Expr::ChooseExprClass: {<br>
-    auto *CE = dyn_cast<ChooseExpr>(E);<br>
+    auto *CE = cast<ChooseExpr>(E);<br>
<br>
     ExprResult LHS = Rebuild(CE->getLHS());<br>
     if (LHS.isInvalid())<br>
@@ -16039,13 +16115,38 @@ static ExprResult rebuildPotentialResult<br>
<br>
   // Step through non-syntactic nodes.<br>
   case Expr::ConstantExprClass: {<br>
-    auto *CE = dyn_cast<ConstantExpr>(E);<br>
+    auto *CE = cast<ConstantExpr>(E);<br>
     ExprResult Sub = Rebuild(CE->getSubExpr());<br>
     if (!Sub.isUsable())<br>
       return Sub;<br>
     return ConstantExpr::Create(S.Context, Sub.get());<br>
   }<br>
<br>
+  // We could mostly rely on the recursive rebuilding to rebuild implicit<br>
+  // casts, but not at the top level, so rebuild them here.<br>
+  case Expr::ImplicitCastExprClass: {<br>
+    auto *ICE = cast<ImplicitCastExpr>(E);<br>
+    // Only step through the narrow set of cast kinds we expect to encounter.<br>
+    // Anything else suggests we've left the region in which potential results<br>
+    // can be found.<br>
+    switch (ICE->getCastKind()) {<br>
+    case CK_NoOp:<br>
+    case CK_DerivedToBase:<br>
+    case CK_UncheckedDerivedToBase: {<br>
+      ExprResult Sub = Rebuild(ICE->getSubExpr());<br>
+      if (!Sub.isUsable())<br>
+        return Sub;<br>
+      CXXCastPath Path(ICE->path());<br>
+      return S.ImpCastExprToType(Sub.get(), ICE->getType(), ICE->getCastKind(),<br>
+                                 ICE->getValueKind(), &Path);<br>
+    }<br>
+<br>
+    default:<br>
+      break;<br>
+    }<br>
+    break;<br>
+  }<br>
+<br>
   default:<br>
     break;<br>
   }<br>
<br>
Added: cfe/trunk/test/CXX/basic/basic.def.odr/p2.cpp<br>
URL: <a href="http://llvm.org/viewvc/llvm-project/cfe/trunk/test/CXX/basic/basic.def.odr/p2.cpp?rev=363295&view=auto" rel="noreferrer" target="_blank">http://llvm.org/viewvc/llvm-project/cfe/trunk/test/CXX/basic/basic.def.odr/p2.cpp?rev=363295&view=auto</a><br>
==============================================================================<br>
--- cfe/trunk/test/CXX/basic/basic.def.odr/p2.cpp (added)<br>
+++ cfe/trunk/test/CXX/basic/basic.def.odr/p2.cpp Thu Jun 13 12:00:16 2019<br>
@@ -0,0 +1,80 @@<br>
+// RUN: %clang_cc1 -std=c++98 %s -Wno-unused -verify<br>
+// RUN: %clang_cc1 -std=c++11 %s -Wno-unused -verify<br>
+// RUN: %clang_cc1 -std=c++2a %s -Wno-unused -verify<br>
+<br>
+void use(int);<br>
+<br>
+void f() {<br>
+  const int a = 1; // expected-note {{here}}<br>
+<br>
+#if __cplusplus >= 201103L<br>
+  constexpr int arr[3] = {1, 2, 3}; // expected-note 2{{here}}<br>
+<br>
+  struct S { int x; int f() const; };<br>
+  constexpr S s = {0}; // expected-note 3{{here}}<br>
+  constexpr S *ps = nullptr;<br>
+  S *const &psr = ps; // expected-note 2{{here}}<br>
+#endif<br>
+<br>
+  struct Inner {<br>
+    void test(int i) {<br>
+      // id-expression<br>
+      use(a);<br>
+<br>
+#if __cplusplus >= 201103L<br>
+      // subscripting operation with an array operand<br>
+      use(arr[i]);<br>
+      use(i[arr]);<br>
+      use((+arr)[i]); // expected-error {{reference to local variable}}<br>
+      use(i[+arr]); // expected-error {{reference to local variable}}<br>
+<br>
+      // class member access naming non-static data member<br>
+      use(s.x);<br>
+      use(s.f()); // expected-error {{reference to local variable}}<br>
+      use((&s)->x); // expected-error {{reference to local variable}}<br>
+      use(ps->x); // ok (lvalue-to-rvalue conversion applied to id-expression)<br>
+      use(psr->x); // expected-error {{reference to local variable}}<br>
+<br>
+      // class member access naming a static data member<br>
+      // FIXME: How to test this?<br>
+<br>
+      // pointer-to-member expression<br>
+      use(s.*&S::x);<br>
+      use((s.*&S::f)()); // expected-error {{reference to local variable}}<br>
+      use(ps->*&S::x); // ok (lvalue-to-rvalue conversion applied to id-expression)<br>
+      use(psr->*&S::x); // expected-error {{reference to local variable}}<br>
+#endif<br>
+<br>
+      // parentheses<br>
+      use((a));<br>
+#if __cplusplus >= 201103L<br>
+      use((s.x));<br>
+#endif<br>
+<br>
+      // glvalue conditional expression<br>
+      use(i ? a : a);<br>
+      use(i ? i : a);<br>
+<br>
+      // comma expression<br>
+      use((i, a));<br>
+      // FIXME: This is not an odr-use because it is a discarded-value<br>
+      // expression applied to an expression whose potential result is 'a'.<br>
+      use((a, a)); // expected-error {{reference to local variable}}<br>
+<br>
+      // (and combinations thereof)<br>
+      use(a ? (i, a) : a);<br>
+#if __cplusplus >= 201103L<br>
+      use(a ? (i, a) : arr[a ? s.x : arr[a]]);<br>
+#endif<br>
+    }<br>
+  };<br>
+}<br>
+<br>
+// FIXME: Test that this behaves properly.<br>
+namespace std_example {<br>
+  struct S { static const int x = 0, y = 0; };<br>
+  const int &f(const int &r);<br>
+  bool b;<br>
+  int n = b ? (1, S::x)<br>
+            : f(S::y);<br>
+}<br>
<br>
Modified: cfe/trunk/test/CXX/drs/dr20xx.cpp<br>
URL: <a href="http://llvm.org/viewvc/llvm-project/cfe/trunk/test/CXX/drs/dr20xx.cpp?rev=363295&r1=363294&r2=363295&view=diff" rel="noreferrer" target="_blank">http://llvm.org/viewvc/llvm-project/cfe/trunk/test/CXX/drs/dr20xx.cpp?rev=363295&r1=363294&r2=363295&view=diff</a><br>
==============================================================================<br>
--- cfe/trunk/test/CXX/drs/dr20xx.cpp (original)<br>
+++ cfe/trunk/test/CXX/drs/dr20xx.cpp Thu Jun 13 12:00:16 2019<br>
@@ -4,12 +4,205 @@<br>
 // RUN: %clang_cc1 -std=c++14 -triple x86_64-unknown-unknown %s -verify -fexceptions -fcxx-exceptions -pedantic-errors<br>
 // RUN: %clang_cc1 -std=c++1z -triple x86_64-unknown-unknown %s -verify -fexceptions -fcxx-exceptions -pedantic-errors<br>
<br>
-// expected-no-diagnostics<br>
-<br>
 #if __cplusplus < 201103L<br>
 #define static_assert(...) _Static_assert(__VA_ARGS__)<br>
 #endif<br>
<br>
+namespace dr2083 { // dr2083: partial<br>
+#if __cplusplus >= 201103L<br>
+  void non_const_mem_ptr() {<br>
+    struct A {<br>
+      int x;<br>
+      int y;<br>
+    };<br>
+    constexpr A a = {1, 2};<br>
+    struct B {<br>
+      int A::*p;<br>
+      constexpr int g() const {<br>
+        // OK, not an odr-use of 'a'.<br>
+        return a.*p;<br>
+      };<br>
+    };<br>
+    static_assert(B{&A::x}.g() == 1, "");<br>
+    static_assert(B{&A::y}.g() == 2, "");<br>
+  }<br>
+#endif<br>
+<br>
+  const int a = 1;<br>
+  int b;<br>
+  // Note, references only get special odr-use / constant initializxer<br>
+  // treatment in C++11 onwards. We continue to apply that even after DR2083.<br>
+  void ref_to_non_const() {<br>
+    int c;<br>
+    const int &ra = a; // expected-note 0-1{{here}}<br>
+    int &rb = b; // expected-note 0-1{{here}}<br>
+    int &rc = c; // expected-note {{here}}<br>
+    struct A {<br>
+      int f() {<br>
+        int a = ra;<br>
+        int b = rb;<br>
+#if __cplusplus < 201103L<br>
+        // expected-error@-3 {{in enclosing function}}<br>
+        // expected-error@-3 {{in enclosing function}}<br>
+#endif<br>
+        int c = rc; // expected-error {{in enclosing function}}<br>
+        return a + b + c;<br>
+      }<br>
+    };<br>
+  }<br>
+<br>
+#if __cplusplus >= 201103L<br>
+  struct NoMut1 { int a, b; };<br>
+  struct NoMut2 { NoMut1 m; };<br>
+  struct NoMut3 : NoMut1 {<br>
+    constexpr NoMut3(int a, int b) : NoMut1{a, b} {}<br>
+  };<br>
+  struct Mut1 {<br>
+    int a;<br>
+    mutable int b;<br>
+  };<br>
+  struct Mut2 { Mut1 m; };<br>
+  struct Mut3 : Mut1 {<br>
+    constexpr Mut3(int a, int b) : Mut1{a, b} {}<br>
+  };<br>
+  void mutable_subobjects() {<br>
+    constexpr NoMut1 nm1 = {1, 2};<br>
+    constexpr NoMut2 nm2 = {1, 2};<br>
+    constexpr NoMut3 nm3 = {1, 2};<br>
+    constexpr Mut1 m1 = {1, 2}; // expected-note {{declared here}}<br>
+    constexpr Mut2 m2 = {1, 2}; // expected-note {{declared here}}<br>
+    constexpr Mut3 m3 = {1, 2}; // expected-note {{declared here}}<br>
+    struct A {<br>
+      void f() {<br>
+        static_assert(nm1.a == 1, "");<br>
+        static_assert(nm2.m.a == 1, "");<br>
+        static_assert(nm3.a == 1, "");<br>
+        // Can't even access a non-mutable member of a variable containing mutable fields.<br>
+        static_assert(m1.a == 1, ""); // expected-error {{enclosing function}}<br>
+        static_assert(m2.m.a == 1, ""); // expected-error {{enclosing function}}<br>
+        static_assert(m3.a == 1, ""); // expected-error {{enclosing function}}<br>
+      }<br>
+    };<br>
+  }<br>
+#endif<br>
+<br>
+  void ellipsis() {<br>
+    void ellipsis(...);<br>
+    struct A {};<br>
+    const int n = 0;<br>
+#if __cplusplus >= 201103L<br>
+    constexpr<br>
+#endif<br>
+      A a = {}; // expected-note {{here}}<br>
+    struct B {<br>
+      void f() {<br>
+        ellipsis(n);<br>
+        // Even though this is technically modelled as an lvalue-to-rvalue<br>
+        // conversion, it calls a constructor and binds 'a' to a reference, so<br>
+        // it results in an odr-use.<br>
+        ellipsis(a); // expected-error {{enclosing function}}<br>
+      }<br>
+    };<br>
+  }<br>
+<br>
+#if __cplusplus >= 201103L<br>
+  void volatile_lval() {<br>
+    struct A { int n; };<br>
+    constexpr A a = {0}; // expected-note {{here}}<br>
+    struct B {<br>
+      void f() {<br>
+        // An lvalue-to-rvalue conversion of a volatile lvalue always results<br>
+        // in odr-use.<br>
+        int A::*p = &A::n;<br>
+        int x = a.*p;<br>
+        volatile int A::*q = p;<br>
+        int y = a.*q; // expected-error {{enclosing function}}<br>
+      }<br>
+    };<br>
+  }<br>
+#endif<br>
+<br>
+  void discarded_lval() {<br>
+    struct A { int x; mutable int y; volatile int z; };<br>
+    A a; // expected-note 1+{{here}}<br>
+    int &r = a.x; // expected-note {{here}}<br>
+    struct B {<br>
+      void f() {<br>
+        a.x; // expected-warning {{unused}}<br>
+        a.*&A::x; // expected-warning {{unused}}<br>
+        true ? a.x : a.y; // expected-warning {{unused}}<br>
+        (void)a.x;<br>
+        a.x, discarded_lval(); // expected-warning {{unused}}<br>
+#if 1 // FIXME: These errors are all incorrect; the above code is valid.<br>
+      // expected-error@-6 {{enclosing function}}<br>
+      // expected-error@-6 {{enclosing function}}<br>
+      // expected-error@-6 2{{enclosing function}}<br>
+      // expected-error@-6 {{enclosing function}}<br>
+      // expected-error@-6 {{enclosing function}}<br>
+#endif<br>
+<br>
+        // 'volatile' qualifier triggers an lvalue-to-rvalue conversion.<br>
+        a.z; // expected-error {{enclosing function}}<br>
+#if __cplusplus < 201103L<br>
+        // expected-warning@-2 {{assign into a variable}}<br>
+#endif<br>
+<br>
+        // References always get "loaded" to determine what they reference,<br>
+        // even if the result is discarded.<br>
+        r; // expected-error {{enclosing function}} expected-warning {{unused}}<br>
+      }<br>
+    };<br>
+  }<br>
+<br>
+  namespace dr_example_1 {<br>
+    extern int globx;<br>
+    int main() {<br>
+      const int &x = globx;<br>
+      struct A {<br>
+#if __cplusplus < 201103L<br>
+        // expected-error@+2 {{enclosing function}} expected-note@-3 {{here}}<br>
+#endif<br>
+        const int *foo() { return &x; }<br>
+      } a;<br>
+      return *a.foo();<br>
+    }<br>
+  }<br>
+<br>
+#if __cplusplus >= 201103L<br>
+  namespace dr_example_2 {<br>
+    struct A {<br>
+      int q;<br>
+      constexpr A(int q) : q(q) {}<br>
+      constexpr A(const A &a) : q(a.q * 2) {} // (note, not called)<br>
+    };<br>
+<br>
+    int main(void) {<br>
+      constexpr A a(42);<br>
+      constexpr int aq = a.q;<br>
+      struct Q {<br>
+        int foo() { return a.q; }<br>
+      } q;<br>
+      return q.foo();<br>
+    }<br>
+<br>
+    // Checking odr-use does not invent an lvalue-to-rvalue conversion (and<br>
+    // hence copy construction) on the potential result variable.<br>
+    struct B {<br>
+      int b = 42;<br>
+      constexpr B() {}<br>
+      constexpr B(const B&) = delete;<br>
+    };<br>
+    void f() {<br>
+      constexpr B b;<br>
+      struct Q {<br>
+        constexpr int foo() const { return b.b; }<br>
+      };<br>
+      static_assert(Q().foo() == 42, "");<br>
+    }<br>
+  }<br>
+#endif<br>
+}<br>
+<br>
 namespace dr2094 { // dr2094: 5<br>
   struct A { int n; };<br>
   struct B { volatile int n; };<br>
<br>
Modified: cfe/trunk/test/CXX/drs/dr21xx.cpp<br>
URL: <a href="http://llvm.org/viewvc/llvm-project/cfe/trunk/test/CXX/drs/dr21xx.cpp?rev=363295&r1=363294&r2=363295&view=diff" rel="noreferrer" target="_blank">http://llvm.org/viewvc/llvm-project/cfe/trunk/test/CXX/drs/dr21xx.cpp?rev=363295&r1=363294&r2=363295&view=diff</a><br>
==============================================================================<br>
--- cfe/trunk/test/CXX/drs/dr21xx.cpp (original)<br>
+++ cfe/trunk/test/CXX/drs/dr21xx.cpp Thu Jun 13 12:00:16 2019<br>
@@ -8,6 +8,19 @@<br>
 #define static_assert(...) __extension__ _Static_assert(__VA_ARGS__)<br>
 #endif<br>
<br>
+namespace dr2103 { // dr2103: yes<br>
+  void f() {<br>
+    int a;<br>
+    int &r = a; // expected-note {{here}}<br>
+    struct Inner {<br>
+      void f() {<br>
+        int &s = r; // expected-error {{enclosing function}}<br>
+        (void)s;<br>
+      }<br>
+    };<br>
+  }<br>
+}<br>
+<br>
 namespace dr2120 { // dr2120: 7<br>
   struct A {};<br>
   struct B : A {};<br>
@@ -19,6 +32,19 @@ namespace dr2120 { // dr2120: 7<br>
   static_assert(!__is_standard_layout(E), "");<br>
 }<br>
<br>
+namespace dr2170 { // dr2170: 9<br>
+#if __cplusplus >= 201103L<br>
+  void f() {<br>
+    constexpr int arr[3] = {1, 2, 3}; // expected-note {{here}}<br>
+    struct S {<br>
+      int get(int n) { return arr[n]; }<br>
+      const int &get_ref(int n) { return arr[n]; } // expected-error {{enclosing function}}<br>
+      // FIXME: expected-warning@-1 {{reference to stack}}<br>
+    };<br>
+  }<br>
+#endif<br>
+}<br>
+<br>
 namespace dr2180 { // dr2180: yes<br>
   class A {<br>
     A &operator=(const A &); // expected-note 0-2{{here}}<br>
<br>
Modified: cfe/trunk/test/CXX/drs/dr23xx.cpp<br>
URL: <a href="http://llvm.org/viewvc/llvm-project/cfe/trunk/test/CXX/drs/dr23xx.cpp?rev=363295&r1=363294&r2=363295&view=diff" rel="noreferrer" target="_blank">http://llvm.org/viewvc/llvm-project/cfe/trunk/test/CXX/drs/dr23xx.cpp?rev=363295&r1=363294&r2=363295&view=diff</a><br>
==============================================================================<br>
--- cfe/trunk/test/CXX/drs/dr23xx.cpp (original)<br>
+++ cfe/trunk/test/CXX/drs/dr23xx.cpp Thu Jun 13 12:00:16 2019<br>
@@ -1,13 +1,45 @@<br>
-// RUN: %clang_cc1 -std=c++98 %s -verify -fexceptions -fcxx-exceptions -pedantic-errors<br>
-// RUN: %clang_cc1 -std=c++11 %s -verify -fexceptions -fcxx-exceptions -pedantic-errors<br>
-// RUN: %clang_cc1 -std=c++14 %s -verify -fexceptions -fcxx-exceptions -pedantic-errors<br>
-// RUN: %clang_cc1 -std=c++17 %s -verify -fexceptions -fcxx-exceptions -pedantic-errors<br>
-// RUN: %clang_cc1 -std=c++2a %s -verify -fexceptions -fcxx-exceptions -pedantic-errors<br>
+// RUN: %clang_cc1 -std=c++98 %s -verify -fexceptions -fcxx-exceptions -pedantic-errors 2>&1 | FileCheck %s<br>
+// RUN: %clang_cc1 -std=c++11 %s -verify -fexceptions -fcxx-exceptions -pedantic-errors 2>&1 | FileCheck %s<br>
+// RUN: %clang_cc1 -std=c++14 %s -verify -fexceptions -fcxx-exceptions -pedantic-errors 2>&1 | FileCheck %s<br>
+// RUN: %clang_cc1 -std=c++17 %s -verify -fexceptions -fcxx-exceptions -pedantic-errors 2>&1 | FileCheck %s<br>
+// RUN: %clang_cc1 -std=c++2a %s -verify -fexceptions -fcxx-exceptions -pedantic-errors 2>&1 | FileCheck %s<br>
<br>
 #if __cplusplus <= 201103L<br>
 // expected-no-diagnostics<br>
 #endif<br>
<br>
+namespace dr2353 { // dr2353: 9<br>
+  struct X {<br>
+    static const int n = 0;<br>
+  };<br>
+<br>
+  // CHECK: FunctionDecl {{.*}} use<br>
+  int use(X x) {<br>
+    // CHECK: MemberExpr {{.*}} .n<br>
+    // CHECK-NOT: non_odr_use<br>
+    // CHECK: DeclRefExpr {{.*}} 'x'<br>
+    // CHECK-NOT: non_odr_use<br>
+    return *&x.n;<br>
+  }<br>
+#pragma clang __debug dump use<br>
+<br>
+  // CHECK: FunctionDecl {{.*}} not_use<br>
+  int not_use(X x) {<br>
+    // CHECK: MemberExpr {{.*}} .n {{.*}} non_odr_use_constant<br>
+    // CHECK: DeclRefExpr {{.*}} 'x'<br>
+    return x.n;<br>
+  }<br>
+#pragma clang __debug dump not_use<br>
+<br>
+  // CHECK: FunctionDecl {{.*}} not_use_2<br>
+  int not_use_2(X *x) {<br>
+    // CHECK: MemberExpr {{.*}} ->n {{.*}} non_odr_use_constant<br>
+    // CHECK: DeclRefExpr {{.*}} 'x'<br>
+    return x->n;<br>
+  }<br>
+#pragma clang __debug dump not_use_2<br>
+}<br>
+<br>
 namespace dr2387 { // dr2387: 9<br>
 #if __cplusplus >= 201402L<br>
   template<int> int a = 0;<br>
<br>
Modified: cfe/trunk/test/CXX/drs/dr6xx.cpp<br>
URL: <a href="http://llvm.org/viewvc/llvm-project/cfe/trunk/test/CXX/drs/dr6xx.cpp?rev=363295&r1=363294&r2=363295&view=diff" rel="noreferrer" target="_blank">http://llvm.org/viewvc/llvm-project/cfe/trunk/test/CXX/drs/dr6xx.cpp?rev=363295&r1=363294&r2=363295&view=diff</a><br>
==============================================================================<br>
--- cfe/trunk/test/CXX/drs/dr6xx.cpp (original)<br>
+++ cfe/trunk/test/CXX/drs/dr6xx.cpp Thu Jun 13 12:00:16 2019<br>
@@ -1132,3 +1132,20 @@ namespace dr692 { // dr692: no<br>
     template void f(int*); // expected-error {{ambiguous}}<br>
   }<br>
 }<br>
+<br>
+namespace dr696 { // dr696: yes<br>
+  void f(const int*);<br>
+  void g() {<br>
+    const int N = 10; // expected-note 1+{{here}}<br>
+    struct A {<br>
+      void h() {<br>
+        int arr[N]; (void)arr;<br>
+        f(&N); // expected-error {{declared in enclosing}}<br>
+      }<br>
+    };<br>
+#if __cplusplus >= 201103L<br>
+    (void) [] { int arr[N]; (void)arr; };<br>
+    (void) [] { f(&N); }; // expected-error {{cannot be implicitly captured}} expected-note {{here}}<br>
+#endif<br>
+  }<br>
+}<br>
<br>
Modified: cfe/trunk/test/CXX/drs/dr7xx.cpp<br>
URL: <a href="http://llvm.org/viewvc/llvm-project/cfe/trunk/test/CXX/drs/dr7xx.cpp?rev=363295&r1=363294&r2=363295&view=diff" rel="noreferrer" target="_blank">http://llvm.org/viewvc/llvm-project/cfe/trunk/test/CXX/drs/dr7xx.cpp?rev=363295&r1=363294&r2=363295&view=diff</a><br>
==============================================================================<br>
--- cfe/trunk/test/CXX/drs/dr7xx.cpp (original)<br>
+++ cfe/trunk/test/CXX/drs/dr7xx.cpp Thu Jun 13 12:00:16 2019<br>
@@ -17,6 +17,42 @@ namespace dr705 { // dr705: yes<br>
   }<br>
 }<br>
<br>
+namespace dr712 { // dr712: partial<br>
+  void use(int);<br>
+  void f() {<br>
+    const int a = 0; // expected-note 5{{here}}<br>
+    struct X {<br>
+      void g(bool cond) {<br>
+        use(a);<br>
+        use((a));<br>
+        use(cond ? a : a);<br>
+        use((cond, a)); // expected-warning 2{{unused}} FIXME: should only warn once<br>
+<br>
+        (void)a; // FIXME: expected-error {{declared in enclosing}}<br>
+        (void)(a); // FIXME: expected-error {{declared in enclosing}}<br>
+        (void)(cond ? a : a); // FIXME: expected-error 2{{declared in enclosing}}<br>
+        (void)(cond, a); // FIXME: expected-error {{declared in enclosing}} expected-warning {{unused}}<br>
+      }<br>
+    };<br>
+  }<br>
+<br>
+#if __cplusplus >= 201103L<br>
+  void g() {<br>
+    struct A { int n; };<br>
+    constexpr A a = {0}; // expected-note 2{{here}}<br>
+    struct X {<br>
+      void g(bool cond) {<br>
+        use(a.n);<br>
+        use(a.*&A::n);<br>
+<br>
+        (void)a.n; // FIXME: expected-error {{declared in enclosing}}<br>
+        (void)(a.*&A::n); // FIXME: expected-error {{declared in enclosing}}<br>
+      }<br>
+    };<br>
+  }<br>
+#endif<br>
+}<br>
+<br>
 namespace dr727 { // dr727: partial<br>
   struct A {<br>
     template<typename T> struct C; // expected-note 6{{here}}<br>
<br>
Added: cfe/trunk/test/CodeGenCXX/no-odr-use.cpp<br>
URL: <a href="http://llvm.org/viewvc/llvm-project/cfe/trunk/test/CodeGenCXX/no-odr-use.cpp?rev=363295&view=auto" rel="noreferrer" target="_blank">http://llvm.org/viewvc/llvm-project/cfe/trunk/test/CodeGenCXX/no-odr-use.cpp?rev=363295&view=auto</a><br>
==============================================================================<br>
--- cfe/trunk/test/CodeGenCXX/no-odr-use.cpp (added)<br>
+++ cfe/trunk/test/CodeGenCXX/no-odr-use.cpp Thu Jun 13 12:00:16 2019<br>
@@ -0,0 +1,27 @@<br>
+// RUN: %clang_cc1 -emit-llvm -o - -triple x86_64-linux-gnu %s | FileCheck %s<br>
+<br>
+// CHECK: @__const._Z1fi.a = private unnamed_addr constant {{.*}} { i32 1, [2 x i32] [i32 2, i32 3], [3 x i32] [i32 4, i32 5, i32 6] }<br>
+<br>
+struct A { int x, y[2]; int arr[3]; };<br>
+// CHECK-LABEL: define i32 @_Z1fi(<br>
+int f(int i) {<br>
+  // CHECK: call void {{.*}}memcpy{{.*}}({{.*}}, {{.*}} @__const._Z1fi.a<br>
+  constexpr A a = {1, 2, 3, 4, 5, 6};<br>
+<br>
+  // CHECK-LABEL: define {{.*}}@"_ZZ1fiENK3$_0clEiM1Ai"(<br>
+  return [] (int n, int A::*p) {<br>
+    // CHECK: br i1<br>
+    return (n >= 0<br>
+      // CHECK: getelementptr inbounds [3 x i32], [3 x i32]* getelementptr inbounds ({{.*}} @__const._Z1fi.a, i32 0, i32 2), i64 0, i64 %<br>
+      ? a.arr[n]<br>
+      // CHECK: br i1<br>
+      : (n == -1<br>
+        // CHECK: getelementptr inbounds i8, i8* bitcast ({{.*}} @__const._Z1fi.a to i8*), i64 %<br>
+        // CHECK: bitcast i8* %{{.*}} to i32*<br>
+        // CHECK: load i32<br>
+        ? a.*p<br>
+        // CHECK: getelementptr inbounds [2 x i32], [2 x i32]* getelementptr inbounds ({{.*}} @__const._Z1fi.a, i32 0, i32 1), i64 0, i64 %<br>
+        // CHECK: load i32<br>
+        : a.y[2 - n]));<br>
+  }(i, &A::x);<br>
+}<br>
<br>
Modified: cfe/trunk/www/cxx_dr_status.html<br>
URL: <a href="http://llvm.org/viewvc/llvm-project/cfe/trunk/www/cxx_dr_status.html?rev=363295&r1=363294&r2=363295&view=diff" rel="noreferrer" target="_blank">http://llvm.org/viewvc/llvm-project/cfe/trunk/www/cxx_dr_status.html?rev=363295&r1=363294&r2=363295&view=diff</a><br>
==============================================================================<br>
--- cfe/trunk/www/cxx_dr_status.html (original)<br>
+++ cfe/trunk/www/cxx_dr_status.html Thu Jun 13 12:00:16 2019<br>
@@ -4219,7 +4219,7 @@ and <I>POD class</I></td><br>
     <td><a href="<a href="http://wg21.link/cwg696" rel="noreferrer" target="_blank">http://wg21.link/cwg696</a>">696</a></td><br>
     <td>C++11</td><br>
     <td>Use of block-scope constants in local classes</td><br>
-    <td class="none" align="center">Unknown</td><br>
+    <td class="full" align="center">Yes</td><br>
   </tr><br>
   <tr class="open" id="697"><br>
     <td><a href="<a href="http://wg21.link/cwg697" rel="noreferrer" target="_blank">http://wg21.link/cwg697</a>">697</a></td><br>
@@ -4315,7 +4315,7 @@ and <I>POD class</I></td><br>
     <td><a href="<a href="http://wg21.link/cwg712" rel="noreferrer" target="_blank">http://wg21.link/cwg712</a>">712</a></td><br>
     <td>CD3</td><br>
     <td>Are integer constant operands of a <I>conditional-expression</I> &#8220;used?&#8221;</td><br>
-    <td class="none" align="center">Unknown</td><br>
+    <td class="partial" align="center">Partial</td><br>
   </tr><br>
   <tr id="713"><br>
     <td><a href="<a href="http://wg21.link/cwg713" rel="noreferrer" target="_blank">http://wg21.link/cwg713</a>">713</a></td><br>
@@ -12313,7 +12313,7 @@ and <I>POD class</I></td><br>
     <td><a href="<a href="http://wg21.link/cwg2083" rel="noreferrer" target="_blank">http://wg21.link/cwg2083</a>">2083</a></td><br>
     <td>DR</td><br>
     <td>Incorrect cases of odr-use</td><br>
-    <td class="none" align="center">Unknown</td><br>
+    <td class="partial" align="center">Partial</td><br>
   </tr><br>
   <tr id="2084"><br>
     <td><a href="<a href="http://wg21.link/cwg2084" rel="noreferrer" target="_blank">http://wg21.link/cwg2084</a>">2084</a></td><br>
@@ -12433,7 +12433,7 @@ and <I>POD class</I></td><br>
     <td><a href="<a href="http://wg21.link/cwg2103" rel="noreferrer" target="_blank">http://wg21.link/cwg2103</a>">2103</a></td><br>
     <td>DR</td><br>
     <td>Lvalue-to-rvalue conversion is irrelevant in odr-use of a reference</td><br>
-    <td class="none" align="center">Unknown</td><br>
+    <td class="full" align="center">Yes</td><br>
   </tr><br>
   <tr id="2104"><br>
     <td><a href="<a href="http://wg21.link/cwg2104" rel="noreferrer" target="_blank">http://wg21.link/cwg2104</a>">2104</a></td><br>
@@ -12835,7 +12835,7 @@ and <I>POD class</I></td><br>
     <td><a href="<a href="http://wg21.link/cwg2170" rel="noreferrer" target="_blank">http://wg21.link/cwg2170</a>">2170</a></td><br>
     <td>DR</td><br>
     <td>Unclear definition of odr-use for arrays</td><br>
-    <td class="none" align="center">Unknown</td><br>
+    <td class="svn" align="center">SVN</td><br>
   </tr><br>
   <tr id="2171"><br>
     <td><a href="<a href="http://wg21.link/cwg2171" rel="noreferrer" target="_blank">http://wg21.link/cwg2171</a>">2171</a></td><br>
@@ -13933,7 +13933,7 @@ and <I>POD class</I></td><br>
     <td><a href="<a href="http://wg21.link/cwg2353" rel="noreferrer" target="_blank">http://wg21.link/cwg2353</a>">2353</a></td><br>
     <td>DR</td><br>
     <td>Potential results of a member access expression for a static data member</td><br>
-    <td class="none" align="center">Unknown</td><br>
+    <td class="svn" align="center">SVN</td><br>
   </tr><br>
   <tr id="2354"><br>
     <td><a href="<a href="http://wg21.link/cwg2354" rel="noreferrer" target="_blank">http://wg21.link/cwg2354</a>">2354</a></td><br>
<br>
<br>
_______________________________________________<br>
cfe-commits mailing list<br>
<a href="mailto:cfe-commits@lists.llvm.org" target="_blank">cfe-commits@lists.llvm.org</a><br>
<a href="https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits" rel="noreferrer" target="_blank">https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits</a><br>
</blockquote></div>
</blockquote></div></div>