struct EvalStatus {
/// Whether the evaluated expression has side effects.
/// For example, (f() && 0) can be folded, but it still has side effects.
- bool HasSideEffects = false;
+ bool HasSideEffects;
/// 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 = false;
+ bool HasUndefinedBehavior;
/// 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
/// 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 = nullptr;
+ SmallVectorImpl<PartialDiagnosticAt> *Diag;
+
+ EvalStatus()
+ : HasSideEffects(false), HasUndefinedBehavior(false), Diag(nullptr) {}
// hasSideEffects - Return true if the evaluated expression has
// side effects.
/// EvalResult is a struct with detailed info about an evaluated expression.
struct EvalResult : EvalStatus {
- /// This is the value the expression can be folded to.
+ /// Val - 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.
/// 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
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,
llvm::APSInt &Value, CCEKind CCE);
ExprResult CheckConvertedConstantExpression(Expr *From, QualType T,
APValue &Value, CCEKind CCE,
- NamedDecl *Dest = nullptr,
- bool *ValueDependent = nullptr);
+ NamedDecl *Dest = nullptr);
/// Abstract base class used to perform a contextual implicit
/// conversion from an expression to any type passing a filter.
if (VD && VD->isTemplated()) {
auto *VarD = dyn_cast<VarDecl>(VD);
if (!VarD || !VarD->hasLocalStorage())
- Dep |= ExprDependence::ValueInstantiation;
+ Dep |= ExprDependence::Value;
}
}
}
if (auto *FirstArg = E->getTemplateArgs()) {
unsigned NumArgs = E->getNumTemplateArgs();
for (auto *Arg = FirstArg, *End = FirstArg + NumArgs; Arg < End; ++Arg)
- Deps |= toExprDependence(Arg->getArgument().getDependence() &
- ~TemplateArgumentDependence::Dependent);
+ Deps |= toExprDependence(Arg->getArgument().getDependence());
}
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;
RefersToEnclosingVariableOrCapture;
DeclRefExprBits.NonOdrUseReason = NOUR;
if (TemplateArgs) {
+ auto Deps = TemplateArgumentDependence::None;
getTrailingObjects<ASTTemplateKWAndArgsInfo>()->initializeFrom(
- TemplateKWLoc, *TemplateArgs,
- getTrailingObjects<TemplateArgumentLoc>());
+ TemplateKWLoc, *TemplateArgs, getTrailingObjects<TemplateArgumentLoc>(),
+ Deps);
+ assert(!(Deps & TemplateArgumentDependence::Dependent) &&
+ "built a DeclRefExpr with dependent template args");
} else if (TemplateKWLoc.isValid()) {
getTrailingObjects<ASTTemplateKWAndArgsInfo>()->initializeFrom(
TemplateKWLoc);
MemberExpr *E = new (Mem) MemberExpr(Base, IsArrow, OperatorLoc, MemberDecl,
NameInfo, T, VK, OK, NOUR);
- // FIXME: Move this into the constructor.
+ // FIXME: remove remaining dependence computation to computeDependence().
+ auto Deps = E->getDependence();
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 =
TemplateArgs || TemplateKWLoc.isValid();
if (TemplateArgs) {
+ auto TemplateArgDeps = TemplateArgumentDependence::None;
E->getTrailingObjects<ASTTemplateKWAndArgsInfo>()->initializeFrom(
TemplateKWLoc, *TemplateArgs,
- E->getTrailingObjects<TemplateArgumentLoc>());
+ E->getTrailingObjects<TemplateArgumentLoc>(), TemplateArgDeps);
+ if (TemplateArgDeps & TemplateArgumentDependence::Instantiation)
+ Deps |= ExprDependence::Instantiation;
} 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;
}
if (TemplateArgs) {
+ auto Deps = TemplateArgumentDependence::None;
getTrailingASTTemplateKWAndArgsInfo()->initializeFrom(
- TemplateKWLoc, *TemplateArgs, getTrailingTemplateArgumentLoc());
+ TemplateKWLoc, *TemplateArgs, getTrailingTemplateArgumentLoc(), Deps);
} else if (TemplateKWLoc.isValid()) {
getTrailingASTTemplateKWAndArgsInfo()->initializeFrom(TemplateKWLoc);
}
DependentScopeDeclRefExprBits.HasTemplateKWAndArgsInfo =
(Args != nullptr) || TemplateKWLoc.isValid();
if (Args) {
+ auto Deps = TemplateArgumentDependence::None;
getTrailingObjects<ASTTemplateKWAndArgsInfo>()->initializeFrom(
- TemplateKWLoc, *Args, getTrailingObjects<TemplateArgumentLoc>());
+ TemplateKWLoc, *Args, getTrailingObjects<TemplateArgumentLoc>(), Deps);
} else if (TemplateKWLoc.isValid()) {
getTrailingObjects<ASTTemplateKWAndArgsInfo>()->initializeFrom(
TemplateKWLoc);
CXXDependentScopeMemberExprBits.OperatorLoc = OperatorLoc;
if (TemplateArgs) {
+ auto Deps = TemplateArgumentDependence::None;
getTrailingObjects<ASTTemplateKWAndArgsInfo>()->initializeFrom(
- TemplateKWLoc, *TemplateArgs,
- getTrailingObjects<TemplateArgumentLoc>());
+ TemplateKWLoc, *TemplateArgs, getTrailingObjects<TemplateArgumentLoc>(),
+ Deps);
} else if (TemplateKWLoc.isValid()) {
getTrailingObjects<ASTTemplateKWAndArgsInfo>()->initializeFrom(
TemplateKWLoc);
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,
- bool &Dependent);
+static bool EvaluateAsRValue(EvalInfo &Info, const Expr *E, APValue &Result);
/// Evaluate an integer or fixed point expression into an APResult.
static bool EvaluateFixedPointOrInteger(const Expr *E, APFixedPoint &Result,
QualType Type, const APValue &Value,
ConstantExprKind Kind,
SourceLocation SubobjectLoc,
- CheckedTemporaries &CheckedTemps,
- bool &Dependent);
+ CheckedTemporaries &CheckedTemps);
/// Check that this reference or pointer core constant expression is a valid
/// value for an address or reference constant expression. Return true if we
static bool CheckLValueConstantExpression(EvalInfo &Info, SourceLocation Loc,
QualType Type, const LValue &LVal,
ConstantExprKind Kind,
- CheckedTemporaries &CheckedTemps,
- bool &Dependent) {
+ CheckedTemporaries &CheckedTemps) {
bool IsReferenceType = Type->isReferenceType();
APValue::LValueBase Base = LVal.getLValueBase();
}
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())
}
} 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()) {
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, Dependent))
+ Info, MTE->getExprLoc(), TempType, *V,
+ Kind, SourceLocation(), CheckedTemps))
return false;
}
}
/// 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, bool &Dependent) {
+static bool CheckMemberPointerConstantExpression(EvalInfo &Info,
+ SourceLocation Loc,
+ QualType Type,
+ const APValue &Value,
+ ConstantExprKind Kind) {
const ValueDecl *Member = Value.getMemberPointerDecl();
- if (!Member)
- return true;
- Dependent |= Member->isTemplated();
- const auto *FD = dyn_cast<CXXMethodDecl>(Member);
+ const auto *FD = dyn_cast_or_null<CXXMethodDecl>(Member);
if (!FD)
return true;
if (FD->isConsteval()) {
QualType Type, const APValue &Value,
ConstantExprKind Kind,
SourceLocation SubobjectLoc,
- CheckedTemporaries &CheckedTemps,
- bool &Dependent) {
+ CheckedTemporaries &CheckedTemps) {
if (!Value.hasValue()) {
Info.FFDiag(DiagLoc, diag::note_constexpr_uninitialized)
<< true << Type;
for (unsigned I = 0, N = Value.getArrayInitializedElts(); I != N; ++I) {
if (!CheckEvaluationResult(CERK, Info, DiagLoc, EltTy,
Value.getArrayInitializedElt(I), Kind,
- SubobjectLoc, CheckedTemps, Dependent))
+ SubobjectLoc, CheckedTemps))
return false;
}
if (!Value.hasArrayFiller())
return true;
return CheckEvaluationResult(CERK, Info, DiagLoc, EltTy,
Value.getArrayFiller(), Kind, SubobjectLoc,
- CheckedTemps, Dependent);
+ CheckedTemps);
}
if (Value.isUnion() && Value.getUnionField()) {
return CheckEvaluationResult(
CERK, Info, DiagLoc, Value.getUnionField()->getType(),
Value.getUnionValue(), Kind, Value.getUnionField()->getLocation(),
- CheckedTemps, Dependent);
+ CheckedTemps);
}
if (Value.isStruct()) {
RecordDecl *RD = Type->castAs<RecordType>()->getDecl();
for (const CXXBaseSpecifier &BS : CD->bases()) {
if (!CheckEvaluationResult(CERK, Info, DiagLoc, BS.getType(),
Value.getStructBase(BaseIndex), Kind,
- BS.getBeginLoc(), CheckedTemps, Dependent))
+ BS.getBeginLoc(), CheckedTemps))
return false;
++BaseIndex;
}
continue;
if (!CheckEvaluationResult(CERK, Info, DiagLoc, I->getType(),
- Value.getStructField(I->getFieldIndex()), Kind,
- I->getLocation(), CheckedTemps, Dependent))
+ Value.getStructField(I->getFieldIndex()),
+ Kind, I->getLocation(), CheckedTemps))
return false;
}
}
LValue LVal;
LVal.setFrom(Info.Ctx, Value);
return CheckLValueConstantExpression(Info, DiagLoc, Type, LVal, Kind,
- CheckedTemps, Dependent);
+ CheckedTemps);
}
if (Value.isMemberPointer() &&
CERK == CheckEvaluationResultKind::ConstantExpression)
- return CheckMemberPointerConstantExpression(Info, DiagLoc, Type, Value,
- Kind, Dependent);
+ return CheckMemberPointerConstantExpression(Info, DiagLoc, Type, Value, Kind);
// Everything else is fine.
return true;
/// check that the expression is of literal type.
static bool CheckConstantExpression(EvalInfo &Info, SourceLocation DiagLoc,
QualType Type, const APValue &Value,
- ConstantExprKind Kind, bool &Dependent) {
+ ConstantExprKind Kind) {
// Nothing to check for a constant expression of type 'cv void'.
if (Type->isVoidType())
return true;
CheckedTemporaries CheckedTemps;
return CheckEvaluationResult(CheckEvaluationResultKind::ConstantExpression,
Info, DiagLoc, Type, Value, Kind,
- SourceLocation(), CheckedTemps, Dependent);
+ SourceLocation(), CheckedTemps);
}
/// 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, Dependent);
+ ConstantExprKind::Normal, SourceLocation(), CheckedTemps);
}
/// Enforce C++2a [expr.const]/4.17, which disallows new-expressions unless
ArgType->isAnyComplexType() || ArgType->isPointerType() ||
ArgType->isNullPtrType()) {
APValue V;
- bool Dependent = false;
- if (!::EvaluateAsRValue(Info, Arg, V, Dependent) ||
- Info.EvalStatus.HasSideEffects) {
+ if (!::EvaluateAsRValue(Info, Arg, V) || Info.EvalStatus.HasSideEffects) {
Fold.keepDiagnostics();
return false;
}
// It's possible for us to be given GLValues if we're called via
// Expr::tryEvaluateObjectSize.
APValue RVal;
- bool Dependent = false;
- if (!EvaluateAsRValue(Info, E, RVal, Dependent))
+ if (!EvaluateAsRValue(Info, E, RVal))
return false;
LVal.setFrom(Info.Ctx, RVal);
} else if (!EvaluatePointer(ignorePointerCastsAndParens(E), LVal, Info,
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, Dependent);
+ ConstantExprKind::Normal);
};
return EvaluateComparisonBinaryOperator(Info, E, OnSuccess, [&]() {
return ExprEvaluatorBaseTy::VisitBinCmp(E);
/// 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,
- bool &Dependent) {
+static bool EvaluateAsRValue(EvalInfo &Info, const Expr *E, APValue &Result) {
assert(!E->isValueDependent());
if (Info.EnableNewConstInterp) {
if (!Info.Ctx.getInterpContext().evaluateAsRValue(Info, E, Result))
// Check this core constant expression is a constant expression.
return CheckConstantExpression(Info, E->getExprLoc(), E->getType(), Result,
- ConstantExprKind::Normal, Dependent) &&
+ ConstantExprKind::Normal) &&
CheckMemoryLeaks(Info);
}
if (FastEvaluateAsRValue(E, Result, Ctx, IsConst))
return IsConst;
- return EvaluateAsRValue(Info, E, Result.Val, Result.Dependent);
+ return EvaluateAsRValue(Info, E, Result.Val);
}
static bool EvaluateAsInt(const Expr *E, Expr::EvalResult &ExprResult,
CheckedTemporaries CheckedTemps;
if (!EvaluateLValue(this, LV, Info) || !Info.discardCleanups() ||
Result.HasSideEffects ||
- !CheckLValueConstantExpression(
- Info, getExprLoc(), Ctx.getLValueReferenceType(getType()), LV,
- ConstantExprKind::Normal, CheckedTemps, Result.Dependent))
+ !CheckLValueConstantExpression(Info, getExprLoc(),
+ Ctx.getLValueReferenceType(getType()), LV,
+ ConstantExprKind::Normal, CheckedTemps))
return false;
LV.moveInto(Result.Val);
llvm_unreachable("Unhandled cleanup; missing full expression marker?");
if (!CheckConstantExpression(Info, getExprLoc(), getStorageType(Ctx, this),
- Result.Val, Kind, Result.Dependent))
+ Result.Val, Kind))
return false;
if (!CheckMemoryLeaks(Info))
return false;
if (!Info.discardCleanups())
llvm_unreachable("Unhandled cleanup; missing full expression marker?");
}
- bool Dependent = false;
return CheckConstantExpression(Info, DeclLoc, DeclTy, Value,
- ConstantExprKind::Normal, Dependent) &&
+ ConstantExprKind::Normal) &&
CheckMemoryLeaks(Info);
}
Info.InConstantContext = true;
Info.CheckingForUndefinedBehavior = true;
- bool Result = ::EvaluateAsRValue(this, EVResult, Ctx, Info);
+ bool Result = ::EvaluateAsRValue(Info, this, EVResult.Val);
(void)Result;
assert(Result && "Could not evaluate expression");
assert(EVResult.Val.isInt() && "Expression did not evaluate to integer");
assert(!isValueDependent() &&
"Expression evaluator can't be called on a dependent expression.");
+ bool IsConst;
EvalResult EVResult;
- EvalInfo Info(Ctx, EVResult, EvalInfo::EM_IgnoreSideEffects);
- Info.CheckingForUndefinedBehavior = true;
- (void)::EvaluateAsRValue(this, EVResult, Ctx, Info);
+ if (!FastEvaluateAsRValue(this, EVResult, Ctx, IsConst)) {
+ EvalInfo Info(Ctx, EVResult, EvalInfo::EM_IgnoreSideEffects);
+ Info.CheckingForUndefinedBehavior = true;
+ (void)::EvaluateAsRValue(Info, this, EVResult.Val);
+ }
}
bool Expr::EvalResult::isGlobalLValue() const {
EvalInfo Info(Ctx, Status, EvalInfo::EM_ConstantExpression);
APValue Scratch;
- bool Dependent = false;
bool IsConstExpr =
- ::EvaluateAsRValue(Info, this, Result ? *Result : Scratch, Dependent) &&
+ ::EvaluateAsRValue(Info, this, Result ? *Result : Scratch) &&
// 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;
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());
- // Instantiation-dependent expression arguments are considered dependent
- // until they're resolved to another form.
- if (Deps & TemplateArgumentDependence::Instantiation)
- Deps |= TemplateArgumentDependence::Dependent;
+ if (isa<PackExpansionExpr>(getAsExpr()))
+ Deps |= TemplateArgumentDependence::Dependent |
+ TemplateArgumentDependence::Instantiation;
return Deps;
case Pack:
NumTemplateArgs = Info.size();
TemplateArgumentLoc *ArgBuffer = getTrailingObjects<TemplateArgumentLoc>();
- std::uninitialized_copy(Info.arguments().begin(), Info.arguments().end(),
- ArgBuffer);
+ for (unsigned i = 0; i != NumTemplateArgs; ++i)
+ new (&ArgBuffer[i]) TemplateArgumentLoc(Info[i]);
}
void ASTTemplateKWAndArgsInfo::initializeFrom(
LAngleLoc = Info.getLAngleLoc();
RAngleLoc = Info.getRAngleLoc();
NumTemplateArgs = Info.size();
- std::uninitialized_copy(Info.arguments().begin(), Info.arguments().end(),
- OutArgArray);
+
+ for (unsigned i = 0; i != NumTemplateArgs; ++i)
+ new (&OutArgArray[i]) TemplateArgumentLoc(Info[i]);
}
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);
QualType T, APValue &Value,
Sema::CCEKind CCE,
bool RequireInt,
- NamedDecl *Dest,
- bool *ValueDependent) {
+ NamedDecl *Dest) {
assert(S.getLangOpts().CPlusPlus11 &&
"converted constant expression outside C++11");
if (Result.get()->isValueDependent()) {
Value = APValue();
- if (ValueDependent)
- *ValueDependent = true;
return Result;
}
Result = ExprError();
} else {
Value = Eval.Val;
- if (ValueDependent)
- *ValueDependent = Eval.Dependent;
if (Notes.empty()) {
// It's a constant expression.
ExprResult Sema::CheckConvertedConstantExpression(Expr *From, QualType T,
APValue &Value, CCEKind CCE,
- NamedDecl *Dest,
- bool *ValueDependent) {
+ NamedDecl *Dest) {
return ::CheckConvertedConstantExpression(*this, From, T, Value, CCE, false,
- Dest, ValueDependent);
+ Dest);
}
ExprResult Sema::CheckConvertedConstantExpression(Expr *From, QualType T,
APValue V;
auto R = ::CheckConvertedConstantExpression(*this, From, T, V, CCE, true,
- /*Dest=*/nullptr,
- /*ValueDependent=*/nullptr);
+ /*Dest=*/nullptr);
if (!R.isInvalid() && !R.get()->isValueDependent())
Value = V.getInt();
return R;
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));
QualType ParamType,
Expr *&ResultArg,
TemplateArgument &Converted) {
+ bool Invalid = false;
+
Expr *Arg = ResultArg;
bool ObjCLifetimeConversion;
// 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 (!ExtraParens) {
+ if (!Invalid && !ExtraParens) {
S.Diag(Arg->getBeginLoc(),
S.getLangOpts().CPlusPlus11
? diag::warn_cxx98_compat_template_arg_extra_parens
ValueDecl *VD = DRE->getDecl();
if (VD->getType()->isMemberPointerType()) {
if (isa<NonTypeTemplateParmDecl>(VD)) {
- Converted = TemplateArgument(Arg);
- return false;
+ if (Arg->isTypeDependent() || Arg->isValueDependent()) {
+ Converted = TemplateArgument(Arg);
+ } else {
+ VD = cast<ValueDecl>(VD->getCanonicalDecl());
+ Converted = TemplateArgument(VD, ParamType);
+ }
+ return Invalid;
}
}
ValueDecl *D = cast<ValueDecl>(DRE->getDecl()->getCanonicalDecl());
Converted = TemplateArgument(D, S.Context.getCanonicalType(ParamType));
}
- return false;
+ return Invalid;
}
// We found something else, but we don't know specifically what it is.
// 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, &ValueDependent);
+ Arg, ParamType, Value, CCEK_TemplateArg, Param);
if (ArgResult.isInvalid())
return ExprError();
// For a value-dependent argument, CheckConvertedConstantExpression is
- // 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) {
+ // permitted (and expected) to be unable to determine a value.
+ if (ArgResult.get()->isValueDependent()) {
Converted = TemplateArgument(ArgResult.get());
return ArgResult;
}
if (FunctionDecl *Pattern =
Function->getInstantiatedFromMemberFunction()) {
- if (TSK != TSK_ImplicitInstantiation &&
- Function->hasAttr<ExcludeFromExplicitInstantiationAttr>())
+ if (Function->hasAttr<ExcludeFromExplicitInstantiationAttr>())
continue;
MemberSpecializationInfo *MSInfo =
continue;
if (Var->isStaticDataMember()) {
- if (TSK != TSK_ImplicitInstantiation &&
- Var->hasAttr<ExcludeFromExplicitInstantiationAttr>())
+ if (Var->hasAttr<ExcludeFromExplicitInstantiationAttr>())
continue;
MemberSpecializationInfo *MSInfo = Var->getMemberSpecializationInfo();
SuppressNew)
continue;
- if (TSK != TSK_ExplicitInstantiationDeclaration) {
+ if (TSK == TSK_ExplicitInstantiationDefinition) {
// C++0x [temp.explicit]p8:
// An explicit instantiation definition that names a class template
// specialization explicitly instantiates the class template
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 2{{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-error3 {{expression must have integral or unscoped enumeration type, not 'char *'}}
for (int i = 0; i < 10; ++i) foo();
return T();
}
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 2{{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-error3 {{expression must have integral or unscoped enumeration type, not 'char *'}}
for (int i = 0; i < 10; ++i) foo();
return T();
}
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 2{{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-error3 {{expression must have integral or unscoped enumeration type, not 'char *'}}
for (int i = 0; i < 10; ++i) foo();
return T();
}
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 2{{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-error3 {{expression must have integral or unscoped enumeration type, not 'char *'}}
for (int i = 0; i < 10; ++i) foo();
return T();
}
#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 1+{{integral constant expression}} expected-note@+1 0+{{constant expression}}
+ // expected-error@+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)
for (int i = ST; i < N; i++)
argv[0][i] = argv[0][i] - argv[0][i - ST];
-// expected-error@+1 {{'ordered' clause with a parameter can not be specified in '#pragma omp target parallel for simd' directive}}
+// expected-error@+1 {{integral constant expression}} expected-note@+1 0+{{constant expression}}
#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];
#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 1+{{integral constant expression}} expected-note@+1 0+{{constant expression}}
+ // expected-error@+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)
#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 2{{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-error3 {{expression must have integral or unscoped enumeration type, not 'char *'}}
for (int i = 0; i < 10; ++i) foo();
return T();
#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 2{{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-error3 {{expression must have integral or unscoped enumeration type, not 'char *'}}
for (int i = 0; i < 10; ++i) foo();
return T();
#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 2{{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-error3 {{expression must have integral or unscoped enumeration type, not 'char *'}}
for (int i = 0; i < 10; ++i) foo();
return T();
#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 2{{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-error3 {{expression must have integral or unscoped enumeration type, not 'char *'}}
for (int i = 0; i < 10; ++i) foo();
return T();
#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 2{{bit fields cannot be used to specify storage in a 'from' clause}}
+#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.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)
{
#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 2{{bit fields cannot be used to specify storage in a 'to' clause}}
+#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.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)
{
#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}}
+#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(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'}}
+#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) 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'}}
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 2{{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-error3 {{expression must have integral or unscoped enumeration type, not 'char *'}}
for (int i = 0; i < 10; ++i) foo();
return T();
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 2{{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-error3 {{expression must have integral or unscoped enumeration type, not 'char *'}}
for (int i = 0; i < 10; ++i) foo();
return T();
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 2{{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-error3 {{expression must have integral or unscoped enumeration type, not 'char *'}}
for (int i = 0; i < 10; ++i) foo();
return T();
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 2{{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-error3 {{expression must have integral or unscoped enumeration type, not 'char *'}}
for (int i = 0; i < 10; ++i) foo();
return T();
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 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_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}}
+++ /dev/null
-// RUN: %clang_cc1 -fsyntax-only -verify -std=c++1z %s
-
-template<typename T, T val> struct A {};
-
-template<typename T, typename U> constexpr bool is_same = false; // expected-note +{{here}}
-template<typename T> constexpr bool is_same<T, T> = true;
-
-namespace String {
- A<const char*, "test"> a; // expected-error {{pointer to subobject of string literal}}
- A<const char (&)[5], "test"> b; // expected-error {{reference to string literal}}
-}
-
-namespace Array {
- char arr[3];
- char x;
- A<const char*, arr> a;
- A<const char(&)[3], arr> b;
- A<const char*, &arr[0]> c;
- A<const char*, &arr[1]> d; // expected-error {{refers to subobject '&arr[1]'}}
- A<const char*, (&arr)[0]> e;
- A<const char*, &x> f;
- A<const char*, &(&x)[0]> g;
- A<const char*, &(&x)[1]> h; // expected-error {{refers to subobject '&x + 1'}}
- A<const char*, 0> i; // expected-error {{not allowed in a converted constant}}
- A<const char*, nullptr> j;
-
- extern char aub[];
- A<char[], aub> k;
-}
-
-namespace Function {
- void f();
- void g() noexcept;
- void h();
- void h(int);
- template<typename...T> void i(T...);
- typedef A<void (*)(), f> a;
- typedef A<void (*)(), &f> a;
- typedef A<void (*)(), g> b;
- typedef A<void (*)(), &g> b;
- typedef A<void (*)(), h> c;
- typedef A<void (*)(), &h> c;
- typedef A<void (*)(), i> d;
- typedef A<void (*)(), &i> d;
- typedef A<void (*)(), i<>> d;
- typedef A<void (*)(), i<int>> e; // expected-error {{is not implicitly convertible}}
-
- typedef A<void (*)(), 0> x; // expected-error {{not allowed in a converted constant}}
- typedef A<void (*)(), nullptr> y;
-}
-
-void Func() {
- A<const char*, __func__> a; // expected-error {{pointer to subobject of predefined '__func__' variable}}
-}
-
-namespace LabelAddrDiff {
- void f() {
- a: b: A<int, __builtin_constant_p(true) ? (__INTPTR_TYPE__)&&b - (__INTPTR_TYPE__)&&a : 0> s; // expected-error {{label address difference}}
- };
-}
-
-namespace Temp {
- struct S { int n; };
- constexpr S &addr(S &&s) { return s; }
- A<S &, addr({})> a; // expected-error {{reference to temporary object}}
- A<S *, &addr({})> b; // expected-error {{pointer to temporary object}}
- A<int &, addr({}).n> c; // expected-error {{reference to subobject of temporary object}}
- A<int *, &addr({}).n> d; // expected-error {{pointer to subobject of temporary object}}
-}
-
-namespace std { struct type_info; }
-
-namespace RTTI {
- A<const std::type_info&, typeid(int)> a; // expected-error {{reference to type_info object}}
- A<const std::type_info*, &typeid(int)> b; // expected-error {{pointer to type_info object}}
-}
-
-namespace PtrMem {
- struct B { int b; };
- struct C : B {};
- struct D : B {};
- struct E : C, D { int e; };
-
- constexpr int B::*b = &B::b;
- constexpr int C::*cb = b;
- constexpr int D::*db = b;
- constexpr int E::*ecb = cb; // expected-note +{{here}}
- constexpr int E::*edb = db; // expected-note +{{here}}
-
- constexpr int E::*e = &E::e;
- constexpr int D::*de = (int D::*)e;
- constexpr int C::*ce = (int C::*)e;
- constexpr int B::*bde = (int B::*)de; // expected-note +{{here}}
- constexpr int B::*bce = (int B::*)ce; // expected-note +{{here}}
-
- // FIXME: This should all be accepted, but we don't yet have a representation
- // nor mangling for this form of template argument.
- using Ab = A<int B::*, b>;
- using Ab = A<int B::*, &B::b>;
- using Abce = A<int B::*, bce>; // expected-error {{not supported}}
- using Abde = A<int B::*, bde>; // expected-error {{not supported}}
- static_assert(!is_same<Ab, Abce>, ""); // expected-error {{undeclared}} expected-error {{must be a type}}
- static_assert(!is_same<Ab, Abde>, ""); // expected-error {{undeclared}} expected-error {{must be a type}}
- static_assert(!is_same<Abce, Abde>, ""); // expected-error 2{{undeclared}} expected-error {{must be a type}}
- static_assert(is_same<Abce, A<int B::*, (int B::*)(int C::*)&E::e>>, ""); // expected-error {{undeclared}} expected-error {{not supported}}
-
- using Ae = A<int E::*, e>;
- using Ae = A<int E::*, &E::e>;
- using Aecb = A<int E::*, ecb>; // expected-error {{not supported}}
- using Aedb = A<int E::*, edb>; // expected-error {{not supported}}
- static_assert(!is_same<Ae, Aecb>, ""); // expected-error {{undeclared}} expected-error {{must be a type}}
- static_assert(!is_same<Ae, Aedb>, ""); // expected-error {{undeclared}} expected-error {{must be a type}}
- static_assert(!is_same<Aecb, Aedb>, ""); // expected-error 2{{undeclared}} expected-error {{must be a type}}
- static_assert(is_same<Aecb, A<int E::*, (int E::*)(int C::*)&B::b>>, ""); // expected-error {{undeclared}} expected-error {{not supported}}
-
- using An = A<int E::*, nullptr>;
- using A0 = A<int E::*, (int E::*)0>;
- static_assert(is_same<An, A0>);
-}
-
-namespace DeduceDifferentType {
- template<int N> struct A {};
- template<long N> int a(A<N>); // expected-note {{does not have the same type}}
- int a_imp = a(A<3>()); // expected-error {{no matching function}}
- int a_exp = a<3>(A<3>());
-
- template<decltype(nullptr)> struct B {};
- template<int *P> int b(B<P>); // expected-error {{value of type 'int *' is not implicitly convertible to 'decltype(nullptr)'}}
- int b_imp = b(B<nullptr>()); // expected-error {{no matching function}}
- int b_exp = b<nullptr>(B<nullptr>()); // expected-error {{no matching function}}
-
- struct X { constexpr operator int() { return 0; } } x;
- template<X &> struct C {};
- template<int N> int c(C<N>); // expected-error {{value of type 'int' is not implicitly convertible to 'DeduceDifferentType::X &'}}
- int c_imp = c(C<x>()); // expected-error {{no matching function}}
- int c_exp = c<x>(C<x>()); // expected-error {{no matching function}}
-
- struct Z;
- struct Y { constexpr operator Z&(); } y;
- struct Z { constexpr operator Y&() { return y; } } z;
- constexpr Y::operator Z&() { return z; }
- template<Y &> struct D {};
- template<Z &z> int d(D<z>); // expected-note {{couldn't infer template argument 'z'}}
- int d_imp = d(D<y>()); // expected-error {{no matching function}}
- int d_exp = d<y>(D<y>());
-}
-
-namespace DeclMatch {
- template<typename T, T> int f();
- template<typename T> class X { friend int f<T, 0>(); static int n; };
- template<typename T, T> int f() { return X<T>::n; }
- int k = f<int, 0>(); // ok, friend
-}
-
-namespace PR24921 {
- enum E { e };
- template<E> void f();
- template<int> void f(int);
- template<> void f<e>() {}
-}
-
-namespace Auto {
- namespace Basic {
- // simple auto
- template<auto x> constexpr auto constant = x; // expected-note {{declared here}}
-
- auto v1 = constant<5>;
- auto v2 = constant<true>;
- auto v3 = constant<'a'>;
- auto v4 = constant<2.5>; // expected-error {{cannot have type 'double'}}
-
- using T1 = decltype(v1);
- using T1 = int;
- using T2 = decltype(v2);
- using T2 = bool;
- using T3 = decltype(v3);
- using T3 = char;
-
- // pointers
- template<auto v> class B { };
- template<auto* p> class B<p> { }; // expected-note {{matches}}
- template<auto** pp> class B<pp> { };
- template<auto* p0> int &f(B<p0> b); // expected-note {{candidate}}
- template<auto** pp0> float &f(B<pp0> b); // expected-note {{candidate}}
-
- int a, *b = &a;
- int &r = f(B<&a>());
- float &s = f(B<&b>());
-
- void type_affects_identity(B<&a>) {}
- void type_affects_identity(B<(const int*)&a>) {}
- void type_affects_identity(B<(void*)&a>) {}
- void type_affects_identity(B<(const void*)&a>) {}
-
- // pointers to members
- template<typename T, auto *T::*p> struct B<p> {};
- template<typename T, auto **T::*p> struct B<p> {};
- template<typename T, auto *T::*p0> char &f(B<p0> b); // expected-note {{candidate}}
- template<typename T, auto **T::*pp0> short &f(B<pp0> b); // expected-note {{candidate}}
-
- struct X { int n; int *p; int **pp; typedef int a, b; };
- auto t = f(B<&X::n>()); // expected-error {{no match}}
- char &u = f(B<&X::p>());
- short &v = f(B<&X::pp>());
-
- struct Y : X {};
- void type_affects_identity(B<&X::n>) {}
- void type_affects_identity(B<(int Y::*)&X::n>) {} // FIXME: expected-error {{sorry}}
- void type_affects_identity(B<(const int X::*)&X::n>) {}
- void type_affects_identity(B<(const int Y::*)&X::n>) {} // FIXME: expected-error {{sorry}}
-
- // A case where we need to do auto-deduction, and check whether the
- // resulting dependent types match during partial ordering. These
- // templates are not ordered due to the mismatching function parameter.
- template<typename T, auto *(*f)(T, typename T::a)> struct B<f> {}; // expected-note {{matches}}
- template<typename T, auto **(*f)(T, typename T::b)> struct B<f> {}; // expected-note {{matches}}
- int **g(X, int);
- B<&g> bg; // expected-error {{ambiguous}}
- }
-
- namespace Chained {
- // chained template argument deduction
- template<long n> struct C { };
- template<class T> struct D;
- template<class T, T n> struct D<C<n>>
- {
- using Q = T;
- };
- using DQ = long;
- using DQ = D<C<short(2)>>::Q;
-
- // chained template argument deduction from an array bound
- template<typename T> struct E;
- template<typename T, T n> struct E<int[n]> {
- using Q = T;
- };
- using EQ = E<int[short(42)]>::Q;
- using EQ = decltype(sizeof 0);
-
- template<int N> struct F;
- template<typename T, T N> int foo(F<N> *) = delete; // expected-note {{explicitly deleted}}
- void foo(void *); // expected-note {{candidate function}}
- void bar(F<0> *p) {
- foo(p); // expected-error {{deleted function}}
- }
- }
-
- namespace ArrayToPointer {
- constexpr char s[] = "test";
- template<const auto* p> struct S { };
- S<s> p;
-
- template<typename R, typename P, R F(P)> struct A {};
- template<typename R, typename P, R F(P)> void x(A<R, P, F> a);
- void g(int) { x(A<void, int, &g>()); }
- }
-
- namespace DecltypeAuto {
- template<auto v> struct A { };
- template<decltype(auto) v> struct DA { };
- template<auto&> struct R { };
-
- auto n = 0; // expected-note + {{declared here}}
- A<n> a; // expected-error {{not a constant}} expected-note {{non-const variable 'n'}}
- DA<n> da1; // expected-error {{not a constant}} expected-note {{non-const variable 'n'}}
- DA<(n)> da2;
- R<n> r;
- }
-
- namespace Decomposition {
- // Types of deduced non-type template arguments must match exactly, so
- // partial ordering fails in both directions here.
- template<auto> struct Any;
- template<int N> struct Any<N> { typedef int Int; }; // expected-note 3{{match}}
- template<short N> struct Any<N> { typedef int Short; }; // expected-note 3{{match}}
- Any<0>::Int is_int; // expected-error {{ambiguous}}
- Any<(short)0>::Short is_short; // expected-error {{ambiguous}}
- Any<(char)0>::Short is_char; // expected-error {{ambiguous}}
-
- template<int, auto> struct NestedAny;
- template<auto N> struct NestedAny<0, N>; // expected-note 3{{match}}
- template<int N> struct NestedAny<0, N> { typedef int Int; }; // expected-note 3{{match}}
- template<short N> struct NestedAny<0, N> { typedef int Short; }; // expected-note 3{{match}}
- NestedAny<0, 0>::Int nested_int; // expected-error {{ambiguous}}
- NestedAny<0, (short)0>::Short nested_short; // expected-error {{ambiguous}}
- NestedAny<0, (char)0>::Short nested_char; // expected-error {{ambiguous}}
-
- double foo(int, bool);
- template<auto& f> struct fn_result_type;
-
- template<class R, class... Args, R (& f)(Args...)>
- struct fn_result_type<f>
- {
- using type = R;
- };
-
- using R1 = fn_result_type<foo>::type;
- using R1 = double;
-
- template<int, auto &f> struct fn_result_type_partial_order;
- template<auto &f> struct fn_result_type_partial_order<0, f>;
- template<class R, class... Args, R (& f)(Args...)>
- struct fn_result_type_partial_order<0, f> {};
- fn_result_type_partial_order<0, foo> frtpo;
- }
-
- namespace Variadic {
- template<auto... vs> struct value_list { };
-
- using size_t = decltype(sizeof 0);
- template<size_t n, class List> struct nth_element;
- template<size_t n, class List> constexpr auto nth_element_v = nth_element<n, List>::value;
-
- template<size_t n, auto v0, auto... vs>
- struct nth_element<n, value_list<v0, vs...>>
- {
- static constexpr auto value = nth_element<n - 1, value_list<vs...>>::value;
- };
- template<auto v0, auto... vs>
- struct nth_element<0, value_list<v0, vs...>>
- {
- static constexpr auto value = v0;
- };
-
- static_assert(nth_element_v<2, value_list<'a', 27U, false>> == false, "value mismatch");
- }
-}
-
-namespace Nested {
- template<typename T> struct A {
- template<auto X> struct B;
- template<auto *P> struct B<P>;
- template<auto **P> struct B<P> { using pointee = decltype(+**P); };
- template<auto (*P)(T)> struct B<P> { using param = T; };
- template<typename U, auto (*P)(T, U)> struct B<P> { using param2 = U; };
- };
-
- using Int = int;
-
- int *n;
- using Int = A<int>::B<&n>::pointee;
-
- void f(int);
- using Int = A<int>::B<&f>::param;
-
- void g(int, int);
- using Int = A<int>::B<&g>::param2;
-}
-
-namespace rdar41852459 {
-template <auto V> struct G {};
-
-template <class T> struct S {
- template <auto V> void f() {
- G<V> x;
- }
- template <auto *PV> void f2() {
- G<PV> x;
- }
- template <decltype(auto) V> void f3() {
- G<V> x;
- }
-};
-
-template <auto *PV> struct I {};
-
-template <class T> struct K {
- template <auto *PV> void f() {
- I<PV> x;
- }
- template <auto V> void f2() {
- I<V> x;
- }
- template <decltype(auto) V> void f3() {
- I<V> x;
- }
-};
-
-template <decltype(auto)> struct L {};
-template <class T> struct M {
- template <auto *PV> void f() {
- L<PV> x;
- }
- template <auto V> void f() {
- L<V> x;
- }
- template <decltype(auto) V> void f() {
- L<V> x;
- }
-};
-}
-
-namespace PR42362 {
- template<auto ...A> struct X { struct Y; void f(int...[A]); };
- template<auto ...A> struct X<A...>::Y {};
- template<auto ...A> void X<A...>::f(int...[A]) {}
- void f() { X<1, 2>::Y y; X<1, 2>().f(0, 0); }
-
- template<typename, auto...> struct Y;
- template<auto ...A> struct Y<int, A...> {};
- Y<int, 1, 2, 3> y;
-
- template<auto (&...F)()> struct Z { struct Q; };
- template<auto (&...F)()> struct Z<F...>::Q {};
- Z<f, f, f>::Q q;
-}
-
-namespace QualConv {
- int *X;
- template<const int *const *P> void f() {
- using T = decltype(P);
- using T = const int* const*;
- }
- template void f<&X>();
-
- template<const int *const &R> void g() {
- using T = decltype(R);
- using T = const int *const &;
- }
- template void g<(const int *const&)X>();
-}
-
-namespace FunctionConversion {
- struct a { void c(char *) noexcept; };
- template<void (a::*f)(char*)> void g() {
- using T = decltype(f);
- using T = void (a::*)(char*); // (not 'noexcept')
- }
- template void g<&a::c>();
-
- void c() noexcept;
- template<void (*p)()> void h() {
- using T = decltype(p);
- using T = void (*)(); // (not 'noexcept')
- }
- template void h<&c>();
-}
-
-namespace VoidPtr {
- // Note, this is an extension in C++17 but valid in C++20.
- template<void *P> void f() {
- using T = decltype(P);
- using T = void*;
- }
- int n;
- template void f<(void*)&n>();
-}
-
-namespace PR42108 {
- struct R {};
- struct S { constexpr S() {} constexpr S(R) {} };
- struct T { constexpr operator S() { return {}; } };
- template <const S &> struct A {};
- void f() {
- A<R{}>(); // expected-error {{would bind reference to a temporary}}
- A<S{}>(); // expected-error {{reference to temporary object}}
- A<T{}>(); // expected-error {{reference to temporary object}}
- }
-}
-
-namespace PR46637 {
- template<auto (*f)() -> auto> struct X { // expected-note {{here}}
- auto call() { return f(); }
- };
- X<nullptr> x; // expected-error {{incompatible initializer}}
-
- void *f();
- X<f> y;
- int n = y.call(); // expected-error {{cannot initialize a variable of type 'int' with an rvalue of type 'void *'}}
-}
-
-namespace PR48517 {
- template<const int *P> struct A { static constexpr const int *p = P; };
- template<typename T> auto make_nonconst() {
- static int n;
- return A<&n>();
- };
- using T = decltype(make_nonconst<int>()); // expected-note {{previous}}
- using U = decltype(make_nonconst<float>());
- static_assert(T::p != U::p);
- using T = U; // expected-error {{different types}}
-
- template<typename T> auto make_const() {
- static constexpr int n = 42;
- return A<&n>();
- };
- using V = decltype(make_const<int>()); // expected-note {{previous}}
- using W = decltype(make_const<float>());
- static_assert(*V::p == *W::p);
- static_assert(V::p != W::p);
- using V = W; // expected-error {{different types}}
-
- template<auto V> struct Q {
- using X = int;
- static_assert(V == "primary template should not be instantiated");
- };
- template<typename T> struct R {
- int n;
- constexpr int f() {
- return Q<&R::n>::X;
- }
- };
- 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;
-}
--- /dev/null
+// RUN: %clang_cc1 -fsyntax-only -verify -std=c++1z %s
+
+template<typename T, T val> struct A {};
+
+template<typename T, typename U> constexpr bool is_same = false; // expected-note +{{here}}
+template<typename T> constexpr bool is_same<T, T> = true;
+
+namespace String {
+ A<const char*, "test"> a; // expected-error {{pointer to subobject of string literal}}
+ A<const char (&)[5], "test"> b; // expected-error {{reference to string literal}}
+}
+
+namespace Array {
+ char arr[3];
+ char x;
+ A<const char*, arr> a;
+ A<const char(&)[3], arr> b;
+ A<const char*, &arr[0]> c;
+ A<const char*, &arr[1]> d; // expected-error {{refers to subobject '&arr[1]'}}
+ A<const char*, (&arr)[0]> e;
+ A<const char*, &x> f;
+ A<const char*, &(&x)[0]> g;
+ A<const char*, &(&x)[1]> h; // expected-error {{refers to subobject '&x + 1'}}
+ A<const char*, 0> i; // expected-error {{not allowed in a converted constant}}
+ A<const char*, nullptr> j;
+
+ extern char aub[];
+ A<char[], aub> k;
+}
+
+namespace Function {
+ void f();
+ void g() noexcept;
+ void h();
+ void h(int);
+ template<typename...T> void i(T...);
+ typedef A<void (*)(), f> a;
+ typedef A<void (*)(), &f> a;
+ typedef A<void (*)(), g> b;
+ typedef A<void (*)(), &g> b;
+ typedef A<void (*)(), h> c;
+ typedef A<void (*)(), &h> c;
+ typedef A<void (*)(), i> d;
+ typedef A<void (*)(), &i> d;
+ typedef A<void (*)(), i<>> d;
+ typedef A<void (*)(), i<int>> e; // expected-error {{is not implicitly convertible}}
+
+ typedef A<void (*)(), 0> x; // expected-error {{not allowed in a converted constant}}
+ typedef A<void (*)(), nullptr> y;
+}
+
+void Func() {
+ A<const char*, __func__> a; // expected-error {{pointer to subobject of predefined '__func__' variable}}
+}
+
+namespace LabelAddrDiff {
+ void f() {
+ a: b: A<int, __builtin_constant_p(true) ? (__INTPTR_TYPE__)&&b - (__INTPTR_TYPE__)&&a : 0> s; // expected-error {{label address difference}}
+ };
+}
+
+namespace Temp {
+ struct S { int n; };
+ constexpr S &addr(S &&s) { return s; }
+ A<S &, addr({})> a; // expected-error {{reference to temporary object}}
+ A<S *, &addr({})> b; // expected-error {{pointer to temporary object}}
+ A<int &, addr({}).n> c; // expected-error {{reference to subobject of temporary object}}
+ A<int *, &addr({}).n> d; // expected-error {{pointer to subobject of temporary object}}
+}
+
+namespace std { struct type_info; }
+
+namespace RTTI {
+ A<const std::type_info&, typeid(int)> a; // expected-error {{reference to type_info object}}
+ A<const std::type_info*, &typeid(int)> b; // expected-error {{pointer to type_info object}}
+}
+
+namespace PtrMem {
+ struct B { int b; };
+ struct C : B {};
+ struct D : B {};
+ struct E : C, D { int e; };
+
+ constexpr int B::*b = &B::b;
+ constexpr int C::*cb = b;
+ constexpr int D::*db = b;
+ constexpr int E::*ecb = cb; // expected-note +{{here}}
+ constexpr int E::*edb = db; // expected-note +{{here}}
+
+ constexpr int E::*e = &E::e;
+ constexpr int D::*de = (int D::*)e;
+ constexpr int C::*ce = (int C::*)e;
+ constexpr int B::*bde = (int B::*)de; // expected-note +{{here}}
+ constexpr int B::*bce = (int B::*)ce; // expected-note +{{here}}
+
+ // FIXME: This should all be accepted, but we don't yet have a representation
+ // nor mangling for this form of template argument.
+ using Ab = A<int B::*, b>;
+ using Ab = A<int B::*, &B::b>;
+ using Abce = A<int B::*, bce>; // expected-error {{not supported}}
+ using Abde = A<int B::*, bde>; // expected-error {{not supported}}
+ static_assert(!is_same<Ab, Abce>, ""); // expected-error {{undeclared}} expected-error {{must be a type}}
+ static_assert(!is_same<Ab, Abde>, ""); // expected-error {{undeclared}} expected-error {{must be a type}}
+ static_assert(!is_same<Abce, Abde>, ""); // expected-error 2{{undeclared}} expected-error {{must be a type}}
+ static_assert(is_same<Abce, A<int B::*, (int B::*)(int C::*)&E::e>>, ""); // expected-error {{undeclared}} expected-error {{not supported}}
+
+ using Ae = A<int E::*, e>;
+ using Ae = A<int E::*, &E::e>;
+ using Aecb = A<int E::*, ecb>; // expected-error {{not supported}}
+ using Aedb = A<int E::*, edb>; // expected-error {{not supported}}
+ static_assert(!is_same<Ae, Aecb>, ""); // expected-error {{undeclared}} expected-error {{must be a type}}
+ static_assert(!is_same<Ae, Aedb>, ""); // expected-error {{undeclared}} expected-error {{must be a type}}
+ static_assert(!is_same<Aecb, Aedb>, ""); // expected-error 2{{undeclared}} expected-error {{must be a type}}
+ static_assert(is_same<Aecb, A<int E::*, (int E::*)(int C::*)&B::b>>, ""); // expected-error {{undeclared}} expected-error {{not supported}}
+
+ using An = A<int E::*, nullptr>;
+ using A0 = A<int E::*, (int E::*)0>;
+ static_assert(is_same<An, A0>);
+}
+
+namespace DeduceDifferentType {
+ template<int N> struct A {};
+ template<long N> int a(A<N>); // expected-note {{does not have the same type}}
+ int a_imp = a(A<3>()); // expected-error {{no matching function}}
+ int a_exp = a<3>(A<3>());
+
+ template<decltype(nullptr)> struct B {};
+ template<int *P> int b(B<P>); // expected-error {{value of type 'int *' is not implicitly convertible to 'decltype(nullptr)'}}
+ int b_imp = b(B<nullptr>()); // expected-error {{no matching function}}
+ int b_exp = b<nullptr>(B<nullptr>()); // expected-error {{no matching function}}
+
+ struct X { constexpr operator int() { return 0; } } x;
+ template<X &> struct C {};
+ template<int N> int c(C<N>); // expected-error {{value of type 'int' is not implicitly convertible to 'DeduceDifferentType::X &'}}
+ int c_imp = c(C<x>()); // expected-error {{no matching function}}
+ int c_exp = c<x>(C<x>()); // expected-error {{no matching function}}
+
+ struct Z;
+ struct Y { constexpr operator Z&(); } y;
+ struct Z { constexpr operator Y&() { return y; } } z;
+ constexpr Y::operator Z&() { return z; }
+ template<Y &> struct D {};
+ template<Z &z> int d(D<z>); // expected-note {{couldn't infer template argument 'z'}}
+ int d_imp = d(D<y>()); // expected-error {{no matching function}}
+ int d_exp = d<y>(D<y>());
+}
+
+namespace DeclMatch {
+ template<typename T, T> int f();
+ template<typename T> class X { friend int f<T, 0>(); static int n; };
+ template<typename T, T> int f() { return X<T>::n; }
+ int k = f<int, 0>(); // ok, friend
+}
+
+namespace PR24921 {
+ enum E { e };
+ template<E> void f();
+ template<int> void f(int);
+ template<> void f<e>() {}
+}
+
+namespace Auto {
+ namespace Basic {
+ // simple auto
+ template<auto x> constexpr auto constant = x; // expected-note {{declared here}}
+
+ auto v1 = constant<5>;
+ auto v2 = constant<true>;
+ auto v3 = constant<'a'>;
+ auto v4 = constant<2.5>; // expected-error {{cannot have type 'double'}}
+
+ using T1 = decltype(v1);
+ using T1 = int;
+ using T2 = decltype(v2);
+ using T2 = bool;
+ using T3 = decltype(v3);
+ using T3 = char;
+
+ // pointers
+ template<auto v> class B { };
+ template<auto* p> class B<p> { }; // expected-note {{matches}}
+ template<auto** pp> class B<pp> { };
+ template<auto* p0> int &f(B<p0> b); // expected-note {{candidate}}
+ template<auto** pp0> float &f(B<pp0> b); // expected-note {{candidate}}
+
+ int a, *b = &a;
+ int &r = f(B<&a>());
+ float &s = f(B<&b>());
+
+ void type_affects_identity(B<&a>) {}
+ void type_affects_identity(B<(const int*)&a>) {}
+ void type_affects_identity(B<(void*)&a>) {}
+ void type_affects_identity(B<(const void*)&a>) {}
+
+ // pointers to members
+ template<typename T, auto *T::*p> struct B<p> {};
+ template<typename T, auto **T::*p> struct B<p> {};
+ template<typename T, auto *T::*p0> char &f(B<p0> b); // expected-note {{candidate}}
+ template<typename T, auto **T::*pp0> short &f(B<pp0> b); // expected-note {{candidate}}
+
+ struct X { int n; int *p; int **pp; typedef int a, b; };
+ auto t = f(B<&X::n>()); // expected-error {{no match}}
+ char &u = f(B<&X::p>());
+ short &v = f(B<&X::pp>());
+
+ struct Y : X {};
+ void type_affects_identity(B<&X::n>) {}
+ void type_affects_identity(B<(int Y::*)&X::n>) {} // FIXME: expected-error {{sorry}}
+ void type_affects_identity(B<(const int X::*)&X::n>) {}
+ void type_affects_identity(B<(const int Y::*)&X::n>) {} // FIXME: expected-error {{sorry}}
+
+ // A case where we need to do auto-deduction, and check whether the
+ // resulting dependent types match during partial ordering. These
+ // templates are not ordered due to the mismatching function parameter.
+ template<typename T, auto *(*f)(T, typename T::a)> struct B<f> {}; // expected-note {{matches}}
+ template<typename T, auto **(*f)(T, typename T::b)> struct B<f> {}; // expected-note {{matches}}
+ int **g(X, int);
+ B<&g> bg; // expected-error {{ambiguous}}
+ }
+
+ namespace Chained {
+ // chained template argument deduction
+ template<long n> struct C { };
+ template<class T> struct D;
+ template<class T, T n> struct D<C<n>>
+ {
+ using Q = T;
+ };
+ using DQ = long;
+ using DQ = D<C<short(2)>>::Q;
+
+ // chained template argument deduction from an array bound
+ template<typename T> struct E;
+ template<typename T, T n> struct E<int[n]> {
+ using Q = T;
+ };
+ using EQ = E<int[short(42)]>::Q;
+ using EQ = decltype(sizeof 0);
+
+ template<int N> struct F;
+ template<typename T, T N> int foo(F<N> *) = delete; // expected-note {{explicitly deleted}}
+ void foo(void *); // expected-note {{candidate function}}
+ void bar(F<0> *p) {
+ foo(p); // expected-error {{deleted function}}
+ }
+ }
+
+ namespace ArrayToPointer {
+ constexpr char s[] = "test";
+ template<const auto* p> struct S { };
+ S<s> p;
+
+ template<typename R, typename P, R F(P)> struct A {};
+ template<typename R, typename P, R F(P)> void x(A<R, P, F> a);
+ void g(int) { x(A<void, int, &g>()); }
+ }
+
+ namespace DecltypeAuto {
+ template<auto v> struct A { };
+ template<decltype(auto) v> struct DA { };
+ template<auto&> struct R { };
+
+ auto n = 0; // expected-note + {{declared here}}
+ A<n> a; // expected-error {{not a constant}} expected-note {{non-const variable 'n'}}
+ DA<n> da1; // expected-error {{not a constant}} expected-note {{non-const variable 'n'}}
+ DA<(n)> da2;
+ R<n> r;
+ }
+
+ namespace Decomposition {
+ // Types of deduced non-type template arguments must match exactly, so
+ // partial ordering fails in both directions here.
+ template<auto> struct Any;
+ template<int N> struct Any<N> { typedef int Int; }; // expected-note 3{{match}}
+ template<short N> struct Any<N> { typedef int Short; }; // expected-note 3{{match}}
+ Any<0>::Int is_int; // expected-error {{ambiguous}}
+ Any<(short)0>::Short is_short; // expected-error {{ambiguous}}
+ Any<(char)0>::Short is_char; // expected-error {{ambiguous}}
+
+ template<int, auto> struct NestedAny;
+ template<auto N> struct NestedAny<0, N>; // expected-note 3{{match}}
+ template<int N> struct NestedAny<0, N> { typedef int Int; }; // expected-note 3{{match}}
+ template<short N> struct NestedAny<0, N> { typedef int Short; }; // expected-note 3{{match}}
+ NestedAny<0, 0>::Int nested_int; // expected-error {{ambiguous}}
+ NestedAny<0, (short)0>::Short nested_short; // expected-error {{ambiguous}}
+ NestedAny<0, (char)0>::Short nested_char; // expected-error {{ambiguous}}
+
+ double foo(int, bool);
+ template<auto& f> struct fn_result_type;
+
+ template<class R, class... Args, R (& f)(Args...)>
+ struct fn_result_type<f>
+ {
+ using type = R;
+ };
+
+ using R1 = fn_result_type<foo>::type;
+ using R1 = double;
+
+ template<int, auto &f> struct fn_result_type_partial_order;
+ template<auto &f> struct fn_result_type_partial_order<0, f>;
+ template<class R, class... Args, R (& f)(Args...)>
+ struct fn_result_type_partial_order<0, f> {};
+ fn_result_type_partial_order<0, foo> frtpo;
+ }
+
+ namespace Variadic {
+ template<auto... vs> struct value_list { };
+
+ using size_t = decltype(sizeof 0);
+ template<size_t n, class List> struct nth_element;
+ template<size_t n, class List> constexpr auto nth_element_v = nth_element<n, List>::value;
+
+ template<size_t n, auto v0, auto... vs>
+ struct nth_element<n, value_list<v0, vs...>>
+ {
+ static constexpr auto value = nth_element<n - 1, value_list<vs...>>::value;
+ };
+ template<auto v0, auto... vs>
+ struct nth_element<0, value_list<v0, vs...>>
+ {
+ static constexpr auto value = v0;
+ };
+
+ static_assert(nth_element_v<2, value_list<'a', 27U, false>> == false, "value mismatch");
+ }
+}
+
+namespace Nested {
+ template<typename T> struct A {
+ template<auto X> struct B;
+ template<auto *P> struct B<P>;
+ template<auto **P> struct B<P> { using pointee = decltype(+**P); };
+ template<auto (*P)(T)> struct B<P> { using param = T; };
+ template<typename U, auto (*P)(T, U)> struct B<P> { using param2 = U; };
+ };
+
+ using Int = int;
+
+ int *n;
+ using Int = A<int>::B<&n>::pointee;
+
+ void f(int);
+ using Int = A<int>::B<&f>::param;
+
+ void g(int, int);
+ using Int = A<int>::B<&g>::param2;
+}
+
+namespace rdar41852459 {
+template <auto V> struct G {};
+
+template <class T> struct S {
+ template <auto V> void f() {
+ G<V> x;
+ }
+ template <auto *PV> void f2() {
+ G<PV> x;
+ }
+ template <decltype(auto) V> void f3() {
+ G<V> x;
+ }
+};
+
+template <auto *PV> struct I {};
+
+template <class T> struct K {
+ template <auto *PV> void f() {
+ I<PV> x;
+ }
+ template <auto V> void f2() {
+ I<V> x;
+ }
+ template <decltype(auto) V> void f3() {
+ I<V> x;
+ }
+};
+
+template <decltype(auto)> struct L {};
+template <class T> struct M {
+ template <auto *PV> void f() {
+ L<PV> x;
+ }
+ template <auto V> void f() {
+ L<V> x;
+ }
+ template <decltype(auto) V> void f() {
+ L<V> x;
+ }
+};
+}
+
+namespace PR42362 {
+ template<auto ...A> struct X { struct Y; void f(int...[A]); };
+ template<auto ...A> struct X<A...>::Y {};
+ template<auto ...A> void X<A...>::f(int...[A]) {}
+ void f() { X<1, 2>::Y y; X<1, 2>().f(0, 0); }
+
+ template<typename, auto...> struct Y;
+ template<auto ...A> struct Y<int, A...> {};
+ Y<int, 1, 2, 3> y;
+
+ template<auto (&...F)()> struct Z { struct Q; };
+ template<auto (&...F)()> struct Z<F...>::Q {};
+ Z<f, f, f>::Q q;
+}
+
+namespace QualConv {
+ int *X;
+ template<const int *const *P> void f() {
+ using T = decltype(P);
+ using T = const int* const*;
+ }
+ template void f<&X>();
+
+ template<const int *const &R> void g() {
+ using T = decltype(R);
+ using T = const int *const &;
+ }
+ template void g<(const int *const&)X>();
+}
+
+namespace FunctionConversion {
+ struct a { void c(char *) noexcept; };
+ template<void (a::*f)(char*)> void g() {
+ using T = decltype(f);
+ using T = void (a::*)(char*); // (not 'noexcept')
+ }
+ template void g<&a::c>();
+
+ void c() noexcept;
+ template<void (*p)()> void h() {
+ using T = decltype(p);
+ using T = void (*)(); // (not 'noexcept')
+ }
+ template void h<&c>();
+}
+
+namespace VoidPtr {
+ // Note, this is an extension in C++17 but valid in C++20.
+ template<void *P> void f() {
+ using T = decltype(P);
+ using T = void*;
+ }
+ int n;
+ template void f<(void*)&n>();
+}
+
+namespace PR42108 {
+ struct R {};
+ struct S { constexpr S() {} constexpr S(R) {} };
+ struct T { constexpr operator S() { return {}; } };
+ template <const S &> struct A {};
+ void f() {
+ A<R{}>(); // expected-error {{would bind reference to a temporary}}
+ A<S{}>(); // expected-error {{reference to temporary object}}
+ A<T{}>(); // expected-error {{reference to temporary object}}
+ }
+}
+
+namespace PR46637 {
+ template<auto (*f)() -> auto> struct X { // expected-note {{here}}
+ auto call() { return f(); }
+ };
+ X<nullptr> x; // expected-error {{incompatible initializer}}
+
+ void *f();
+ X<f> y;
+ int n = y.call(); // expected-error {{cannot initialize a variable of type 'int' with an rvalue of type 'void *'}}
+}
+
+namespace PR48517 {
+ template<const int *P> struct A { static constexpr const int *p = P; };
+ template<typename T> auto make_nonconst() {
+ static int n;
+ return A<&n>();
+ };
+ using T = decltype(make_nonconst<int>()); // expected-note {{previous}}
+ using U = decltype(make_nonconst<float>());
+ static_assert(T::p != U::p);
+ using T = U; // expected-error {{different types}}
+
+ template<typename T> auto make_const() {
+ static constexpr int n = 42;
+ return A<&n>();
+ };
+ using V = decltype(make_const<int>()); // expected-note {{previous}}
+ using W = decltype(make_const<float>());
+ static_assert(*V::p == *W::p);
+ static_assert(V::p != W::p);
+ using V = W; // expected-error {{different types}}
+
+ template<auto V> struct Q {
+ using X = int;
+ static_assert(V == "primary template should not be instantiated");
+ };
+ template<typename T> struct R {
+ int n;
+ constexpr int f() {
+ return Q<&R::n>::X;
+ }
+ };
+ template<> struct Q<&R<int>::n> { static constexpr int X = 1; };
+ static_assert(R<int>().f() == 1);
+}
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>();
-}