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.

Nico Weber via cfe-commits cfe-commits at lists.llvm.org
Thu Jun 13 21:02:49 PDT 2019


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.

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/931942ca/attachment-0001.html>


More information about the cfe-commits mailing list