r363295 - 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.

Richard Smith via cfe-commits cfe-commits at lists.llvm.org
Fri Jun 14 10:46:52 PDT 2019


On Thu, 13 Jun 2019 at 21:02, Nico Weber <thakis at chromium.org> wrote:

> Hi,
>
> 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.
>

Thanks for the revert and the reduced testcase. Fixed and recommitted as
r363428-r363430.


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


More information about the cfe-commits mailing list