[clang] 5a391d3 - Following up on PR48517, fix handling of template arguments that refer

Hans Wennborg via cfe-commits cfe-commits at lists.llvm.org
Wed Jan 20 07:03:02 PST 2021


Combined with da986511fb9da1a46a0ca4dba2e49e2426036303 this broke
Chromium's build. See
https://bugs.chromium.org/p/chromium/issues/detail?id=1168494#c1 for a
repro.

I've reverted this change and the changes that depended on it in
8ba442bc2136c9ab91c74826db7195e406b94fb7 in the meantime.

On Tue, Jan 19, 2021 at 6:06 AM Richard Smith via cfe-commits
<cfe-commits at lists.llvm.org> wrote:
>
>
> Author: Richard Smith
> Date: 2021-01-18T21:05:01-08:00
> New Revision: 5a391d38ac6c561ba908334d427f26124ed9132e
>
> URL: https://github.com/llvm/llvm-project/commit/5a391d38ac6c561ba908334d427f26124ed9132e
> DIFF: https://github.com/llvm/llvm-project/commit/5a391d38ac6c561ba908334d427f26124ed9132e.diff
>
> LOG: Following up on PR48517, fix handling of template arguments that refer
> to dependent declarations.
>
> Treat an id-expression that names a local variable in a templated
> function as being instantiation-dependent.
>
> This addresses a language defect whereby a reference to a dependent
> declaration can be formed without any construct being value-dependent.
> Fixing that through value-dependence turns out to be problematic, so
> instead this patch takes the approach (proposed on the core reflector)
> of allowing the use of pointers or references to (but not values of)
> dependent declarations inside value-dependent expressions, and instead
> treating template arguments as dependent if they evaluate to a constant
> involving such dependent declarations.
>
> This ends up affecting a bunch of OpenMP tests, due to OpenMP
> imprecisely handling instantiation-dependent constructs, bailing out
> early instead of processing dependent constructs to the extent possible
> when handling the template.
>
> Previously committed as 8c1f2d15b826591cdf6bd6b468b8a7d23377b29e, and
> reverted because a dependency commit was reverted.
>
> Added:
>     clang/test/SemaTemplate/temp_arg_nontype_cxx17.cpp
>
> Modified:
>     clang/include/clang/AST/Expr.h
>     clang/include/clang/AST/TemplateBase.h
>     clang/include/clang/Sema/Sema.h
>     clang/lib/AST/ComputeDependence.cpp
>     clang/lib/AST/Expr.cpp
>     clang/lib/AST/ExprCXX.cpp
>     clang/lib/AST/ExprConstant.cpp
>     clang/lib/AST/TemplateBase.cpp
>     clang/lib/Sema/SemaOverload.cpp
>     clang/lib/Sema/SemaTemplate.cpp
>     clang/lib/Sema/SemaTemplateInstantiate.cpp
>     clang/test/OpenMP/distribute_dist_schedule_messages.cpp
>     clang/test/OpenMP/distribute_parallel_for_dist_schedule_messages.cpp
>     clang/test/OpenMP/distribute_parallel_for_simd_dist_schedule_messages.cpp
>     clang/test/OpenMP/distribute_simd_dist_schedule_messages.cpp
>     clang/test/OpenMP/target_parallel_for_simd_collapse_messages.cpp
>     clang/test/OpenMP/target_parallel_for_simd_ordered_messages.cpp
>     clang/test/OpenMP/target_simd_collapse_messages.cpp
>     clang/test/OpenMP/target_teams_distribute_dist_schedule_messages.cpp
>     clang/test/OpenMP/target_teams_distribute_parallel_for_dist_schedule_messages.cpp
>     clang/test/OpenMP/target_teams_distribute_parallel_for_simd_dist_schedule_messages.cpp
>     clang/test/OpenMP/target_teams_distribute_simd_dist_schedule_messages.cpp
>     clang/test/OpenMP/target_update_from_messages.cpp
>     clang/test/OpenMP/target_update_to_messages.cpp
>     clang/test/OpenMP/task_messages.cpp
>     clang/test/OpenMP/teams_distribute_dist_schedule_messages.cpp
>     clang/test/OpenMP/teams_distribute_parallel_for_dist_schedule_messages.cpp
>     clang/test/OpenMP/teams_distribute_parallel_for_simd_dist_schedule_messages.cpp
>     clang/test/OpenMP/teams_distribute_simd_dist_schedule_messages.cpp
>     clang/test/SemaCXX/warn-unused-lambda-capture.cpp
>     clang/test/SemaTemplate/temp_arg_nontype_cxx20.cpp
>
> Removed:
>     clang/test/SemaTemplate/temp_arg_nontype_cxx1z.cpp
>
>
> ################################################################################
> diff  --git a/clang/include/clang/AST/Expr.h b/clang/include/clang/AST/Expr.h
> index a44d06967431..c963be98d3cb 100644
> --- a/clang/include/clang/AST/Expr.h
> +++ b/clang/include/clang/AST/Expr.h
> @@ -578,12 +578,12 @@ class Expr : public ValueStmt {
>    struct EvalStatus {
>      /// Whether the evaluated expression has side effects.
>      /// For example, (f() && 0) can be folded, but it still has side effects.
> -    bool HasSideEffects;
> +    bool HasSideEffects = false;
>
>      /// Whether the evaluation hit undefined behavior.
>      /// For example, 1.0 / 0.0 can be folded to Inf, but has undefined behavior.
>      /// Likewise, INT_MAX + 1 can be folded to INT_MIN, but has UB.
> -    bool HasUndefinedBehavior;
> +    bool HasUndefinedBehavior = false;
>
>      /// Diag - If this is non-null, it will be filled in with a stack of notes
>      /// indicating why evaluation failed (or why it failed to produce a constant
> @@ -592,10 +592,7 @@ class Expr : public ValueStmt {
>      /// foldable. If the expression is foldable, but not a constant expression,
>      /// the notes will describes why it isn't a constant expression. If the
>      /// expression *is* a constant expression, no notes will be produced.
> -    SmallVectorImpl<PartialDiagnosticAt> *Diag;
> -
> -    EvalStatus()
> -        : HasSideEffects(false), HasUndefinedBehavior(false), Diag(nullptr) {}
> +    SmallVectorImpl<PartialDiagnosticAt> *Diag = nullptr;
>
>      // hasSideEffects - Return true if the evaluated expression has
>      // side effects.
> @@ -606,8 +603,11 @@ class Expr : public ValueStmt {
>
>    /// EvalResult is a struct with detailed info about an evaluated expression.
>    struct EvalResult : EvalStatus {
> -    /// Val - This is the value the expression can be folded to.
> +    /// This is the value the expression can be folded to.
>      APValue Val;
> +    /// Indicates whether Val contains a pointer or reference or pointer to
> +    /// member naming a templated entity, and thus the value is dependent.
> +    bool Dependent = false;
>
>      // isGlobalLValue - Return true if the evaluated lvalue expression
>      // is global.
>
> diff  --git a/clang/include/clang/AST/TemplateBase.h b/clang/include/clang/AST/TemplateBase.h
> index 1671637521e2..5fbb25c315cf 100644
> --- a/clang/include/clang/AST/TemplateBase.h
> +++ b/clang/include/clang/AST/TemplateBase.h
> @@ -252,6 +252,12 @@ class TemplateArgument {
>    /// Whether this template argument is dependent on a template
>    /// parameter such that its result can change from one instantiation to
>    /// another.
> +  ///
> +  /// It's not always meaningful to ask whether a template argument is
> +  /// dependent before it's been converted to match a template parameter;
> +  /// whether a non-type template argument is dependent depends on the
> +  /// corresponding parameter. For an unconverted template argument, this
> +  /// returns true if the argument *might* be dependent.
>    bool isDependent() const;
>
>    /// Whether this template argument is dependent on a template
> @@ -674,13 +680,6 @@ struct alignas(void *) ASTTemplateKWAndArgsInfo {
>    void initializeFrom(SourceLocation TemplateKWLoc,
>                        const TemplateArgumentListInfo &List,
>                        TemplateArgumentLoc *OutArgArray);
> -  // FIXME: The parameter Deps is the result populated by this method, the
> -  // caller doesn't need it since it is populated by computeDependence. remove
> -  // it.
> -  void initializeFrom(SourceLocation TemplateKWLoc,
> -                      const TemplateArgumentListInfo &List,
> -                      TemplateArgumentLoc *OutArgArray,
> -                      TemplateArgumentDependence &Deps);
>    void initializeFrom(SourceLocation TemplateKWLoc);
>
>    void copyInto(const TemplateArgumentLoc *ArgArray,
>
> diff  --git a/clang/include/clang/Sema/Sema.h b/clang/include/clang/Sema/Sema.h
> index 7f7c84eb1b1d..7cdfe24a3a3f 100644
> --- a/clang/include/clang/Sema/Sema.h
> +++ b/clang/include/clang/Sema/Sema.h
> @@ -3465,7 +3465,8 @@ class Sema final {
>                                                llvm::APSInt &Value, CCEKind CCE);
>    ExprResult CheckConvertedConstantExpression(Expr *From, QualType T,
>                                                APValue &Value, CCEKind CCE,
> -                                              NamedDecl *Dest = nullptr);
> +                                              NamedDecl *Dest = nullptr,
> +                                              bool *ValueDependent = nullptr);
>
>    /// Abstract base class used to perform a contextual implicit
>    /// conversion from an expression to any type passing a filter.
>
> diff  --git a/clang/lib/AST/ComputeDependence.cpp b/clang/lib/AST/ComputeDependence.cpp
> index 4026fdc76fd6..5262e3cbe233 100644
> --- a/clang/lib/AST/ComputeDependence.cpp
> +++ b/clang/lib/AST/ComputeDependence.cpp
> @@ -64,7 +64,7 @@ ExprDependence clang::computeDependence(UnaryOperator *E,
>        if (VD && VD->isTemplated()) {
>          auto *VarD = dyn_cast<VarDecl>(VD);
>          if (!VarD || !VarD->hasLocalStorage())
> -          Dep |= ExprDependence::Value;
> +          Dep |= ExprDependence::ValueInstantiation;
>        }
>      }
>    }
> @@ -443,12 +443,21 @@ ExprDependence clang::computeDependence(DeclRefExpr *E, const ASTContext &Ctx) {
>    if (auto *FirstArg = E->getTemplateArgs()) {
>      unsigned NumArgs = E->getNumTemplateArgs();
>      for (auto *Arg = FirstArg, *End = FirstArg + NumArgs; Arg < End; ++Arg)
> -      Deps |= toExprDependence(Arg->getArgument().getDependence());
> +      Deps |= toExprDependence(Arg->getArgument().getDependence() &
> +                               ~TemplateArgumentDependence::Dependent);
>    }
>
>    auto *Decl = E->getDecl();
> +  auto *Found = E->getFoundDecl();
>    auto Type = E->getType();
>
> +  // FIXME: For a ParmVarDecl referenced in a function signature, we don't know
> +  // its dependence yet!
> +  if (!isa<ParmVarDecl>(Decl)) {
> +    if (Decl->getDeclContext()->isDependentContext() ||
> +        (Found && Found->getDeclContext()->isDependentContext()))
> +      Deps |= ExprDependence::Instantiation;
> +  }
>    if (Decl->isParameterPack())
>      Deps |= ExprDependence::UnexpandedPack;
>    Deps |= toExprDependence(Type->getDependence()) & ExprDependence::Error;
>
> diff  --git a/clang/lib/AST/Expr.cpp b/clang/lib/AST/Expr.cpp
> index 5d7066cc2699..6e12b3be01b2 100644
> --- a/clang/lib/AST/Expr.cpp
> +++ b/clang/lib/AST/Expr.cpp
> @@ -416,12 +416,9 @@ DeclRefExpr::DeclRefExpr(const ASTContext &Ctx,
>        RefersToEnclosingVariableOrCapture;
>    DeclRefExprBits.NonOdrUseReason = NOUR;
>    if (TemplateArgs) {
> -    auto Deps = TemplateArgumentDependence::None;
>      getTrailingObjects<ASTTemplateKWAndArgsInfo>()->initializeFrom(
> -        TemplateKWLoc, *TemplateArgs, getTrailingObjects<TemplateArgumentLoc>(),
> -        Deps);
> -    assert(!(Deps & TemplateArgumentDependence::Dependent) &&
> -           "built a DeclRefExpr with dependent template args");
> +        TemplateKWLoc, *TemplateArgs,
> +        getTrailingObjects<TemplateArgumentLoc>());
>    } else if (TemplateKWLoc.isValid()) {
>      getTrailingObjects<ASTTemplateKWAndArgsInfo>()->initializeFrom(
>          TemplateKWLoc);
> @@ -1524,16 +1521,8 @@ MemberExpr *MemberExpr::Create(
>    MemberExpr *E = new (Mem) MemberExpr(Base, IsArrow, OperatorLoc, MemberDecl,
>                                         NameInfo, T, VK, OK, NOUR);
>
> -  // FIXME: remove remaining dependence computation to computeDependence().
> -  auto Deps = E->getDependence();
> +  // FIXME: Move this into the constructor.
>    if (HasQualOrFound) {
> -    // FIXME: Wrong. We should be looking at the member declaration we found.
> -    if (QualifierLoc && QualifierLoc.getNestedNameSpecifier()->isDependent())
> -      Deps |= ExprDependence::TypeValueInstantiation;
> -    else if (QualifierLoc &&
> -             QualifierLoc.getNestedNameSpecifier()->isInstantiationDependent())
> -      Deps |= ExprDependence::Instantiation;
> -
>      E->MemberExprBits.HasQualifierOrFoundDecl = true;
>
>      MemberExprNameQualifier *NQ =
> @@ -1546,16 +1535,26 @@ MemberExpr *MemberExpr::Create(
>        TemplateArgs || TemplateKWLoc.isValid();
>
>    if (TemplateArgs) {
> -    auto TemplateArgDeps = TemplateArgumentDependence::None;
>      E->getTrailingObjects<ASTTemplateKWAndArgsInfo>()->initializeFrom(
>          TemplateKWLoc, *TemplateArgs,
> -        E->getTrailingObjects<TemplateArgumentLoc>(), TemplateArgDeps);
> -    if (TemplateArgDeps & TemplateArgumentDependence::Instantiation)
> -      Deps |= ExprDependence::Instantiation;
> +        E->getTrailingObjects<TemplateArgumentLoc>());
>    } else if (TemplateKWLoc.isValid()) {
>      E->getTrailingObjects<ASTTemplateKWAndArgsInfo>()->initializeFrom(
>          TemplateKWLoc);
>    }
> +
> +  // FIXME: remove remaining dependence computation to computeDependence().
> +  auto Deps = E->getDependence();
> +  if (NestedNameSpecifier *Qual = E->getQualifier()) {
> +    // FIXME: Wrong. We should be looking at the member declaration we found.
> +    if (Qual->isDependent())
> +      Deps |= ExprDependence::TypeValueInstantiation;
> +    else if (Qual->isInstantiationDependent())
> +      Deps |= ExprDependence::Instantiation;
> +  }
> +  if (TemplateSpecializationType::anyInstantiationDependentTemplateArguments(
> +          E->template_arguments()))
> +    Deps |= ExprDependence::Instantiation;
>    E->setDependence(Deps);
>
>    return E;
>
> diff  --git a/clang/lib/AST/ExprCXX.cpp b/clang/lib/AST/ExprCXX.cpp
> index 8dc9d4296e14..e1f658923519 100644
> --- a/clang/lib/AST/ExprCXX.cpp
> +++ b/clang/lib/AST/ExprCXX.cpp
> @@ -433,9 +433,8 @@ OverloadExpr::OverloadExpr(StmtClass SC, const ASTContext &Context,
>    }
>
>    if (TemplateArgs) {
> -    auto Deps = TemplateArgumentDependence::None;
>      getTrailingASTTemplateKWAndArgsInfo()->initializeFrom(
> -        TemplateKWLoc, *TemplateArgs, getTrailingTemplateArgumentLoc(), Deps);
> +        TemplateKWLoc, *TemplateArgs, getTrailingTemplateArgumentLoc());
>    } else if (TemplateKWLoc.isValid()) {
>      getTrailingASTTemplateKWAndArgsInfo()->initializeFrom(TemplateKWLoc);
>    }
> @@ -464,9 +463,8 @@ DependentScopeDeclRefExpr::DependentScopeDeclRefExpr(
>    DependentScopeDeclRefExprBits.HasTemplateKWAndArgsInfo =
>        (Args != nullptr) || TemplateKWLoc.isValid();
>    if (Args) {
> -    auto Deps = TemplateArgumentDependence::None;
>      getTrailingObjects<ASTTemplateKWAndArgsInfo>()->initializeFrom(
> -        TemplateKWLoc, *Args, getTrailingObjects<TemplateArgumentLoc>(), Deps);
> +        TemplateKWLoc, *Args, getTrailingObjects<TemplateArgumentLoc>());
>    } else if (TemplateKWLoc.isValid()) {
>      getTrailingObjects<ASTTemplateKWAndArgsInfo>()->initializeFrom(
>          TemplateKWLoc);
> @@ -1376,10 +1374,9 @@ CXXDependentScopeMemberExpr::CXXDependentScopeMemberExpr(
>    CXXDependentScopeMemberExprBits.OperatorLoc = OperatorLoc;
>
>    if (TemplateArgs) {
> -    auto Deps = TemplateArgumentDependence::None;
>      getTrailingObjects<ASTTemplateKWAndArgsInfo>()->initializeFrom(
> -        TemplateKWLoc, *TemplateArgs, getTrailingObjects<TemplateArgumentLoc>(),
> -        Deps);
> +        TemplateKWLoc, *TemplateArgs,
> +        getTrailingObjects<TemplateArgumentLoc>());
>    } else if (TemplateKWLoc.isValid()) {
>      getTrailingObjects<ASTTemplateKWAndArgsInfo>()->initializeFrom(
>          TemplateKWLoc);
>
> diff  --git a/clang/lib/AST/ExprConstant.cpp b/clang/lib/AST/ExprConstant.cpp
> index b153e22259f7..6ec6df09c83f 100644
> --- a/clang/lib/AST/ExprConstant.cpp
> +++ b/clang/lib/AST/ExprConstant.cpp
> @@ -1819,7 +1819,8 @@ static bool EvaluateFloat(const Expr *E, APFloat &Result, EvalInfo &Info);
>  static bool EvaluateComplex(const Expr *E, ComplexValue &Res, EvalInfo &Info);
>  static bool EvaluateAtomic(const Expr *E, const LValue *This, APValue &Result,
>                             EvalInfo &Info);
> -static bool EvaluateAsRValue(EvalInfo &Info, const Expr *E, APValue &Result);
> +static bool EvaluateAsRValue(EvalInfo &Info, const Expr *E, APValue &Result,
> +                             bool &Dependent);
>
>  /// Evaluate an integer or fixed point expression into an APResult.
>  static bool EvaluateFixedPointOrInteger(const Expr *E, APFixedPoint &Result,
> @@ -2107,7 +2108,8 @@ static bool CheckEvaluationResult(CheckEvaluationResultKind CERK,
>                                    QualType Type, const APValue &Value,
>                                    ConstantExprKind Kind,
>                                    SourceLocation SubobjectLoc,
> -                                  CheckedTemporaries &CheckedTemps);
> +                                  CheckedTemporaries &CheckedTemps,
> +                                  bool &Dependent);
>
>  /// Check that this reference or pointer core constant expression is a valid
>  /// value for an address or reference constant expression. Return true if we
> @@ -2115,7 +2117,8 @@ static bool CheckEvaluationResult(CheckEvaluationResultKind CERK,
>  static bool CheckLValueConstantExpression(EvalInfo &Info, SourceLocation Loc,
>                                            QualType Type, const LValue &LVal,
>                                            ConstantExprKind Kind,
> -                                          CheckedTemporaries &CheckedTemps) {
> +                                          CheckedTemporaries &CheckedTemps,
> +                                          bool &Dependent) {
>    bool IsReferenceType = Type->isReferenceType();
>
>    APValue::LValueBase Base = LVal.getLValueBase();
> @@ -2200,6 +2203,8 @@ static bool CheckLValueConstantExpression(EvalInfo &Info, SourceLocation Loc,
>    }
>
>    if (BaseVD) {
> +    Dependent |= BaseVD->isTemplated();
> +
>      if (const VarDecl *Var = dyn_cast<const VarDecl>(BaseVD)) {
>        // Check if this is a thread-local variable.
>        if (Var->getTLSKind())
> @@ -2230,6 +2235,9 @@ static bool CheckLValueConstantExpression(EvalInfo &Info, SourceLocation Loc,
>      }
>    } else if (const auto *MTE =
>                   dyn_cast_or_null<MaterializeTemporaryExpr>(BaseE)) {
> +    if (auto *Extending = MTE->getExtendingDecl())
> +      Dependent |= Extending->isTemplated();
> +
>      if (CheckedTemps.insert(MTE).second) {
>        QualType TempType = getType(Base);
>        if (TempType.isDestructedType()) {
> @@ -2242,8 +2250,8 @@ static bool CheckLValueConstantExpression(EvalInfo &Info, SourceLocation Loc,
>        APValue *V = MTE->getOrCreateValue(false);
>        assert(V && "evasluation result refers to uninitialised temporary");
>        if (!CheckEvaluationResult(CheckEvaluationResultKind::ConstantExpression,
> -                                 Info, MTE->getExprLoc(), TempType, *V,
> -                                 Kind, SourceLocation(), CheckedTemps))
> +                                 Info, MTE->getExprLoc(), TempType, *V, Kind,
> +                                 SourceLocation(), CheckedTemps, Dependent))
>          return false;
>      }
>    }
> @@ -2272,13 +2280,15 @@ static bool CheckLValueConstantExpression(EvalInfo &Info, SourceLocation Loc,
>
>  /// Member pointers are constant expressions unless they point to a
>  /// non-virtual dllimport member function.
> -static bool CheckMemberPointerConstantExpression(EvalInfo &Info,
> -                                                 SourceLocation Loc,
> -                                                 QualType Type,
> -                                                 const APValue &Value,
> -                                                 ConstantExprKind Kind) {
> +static bool
> +CheckMemberPointerConstantExpression(EvalInfo &Info, SourceLocation Loc,
> +                                     QualType Type, const APValue &Value,
> +                                     ConstantExprKind Kind, bool &Dependent) {
>    const ValueDecl *Member = Value.getMemberPointerDecl();
> -  const auto *FD = dyn_cast_or_null<CXXMethodDecl>(Member);
> +  if (!Member)
> +    return true;
> +  Dependent |= Member->isTemplated();
> +  const auto *FD = dyn_cast<CXXMethodDecl>(Member);
>    if (!FD)
>      return true;
>    if (FD->isConsteval()) {
> @@ -2327,7 +2337,8 @@ static bool CheckEvaluationResult(CheckEvaluationResultKind CERK,
>                                    QualType Type, const APValue &Value,
>                                    ConstantExprKind Kind,
>                                    SourceLocation SubobjectLoc,
> -                                  CheckedTemporaries &CheckedTemps) {
> +                                  CheckedTemporaries &CheckedTemps,
> +                                  bool &Dependent) {
>    if (!Value.hasValue()) {
>      Info.FFDiag(DiagLoc, diag::note_constexpr_uninitialized)
>        << true << Type;
> @@ -2349,20 +2360,20 @@ static bool CheckEvaluationResult(CheckEvaluationResultKind CERK,
>      for (unsigned I = 0, N = Value.getArrayInitializedElts(); I != N; ++I) {
>        if (!CheckEvaluationResult(CERK, Info, DiagLoc, EltTy,
>                                   Value.getArrayInitializedElt(I), Kind,
> -                                 SubobjectLoc, CheckedTemps))
> +                                 SubobjectLoc, CheckedTemps, Dependent))
>          return false;
>      }
>      if (!Value.hasArrayFiller())
>        return true;
>      return CheckEvaluationResult(CERK, Info, DiagLoc, EltTy,
>                                   Value.getArrayFiller(), Kind, SubobjectLoc,
> -                                 CheckedTemps);
> +                                 CheckedTemps, Dependent);
>    }
>    if (Value.isUnion() && Value.getUnionField()) {
>      return CheckEvaluationResult(
>          CERK, Info, DiagLoc, Value.getUnionField()->getType(),
>          Value.getUnionValue(), Kind, Value.getUnionField()->getLocation(),
> -        CheckedTemps);
> +        CheckedTemps, Dependent);
>    }
>    if (Value.isStruct()) {
>      RecordDecl *RD = Type->castAs<RecordType>()->getDecl();
> @@ -2371,7 +2382,7 @@ static bool CheckEvaluationResult(CheckEvaluationResultKind CERK,
>        for (const CXXBaseSpecifier &BS : CD->bases()) {
>          if (!CheckEvaluationResult(CERK, Info, DiagLoc, BS.getType(),
>                                     Value.getStructBase(BaseIndex), Kind,
> -                                   BS.getBeginLoc(), CheckedTemps))
> +                                   BS.getBeginLoc(), CheckedTemps, Dependent))
>            return false;
>          ++BaseIndex;
>        }
> @@ -2381,8 +2392,8 @@ static bool CheckEvaluationResult(CheckEvaluationResultKind CERK,
>          continue;
>
>        if (!CheckEvaluationResult(CERK, Info, DiagLoc, I->getType(),
> -                                 Value.getStructField(I->getFieldIndex()),
> -                                 Kind, I->getLocation(), CheckedTemps))
> +                                 Value.getStructField(I->getFieldIndex()), Kind,
> +                                 I->getLocation(), CheckedTemps, Dependent))
>          return false;
>      }
>    }
> @@ -2392,12 +2403,13 @@ static bool CheckEvaluationResult(CheckEvaluationResultKind CERK,
>      LValue LVal;
>      LVal.setFrom(Info.Ctx, Value);
>      return CheckLValueConstantExpression(Info, DiagLoc, Type, LVal, Kind,
> -                                         CheckedTemps);
> +                                         CheckedTemps, Dependent);
>    }
>
>    if (Value.isMemberPointer() &&
>        CERK == CheckEvaluationResultKind::ConstantExpression)
> -    return CheckMemberPointerConstantExpression(Info, DiagLoc, Type, Value, Kind);
> +    return CheckMemberPointerConstantExpression(Info, DiagLoc, Type, Value,
> +                                                Kind, Dependent);
>
>    // Everything else is fine.
>    return true;
> @@ -2408,7 +2420,7 @@ static bool CheckEvaluationResult(CheckEvaluationResultKind CERK,
>  /// check that the expression is of literal type.
>  static bool CheckConstantExpression(EvalInfo &Info, SourceLocation DiagLoc,
>                                      QualType Type, const APValue &Value,
> -                                    ConstantExprKind Kind) {
> +                                    ConstantExprKind Kind, bool &Dependent) {
>    // Nothing to check for a constant expression of type 'cv void'.
>    if (Type->isVoidType())
>      return true;
> @@ -2416,17 +2428,18 @@ static bool CheckConstantExpression(EvalInfo &Info, SourceLocation DiagLoc,
>    CheckedTemporaries CheckedTemps;
>    return CheckEvaluationResult(CheckEvaluationResultKind::ConstantExpression,
>                                 Info, DiagLoc, Type, Value, Kind,
> -                               SourceLocation(), CheckedTemps);
> +                               SourceLocation(), CheckedTemps, Dependent);
>  }
>
>  /// Check that this evaluated value is fully-initialized and can be loaded by
>  /// an lvalue-to-rvalue conversion.
>  static bool CheckFullyInitialized(EvalInfo &Info, SourceLocation DiagLoc,
>                                    QualType Type, const APValue &Value) {
> +  bool Dependent = false;
>    CheckedTemporaries CheckedTemps;
>    return CheckEvaluationResult(
>        CheckEvaluationResultKind::FullyInitialized, Info, DiagLoc, Type, Value,
> -      ConstantExprKind::Normal, SourceLocation(), CheckedTemps);
> +      ConstantExprKind::Normal, SourceLocation(), CheckedTemps, Dependent);
>  }
>
>  /// Enforce C++2a [expr.const]/4.17, which disallows new-expressions unless
> @@ -11098,7 +11111,9 @@ static bool EvaluateBuiltinConstantP(EvalInfo &Info, const Expr *Arg) {
>        ArgType->isAnyComplexType() || ArgType->isPointerType() ||
>        ArgType->isNullPtrType()) {
>      APValue V;
> -    if (!::EvaluateAsRValue(Info, Arg, V) || Info.EvalStatus.HasSideEffects) {
> +    bool Dependent = false;
> +    if (!::EvaluateAsRValue(Info, Arg, V, Dependent) ||
> +        Info.EvalStatus.HasSideEffects) {
>        Fold.keepDiagnostics();
>        return false;
>      }
> @@ -11400,7 +11415,8 @@ static bool tryEvaluateBuiltinObjectSize(const Expr *E, unsigned Type,
>        // It's possible for us to be given GLValues if we're called via
>        // Expr::tryEvaluateObjectSize.
>        APValue RVal;
> -      if (!EvaluateAsRValue(Info, E, RVal))
> +      bool Dependent = false;
> +      if (!EvaluateAsRValue(Info, E, RVal, Dependent))
>          return false;
>        LVal.setFrom(Info.Ctx, RVal);
>      } else if (!EvaluatePointer(ignorePointerCastsAndParens(E), LVal, Info,
> @@ -12829,8 +12845,9 @@ bool RecordExprEvaluator::VisitBinCmp(const BinaryOperator *E) {
>      LV.set(VD);
>      if (!handleLValueToRValueConversion(Info, E, E->getType(), LV, Result))
>        return false;
> +    bool Dependent = false;
>      return CheckConstantExpression(Info, E->getExprLoc(), E->getType(), Result,
> -                                   ConstantExprKind::Normal);
> +                                   ConstantExprKind::Normal, Dependent);
>    };
>    return EvaluateComparisonBinaryOperator(Info, E, OnSuccess, [&]() {
>      return ExprEvaluatorBaseTy::VisitBinCmp(E);
> @@ -14594,7 +14611,8 @@ static bool EvaluateInPlace(APValue &Result, EvalInfo &Info, const LValue &This,
>
>  /// EvaluateAsRValue - Try to evaluate this expression, performing an implicit
>  /// lvalue-to-rvalue cast if it is an lvalue.
> -static bool EvaluateAsRValue(EvalInfo &Info, const Expr *E, APValue &Result) {
> +static bool EvaluateAsRValue(EvalInfo &Info, const Expr *E, APValue &Result,
> +                             bool &Dependent) {
>    assert(!E->isValueDependent());
>    if (Info.EnableNewConstInterp) {
>      if (!Info.Ctx.getInterpContext().evaluateAsRValue(Info, E, Result))
> @@ -14619,7 +14637,7 @@ static bool EvaluateAsRValue(EvalInfo &Info, const Expr *E, APValue &Result) {
>
>    // Check this core constant expression is a constant expression.
>    return CheckConstantExpression(Info, E->getExprLoc(), E->getType(), Result,
> -                                 ConstantExprKind::Normal) &&
> +                                 ConstantExprKind::Normal, Dependent) &&
>           CheckMemoryLeaks(Info);
>  }
>
> @@ -14665,7 +14683,7 @@ static bool EvaluateAsRValue(const Expr *E, Expr::EvalResult &Result,
>    if (FastEvaluateAsRValue(E, Result, Ctx, IsConst))
>      return IsConst;
>
> -  return EvaluateAsRValue(Info, E, Result.Val);
> +  return EvaluateAsRValue(Info, E, Result.Val, Result.Dependent);
>  }
>
>  static bool EvaluateAsInt(const Expr *E, Expr::EvalResult &ExprResult,
> @@ -14775,9 +14793,9 @@ bool Expr::EvaluateAsLValue(EvalResult &Result, const ASTContext &Ctx,
>    CheckedTemporaries CheckedTemps;
>    if (!EvaluateLValue(this, LV, Info) || !Info.discardCleanups() ||
>        Result.HasSideEffects ||
> -      !CheckLValueConstantExpression(Info, getExprLoc(),
> -                                     Ctx.getLValueReferenceType(getType()), LV,
> -                                     ConstantExprKind::Normal, CheckedTemps))
> +      !CheckLValueConstantExpression(
> +          Info, getExprLoc(), Ctx.getLValueReferenceType(getType()), LV,
> +          ConstantExprKind::Normal, CheckedTemps, Result.Dependent))
>      return false;
>
>    LV.moveInto(Result.Val);
> @@ -14836,7 +14854,7 @@ bool Expr::EvaluateAsConstantExpr(EvalResult &Result, const ASTContext &Ctx,
>      llvm_unreachable("Unhandled cleanup; missing full expression marker?");
>
>    if (!CheckConstantExpression(Info, getExprLoc(), getStorageType(Ctx, this),
> -                               Result.Val, Kind))
> +                               Result.Val, Kind, Result.Dependent))
>      return false;
>    if (!CheckMemoryLeaks(Info))
>      return false;
> @@ -14900,8 +14918,9 @@ bool Expr::EvaluateAsInitializer(APValue &Value, const ASTContext &Ctx,
>      if (!Info.discardCleanups())
>        llvm_unreachable("Unhandled cleanup; missing full expression marker?");
>    }
> +  bool Dependent = false;
>    return CheckConstantExpression(Info, DeclLoc, DeclTy, Value,
> -                                 ConstantExprKind::Normal) &&
> +                                 ConstantExprKind::Normal, Dependent) &&
>           CheckMemoryLeaks(Info);
>  }
>
> @@ -14968,7 +14987,7 @@ APSInt Expr::EvaluateKnownConstIntCheckOverflow(
>    Info.InConstantContext = true;
>    Info.CheckingForUndefinedBehavior = true;
>
> -  bool Result = ::EvaluateAsRValue(Info, this, EVResult.Val);
> +  bool Result = ::EvaluateAsRValue(this, EVResult, Ctx, Info);
>    (void)Result;
>    assert(Result && "Could not evaluate expression");
>    assert(EVResult.Val.isInt() && "Expression did not evaluate to integer");
> @@ -14980,13 +14999,10 @@ void Expr::EvaluateForOverflow(const ASTContext &Ctx) const {
>    assert(!isValueDependent() &&
>           "Expression evaluator can't be called on a dependent expression.");
>
> -  bool IsConst;
>    EvalResult EVResult;
> -  if (!FastEvaluateAsRValue(this, EVResult, Ctx, IsConst)) {
> -    EvalInfo Info(Ctx, EVResult, EvalInfo::EM_IgnoreSideEffects);
> -    Info.CheckingForUndefinedBehavior = true;
> -    (void)::EvaluateAsRValue(Info, this, EVResult.Val);
> -  }
> +  EvalInfo Info(Ctx, EVResult, EvalInfo::EM_IgnoreSideEffects);
> +  Info.CheckingForUndefinedBehavior = true;
> +  (void)::EvaluateAsRValue(this, EVResult, Ctx, Info);
>  }
>
>  bool Expr::EvalResult::isGlobalLValue() const {
> @@ -15536,8 +15552,9 @@ bool Expr::isCXX11ConstantExpr(const ASTContext &Ctx, APValue *Result,
>    EvalInfo Info(Ctx, Status, EvalInfo::EM_ConstantExpression);
>
>    APValue Scratch;
> +  bool Dependent = false;
>    bool IsConstExpr =
> -      ::EvaluateAsRValue(Info, this, Result ? *Result : Scratch) &&
> +      ::EvaluateAsRValue(Info, this, Result ? *Result : Scratch, Dependent) &&
>        // FIXME: We don't produce a diagnostic for this, but the callers that
>        // call us on arbitrary full-expressions should generally not care.
>        Info.discardCleanups() && !Status.HasSideEffects;
>
> diff  --git a/clang/lib/AST/TemplateBase.cpp b/clang/lib/AST/TemplateBase.cpp
> index baf62bd115a8..8cbb595b5bd1 100644
> --- a/clang/lib/AST/TemplateBase.cpp
> +++ b/clang/lib/AST/TemplateBase.cpp
> @@ -131,25 +131,17 @@ TemplateArgumentDependence TemplateArgument::getDependence() const {
>      return TemplateArgumentDependence::Dependent |
>             TemplateArgumentDependence::Instantiation;
>
> -  case Declaration: {
> -    auto *DC = dyn_cast<DeclContext>(getAsDecl());
> -    if (!DC)
> -      DC = getAsDecl()->getDeclContext();
> -    if (DC->isDependentContext())
> -      Deps = TemplateArgumentDependence::Dependent |
> -             TemplateArgumentDependence::Instantiation;
> -    return Deps;
> -  }
> -
>    case NullPtr:
>    case Integral:
> +  case Declaration:
>      return TemplateArgumentDependence::None;
>
>    case Expression:
>      Deps = toTemplateArgumentDependence(getAsExpr()->getDependence());
> -    if (isa<PackExpansionExpr>(getAsExpr()))
> -      Deps |= TemplateArgumentDependence::Dependent |
> -              TemplateArgumentDependence::Instantiation;
> +    // Instantiation-dependent expression arguments are considered dependent
> +    // until they're resolved to another form.
> +    if (Deps & TemplateArgumentDependence::Instantiation)
> +      Deps |= TemplateArgumentDependence::Dependent;
>      return Deps;
>
>    case Pack:
> @@ -544,8 +536,8 @@ ASTTemplateArgumentListInfo::ASTTemplateArgumentListInfo(
>    NumTemplateArgs = Info.size();
>
>    TemplateArgumentLoc *ArgBuffer = getTrailingObjects<TemplateArgumentLoc>();
> -  for (unsigned i = 0; i != NumTemplateArgs; ++i)
> -    new (&ArgBuffer[i]) TemplateArgumentLoc(Info[i]);
> +  std::uninitialized_copy(Info.arguments().begin(), Info.arguments().end(),
> +                          ArgBuffer);
>  }
>
>  void ASTTemplateKWAndArgsInfo::initializeFrom(
> @@ -555,9 +547,8 @@ void ASTTemplateKWAndArgsInfo::initializeFrom(
>    LAngleLoc = Info.getLAngleLoc();
>    RAngleLoc = Info.getRAngleLoc();
>    NumTemplateArgs = Info.size();
> -
> -  for (unsigned i = 0; i != NumTemplateArgs; ++i)
> -    new (&OutArgArray[i]) TemplateArgumentLoc(Info[i]);
> +  std::uninitialized_copy(Info.arguments().begin(), Info.arguments().end(),
> +                          OutArgArray);
>  }
>
>  void ASTTemplateKWAndArgsInfo::initializeFrom(SourceLocation TemplateKWLoc) {
> @@ -568,21 +559,6 @@ void ASTTemplateKWAndArgsInfo::initializeFrom(SourceLocation TemplateKWLoc) {
>    NumTemplateArgs = 0;
>  }
>
> -void ASTTemplateKWAndArgsInfo::initializeFrom(
> -    SourceLocation TemplateKWLoc, const TemplateArgumentListInfo &Info,
> -    TemplateArgumentLoc *OutArgArray, TemplateArgumentDependence &Deps) {
> -  this->TemplateKWLoc = TemplateKWLoc;
> -  LAngleLoc = Info.getLAngleLoc();
> -  RAngleLoc = Info.getRAngleLoc();
> -  NumTemplateArgs = Info.size();
> -
> -  for (unsigned i = 0; i != NumTemplateArgs; ++i) {
> -    Deps |= Info[i].getArgument().getDependence();
> -
> -    new (&OutArgArray[i]) TemplateArgumentLoc(Info[i]);
> -  }
> -}
> -
>  void ASTTemplateKWAndArgsInfo::copyInto(const TemplateArgumentLoc *ArgArray,
>                                          TemplateArgumentListInfo &Info) const {
>    Info.setLAngleLoc(LAngleLoc);
>
> diff  --git a/clang/lib/Sema/SemaOverload.cpp b/clang/lib/Sema/SemaOverload.cpp
> index 13d2125d1a28..ac52612ea3b0 100644
> --- a/clang/lib/Sema/SemaOverload.cpp
> +++ b/clang/lib/Sema/SemaOverload.cpp
> @@ -5619,7 +5619,8 @@ static ExprResult CheckConvertedConstantExpression(Sema &S, Expr *From,
>                                                     QualType T, APValue &Value,
>                                                     Sema::CCEKind CCE,
>                                                     bool RequireInt,
> -                                                   NamedDecl *Dest) {
> +                                                   NamedDecl *Dest,
> +                                                   bool *ValueDependent) {
>    assert(S.getLangOpts().CPlusPlus11 &&
>           "converted constant expression outside C++11");
>
> @@ -5743,6 +5744,8 @@ static ExprResult CheckConvertedConstantExpression(Sema &S, Expr *From,
>
>    if (Result.get()->isValueDependent()) {
>      Value = APValue();
> +    if (ValueDependent)
> +      *ValueDependent = true;
>      return Result;
>    }
>
> @@ -5766,6 +5769,8 @@ static ExprResult CheckConvertedConstantExpression(Sema &S, Expr *From,
>      Result = ExprError();
>    } else {
>      Value = Eval.Val;
> +    if (ValueDependent)
> +      *ValueDependent = Eval.Dependent;
>
>      if (Notes.empty()) {
>        // It's a constant expression.
> @@ -5796,9 +5801,10 @@ static ExprResult CheckConvertedConstantExpression(Sema &S, Expr *From,
>
>  ExprResult Sema::CheckConvertedConstantExpression(Expr *From, QualType T,
>                                                    APValue &Value, CCEKind CCE,
> -                                                  NamedDecl *Dest) {
> +                                                  NamedDecl *Dest,
> +                                                  bool *ValueDependent) {
>    return ::CheckConvertedConstantExpression(*this, From, T, Value, CCE, false,
> -                                            Dest);
> +                                            Dest, ValueDependent);
>  }
>
>  ExprResult Sema::CheckConvertedConstantExpression(Expr *From, QualType T,
> @@ -5808,7 +5814,8 @@ ExprResult Sema::CheckConvertedConstantExpression(Expr *From, QualType T,
>
>    APValue V;
>    auto R = ::CheckConvertedConstantExpression(*this, From, T, V, CCE, true,
> -                                              /*Dest=*/nullptr);
> +                                              /*Dest=*/nullptr,
> +                                              /*ValueDependent=*/nullptr);
>    if (!R.isInvalid() && !R.get()->isValueDependent())
>      Value = V.getInt();
>    return R;
>
> diff  --git a/clang/lib/Sema/SemaTemplate.cpp b/clang/lib/Sema/SemaTemplate.cpp
> index 12880b95b9c6..9f314685faf0 100644
> --- a/clang/lib/Sema/SemaTemplate.cpp
> +++ b/clang/lib/Sema/SemaTemplate.cpp
> @@ -6620,6 +6620,12 @@ CheckTemplateArgumentAddressOfObjectOrFunction(Sema &S,
>                                                       Arg, ArgType))
>      return true;
>
> +  // Don't build a resolved template argument naming a dependent declaration.
> +  if (Entity->isTemplated()) {
> +    Converted = TemplateArgument(ArgIn);
> +    return false;
> +  }
> +
>    // Create the template argument.
>    Converted = TemplateArgument(cast<ValueDecl>(Entity->getCanonicalDecl()),
>                                 S.Context.getCanonicalType(ParamType));
> @@ -6634,8 +6640,6 @@ static bool CheckTemplateArgumentPointerToMember(Sema &S,
>                                                   QualType ParamType,
>                                                   Expr *&ResultArg,
>                                                   TemplateArgument &Converted) {
> -  bool Invalid = false;
> -
>    Expr *Arg = ResultArg;
>    bool ObjCLifetimeConversion;
>
> @@ -6651,7 +6655,7 @@ static bool CheckTemplateArgumentPointerToMember(Sema &S,
>    // See http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_defects.html#773
>    bool ExtraParens = false;
>    while (ParenExpr *Parens = dyn_cast<ParenExpr>(Arg)) {
> -    if (!Invalid && !ExtraParens) {
> +    if (!ExtraParens) {
>        S.Diag(Arg->getBeginLoc(),
>               S.getLangOpts().CPlusPlus11
>                   ? diag::warn_cxx98_compat_template_arg_extra_parens
> @@ -6680,13 +6684,8 @@ static bool CheckTemplateArgumentPointerToMember(Sema &S,
>      ValueDecl *VD = DRE->getDecl();
>      if (VD->getType()->isMemberPointerType()) {
>        if (isa<NonTypeTemplateParmDecl>(VD)) {
> -        if (Arg->isTypeDependent() || Arg->isValueDependent()) {
> -          Converted = TemplateArgument(Arg);
> -        } else {
> -          VD = cast<ValueDecl>(VD->getCanonicalDecl());
> -          Converted = TemplateArgument(VD, ParamType);
> -        }
> -        return Invalid;
> +        Converted = TemplateArgument(Arg);
> +        return false;
>        }
>      }
>
> @@ -6745,7 +6744,7 @@ static bool CheckTemplateArgumentPointerToMember(Sema &S,
>        ValueDecl *D = cast<ValueDecl>(DRE->getDecl()->getCanonicalDecl());
>        Converted = TemplateArgument(D, S.Context.getCanonicalType(ParamType));
>      }
> -    return Invalid;
> +    return false;
>    }
>
>    // We found something else, but we don't know specifically what it is.
> @@ -6922,14 +6921,17 @@ ExprResult Sema::CheckTemplateArgument(NonTypeTemplateParmDecl *Param,
>      //   A template-argument for a non-type template parameter shall be
>      //   a converted constant expression of the type of the template-parameter.
>      APValue Value;
> +    bool ValueDependent = false;
>      ExprResult ArgResult = CheckConvertedConstantExpression(
> -        Arg, ParamType, Value, CCEK_TemplateArg, Param);
> +        Arg, ParamType, Value, CCEK_TemplateArg, Param, &ValueDependent);
>      if (ArgResult.isInvalid())
>        return ExprError();
>
>      // For a value-dependent argument, CheckConvertedConstantExpression is
> -    // permitted (and expected) to be unable to determine a value.
> -    if (ArgResult.get()->isValueDependent()) {
> +    // permitted (and expected) to be unable to determine a value. We might find
> +    // the evaluated result refers to a dependent declaration even though the
> +    // template argument is not a value-dependent expression.
> +    if (ValueDependent) {
>        Converted = TemplateArgument(ArgResult.get());
>        return ArgResult;
>      }
>
> diff  --git a/clang/lib/Sema/SemaTemplateInstantiate.cpp b/clang/lib/Sema/SemaTemplateInstantiate.cpp
> index 7e0cc2da2f58..49ff7cd33fab 100644
> --- a/clang/lib/Sema/SemaTemplateInstantiate.cpp
> +++ b/clang/lib/Sema/SemaTemplateInstantiate.cpp
> @@ -3227,7 +3227,8 @@ Sema::InstantiateClassMembers(SourceLocation PointOfInstantiation,
>        if (FunctionDecl *Pattern =
>                Function->getInstantiatedFromMemberFunction()) {
>
> -        if (Function->hasAttr<ExcludeFromExplicitInstantiationAttr>())
> +        if (TSK != TSK_ImplicitInstantiation &&
> +            Function->hasAttr<ExcludeFromExplicitInstantiationAttr>())
>            continue;
>
>          MemberSpecializationInfo *MSInfo =
> @@ -3272,7 +3273,8 @@ Sema::InstantiateClassMembers(SourceLocation PointOfInstantiation,
>          continue;
>
>        if (Var->isStaticDataMember()) {
> -        if (Var->hasAttr<ExcludeFromExplicitInstantiationAttr>())
> +        if (TSK != TSK_ImplicitInstantiation &&
> +            Var->hasAttr<ExcludeFromExplicitInstantiationAttr>())
>            continue;
>
>          MemberSpecializationInfo *MSInfo = Var->getMemberSpecializationInfo();
> @@ -3289,7 +3291,7 @@ Sema::InstantiateClassMembers(SourceLocation PointOfInstantiation,
>              SuppressNew)
>            continue;
>
> -        if (TSK == TSK_ExplicitInstantiationDefinition) {
> +        if (TSK != TSK_ExplicitInstantiationDeclaration) {
>            // C++0x [temp.explicit]p8:
>            //   An explicit instantiation definition that names a class template
>            //   specialization explicitly instantiates the class template
>
> diff  --git a/clang/test/OpenMP/distribute_dist_schedule_messages.cpp b/clang/test/OpenMP/distribute_dist_schedule_messages.cpp
> index cd232f40feb4..0f7b2172f5a5 100644
> --- a/clang/test/OpenMP/distribute_dist_schedule_messages.cpp
> +++ b/clang/test/OpenMP/distribute_dist_schedule_messages.cpp
> @@ -35,7 +35,7 @@ T tmain(T argc) {
>    for (int i = 0; i < 10; ++i) foo();
>    #pragma omp distribute dist_schedule (static, S1) // expected-error {{'S1' does not refer to a value}}
>    for (int i = 0; i < 10; ++i) foo();
> -  #pragma omp distribute dist_schedule (static, argv[1]=2) // expected-error {{expected ')'}} expected-note {{to match this '('}} expected-error3 {{expression must have integral or unscoped enumeration type, not 'char *'}}
> +  #pragma omp distribute dist_schedule (static, argv[1]=2) // expected-error {{expected ')'}} expected-note {{to match this '('}} expected-error 2{{expression must have integral or unscoped enumeration type, not 'char *'}}
>    for (int i = 0; i < 10; ++i) foo();
>    return T();
>  }
>
> diff  --git a/clang/test/OpenMP/distribute_parallel_for_dist_schedule_messages.cpp b/clang/test/OpenMP/distribute_parallel_for_dist_schedule_messages.cpp
> index 07e7704dffde..18dcac555f74 100644
> --- a/clang/test/OpenMP/distribute_parallel_for_dist_schedule_messages.cpp
> +++ b/clang/test/OpenMP/distribute_parallel_for_dist_schedule_messages.cpp
> @@ -54,7 +54,7 @@ T tmain(T argc) {
>    for (int i = 0; i < 10; ++i) foo();
>  #pragma omp target
>  #pragma omp teams
> -#pragma omp distribute parallel for dist_schedule (static, argv[1]=2) // expected-error {{expected ')'}} expected-note {{to match this '('}} expected-error3 {{expression must have integral or unscoped enumeration type, not 'char *'}}
> +#pragma omp distribute parallel for dist_schedule (static, argv[1]=2) // expected-error {{expected ')'}} expected-note {{to match this '('}} expected-error 2{{expression must have integral or unscoped enumeration type, not 'char *'}}
>    for (int i = 0; i < 10; ++i) foo();
>    return T();
>  }
>
> diff  --git a/clang/test/OpenMP/distribute_parallel_for_simd_dist_schedule_messages.cpp b/clang/test/OpenMP/distribute_parallel_for_simd_dist_schedule_messages.cpp
> index ed7b19111dee..63f8cfe917cd 100644
> --- a/clang/test/OpenMP/distribute_parallel_for_simd_dist_schedule_messages.cpp
> +++ b/clang/test/OpenMP/distribute_parallel_for_simd_dist_schedule_messages.cpp
> @@ -55,7 +55,7 @@ T tmain(T argc) {
>    for (int i = 0; i < 10; ++i) foo();
>  #pragma omp target
>  #pragma omp teams
> -#pragma omp distribute parallel for simd dist_schedule (static, argv[1]=2) // expected-error {{expected ')'}} expected-note {{to match this '('}} expected-error3 {{expression must have integral or unscoped enumeration type, not 'char *'}}
> +#pragma omp distribute parallel for simd dist_schedule (static, argv[1]=2) // expected-error {{expected ')'}} expected-note {{to match this '('}} expected-error 2{{expression must have integral or unscoped enumeration type, not 'char *'}}
>    for (int i = 0; i < 10; ++i) foo();
>    return T();
>  }
>
> diff  --git a/clang/test/OpenMP/distribute_simd_dist_schedule_messages.cpp b/clang/test/OpenMP/distribute_simd_dist_schedule_messages.cpp
> index 794681c02646..a6593cfbe0d3 100644
> --- a/clang/test/OpenMP/distribute_simd_dist_schedule_messages.cpp
> +++ b/clang/test/OpenMP/distribute_simd_dist_schedule_messages.cpp
> @@ -63,7 +63,7 @@ T tmain(T argc) {
>    for (int i = 0; i < 10; ++i) foo();
>  #pragma omp target
>  #pragma omp teams
> -#pragma omp distribute simd dist_schedule (static, argv[1]=2) // expected-error {{expected ')'}} expected-note {{to match this '('}} expected-error3 {{expression must have integral or unscoped enumeration type, not 'char *'}}
> +#pragma omp distribute simd dist_schedule (static, argv[1]=2) // expected-error {{expected ')'}} expected-note {{to match this '('}} expected-error 2{{expression must have integral or unscoped enumeration type, not 'char *'}}
>    for (int i = 0; i < 10; ++i) foo();
>    return T();
>  }
>
> diff  --git a/clang/test/OpenMP/target_parallel_for_simd_collapse_messages.cpp b/clang/test/OpenMP/target_parallel_for_simd_collapse_messages.cpp
> index 7acb2587f976..f829874864da 100644
> --- a/clang/test/OpenMP/target_parallel_for_simd_collapse_messages.cpp
> +++ b/clang/test/OpenMP/target_parallel_for_simd_collapse_messages.cpp
> @@ -46,7 +46,7 @@ T tmain(T argc, S **argv) {
>    #pragma omp target parallel for simd collapse (S) // expected-error {{'S' does not refer to a value}}
>    for (int i = ST; i < N; i++) argv[0][i] = argv[0][i] - argv[0][i-ST];
>
> -  // expected-error at +1 {{integral constant expression}} expected-note at +1 0+{{constant expression}}
> +  // expected-error at +1 1+{{integral constant expression}} expected-note at +1 0+{{constant expression}}
>    #pragma omp target parallel for simd collapse (j=2) // expected-error {{expected ')'}} expected-note {{to match this '('}}
>    for (int i = ST; i < N; i++) argv[0][i] = argv[0][i] - argv[0][i-ST];
>    #pragma omp target parallel for simd collapse (1)
>
> diff  --git a/clang/test/OpenMP/target_parallel_for_simd_ordered_messages.cpp b/clang/test/OpenMP/target_parallel_for_simd_ordered_messages.cpp
> index 8dd7f68c25fd..972aa5753e36 100644
> --- a/clang/test/OpenMP/target_parallel_for_simd_ordered_messages.cpp
> +++ b/clang/test/OpenMP/target_parallel_for_simd_ordered_messages.cpp
> @@ -56,7 +56,7 @@ T tmain(T argc, S **argv) {
>    for (int i = ST; i < N; i++)
>      argv[0][i] = argv[0][i] - argv[0][i - ST];
>
> -// expected-error at +1 {{integral constant expression}} expected-note at +1 0+{{constant expression}}
> +// expected-error at +1 {{'ordered' clause with a parameter can not be specified in '#pragma omp target parallel for simd' directive}}
>  #pragma omp target parallel for simd ordered(j = 2) // expected-error {{expected ')'}} expected-note {{to match this '('}}
>    for (int i = ST; i < N; i++)
>      argv[0][i] = argv[0][i] - argv[0][i - ST];
>
> diff  --git a/clang/test/OpenMP/target_simd_collapse_messages.cpp b/clang/test/OpenMP/target_simd_collapse_messages.cpp
> index 00fa3c85279f..d8b0a91f97d7 100644
> --- a/clang/test/OpenMP/target_simd_collapse_messages.cpp
> +++ b/clang/test/OpenMP/target_simd_collapse_messages.cpp
> @@ -44,7 +44,7 @@ T tmain(T argc, S **argv) {
>    #pragma omp target simd collapse (S) // expected-error {{'S' does not refer to a value}}
>    for (int i = ST; i < N; i++) argv[0][i] = argv[0][i] - argv[0][i-ST];
>
> -  // expected-error at +1 {{integral constant expression}} expected-note at +1 0+{{constant expression}}
> +  // expected-error at +1 1+{{integral constant expression}} expected-note at +1 0+{{constant expression}}
>    #pragma omp target simd collapse (j=2) // expected-error {{expected ')'}} expected-note {{to match this '('}}
>    for (int i = ST; i < N; i++) argv[0][i] = argv[0][i] - argv[0][i-ST];
>    #pragma omp target simd collapse (1)
>
> diff  --git a/clang/test/OpenMP/target_teams_distribute_dist_schedule_messages.cpp b/clang/test/OpenMP/target_teams_distribute_dist_schedule_messages.cpp
> index 69c1e55eeaa3..e31df97ba31c 100644
> --- a/clang/test/OpenMP/target_teams_distribute_dist_schedule_messages.cpp
> +++ b/clang/test/OpenMP/target_teams_distribute_dist_schedule_messages.cpp
> @@ -45,7 +45,7 @@ T tmain(T argc) {
>  #pragma omp target teams distribute dist_schedule (static, S1) // expected-error {{'S1' does not refer to a value}}
>    for (int i = 0; i < 10; ++i) foo();
>
> -#pragma omp target teams distribute dist_schedule (static, argv[1]=2) // expected-error {{expected ')'}} expected-note {{to match this '('}} expected-error3 {{expression must have integral or unscoped enumeration type, not 'char *'}}
> +#pragma omp target teams distribute dist_schedule (static, argv[1]=2) // expected-error {{expected ')'}} expected-note {{to match this '('}} expected-error 2{{expression must have integral or unscoped enumeration type, not 'char *'}}
>    for (int i = 0; i < 10; ++i) foo();
>
>    return T();
>
> diff  --git a/clang/test/OpenMP/target_teams_distribute_parallel_for_dist_schedule_messages.cpp b/clang/test/OpenMP/target_teams_distribute_parallel_for_dist_schedule_messages.cpp
> index a0efad18668e..4f3c58125446 100644
> --- a/clang/test/OpenMP/target_teams_distribute_parallel_for_dist_schedule_messages.cpp
> +++ b/clang/test/OpenMP/target_teams_distribute_parallel_for_dist_schedule_messages.cpp
> @@ -45,7 +45,7 @@ T tmain(T argc) {
>  #pragma omp target teams distribute parallel for dist_schedule (static, S1) // expected-error {{'S1' does not refer to a value}}
>    for (int i = 0; i < 10; ++i) foo();
>
> -#pragma omp target teams distribute parallel for dist_schedule (static, argv[1]=2) // expected-error {{expected ')'}} expected-note {{to match this '('}} expected-error3 {{expression must have integral or unscoped enumeration type, not 'char *'}}
> +#pragma omp target teams distribute parallel for dist_schedule (static, argv[1]=2) // expected-error {{expected ')'}} expected-note {{to match this '('}} expected-error 2{{expression must have integral or unscoped enumeration type, not 'char *'}}
>    for (int i = 0; i < 10; ++i) foo();
>
>    return T();
>
> diff  --git a/clang/test/OpenMP/target_teams_distribute_parallel_for_simd_dist_schedule_messages.cpp b/clang/test/OpenMP/target_teams_distribute_parallel_for_simd_dist_schedule_messages.cpp
> index ec634c8ac01c..8b272d4358f6 100644
> --- a/clang/test/OpenMP/target_teams_distribute_parallel_for_simd_dist_schedule_messages.cpp
> +++ b/clang/test/OpenMP/target_teams_distribute_parallel_for_simd_dist_schedule_messages.cpp
> @@ -45,7 +45,7 @@ T tmain(T argc) {
>  #pragma omp target teams distribute parallel for simd dist_schedule (static, S1) // expected-error {{'S1' does not refer to a value}}
>    for (int i = 0; i < 10; ++i) foo();
>
> -#pragma omp target teams distribute parallel for simd dist_schedule (static, argv[1]=2) // expected-error {{expected ')'}} expected-note {{to match this '('}} expected-error3 {{expression must have integral or unscoped enumeration type, not 'char *'}}
> +#pragma omp target teams distribute parallel for simd dist_schedule (static, argv[1]=2) // expected-error {{expected ')'}} expected-note {{to match this '('}} expected-error 2{{expression must have integral or unscoped enumeration type, not 'char *'}}
>    for (int i = 0; i < 10; ++i) foo();
>
>    return T();
>
> diff  --git a/clang/test/OpenMP/target_teams_distribute_simd_dist_schedule_messages.cpp b/clang/test/OpenMP/target_teams_distribute_simd_dist_schedule_messages.cpp
> index 507ddabd2fc2..b583c14831e7 100644
> --- a/clang/test/OpenMP/target_teams_distribute_simd_dist_schedule_messages.cpp
> +++ b/clang/test/OpenMP/target_teams_distribute_simd_dist_schedule_messages.cpp
> @@ -45,7 +45,7 @@ T tmain(T argc) {
>  #pragma omp target teams distribute simd dist_schedule (static, S1) // expected-error {{'S1' does not refer to a value}}
>    for (int i = 0; i < 10; ++i) foo();
>
> -#pragma omp target teams distribute simd dist_schedule (static, argv[1]=2) // expected-error {{expected ')'}} expected-note {{to match this '('}} expected-error3 {{expression must have integral or unscoped enumeration type, not 'char *'}}
> +#pragma omp target teams distribute simd dist_schedule (static, argv[1]=2) // expected-error {{expected ')'}} expected-note {{to match this '('}} expected-error 2{{expression must have integral or unscoped enumeration type, not 'char *'}}
>    for (int i = 0; i < 10; ++i) foo();
>
>    return T();
>
> diff  --git a/clang/test/OpenMP/target_update_from_messages.cpp b/clang/test/OpenMP/target_update_from_messages.cpp
> index 3dc377c4ca4c..42ecc2814e12 100644
> --- a/clang/test/OpenMP/target_update_from_messages.cpp
> +++ b/clang/test/OpenMP/target_update_from_messages.cpp
> @@ -131,7 +131,7 @@ T tmain(T argc) {
>  #pragma omp target update from(x, s7.s6[:5].aa[6]) // expected-error {{OpenMP array section is not allowed here}}
>  #pragma omp target update from(x, s7.s6[:5].aa[:6]) // expected-error {{OpenMP array section is not allowed here}}
>  #pragma omp target update from(s7.p[:10])
> -#pragma omp target update from(x, s7.bfa) // expected-error {{bit fields cannot be used to specify storage in a 'from' clause}}
> +#pragma omp target update from(x, s7.bfa) // expected-error 2{{bit fields cannot be used to specify storage in a 'from' clause}}
>  #pragma omp target update from(x, s7.p[:]) // expected-error {{section length is unspecified and cannot be inferred because subscripted value is not an array}}
>  #pragma omp target data map(to: s7.i)
>    {
>
> diff  --git a/clang/test/OpenMP/target_update_to_messages.cpp b/clang/test/OpenMP/target_update_to_messages.cpp
> index fca4e21304fc..941c781119e6 100644
> --- a/clang/test/OpenMP/target_update_to_messages.cpp
> +++ b/clang/test/OpenMP/target_update_to_messages.cpp
> @@ -138,7 +138,7 @@ T tmain(T argc) {
>  #pragma omp target update to(x, s7.s6[:5].aa[6]) // expected-error {{OpenMP array section is not allowed here}}
>  #pragma omp target update to(x, s7.s6[:5].aa[:6]) // expected-error {{OpenMP array section is not allowed here}}
>  #pragma omp target update to(s7.p[:10])
> -#pragma omp target update to(x, s7.bfa) // expected-error {{bit fields cannot be used to specify storage in a 'to' clause}}
> +#pragma omp target update to(x, s7.bfa) // expected-error 2{{bit fields cannot be used to specify storage in a 'to' clause}}
>  #pragma omp target update to(x, s7.p[:]) // expected-error {{section length is unspecified and cannot be inferred because subscripted value is not an array}}
>  #pragma omp target data map(to: s7.i)
>    {
>
> diff  --git a/clang/test/OpenMP/task_messages.cpp b/clang/test/OpenMP/task_messages.cpp
> index 13cbfb6c4569..2f9ee9a44402 100644
> --- a/clang/test/OpenMP/task_messages.cpp
> +++ b/clang/test/OpenMP/task_messages.cpp
> @@ -156,11 +156,11 @@ int foo() {
>  #pragma omp task detach(a) // omp45-error {{unexpected OpenMP clause 'detach' in directive '#pragma omp task'}} omp50-error {{expected variable of the 'omp_event_handle_t' type, not 'int'}} omp50-error {{expected variable of the 'omp_event_handle_t' type, not 'S'}}
>    ;
>  #pragma omp task detach(evt) detach(evt) // omp45-error 2 {{unexpected OpenMP clause 'detach' in directive '#pragma omp task'}} expected-error {{directive '#pragma omp task' cannot contain more than one 'detach' clause}}
> -#pragma omp task detach(cevt) detach(revt) // omp45-error 2 {{unexpected OpenMP clause 'detach' in directive '#pragma omp task'}} expected-error {{directive '#pragma omp task' cannot contain more than one 'detach' clause}} omp50-error {{expected variable of the 'omp_event_handle_t' type, not 'const omp_event_handle_t' (aka 'const unsigned long')}} omp50-error {{expected variable of the 'omp_event_handle_t' type, not 'omp_event_handle_t &' (aka 'unsigned long &')}}
> +#pragma omp task detach(cevt) detach(revt) // omp45-error 2 {{unexpected OpenMP clause 'detach' in directive '#pragma omp task'}} expected-error {{directive '#pragma omp task' cannot contain more than one 'detach' clause}}
>  #pragma omp task detach(evt) mergeable // omp45-error {{unexpected OpenMP clause 'detach' in directive '#pragma omp task'}} omp50-error {{'mergeable' and 'detach' clause are mutually exclusive and may not appear on the same directive}} omp50-note {{'detach' clause is specified here}}
>    ;
>  #pragma omp task mergeable detach(evt) // omp45-error {{unexpected OpenMP clause 'detach' in directive '#pragma omp task'}} omp50-error {{'detach' and 'mergeable' clause are mutually exclusive and may not appear on the same directive}} omp50-note {{'mergeable' clause is specified here}}
> -#pragma omp task detach(-evt) // omp45-error {{unexpected OpenMP clause 'detach' in directive '#pragma omp task'}} omp50-error {{expected variable of the 'omp_event_handle_t' type}}
> +#pragma omp task detach(-evt) // omp45-error {{unexpected OpenMP clause 'detach' in directive '#pragma omp task'}}
>    ;
>  #pragma omp task detach(evt) shared(evt) // omp45-error {{unexpected OpenMP clause 'detach' in directive '#pragma omp task'}}
>  #pragma omp task detach(evt) firstprivate(evt) // omp45-error {{unexpected OpenMP clause 'detach' in directive '#pragma omp task'}}
>
> diff  --git a/clang/test/OpenMP/teams_distribute_dist_schedule_messages.cpp b/clang/test/OpenMP/teams_distribute_dist_schedule_messages.cpp
> index 22d2408d3f17..bd1aaa5c6289 100644
> --- a/clang/test/OpenMP/teams_distribute_dist_schedule_messages.cpp
> +++ b/clang/test/OpenMP/teams_distribute_dist_schedule_messages.cpp
> @@ -55,7 +55,7 @@ T tmain(T argc) {
>    for (int i = 0; i < 10; ++i) foo();
>
>  #pragma omp target
> -#pragma omp teams distribute dist_schedule (static, argv[1]=2) // expected-error {{expected ')'}} expected-note {{to match this '('}} expected-error3 {{expression must have integral or unscoped enumeration type, not 'char *'}}
> +#pragma omp teams distribute dist_schedule (static, argv[1]=2) // expected-error {{expected ')'}} expected-note {{to match this '('}} expected-error 2{{expression must have integral or unscoped enumeration type, not 'char *'}}
>    for (int i = 0; i < 10; ++i) foo();
>
>    return T();
>
> diff  --git a/clang/test/OpenMP/teams_distribute_parallel_for_dist_schedule_messages.cpp b/clang/test/OpenMP/teams_distribute_parallel_for_dist_schedule_messages.cpp
> index 27ff4125daf7..a70d80ad1251 100644
> --- a/clang/test/OpenMP/teams_distribute_parallel_for_dist_schedule_messages.cpp
> +++ b/clang/test/OpenMP/teams_distribute_parallel_for_dist_schedule_messages.cpp
> @@ -55,7 +55,7 @@ T tmain(T argc) {
>    for (int i = 0; i < 10; ++i) foo();
>
>  #pragma omp target
> -#pragma omp teams distribute parallel for dist_schedule (static, argv[1]=2) // expected-error {{expected ')'}} expected-note {{to match this '('}} expected-error3 {{expression must have integral or unscoped enumeration type, not 'char *'}}
> +#pragma omp teams distribute parallel for dist_schedule (static, argv[1]=2) // expected-error {{expected ')'}} expected-note {{to match this '('}} expected-error 2{{expression must have integral or unscoped enumeration type, not 'char *'}}
>    for (int i = 0; i < 10; ++i) foo();
>
>    return T();
>
> diff  --git a/clang/test/OpenMP/teams_distribute_parallel_for_simd_dist_schedule_messages.cpp b/clang/test/OpenMP/teams_distribute_parallel_for_simd_dist_schedule_messages.cpp
> index cbd4ec4ce979..b87301fa98d8 100644
> --- a/clang/test/OpenMP/teams_distribute_parallel_for_simd_dist_schedule_messages.cpp
> +++ b/clang/test/OpenMP/teams_distribute_parallel_for_simd_dist_schedule_messages.cpp
> @@ -55,7 +55,7 @@ T tmain(T argc) {
>    for (int i = 0; i < 10; ++i) foo();
>
>  #pragma omp target
> -#pragma omp teams distribute parallel for simd dist_schedule (static, argv[1]=2) // expected-error {{expected ')'}} expected-note {{to match this '('}} expected-error3 {{expression must have integral or unscoped enumeration type, not 'char *'}}
> +#pragma omp teams distribute parallel for simd dist_schedule (static, argv[1]=2) // expected-error {{expected ')'}} expected-note {{to match this '('}} expected-error 2{{expression must have integral or unscoped enumeration type, not 'char *'}}
>    for (int i = 0; i < 10; ++i) foo();
>
>    return T();
>
> diff  --git a/clang/test/OpenMP/teams_distribute_simd_dist_schedule_messages.cpp b/clang/test/OpenMP/teams_distribute_simd_dist_schedule_messages.cpp
> index 424797576837..6e653fae08c8 100644
> --- a/clang/test/OpenMP/teams_distribute_simd_dist_schedule_messages.cpp
> +++ b/clang/test/OpenMP/teams_distribute_simd_dist_schedule_messages.cpp
> @@ -55,7 +55,7 @@ T tmain(T argc) {
>    for (int i = 0; i < 10; ++i) foo();
>
>  #pragma omp target
> -#pragma omp teams distribute simd dist_schedule (static, argv[1]=2) // expected-error {{expected ')'}} expected-note {{to match this '('}} expected-error3 {{expression must have integral or unscoped enumeration type, not 'char *'}}
> +#pragma omp teams distribute simd dist_schedule (static, argv[1]=2) // expected-error {{expected ')'}} expected-note {{to match this '('}} expected-error 2{{expression must have integral or unscoped enumeration type, not 'char *'}}
>    for (int i = 0; i < 10; ++i) foo();
>
>    return T();
>
> diff  --git a/clang/test/SemaCXX/warn-unused-lambda-capture.cpp b/clang/test/SemaCXX/warn-unused-lambda-capture.cpp
> index 52ec390b0bba..764a4a42a084 100644
> --- a/clang/test/SemaCXX/warn-unused-lambda-capture.cpp
> +++ b/clang/test/SemaCXX/warn-unused-lambda-capture.cpp
> @@ -147,7 +147,7 @@ void test_templated() {
>
>    auto explicit_by_value_unused = [i] {}; // expected-warning{{lambda capture 'i' is not used}}
>    auto explicit_by_value_unused_sizeof = [i] { return sizeof(i); }; // expected-warning{{lambda capture 'i' is not required to be captured for this use}}
> -  auto explicit_by_value_unused_decltype = [i] { decltype(i) j = 0; }; // expected-warning{{lambda capture 'i' is not used}}
> +  auto explicit_by_value_unused_decltype = [i] { decltype(i) j = 0; }; // expected-warning{{lambda capture 'i' is not required to be captured for this use}}
>    auto explicit_by_value_unused_const = [k] { return k + 1; };         // expected-warning{{lambda capture 'k' is not required to be captured for this use}}
>    auto explicit_by_value_unused_const_generic = [k](auto c) { return k + 1; }; // expected-warning{{lambda capture 'k' is not required to be captured for this use}}
>
>
> diff  --git a/clang/test/SemaTemplate/temp_arg_nontype_cxx1z.cpp b/clang/test/SemaTemplate/temp_arg_nontype_cxx17.cpp
> similarity index 98%
> rename from clang/test/SemaTemplate/temp_arg_nontype_cxx1z.cpp
> rename to clang/test/SemaTemplate/temp_arg_nontype_cxx17.cpp
> index 675f957ef6fa..52cf51719f05 100644
> --- a/clang/test/SemaTemplate/temp_arg_nontype_cxx1z.cpp
> +++ b/clang/test/SemaTemplate/temp_arg_nontype_cxx17.cpp
> @@ -503,3 +503,13 @@ namespace PR48517 {
>    template<> struct Q<&R<int>::n> { static constexpr int X = 1; };
>    static_assert(R<int>().f() == 1);
>  }
> +
> +namespace dependent_reference {
> +  template<int &r> struct S { int *q = &r; };
> +  template<int> auto f() { static int n; return S<n>(); }
> +  auto v = f<0>();
> +  auto w = f<1>();
> +  static_assert(!is_same<decltype(v), decltype(w)>);
> +  // Ensure that we can instantiate the definition of S<...>.
> +  int n = *v.q + *w.q;
> +}
>
> diff  --git a/clang/test/SemaTemplate/temp_arg_nontype_cxx20.cpp b/clang/test/SemaTemplate/temp_arg_nontype_cxx20.cpp
> index c42fda780430..d514465f7d67 100644
> --- a/clang/test/SemaTemplate/temp_arg_nontype_cxx20.cpp
> +++ b/clang/test/SemaTemplate/temp_arg_nontype_cxx20.cpp
> @@ -292,3 +292,47 @@ namespace Predefined {
>      Y<B{__func__[0]}>(); // expected-error {{reference to subobject of predefined '__func__' variable}}
>    }
>  }
> +
> +namespace dependent {
> +  template<auto &V> struct R { static inline auto &v = V; };
> +  template<auto &V, auto &W> constexpr bool operator==(R<V>, R<W>) { return &V == &W; }
> +  template<auto *V> struct S { static inline auto *v = V; };
> +  template<auto *V, auto *W> constexpr bool operator==(S<V>, S<W>) { return V == W; }
> +  template<auto V> struct T { static inline const auto &v = V; };
> +  template<auto V, auto W> constexpr bool operator==(T<V>, T<W>) { return &V == &W; }
> +  template<typename T> struct V { T v; };
> +  template<int N> auto f() {
> +    static int n;
> +    static V<int> vn;
> +    if constexpr (N < 10)
> +      return R<n>();
> +    else if constexpr (N < 20)
> +      return R<vn.v>(); // FIXME: expected-error 2{{refers to subobject}}
> +    else if constexpr (N < 30)
> +      return S<&n>();
> +    else if constexpr (N < 40)
> +      return S<&vn.v>(); // FIXME: expected-error 2{{refers to subobject}}
> +    else if constexpr (N < 50)
> +      return T<V<int&>{n}>();
> +    else if constexpr (N < 60)
> +      return T<V<int*>{&n}>();
> +    else if constexpr (N < 70)
> +      return T<V<int&>{vn.v}>();
> +    else if constexpr (N < 80)
> +      return T<V<int*>{&vn.v}>();
> +  }
> +  template<int Base> void check() {
> +    auto v = f<Base + 0>(); // FIXME: expected-note 2{{instantiation of}}
> +    auto w = f<Base + 1>(); // FIXME: expected-note 2{{instantiation of}}
> +    static_assert(!__is_same(decltype(v), decltype(w)));
> +    static_assert(v != w);
> +  }
> +  template void check<0>();
> +  template void check<10>(); // FIXME: expected-note 2{{instantiation of}}
> +  template void check<20>();
> +  template void check<30>(); // FIXME: expected-note 2{{instantiation of}}
> +  template void check<40>();
> +  template void check<50>();
> +  template void check<60>();
> +  template void check<70>();
> +}
>
>
>
> _______________________________________________
> cfe-commits mailing list
> cfe-commits at lists.llvm.org
> https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits


More information about the cfe-commits mailing list