Following up on PR48517, fix handling of template arguments that refer
authorRichard Smith <richard@metafoo.co.uk>
Wed, 16 Dec 2020 21:51:56 +0000 (13:51 -0800)
committerRichard Smith <richard@metafoo.co.uk>
Tue, 19 Jan 2021 05:05:01 +0000 (21:05 -0800)
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.

32 files changed:
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_cxx17.cpp [moved from clang/test/SemaTemplate/temp_arg_nontype_cxx1z.cpp with 98% similarity]
clang/test/SemaTemplate/temp_arg_nontype_cxx20.cpp

index a44d069..c963be9 100644 (file)
@@ -578,12 +578,12 @@ public:
   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 @@ public:
     /// 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 @@ public:
 
   /// 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.
index 1671637..5fbb25c 100644 (file)
@@ -252,6 +252,12 @@ public:
   /// 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,
index 7f7c84e..7cdfe24 100644 (file)
@@ -3465,7 +3465,8 @@ public:
                                               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.
index 4026fdc..5262e3c 100644 (file)
@@ -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;
index 5d7066c..6e12b3b 100644 (file)
@@ -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;
index 8dc9d42..e1f6589 100644 (file)
@@ -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);
index b153e22..6ec6df0 100644 (file)
@@ -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;
index baf62bd..8cbb595 100644 (file)
@@ -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);
index 13d2125..ac52612 100644 (file)
@@ -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;
index 12880b9..9f31468 100644 (file)
@@ -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;
     }
index 7e0cc2d..49ff7cd 100644 (file)
@@ -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
index cd232f4..0f7b217 100644 (file)
@@ -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-error{{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();
 }
index 07e7704..18dcac5 100644 (file)
@@ -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-error{{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();
 }
index ed7b191..63f8cfe 100644 (file)
@@ -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-error{{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();
 }
index 794681c..a6593cf 100644 (file)
@@ -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-error{{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();
 }
index 7acb258..f829874 100644 (file)
@@ -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@+1 {{integral constant expression}} expected-note@+1 0+{{constant expression}}
+  // expected-error@+1 1+{{integral constant expression}} expected-note@+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)
index 8dd7f68..972aa57 100644 (file)
@@ -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@+1 {{integral constant expression}} expected-note@+1 0+{{constant expression}}
+// expected-error@+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];
index 00fa3c8..d8b0a91 100644 (file)
@@ -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@+1 {{integral constant expression}} expected-note@+1 0+{{constant expression}}
+  // expected-error@+1 1+{{integral constant expression}} expected-note@+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)
index 69c1e55..e31df97 100644 (file)
@@ -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-error{{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();
index a0efad1..4f3c581 100644 (file)
@@ -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-error{{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();
index ec634c8..8b272d4 100644 (file)
@@ -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-error{{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();
index 507ddab..b583c14 100644 (file)
@@ -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-error{{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();
index 3dc377c..42ecc28 100644 (file)
@@ -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)
   {
index fca4e21..941c781 100644 (file)
@@ -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)
   {
index 13cbfb6..2f9ee9a 100644 (file)
@@ -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'}}
index 22d2408..bd1aaa5 100644 (file)
@@ -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-error{{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();
index 27ff412..a70d80a 100644 (file)
@@ -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-error{{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();
index cbd4ec4..b87301f 100644 (file)
@@ -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-error{{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();
index 4247975..6e653fa 100644 (file)
@@ -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-error{{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();
index 52ec390..764a4a4 100644 (file)
@@ -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}}
 
@@ -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;
+}
index c42fda7..d514465 100644 (file)
@@ -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>();
+}