35 changes: 18 additions & 17 deletions clang/lib/AST/Expr.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -416,9 +416,12 @@ DeclRefExpr::DeclRefExpr(const ASTContext &Ctx,
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);
Expand Down Expand Up @@ -1521,8 +1524,16 @@ MemberExpr *MemberExpr::Create(
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 =
Expand All @@ -1535,26 +1546,16 @@ MemberExpr *MemberExpr::Create(
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;
Expand Down
11 changes: 7 additions & 4 deletions clang/lib/AST/ExprCXX.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -433,8 +433,9 @@ OverloadExpr::OverloadExpr(StmtClass SC, const ASTContext &Context,
}

if (TemplateArgs) {
auto Deps = TemplateArgumentDependence::None;
getTrailingASTTemplateKWAndArgsInfo()->initializeFrom(
TemplateKWLoc, *TemplateArgs, getTrailingTemplateArgumentLoc());
TemplateKWLoc, *TemplateArgs, getTrailingTemplateArgumentLoc(), Deps);
} else if (TemplateKWLoc.isValid()) {
getTrailingASTTemplateKWAndArgsInfo()->initializeFrom(TemplateKWLoc);
}
Expand Down Expand Up @@ -463,8 +464,9 @@ DependentScopeDeclRefExpr::DependentScopeDeclRefExpr(
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);
Expand Down Expand Up @@ -1374,9 +1376,10 @@ CXXDependentScopeMemberExpr::CXXDependentScopeMemberExpr(
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);
Expand Down
101 changes: 42 additions & 59 deletions clang/lib/AST/ExprConstant.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1819,8 +1819,7 @@ 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,
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,
Expand Down Expand Up @@ -2108,17 +2107,15 @@ static bool CheckEvaluationResult(CheckEvaluationResultKind CERK,
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
/// can fold this expression, whether or not it's a constant expression.
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();
Expand Down Expand Up @@ -2203,8 +2200,6 @@ 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())
Expand Down Expand Up @@ -2235,9 +2230,6 @@ 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()) {
Expand All @@ -2250,8 +2242,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, Dependent))
Info, MTE->getExprLoc(), TempType, *V,
Kind, SourceLocation(), CheckedTemps))
return false;
}
}
Expand Down Expand Up @@ -2280,15 +2272,13 @@ 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, 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()) {
Expand Down Expand Up @@ -2337,8 +2327,7 @@ static bool CheckEvaluationResult(CheckEvaluationResultKind CERK,
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;
Expand All @@ -2360,20 +2349,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, 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();
Expand All @@ -2382,7 +2371,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, Dependent))
BS.getBeginLoc(), CheckedTemps))
return false;
++BaseIndex;
}
Expand All @@ -2392,8 +2381,8 @@ static bool CheckEvaluationResult(CheckEvaluationResultKind CERK,
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;
}
}
Expand All @@ -2403,13 +2392,12 @@ static bool CheckEvaluationResult(CheckEvaluationResultKind CERK,
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;
Expand All @@ -2420,26 +2408,25 @@ 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, 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
Expand Down Expand Up @@ -11111,9 +11098,7 @@ static bool EvaluateBuiltinConstantP(EvalInfo &Info, const Expr *Arg) {
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;
}
Expand Down Expand Up @@ -11415,8 +11400,7 @@ 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;
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,
Expand Down Expand Up @@ -12845,9 +12829,8 @@ 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, Dependent);
ConstantExprKind::Normal);
};
return EvaluateComparisonBinaryOperator(Info, E, OnSuccess, [&]() {
return ExprEvaluatorBaseTy::VisitBinCmp(E);
Expand Down Expand Up @@ -14611,8 +14594,7 @@ 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,
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))
Expand All @@ -14637,7 +14619,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, Dependent) &&
ConstantExprKind::Normal) &&
CheckMemoryLeaks(Info);
}

Expand Down Expand Up @@ -14683,7 +14665,7 @@ static bool EvaluateAsRValue(const Expr *E, Expr::EvalResult &Result,
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,
Expand Down Expand Up @@ -14793,9 +14775,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, Result.Dependent))
!CheckLValueConstantExpression(Info, getExprLoc(),
Ctx.getLValueReferenceType(getType()), LV,
ConstantExprKind::Normal, CheckedTemps))
return false;

LV.moveInto(Result.Val);
Expand Down Expand Up @@ -14854,7 +14836,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.Dependent))
Result.Val, Kind))
return false;
if (!CheckMemoryLeaks(Info))
return false;
Expand Down Expand Up @@ -14918,9 +14900,8 @@ 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, Dependent) &&
ConstantExprKind::Normal) &&
CheckMemoryLeaks(Info);
}

Expand Down Expand Up @@ -14987,7 +14968,7 @@ APSInt Expr::EvaluateKnownConstIntCheckOverflow(
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");
Expand All @@ -14999,10 +14980,13 @@ void Expr::EvaluateForOverflow(const ASTContext &Ctx) const {
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 {
Expand Down Expand Up @@ -15552,9 +15536,8 @@ 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, 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;
Expand Down
48 changes: 4 additions & 44 deletions clang/lib/AST/ItaniumMangle.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -2582,11 +2582,6 @@ void CXXNameMangler::mangleType(QualType T) {
// instantation-dependent qualifiers. See
// https://github.com/itanium-cxx-abi/cxx-abi/issues/114.

// Don't desugar instantiation-dependent decltype / typeof types. We need
// to mangle the expression as written.
if (isa<DecltypeType, TypeOfType>(T))
break;

QualType Desugared
= T.getSingleStepDesugaredType(Context.getASTContext());
if (Desugared == T)
Expand Down Expand Up @@ -4079,28 +4074,10 @@ void CXXNameMangler::mangleExpression(const Expr *E, unsigned Arity) {
mangleExpression(cast<CXXStdInitializerListExpr>(E)->getSubExpr(), Arity);
break;

case Expr::SubstNonTypeTemplateParmExprClass: {
// Mangle a substituted parameter the same way we mangle the template
// argument.
// As proposed in https://github.com/itanium-cxx-abi/cxx-abi/issues/111.
auto *SNTTPE = cast<SubstNonTypeTemplateParmExpr>(E);
if (auto *CE = dyn_cast<ConstantExpr>(SNTTPE->getReplacement())) {
// Pull out the constant value and mangle it as a template argument.
QualType ParamType = SNTTPE->getParameterType(Context.getASTContext());
if (CE->hasAPValueResult())
mangleValueInTemplateArg(ParamType, CE->getResultAsAPValue(), false,
/*NeedExactType=*/true);
else
mangleValueInTemplateArg(ParamType, CE->getAPValueResult(), false,
/*NeedExactType=*/true);
} else {
// The remaining cases all happen to be substituted with expressions that
// mangle the same as a corresponding template argument anyway.
mangleExpression(cast<SubstNonTypeTemplateParmExpr>(E)->getReplacement(),
Arity);
}
case Expr::SubstNonTypeTemplateParmExprClass:
mangleExpression(cast<SubstNonTypeTemplateParmExpr>(E)->getReplacement(),
Arity);
break;
}

case Expr::UserDefinedLiteralClass:
// We follow g++'s approach of mangling a UDL as a call to the literal
Expand Down Expand Up @@ -5057,10 +5034,6 @@ void CXXNameMangler::mangleTemplateArg(TemplateArgument A, bool NeedExactType) {
mangleNullPointer(A.getNullPtrType());
break;
}
case TemplateArgument::UncommonValue:
mangleValueInTemplateArg(A.getUncommonValueType(), A.getAsUncommonValue(),
/*TopLevel=*/true, NeedExactType);
break;
case TemplateArgument::Pack: {
// <template-arg> ::= J <template-arg>* E
Out << 'J';
Expand Down Expand Up @@ -5395,20 +5368,7 @@ void CXXNameMangler::mangleValueInTemplateArg(QualType T, const APValue &V,
Out << "plcvPcad";
Kind = Offset;
} else {
// Clang 11 and before mangled an array subject to array-to-pointer decay
// as if it were the declaration itself.
bool IsArrayToPointerDecayMangledAsDecl = false;
if (TopLevel && Ctx.getLangOpts().getClangABICompat() <=
LangOptions::ClangABI::Ver11) {
QualType BType = B.getType();
IsArrayToPointerDecayMangledAsDecl =
BType->isArrayType() && V.getLValuePath().size() == 1 &&
V.getLValuePath()[0].getAsArrayIndex() == 0 &&
Ctx.hasSimilarType(T, Ctx.getDecayedType(BType));
}

if ((!V.getLValuePath().empty() || V.isLValueOnePastTheEnd()) &&
!IsArrayToPointerDecayMangledAsDecl) {
if (!V.getLValuePath().empty() || V.isLValueOnePastTheEnd()) {
NotPrimaryExpr();
// A final conversion to the template parameter's type is usually
// folded into the 'so' mangling, but we can't do that for 'void*'
Expand Down
11 changes: 0 additions & 11 deletions clang/lib/AST/MicrosoftMangle.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1575,17 +1575,6 @@ void MicrosoftCXXNameMangler::mangleTemplateArg(const TemplateDecl *TD,
cast<NonTypeTemplateParmDecl>(Parm), T);
break;
}
case TemplateArgument::UncommonValue:
Out << "$";
if (cast<NonTypeTemplateParmDecl>(Parm)
->getType()
->getContainedDeducedType()) {
Out << "M";
mangleType(TA.getNonTypeTemplateArgumentType(), SourceRange(), QMM_Drop);
}
mangleTemplateArgValue(TA.getUncommonValueType(), TA.getAsUncommonValue(),
/*WithScalarType=*/false);
break;
case TemplateArgument::Expression:
mangleExpression(TA.getAsExpr(), cast<NonTypeTemplateParmDecl>(Parm));
break;
Expand Down
2 changes: 0 additions & 2 deletions clang/lib/AST/ODRHash.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -169,8 +169,6 @@ void ODRHash::AddTemplateArgument(TemplateArgument TA) {
break;
case TemplateArgument::NullPtr:
case TemplateArgument::Integral:
case TemplateArgument::UncommonValue:
// FIXME: Include a representation of these arguments.
break;
case TemplateArgument::Template:
case TemplateArgument::TemplateExpansion:
Expand Down
6 changes: 0 additions & 6 deletions clang/lib/AST/StmtProfile.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -2208,12 +2208,6 @@ void StmtProfiler::VisitTemplateArgument(const TemplateArgument &Arg) {
Arg.getAsIntegral().Profile(ID);
break;

case TemplateArgument::UncommonValue:
VisitType(Arg.getUncommonValueType());
// FIXME: Do we need to recursively decompose this ourselves?
Arg.getAsUncommonValue().Profile(ID);
break;

case TemplateArgument::Expression:
Visit(Arg.getAsExpr());
break;
Expand Down
127 changes: 36 additions & 91 deletions clang/lib/AST/TemplateBase.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -84,8 +84,8 @@ static void printIntegral(const TemplateArgument &TemplArg,
// TemplateArgument Implementation
//===----------------------------------------------------------------------===//

TemplateArgument::TemplateArgument(const ASTContext &Ctx,
const llvm::APSInt &Value, QualType Type) {
TemplateArgument::TemplateArgument(ASTContext &Ctx, const llvm::APSInt &Value,
QualType Type) {
Integer.Kind = Integral;
// Copy the APSInt value into our decomposed form.
Integer.BitWidth = Value.getBitWidth();
Expand All @@ -103,45 +103,6 @@ TemplateArgument::TemplateArgument(const ASTContext &Ctx,
Integer.Type = Type.getAsOpaquePtr();
}

static const ValueDecl *getAsSimpleValueDeclRef(const ASTContext &Ctx,
QualType T, const APValue &V) {
// Pointers to members are relatively easy.
if (V.isMemberPointer() && V.getMemberPointerPath().empty())
return V.getMemberPointerDecl();

// We model class non-type template parameters as their template parameter
// object declaration.
if (V.isStruct() || V.isUnion())
return Ctx.getTemplateParamObjectDecl(T, V);

// Pointers and references with an empty path use the special 'Declaration'
// representation.
if (V.isLValue() && V.hasLValuePath() &&
V.getLValuePath().empty() && !V.isLValueOnePastTheEnd())
return V.getLValueBase().dyn_cast<const ValueDecl *>();

// Everything else uses the 'uncommon' representation.
return nullptr;
}

TemplateArgument::TemplateArgument(const ASTContext &Ctx, QualType Type,
const APValue &V) {
if (Type->isIntegralOrEnumerationType() && V.isInt())
*this = TemplateArgument(Ctx, V.getInt(), Type);
else if ((V.isLValue() && V.isNullPointer()) ||
(V.isMemberPointer() && !V.getMemberPointerDecl()))
*this = TemplateArgument(Type, /*isNullPtr=*/true);
else if (const ValueDecl *VD = getAsSimpleValueDeclRef(Ctx, Type, V))
// FIXME: The Declaration form should expose a const ValueDecl*.
*this = TemplateArgument(const_cast<ValueDecl*>(VD), Type);
else {
Value.Kind = UncommonValue;
Value.Value = new (Ctx) APValue(V);
Ctx.addDestruction(Value.Value);
Value.Type = Type.getAsOpaquePtr();
}
}

TemplateArgument
TemplateArgument::CreatePackCopy(ASTContext &Context,
ArrayRef<TemplateArgument> Args) {
Expand Down Expand Up @@ -170,18 +131,25 @@ 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:
case UncommonValue:
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:
Expand All @@ -205,7 +173,6 @@ bool TemplateArgument::isPackExpansion() const {
case Null:
case Declaration:
case Integral:
case UncommonValue:
case Pack:
case Template:
case NullPtr:
Expand Down Expand Up @@ -256,9 +223,6 @@ QualType TemplateArgument::getNonTypeTemplateArgumentType() const {

case TemplateArgument::NullPtr:
return getNullPtrType();

case TemplateArgument::UncommonValue:
return getUncommonValueType();
}

llvm_unreachable("Invalid TemplateArgument Kind!");
Expand Down Expand Up @@ -303,13 +267,8 @@ void TemplateArgument::Profile(llvm::FoldingSetNodeID &ID,
}

case Integral:
getIntegralType().Profile(ID);
getAsIntegral().Profile(ID);
break;

case UncommonValue:
getUncommonValueType().Profile(ID);
getAsUncommonValue().Profile(ID);
getIntegralType().Profile(ID);
break;

case Expression:
Expand Down Expand Up @@ -345,16 +304,6 @@ bool TemplateArgument::structurallyEquals(const TemplateArgument &Other) const {
return getIntegralType() == Other.getIntegralType() &&
getAsIntegral() == Other.getAsIntegral();

case UncommonValue: {
if (getUncommonValueType() != Other.getUncommonValueType())
return false;

llvm::FoldingSetNodeID A, B;
getAsUncommonValue().Profile(A);
Other.getAsUncommonValue().Profile(B);
return A == B;
}

case Pack:
if (Args.NumArgs != Other.Args.NumArgs) return false;
for (unsigned I = 0, E = Args.NumArgs; I != E; ++I)
Expand All @@ -381,7 +330,6 @@ TemplateArgument TemplateArgument::getPackExpansionPattern() const {

case Declaration:
case Integral:
case UncommonValue:
case Pack:
case Null:
case Template:
Expand Down Expand Up @@ -421,10 +369,6 @@ void TemplateArgument::print(const PrintingPolicy &Policy,
break;
}

case UncommonValue:
getAsUncommonValue().printPretty(Out, Policy, getUncommonValueType());
break;

case NullPtr:
Out << "nullptr";
break;
Expand Down Expand Up @@ -507,9 +451,6 @@ SourceRange TemplateArgumentLoc::getSourceRange() const {
case TemplateArgument::Integral:
return getSourceIntegralExpression()->getSourceRange();

case TemplateArgument::UncommonValue:
return getSourceUncommonValueExpression()->getSourceRange();

case TemplateArgument::Pack:
case TemplateArgument::Null:
return SourceRange();
Expand Down Expand Up @@ -538,18 +479,6 @@ static const T &DiagTemplateArg(const T &DB, const TemplateArgument &Arg) {
case TemplateArgument::Integral:
return DB << Arg.getAsIntegral().toString(10);

case TemplateArgument::UncommonValue: {
// FIXME: We're guessing at LangOptions!
SmallString<32> Str;
llvm::raw_svector_ostream OS(Str);
LangOptions LangOpts;
LangOpts.CPlusPlus = true;
PrintingPolicy Policy(LangOpts);
Arg.getAsUncommonValue().printPretty(OS, Policy,
Arg.getUncommonValueType());
return DB << OS.str();
}

case TemplateArgument::Template:
return DB << Arg.getAsTemplate();

Expand Down Expand Up @@ -615,8 +544,8 @@ ASTTemplateArgumentListInfo::ASTTemplateArgumentListInfo(
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(
Expand All @@ -626,8 +555,9 @@ 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) {
Expand All @@ -638,6 +568,21 @@ 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);
Expand Down
20 changes: 14 additions & 6 deletions clang/lib/AST/Type.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -125,7 +125,8 @@ ArrayType::ArrayType(TypeClass tc, QualType et, QualType can,
// template<int ...N> int arr[] = {N...};
: Type(tc, can,
et->getDependence() |
(sz ? toTypeDependence(sz->getDependence())
(sz ? toTypeDependence(
turnValueToTypeDependence(sz->getDependence()))
: TypeDependence::None) |
(tc == VariableArray ? TypeDependence::VariablyModified
: TypeDependence::None) |
Expand Down Expand Up @@ -3395,8 +3396,9 @@ QualType MacroQualifiedType::getModifiedType() const {

TypeOfExprType::TypeOfExprType(Expr *E, QualType can)
: Type(TypeOfExpr, can,
typeToTypeDependence(E->getDependence(),
E->getType()->getDependence())),
toTypeDependence(E->getDependence()) |
(E->getType()->getDependence() &
TypeDependence::VariablyModified)),
TOExpr(E) {}

bool TypeOfExprType::isSugared() const {
Expand All @@ -3416,12 +3418,18 @@ void DependentTypeOfExprType::Profile(llvm::FoldingSetNodeID &ID,
}

DecltypeType::DecltypeType(Expr *E, QualType underlyingType, QualType can)
// C++11 [temp.type]p2: "If an expression e involves a template parameter,
// decltype(e) denotes a unique dependent type." Hence a decltype type is
// type-dependent even if its expression is only instantiation-dependent.
: Type(Decltype, can,
typeToTypeDependence(E->getDependence(),
E->getType()->getDependence())),
toTypeDependence(E->getDependence()) |
(E->isInstantiationDependent() ? TypeDependence::Dependent
: TypeDependence::None) |
(E->getType()->getDependence() &
TypeDependence::VariablyModified)),
E(E), UnderlyingType(underlyingType) {}

bool DecltypeType::isSugared() const { return !E->isTypeDependent(); }
bool DecltypeType::isSugared() const { return !E->isInstantiationDependent(); }

QualType DecltypeType::desugar() const {
if (isSugared())
Expand Down
1 change: 0 additions & 1 deletion clang/lib/AST/TypeLoc.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -562,7 +562,6 @@ void TemplateSpecializationTypeLoc::initializeArgLocs(ASTContext &Context,
case TemplateArgument::Integral:
case TemplateArgument::Declaration:
case TemplateArgument::NullPtr:
case TemplateArgument::UncommonValue:
ArgInfos[i] = TemplateArgumentLocInfo();
break;

Expand Down
8 changes: 0 additions & 8 deletions clang/lib/CodeGen/CGDebugInfo.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1953,14 +1953,6 @@ CGDebugInfo::CollectTemplateParams(const TemplateParameterList *TPList,
TemplateParams.push_back(DBuilder.createTemplateValueParameter(
TheCU, Name, TTy, defaultParameter, V));
} break;
case TemplateArgument::UncommonValue: {
QualType T = TA.getUncommonValueType();
llvm::DIType *TTy = getOrCreateType(T, Unit);
llvm::Constant *V = ConstantEmitter(CGM).emitAbstract(
SourceLocation(), TA.getAsUncommonValue(), T);
TemplateParams.push_back(DBuilder.createTemplateValueParameter(
TheCU, Name, TTy, defaultParameter, V));
} break;
case TemplateArgument::Template:
TemplateParams.push_back(DBuilder.createTemplateTemplateParameter(
TheCU, Name, nullptr,
Expand Down
10 changes: 5 additions & 5 deletions clang/lib/CodeGen/CGExprConstant.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1366,11 +1366,11 @@ llvm::Constant *ConstantEmitter::tryEmitConstantExpr(const ConstantExpr *CE) {
if (!CE->hasAPValueResult())
return nullptr;
const Expr *Inner = CE->getSubExpr()->IgnoreImplicit();
QualType RetType = Inner->getType();
if (Inner->isLValue())
RetType = CGF->getContext().getLValueReferenceType(RetType);
else if (Inner->isXValue())
RetType = CGF->getContext().getRValueReferenceType(RetType);
QualType RetType;
if (auto *Call = dyn_cast<CallExpr>(Inner))
RetType = Call->getCallReturnType(CGF->getContext());
else if (auto *Ctor = dyn_cast<CXXConstructExpr>(Inner))
RetType = Ctor->getType();
llvm::Constant *Res =
emitAbstract(CE->getBeginLoc(), CE->getAPValueResult(), RetType);
return Res;
Expand Down
4 changes: 0 additions & 4 deletions clang/lib/Index/USRGeneration.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -983,10 +983,6 @@ void USRGenerator::VisitTemplateArgument(const TemplateArgument &Arg) {
VisitType(Arg.getIntegralType());
Out << Arg.getAsIntegral();
break;

case TemplateArgument::UncommonValue:
// FIXME: Visit value.
break;
}
}

Expand Down
1 change: 0 additions & 1 deletion clang/lib/Sema/SemaLookup.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -2657,7 +2657,6 @@ addAssociatedClassesAndNamespaces(AssociatedLookup &Result,
case TemplateArgument::Integral:
case TemplateArgument::Expression:
case TemplateArgument::NullPtr:
case TemplateArgument::UncommonValue:
// [Note: non-type template arguments do not contribute to the set of
// associated namespaces. ]
break;
Expand Down
19 changes: 5 additions & 14 deletions clang/lib/Sema/SemaOverload.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -5619,8 +5619,7 @@ static ExprResult CheckConvertedConstantExpression(Sema &S, Expr *From,
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");

Expand Down Expand Up @@ -5744,8 +5743,6 @@ static ExprResult CheckConvertedConstantExpression(Sema &S, Expr *From,

if (Result.get()->isValueDependent()) {
Value = APValue();
if (ValueDependent)
*ValueDependent = true;
return Result;
}

Expand All @@ -5769,14 +5766,10 @@ 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.
Expr *E = Result.get();
if (!isa<ConstantExpr>(E))
E = ConstantExpr::Create(S.Context, Result.get(), Value);
Expr *E = ConstantExpr::Create(S.Context, Result.get(), Value);
if (ReturnPreNarrowingValue)
Value = std::move(PreNarrowingValue);
return E;
Expand All @@ -5803,10 +5796,9 @@ static ExprResult CheckConvertedConstantExpression(Sema &S, Expr *From,

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,
Expand All @@ -5816,8 +5808,7 @@ 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;
Expand Down
232 changes: 87 additions & 145 deletions clang/lib/Sema/SemaTemplate.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -4086,7 +4086,6 @@ static bool isTemplateArgumentTemplateParameter(
case TemplateArgument::NullPtr:
case TemplateArgument::Integral:
case TemplateArgument::Declaration:
case TemplateArgument::UncommonValue:
case TemplateArgument::Pack:
case TemplateArgument::TemplateExpansion:
return false;
Expand Down Expand Up @@ -5420,7 +5419,6 @@ bool Sema::CheckTemplateArgument(NamedDecl *Param,

case TemplateArgument::Declaration:
case TemplateArgument::Integral:
case TemplateArgument::UncommonValue:
case TemplateArgument::NullPtr:
// We've already checked this template argument, so just copy
// it to the list of converted arguments.
Expand Down Expand Up @@ -5567,10 +5565,11 @@ bool Sema::CheckTemplateArgument(NamedDecl *Param,
return true;

case TemplateArgument::Declaration:
llvm_unreachable("Declaration argument with template template parameter");
case TemplateArgument::Integral:
case TemplateArgument::UncommonValue:
llvm_unreachable("Integral argument with template template parameter");
case TemplateArgument::NullPtr:
llvm_unreachable("non-type argument with template template parameter");
llvm_unreachable("Null pointer argument with template template parameter");

case TemplateArgument::Pack:
llvm_unreachable("Caller must expand template argument packs");
Expand Down Expand Up @@ -6621,12 +6620,6 @@ 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));
Expand All @@ -6641,6 +6634,8 @@ static bool CheckTemplateArgumentPointerToMember(Sema &S,
QualType ParamType,
Expr *&ResultArg,
TemplateArgument &Converted) {
bool Invalid = false;

Expr *Arg = ResultArg;
bool ObjCLifetimeConversion;

Expand All @@ -6656,7 +6651,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 (!ExtraParens) {
if (!Invalid && !ExtraParens) {
S.Diag(Arg->getBeginLoc(),
S.getLangOpts().CPlusPlus11
? diag::warn_cxx98_compat_template_arg_extra_parens
Expand Down Expand Up @@ -6685,8 +6680,13 @@ static bool CheckTemplateArgumentPointerToMember(Sema &S,
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;
}
}

Expand Down Expand Up @@ -6745,7 +6745,7 @@ static bool CheckTemplateArgumentPointerToMember(Sema &S,
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.
Expand Down Expand Up @@ -6922,24 +6922,49 @@ 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, &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;
}

// Prior to C++20, enforce restrictions on possible template argument
// values.
if (!getLangOpts().CPlusPlus20 && Value.isLValue()) {
// Convert the APValue to a TemplateArgument.
switch (Value.getKind()) {
case APValue::None:
assert(ParamType->isNullPtrType());
Converted = TemplateArgument(CanonParamType, /*isNullPtr*/true);
break;
case APValue::Indeterminate:
llvm_unreachable("result of constant evaluation should be initialized");
break;
case APValue::Int:
assert(ParamType->isIntegralOrEnumerationType());
Converted = TemplateArgument(Context, Value.getInt(), CanonParamType);
break;
case APValue::MemberPointer: {
assert(ParamType->isMemberPointerType());

// FIXME: We need TemplateArgument representation and mangling for these.
if (!Value.getMemberPointerPath().empty()) {
Diag(Arg->getBeginLoc(),
diag::err_template_arg_member_ptr_base_derived_not_supported)
<< Value.getMemberPointerDecl() << ParamType
<< Arg->getSourceRange();
return ExprError();
}

auto *VD = const_cast<ValueDecl*>(Value.getMemberPointerDecl());
Converted = VD ? TemplateArgument(VD, CanonParamType)
: TemplateArgument(CanonParamType, /*isNullPtr*/true);
break;
}
case APValue::LValue: {
// For a non-type template-parameter of pointer or reference type,
// the value of the constant expression shall not refer to
assert(ParamType->isPointerType() || ParamType->isReferenceType() ||
Expand All @@ -6955,7 +6980,8 @@ ExprResult Sema::CheckTemplateArgument(NonTypeTemplateParmDecl *Param,
<< Arg->getSourceRange();
return ExprError();
}
// -- a subobject [until C++20]
// -- a subobject
// FIXME: Until C++20
if (Value.hasLValuePath() && Value.getLValuePath().size() == 1 &&
VD && VD->getType()->isArrayType() &&
Value.getLValuePath()[0].getAsArrayIndex() == 0 &&
Expand All @@ -6973,12 +6999,29 @@ ExprResult Sema::CheckTemplateArgument(NonTypeTemplateParmDecl *Param,
"null reference should not be a constant expression");
assert((!VD || !ParamType->isNullPtrType()) &&
"non-null value of type nullptr_t?");
Converted = VD ? TemplateArgument(VD, CanonParamType)
: TemplateArgument(CanonParamType, /*isNullPtr*/true);
break;
}

if (Value.isAddrLabelDiff())
case APValue::Struct:
case APValue::Union:
// Get or create the corresponding template parameter object.
Converted = TemplateArgument(
Context.getTemplateParamObjectDecl(CanonParamType, Value),
CanonParamType);
break;
case APValue::AddrLabelDiff:
return Diag(StartLoc, diag::err_non_type_template_arg_addr_label_diff);
case APValue::FixedPoint:
case APValue::Float:
case APValue::ComplexInt:
case APValue::ComplexFloat:
case APValue::Vector:
case APValue::Array:
return Diag(StartLoc, diag::err_non_type_template_arg_unsupported)
<< ParamType;
}

Converted = TemplateArgument(Context, CanonParamType, Value);
return ArgResult.get();
}

Expand Down Expand Up @@ -7516,9 +7559,12 @@ Sema::BuildExpressionFromDeclTemplateArgument(const TemplateArgument &Arg,
/// This routine takes care of the mapping from an integral template
/// argument (which may have any integral type) to the appropriate
/// literal value.
static Expr *BuildExpressionFromIntegralTemplateArgumentValue(
Sema &S, QualType OrigT, const llvm::APSInt &Int, SourceLocation Loc) {
assert(OrigT->isIntegralOrEnumerationType());
ExprResult
Sema::BuildExpressionFromIntegralTemplateArgument(const TemplateArgument &Arg,
SourceLocation Loc) {
assert(Arg.getKind() == TemplateArgument::Integral &&
"Operation is only valid for integral template arguments");
QualType OrigT = Arg.getIntegralType();

// If this is an enum type that we're instantiating, we need to use an integer
// type the same size as the enumerator. We don't want to build an
Expand All @@ -7534,7 +7580,7 @@ static Expr *BuildExpressionFromIntegralTemplateArgumentValue(
CharacterLiteral::CharacterKind Kind;
if (T->isWideCharType())
Kind = CharacterLiteral::Wide;
else if (T->isChar8Type() && S.getLangOpts().Char8)
else if (T->isChar8Type() && getLangOpts().Char8)
Kind = CharacterLiteral::UTF8;
else if (T->isChar16Type())
Kind = CharacterLiteral::UTF16;
Expand All @@ -7543,133 +7589,29 @@ static Expr *BuildExpressionFromIntegralTemplateArgumentValue(
else
Kind = CharacterLiteral::Ascii;

E = new (S.Context) CharacterLiteral(Int.getZExtValue(), Kind, T, Loc);
E = new (Context) CharacterLiteral(Arg.getAsIntegral().getZExtValue(),
Kind, T, Loc);
} else if (T->isBooleanType()) {
E = new (S.Context) CXXBoolLiteralExpr(Int.getBoolValue(), T, Loc);
E = new (Context) CXXBoolLiteralExpr(Arg.getAsIntegral().getBoolValue(),
T, Loc);
} else if (T->isNullPtrType()) {
E = new (Context) CXXNullPtrLiteralExpr(Context.NullPtrTy, Loc);
} else {
E = IntegerLiteral::Create(S.Context, Int, T, Loc);
E = IntegerLiteral::Create(Context, Arg.getAsIntegral(), T, Loc);
}

if (OrigT->isEnumeralType()) {
// FIXME: This is a hack. We need a better way to handle substituted
// non-type template parameters.
E = CStyleCastExpr::Create(S.Context, OrigT, VK_RValue, CK_IntegralCast, E,
nullptr, S.CurFPFeatureOverrides(),
S.Context.getTrivialTypeSourceInfo(OrigT, Loc),
E = CStyleCastExpr::Create(Context, OrigT, VK_RValue, CK_IntegralCast, E,
nullptr, CurFPFeatureOverrides(),
Context.getTrivialTypeSourceInfo(OrigT, Loc),
Loc, Loc);
}

return E;
}

static Expr *BuildExpressionFromNonTypeTemplateArgumentValue(
Sema &S, QualType T, const APValue &Val, SourceLocation Loc) {
auto MakeInitList = [&] (ArrayRef<Expr*> Elts) -> Expr* {
auto *ILE = new (S.Context) InitListExpr(S.Context, Loc, Elts, Loc);
ILE->setType(T);
return ILE;
};

switch (Val.getKind()) {
case APValue::AddrLabelDiff:
// This cannot occur in a template argument at all.
case APValue::Array:
case APValue::Struct:
case APValue::Union:
// These can only occur within a template parameter object, which is
// represented as a TemplateArgument::Declaration.
llvm_unreachable("unexpected template argument value");

case APValue::Int:
return BuildExpressionFromIntegralTemplateArgumentValue(S, T, Val.getInt(),
Loc);

case APValue::Float:
return FloatingLiteral::Create(S.Context, Val.getFloat(), /*IsExact=*/true,
T, Loc);

case APValue::FixedPoint:
return FixedPointLiteral::CreateFromRawInt(
S.Context, Val.getFixedPoint().getValue(), T, Loc,
Val.getFixedPoint().getScale());

case APValue::ComplexInt: {
QualType ElemT = T->castAs<ComplexType>()->getElementType();
return MakeInitList({BuildExpressionFromIntegralTemplateArgumentValue(
S, ElemT, Val.getComplexIntReal(), Loc),
BuildExpressionFromIntegralTemplateArgumentValue(
S, ElemT, Val.getComplexIntImag(), Loc)});
}

case APValue::ComplexFloat: {
QualType ElemT = T->castAs<ComplexType>()->getElementType();
return MakeInitList(
{FloatingLiteral::Create(S.Context, Val.getComplexFloatReal(), true,
ElemT, Loc),
FloatingLiteral::Create(S.Context, Val.getComplexFloatImag(), true,
ElemT, Loc)});
}

case APValue::Vector: {
QualType ElemT = T->castAs<VectorType>()->getElementType();
llvm::SmallVector<Expr *, 8> Elts;
for (unsigned I = 0, N = Val.getVectorLength(); I != N; ++I)
Elts.push_back(BuildExpressionFromNonTypeTemplateArgumentValue(
S, ElemT, Val.getVectorElt(I), Loc));
return MakeInitList(Elts);
}

case APValue::None:
case APValue::Indeterminate:
// FIXME: Are these values possible?
case APValue::LValue:
case APValue::MemberPointer:
// There isn't necessarily a valid equivalent source-level syntax for
// these; in particular, a naive lowering might violate access control.
// So for now we lower to a ConstantExpr holding the value, wrapped around
// an OpaqueValueExpr.
// FIXME: We should have a better representation for this.
ExprValueKind VK = VK_RValue;
if (T->isReferenceType()) {
T = T->getPointeeType();
VK = VK_LValue;
}
auto *OVE = new (S.Context) OpaqueValueExpr(Loc, T, VK);
return ConstantExpr::Create(S.Context, OVE, Val);
}
llvm_unreachable("Unhandled APValue::ValueKind enum");
}

ExprResult
Sema::BuildExpressionFromNonTypeTemplateArgument(const TemplateArgument &Arg,
SourceLocation Loc) {
switch (Arg.getKind()) {
case TemplateArgument::Null:
case TemplateArgument::Type:
case TemplateArgument::Template:
case TemplateArgument::TemplateExpansion:
case TemplateArgument::Pack:
llvm_unreachable("not a non-type template argument");

case TemplateArgument::Expression:
return Arg.getAsExpr();

case TemplateArgument::NullPtr:
case TemplateArgument::Declaration:
return BuildExpressionFromDeclTemplateArgument(
Arg, Arg.getNonTypeTemplateArgumentType(), Loc);

case TemplateArgument::Integral:
return BuildExpressionFromIntegralTemplateArgumentValue(
*this, Arg.getIntegralType(), Arg.getAsIntegral(), Loc);

case TemplateArgument::UncommonValue:
return BuildExpressionFromNonTypeTemplateArgumentValue(
*this, Arg.getUncommonValueType(), Arg.getAsUncommonValue(), Loc);
}
llvm_unreachable("Unhandled TemplateArgument::ArgKind enum");
}

/// Match two template parameters within template parameter lists.
static bool MatchTemplateParameterKind(Sema &S, NamedDecl *New, NamedDecl *Old,
bool Complain,
Expand Down
94 changes: 40 additions & 54 deletions clang/lib/Sema/SemaTemplateDeduction.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -276,16 +276,6 @@ checkDeducedTemplateArguments(ASTContext &Context,
// All other combinations are incompatible.
return DeducedTemplateArgument();

case TemplateArgument::UncommonValue:
// If we deduced a value and a dependent expression, keep the value.
if (Y.getKind() == TemplateArgument::Expression ||
(Y.getKind() == TemplateArgument::UncommonValue &&
X.structurallyEquals(Y)))
return X;

// All other combinations are incompatible.
return DeducedTemplateArgument();

case TemplateArgument::Template:
if (Y.getKind() == TemplateArgument::Template &&
Context.hasSameTemplateName(X.getAsTemplate(), Y.getAsTemplate()))
Expand Down Expand Up @@ -2371,18 +2361,20 @@ DeduceTemplateArguments(Sema &S,
return Sema::TDK_NonDeducedMismatch;

case TemplateArgument::Integral:
if (Arg.getKind() == TemplateArgument::Integral &&
hasSameExtendedValue(Param.getAsIntegral(), Arg.getAsIntegral()))
return Sema::TDK_Success;
if (Arg.getKind() == TemplateArgument::Integral) {
if (hasSameExtendedValue(Param.getAsIntegral(), Arg.getAsIntegral()))
return Sema::TDK_Success;

Info.FirstArg = Param;
Info.SecondArg = Arg;
return Sema::TDK_NonDeducedMismatch;
Info.FirstArg = Param;
Info.SecondArg = Arg;
return Sema::TDK_NonDeducedMismatch;
}

case TemplateArgument::UncommonValue:
if (Arg.getKind() == TemplateArgument::UncommonValue &&
Arg.structurallyEquals(Param))
return Sema::TDK_Success;
if (Arg.getKind() == TemplateArgument::Expression) {
Info.FirstArg = Param;
Info.SecondArg = Arg;
return Sema::TDK_NonDeducedMismatch;
}

Info.FirstArg = Param;
Info.SecondArg = Arg;
Expand All @@ -2391,34 +2383,28 @@ DeduceTemplateArguments(Sema &S,
case TemplateArgument::Expression:
if (const NonTypeTemplateParmDecl *NTTP =
getDeducedParameterFromExpr(Info, Param.getAsExpr())) {
switch (Arg.getKind()) {
case TemplateArgument::Integral:
case TemplateArgument::Expression:
case TemplateArgument::UncommonValue:
return DeduceNonTypeTemplateArgument(
S, TemplateParams, NTTP, DeducedTemplateArgument(Arg),
Arg.getNonTypeTemplateArgumentType(), Info, Deduced);

case TemplateArgument::NullPtr:
return DeduceNullPtrTemplateArgument(
S, TemplateParams, NTTP, Arg.getNullPtrType(), Info, Deduced);

if (Arg.getKind() == TemplateArgument::Integral)
return DeduceNonTypeTemplateArgument(S, TemplateParams, NTTP,
Arg.getAsIntegral(),
Arg.getIntegralType(),
/*ArrayBound=*/false,
Info, Deduced);
if (Arg.getKind() == TemplateArgument::NullPtr)
return DeduceNullPtrTemplateArgument(S, TemplateParams, NTTP,
Arg.getNullPtrType(),
Info, Deduced);
if (Arg.getKind() == TemplateArgument::Expression)
return DeduceNonTypeTemplateArgument(S, TemplateParams, NTTP,
Arg.getAsExpr(), Info, Deduced);
if (Arg.getKind() == TemplateArgument::Declaration)
return DeduceNonTypeTemplateArgument(S, TemplateParams, NTTP,
Arg.getAsDecl(),
Arg.getParamTypeForDecl(),
Info, Deduced);

case TemplateArgument::Declaration:
return DeduceNonTypeTemplateArgument(
S, TemplateParams, NTTP, Arg.getAsDecl(), Arg.getParamTypeForDecl(),
Info, Deduced);

case TemplateArgument::Null:
case TemplateArgument::Type:
case TemplateArgument::Template:
case TemplateArgument::TemplateExpansion:
case TemplateArgument::Pack:
Info.FirstArg = Param;
Info.SecondArg = Arg;
return Sema::TDK_NonDeducedMismatch;
}
llvm_unreachable("Unknown template argument kind");
Info.FirstArg = Param;
Info.SecondArg = Arg;
return Sema::TDK_NonDeducedMismatch;
}

// Can't deduce anything, but that's okay.
Expand Down Expand Up @@ -2606,9 +2592,6 @@ static bool isSameTemplateArg(ASTContext &Context,
case TemplateArgument::Integral:
return hasSameExtendedValue(X.getAsIntegral(), Y.getAsIntegral());

case TemplateArgument::UncommonValue:
return X.structurallyEquals(Y);

case TemplateArgument::Expression: {
llvm::FoldingSetNodeID XID, YID;
X.getAsExpr()->Profile(XID, Context, true);
Expand Down Expand Up @@ -2674,9 +2657,9 @@ Sema::getTrivialTemplateArgumentLoc(const TemplateArgument &Arg,
E);
}

case TemplateArgument::Integral:
case TemplateArgument::UncommonValue: {
Expr *E = BuildExpressionFromNonTypeTemplateArgument(Arg, Loc).get();
case TemplateArgument::Integral: {
Expr *E =
BuildExpressionFromIntegralTemplateArgument(Arg, Loc).getAs<Expr>();
return TemplateArgumentLoc(TemplateArgument(E), E);
}

Expand Down Expand Up @@ -6120,8 +6103,11 @@ MarkUsedTemplateParameters(ASTContext &Ctx,
case TemplateArgument::Null:
case TemplateArgument::Integral:
case TemplateArgument::Declaration:
break;

case TemplateArgument::NullPtr:
case TemplateArgument::UncommonValue:
MarkUsedTemplateParameters(Ctx, TemplateArg.getNullPtrType(), OnlyDeduced,
Depth, Used);
break;

case TemplateArgument::Type:
Expand Down
16 changes: 6 additions & 10 deletions clang/lib/Sema/SemaTemplateInstantiate.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1556,18 +1556,16 @@ ExprResult TemplateInstantiator::transformNonTypeTemplateParmRef(
VD = nullptr;
}

QualType paramType = arg.getNonTypeTemplateArgumentType();
QualType paramType = VD ? arg.getParamTypeForDecl() : arg.getNullPtrType();
assert(!paramType.isNull() && "type substitution failed for param type");
assert(!paramType->isDependentType() && "param type still dependent");
result = SemaRef.BuildExpressionFromDeclTemplateArgument(arg, paramType, loc);
refParam = paramType->isReferenceType();
} else {
QualType paramType = arg.getNonTypeTemplateArgumentType();
result = SemaRef.BuildExpressionFromNonTypeTemplateArgument(arg, loc);
refParam = paramType->isReferenceType();
result = SemaRef.BuildExpressionFromIntegralTemplateArgument(arg, loc);
assert(result.isInvalid() ||
SemaRef.Context.hasSameType(result.get()->getType(),
paramType.getNonReferenceType()));
arg.getIntegralType()));
}

if (result.isInvalid())
Expand Down Expand Up @@ -3229,8 +3227,7 @@ Sema::InstantiateClassMembers(SourceLocation PointOfInstantiation,
if (FunctionDecl *Pattern =
Function->getInstantiatedFromMemberFunction()) {

if (TSK != TSK_ImplicitInstantiation &&
Function->hasAttr<ExcludeFromExplicitInstantiationAttr>())
if (Function->hasAttr<ExcludeFromExplicitInstantiationAttr>())
continue;

MemberSpecializationInfo *MSInfo =
Expand Down Expand Up @@ -3275,8 +3272,7 @@ Sema::InstantiateClassMembers(SourceLocation PointOfInstantiation,
continue;

if (Var->isStaticDataMember()) {
if (TSK != TSK_ImplicitInstantiation &&
Var->hasAttr<ExcludeFromExplicitInstantiationAttr>())
if (Var->hasAttr<ExcludeFromExplicitInstantiationAttr>())
continue;

MemberSpecializationInfo *MSInfo = Var->getMemberSpecializationInfo();
Expand All @@ -3293,7 +3289,7 @@ Sema::InstantiateClassMembers(SourceLocation PointOfInstantiation,
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
Expand Down
2 changes: 0 additions & 2 deletions clang/lib/Sema/SemaTemplateVariadic.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1103,7 +1103,6 @@ Sema::getTemplateArgumentPackExpansionPattern(
case TemplateArgument::NullPtr:
case TemplateArgument::Template:
case TemplateArgument::Integral:
case TemplateArgument::UncommonValue:
case TemplateArgument::Pack:
case TemplateArgument::Null:
return TemplateArgumentLoc();
Expand Down Expand Up @@ -1154,7 +1153,6 @@ Optional<unsigned> Sema::getFullyPackExpandedSize(TemplateArgument Arg) {
case TemplateArgument::NullPtr:
case TemplateArgument::TemplateExpansion:
case TemplateArgument::Integral:
case TemplateArgument::UncommonValue:
case TemplateArgument::Pack:
case TemplateArgument::Null:
return None;
Expand Down
12 changes: 2 additions & 10 deletions clang/lib/Sema/TreeTransform.h
Original file line number Diff line number Diff line change
Expand Up @@ -3557,7 +3557,6 @@ class TreeTransform {
case TemplateArgument::Null:
case TemplateArgument::Integral:
case TemplateArgument::Declaration:
case TemplateArgument::UncommonValue:
case TemplateArgument::Pack:
case TemplateArgument::TemplateExpansion:
case TemplateArgument::NullPtr:
Expand Down Expand Up @@ -4230,8 +4229,7 @@ bool TreeTransform<Derived>::TransformTemplateArgument(

case TemplateArgument::Integral:
case TemplateArgument::NullPtr:
case TemplateArgument::Declaration:
case TemplateArgument::UncommonValue: {
case TemplateArgument::Declaration: {
// Transform a resolved template argument straight to a resolved template
// argument. We get here when substituting into an already-substituted
// template type argument during concept satisfaction checking.
Expand All @@ -4258,15 +4256,9 @@ bool TreeTransform<Derived>::TransformTemplateArgument(
else if (Arg.getKind() == TemplateArgument::NullPtr)
Output = TemplateArgumentLoc(TemplateArgument(NewT, /*IsNullPtr=*/true),
TemplateArgumentLocInfo());
else if (Arg.getKind() == TemplateArgument::Declaration)
else
Output = TemplateArgumentLoc(TemplateArgument(NewD, NewT),
TemplateArgumentLocInfo());
else if (Arg.getKind() == TemplateArgument::UncommonValue)
Output = TemplateArgumentLoc(
TemplateArgument(getSema().Context, NewT, Arg.getAsUncommonValue()),
TemplateArgumentLocInfo());
else
llvm_unreachable("unexpected template argument kind");

return false;
}
Expand Down
1 change: 0 additions & 1 deletion clang/lib/Serialization/ASTReader.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -7100,7 +7100,6 @@ ASTRecordReader::readTemplateArgumentLocInfo(TemplateArgument::ArgKind Kind) {
case TemplateArgument::Integral:
case TemplateArgument::Declaration:
case TemplateArgument::NullPtr:
case TemplateArgument::UncommonValue:
case TemplateArgument::Pack:
// FIXME: Is this right?
return TemplateArgumentLocInfo();
Expand Down
1 change: 0 additions & 1 deletion clang/lib/Serialization/ASTWriter.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -5350,7 +5350,6 @@ void ASTRecordWriter::AddTemplateArgumentLocInfo(
case TemplateArgument::Integral:
case TemplateArgument::Declaration:
case TemplateArgument::NullPtr:
case TemplateArgument::UncommonValue:
case TemplateArgument::Pack:
// FIXME: Is this right?
break;
Expand Down
12 changes: 0 additions & 12 deletions clang/test/CXX/drs/dr20xx.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -49,18 +49,6 @@ namespace dr2026 { // dr2026: 11
}
}

namespace dr2064 { // dr2064: 12
#if __cplusplus >= 201103L
template<typename T> struct X {
template<typename U> struct Y {};
};
template<typename T> void f() {
X<decltype(sizeof(T))>::Y<int> y; // ok
return X<decltype(sizeof(T))>::f(); // expected-error {{no member named 'f' in 'dr2064::X<unsigned}}
}
#endif
}

namespace dr2082 { // dr2082: 11
void test1(int x, int = sizeof(x)); // ok
#if __cplusplus >= 201103L
Expand Down
10 changes: 0 additions & 10 deletions clang/test/CodeGenCXX/mangle-ms-templates.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,6 @@
// RUN: %clang_cc1 -std=c++11 -fms-compatibility-version=19 -emit-llvm %s -o - -fms-extensions -fdelayed-template-parsing -triple=x86_64-pc-win32 | FileCheck -check-prefix X64 %s
// RUN: %clang_cc1 -std=c++17 -fms-compatibility-version=19 -emit-llvm %s -o - -fms-extensions -fdelayed-template-parsing -triple=i386-pc-win32 | FileCheck %s
// RUN: %clang_cc1 -std=c++17 -fms-compatibility-version=19 -emit-llvm %s -o - -fms-extensions -fdelayed-template-parsing -triple=x86_64-pc-win32 | FileCheck -check-prefix X64 %s
// RUN: %clang_cc1 -std=c++20 -fms-compatibility-version=19 -emit-llvm %s -o - -fms-extensions -fdelayed-template-parsing -triple=x86_64-pc-win32 | FileCheck -check-prefix CXX20-X64 %s

template<typename T>
class Class {
Expand Down Expand Up @@ -328,12 +327,3 @@ void fun_uint128(UInt128<(unsigned __int128)-1>) {}
// X64: define {{.*}} @"?fun_uint128@@YAXU?$UInt128@$0DPPPPPPPPPPPPPPPAAAAAAAAAAAAAAAB@@@@Z"(
void fun_uint128(UInt128<(unsigned __int128)9223372036854775807 * (unsigned __int128)9223372036854775807>) {}
#endif

#if __cplusplus >= 202002L
template<float> struct Float {};
// CXX20-X64: define {{.*}} @"?f@@YAXU?$Float@$ADPIAAAAA@@@@Z"(
void f(Float<1.0f>) {}
template<auto> struct Auto {};
// CXX20-X64: define {{.*}} @"?f@@YAXU?$Auto@$MMADPIAAAAA@@@@Z"(
void f(Auto<1.0f>) {}
#endif
40 changes: 1 addition & 39 deletions clang/test/CodeGenCXX/mangle-template.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -226,16 +226,6 @@ namespace test16 {
namespace cxx20 {
template<auto> struct A {};
template<typename T, T V> struct B {};
// CXX20: define {{.*}} @_ZN5cxx201fENS_1AILf3f800000EEE(
void f(A<1.0f>) {}
// CXX20: define {{.*}} @_ZN5cxx201fENS_1AILd3ff0000000000000EEE(
void f(A<1.0>) {}
// CXX20: define {{.*}} @_ZN5cxx201fENS_1AILe3fff8000000000000000EEE(
void f(A<1.0l>) {}
// CXX20: define {{.*}} @_ZN5cxx201fENS_1AIXtlCiLi0ELi1EEEEE(
void f(A<1i>) {}
// CXX20: define {{.*}} @_ZN5cxx201fENS_1AIXtlCdLd0000000000000000ELd3ff0000000000000EEEEE(
void f(A<1.0i>) {}

int x;
// CXX20: define {{.*}} @_ZN5cxx201fENS_1AIXadL_ZNS_1xEEEEE(
Expand All @@ -255,24 +245,7 @@ namespace cxx20 {
// CXX20: define {{.*}} @_ZN5cxx201fENS_1BIPKvXadL_ZNS_1xEEEEE(
void f(B<const void*, (const void*)&x>) {}

struct Q { int x; } q;

// CXX20: define {{.*}} @_ZN5cxx201fENS_1AIXadsoiL_ZNS_1qEEEEEE(
void f(A<&q.x>) {}
// CXX20: define {{.*}} @_ZN5cxx201fENS_1BIPiXadsoiL_ZNS_1qEEEEEE(
void f(B<int*, &q.x>) {}
// CXX20: define {{.*}} @_ZN5cxx201fENS_1AIXadsoKiL_ZNS_1qEEEEEE(
void f(A<(const int*)&q.x>) {}
// CXX20: define {{.*}} @_ZN5cxx201fENS_1BIPKiXadsoS1_L_ZNS_1qEEEEEE
void f(B<const int*, (const int*)&q.x>) {}
// CXX20: define {{.*}} @_ZN5cxx201fENS_1AIXcvPvadsoiL_ZNS_1qEEEEEE(
void f(A<(void*)&q.x>) {}
// CXX20: define {{.*}} @_ZN5cxx201fENS_1BIPvXadsoiL_ZNS_1qEEEEEE(
void f(B<void*, (void*)&q.x>) {}
// CXX20: define {{.*}} @_ZN5cxx201fENS_1AIXcvPKvadsoiL_ZNS_1qEEEEEE(
void f(A<(const void*)&q.x>) {}
// CXX20: define {{.*}} @_ZN5cxx201fENS_1BIPKvXadsoiL_ZNS_1qEEEEEE(
void f(B<const void*, (const void*)&q.x>) {}
struct Q { int x; };

// CXX20: define {{.*}} @_ZN5cxx201fENS_1AIXadL_ZNS_1Q1xEEEEE(
void f(A<&Q::x>) {}
Expand All @@ -282,17 +255,6 @@ namespace cxx20 {
void f(A<(const int Q::*)&Q::x>) {}
// CXX20: define {{.*}} @_ZN5cxx201fENS_1BIMNS_1QEKiXadL_ZNS1_1xEEEEE(
void f(B<const int Q::*, (const int Q::*)&Q::x>) {}

struct R : Q {};

// CXX20: define {{.*}} @_ZN5cxx201fENS_1AIXmcMNS_1REiadL_ZNS_1Q1xEEEEEE(
void f(A<(int R::*)&Q::x>) {}
// CXX20: define {{.*}} @_ZN5cxx201fENS_1BIMNS_1REiXmcS2_adL_ZNS_1Q1xEEEEEE(
void f(B<int R::*, (int R::*)&Q::x>) {}
// CXX20: define {{.*}} @_ZN5cxx201fENS_1AIXmcMNS_1REKiadL_ZNS_1Q1xEEEEEE(
void f(A<(const int R::*)&Q::x>) {}
// CXX20: define {{.*}} @_ZN5cxx201fENS_1BIMNS_1REKiXmcS3_adL_ZNS_1Q1xEEEEEE(
void f(B<const int R::*, (const int R::*)&Q::x>) {}
}
#endif

Expand Down
81 changes: 0 additions & 81 deletions clang/test/CodeGenCXX/template-arguments.cpp

This file was deleted.

2 changes: 1 addition & 1 deletion clang/test/OpenMP/distribute_dist_schedule_messages.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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 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();
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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 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();
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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 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();
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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 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();
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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 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)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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 {{'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];
Expand Down
2 changes: 1 addition & 1 deletion clang/test/OpenMP/target_simd_collapse_messages.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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 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)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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 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();
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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 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();
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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 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();
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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 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();
Expand Down
2 changes: 1 addition & 1 deletion clang/test/OpenMP/target_update_from_messages.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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 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)
{
Expand Down
2 changes: 1 addition & 1 deletion clang/test/OpenMP/target_update_to_messages.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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 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)
{
Expand Down
4 changes: 2 additions & 2 deletions clang/test/OpenMP/task_messages.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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}}
#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'}}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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 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();
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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 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();
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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 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();
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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 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();
Expand Down
1 change: 0 additions & 1 deletion clang/test/Sema/invalid-bitwidth-expr.mm
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,6 @@ auto func() {
auto func() {
// error-bit should be propagated from TemplateArgument to NestNameSpecifier.
class Base<decltype(Foo(T()))>::type C; // expected-error {{no matching function for call to 'Foo'}}
// expected-error@-1 {{no class named 'type' in 'Base<bool>'}}
return C;
}
struct Z {
Expand Down
4 changes: 2 additions & 2 deletions clang/test/SemaCXX/invalid-template-base-specifier.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -12,11 +12,11 @@ void test() { Crash<int>(); } // expected-note {{in instantiation of template cl
template <typename T>
using Alias = decltype(Foo(T())); // expected-error {{no matching function for call to 'Foo'}}
template <typename T>
struct Crash2 : decltype(Alias<T>()) { // expected-note {{in instantiation of template type alias 'Alias' requested here}} expected-error {{base specifier must name a class}}
struct Crash2 : decltype(Alias<T>()) { // expected-note {{in instantiation of template type alias 'Alias' requested here}}
Crash2(){};
};

void test2() { Crash2<int>(); } // expected-note 2{{in instantiation of template class 'Crash2<int>' requested here}}
void test2() { Crash2<int>(); } // expected-note {{in instantiation of template class 'Crash2<int>' requested here}}

template <typename T>
class Base {};
Expand Down
2 changes: 1 addition & 1 deletion clang/test/SemaCXX/warn-unused-lambda-capture.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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 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}}

Expand Down
7 changes: 1 addition & 6 deletions clang/test/SemaTemplate/dependent-expr.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -129,12 +129,7 @@ namespace PR45083 {
template<typename> void f() {
decltype(({})) x; // expected-error {{incomplete type}}
}
template void f<int>();

template<typename T> void f2() {
decltype(({T();})) x; // expected-error {{incomplete type}}
}
template void f2<void>(); // expected-note {{instantiation of}}
template void f<int>(); // expected-note {{instantiation of}}

template<typename> auto g() {
auto c = [](auto, int) -> decltype(({})) {};
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@

template<typename T, T val> struct A {};

template<typename T, typename U> constexpr bool is_same = false;
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 {
Expand Down Expand Up @@ -84,32 +84,34 @@ namespace PtrMem {
constexpr int B::*b = &B::b;
constexpr int C::*cb = b;
constexpr int D::*db = b;
constexpr int E::*ecb = cb;
constexpr int E::*edb = db;
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;
constexpr int B::*bce = (int B::*)ce;
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>;
using Abde = A<int B::*, bde>;
static_assert(!is_same<Ab, Abce>, "");
static_assert(!is_same<Ab, Abde>, "");
static_assert(!is_same<Abce, Abde>, "");
static_assert(is_same<Abce, A<int B::*, (int B::*)(int C::*)&E::e>>, "");
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>;
using Aedb = A<int E::*, edb>;
static_assert(!is_same<Ae, Aecb>, "");
static_assert(!is_same<Ae, Aedb>, "");
static_assert(!is_same<Aecb, Aedb>, "");
static_assert(is_same<Aecb, A<int E::*, (int E::*)(int C::*)&B::b>>, "");
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>;
Expand Down Expand Up @@ -203,9 +205,9 @@ namespace Auto {

struct Y : X {};
void type_affects_identity(B<&X::n>) {}
void type_affects_identity(B<(int Y::*)&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>) {}
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
Expand Down Expand Up @@ -501,13 +503,3 @@ 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;
}
80 changes: 18 additions & 62 deletions clang/test/SemaTemplate/temp_arg_nontype_cxx20.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -8,33 +8,33 @@ namespace std {

// floating-point arguments
template<float> struct Float {};
using F1 = Float<1.0f>;
using F1 = Float<2.0f / 2>;
using F1 = Float<1.0f>; // FIXME expected-error {{sorry}}
using F1 = Float<2.0f / 2>; // FIXME expected-error {{sorry}}

struct S { int n[3]; } s; // expected-note 1+{{here}}
union U { int a, b; } u;
int n; // expected-note 1+{{here}}

// pointers to subobjects
template<int *> struct IntPtr {};
using IPn = IntPtr<&n + 1>;
using IPn = IntPtr<&n + 1>;
using IPn = IntPtr<&n + 1>; // FIXME expected-error {{refers to subobject}}
using IPn = IntPtr<&n + 1>; // FIXME expected-error {{refers to subobject}}

using IP2 = IntPtr<&s.n[2]>;
using IP2 = IntPtr<s.n + 2>;
using IP2 = IntPtr<&s.n[2]>; // FIXME expected-error {{refers to subobject}}
using IP2 = IntPtr<s.n + 2>; // FIXME expected-error {{refers to subobject}}

using IP3 = IntPtr<&s.n[3]>;
using IP3 = IntPtr<s.n + 3>;
using IP3 = IntPtr<&s.n[3]>; // FIXME expected-error {{refers to subobject}}
using IP3 = IntPtr<s.n + 3>; // FIXME expected-error {{refers to subobject}}

template<int &> struct IntRef {};
using IRn = IntRef<*(&n + 1)>; // expected-error {{not a constant expression}} expected-note {{dereferenced pointer past the end of 'n'}}
using IRn = IntRef<*(&n + 1)>; // expected-error {{not a constant expression}} expected-note {{dereferenced pointer past the end of 'n'}}
using IPn = IntRef<*(&n + 1)>; // expected-error {{not a constant expression}} expected-note {{dereferenced pointer past the end of 'n'}}
using IPn = IntRef<*(&n + 1)>; // expected-error {{not a constant expression}} expected-note {{dereferenced pointer past the end of 'n'}}

using IR2 = IntRef<s.n[2]>;
using IR2 = IntRef<*(s.n + 2)>;
using IP2 = IntRef<s.n[2]>; // FIXME expected-error {{refers to subobject}}
using IP2 = IntRef<*(s.n + 2)>; // FIXME expected-error {{refers to subobject}}

using IR3 = IntRef<s.n[3]>; // expected-error {{not a constant expression}} expected-note {{dereferenced pointer past the end of subobject of 's'}}
using IR3 = IntRef<*(s.n + 3)>; // expected-error {{not a constant expression}} expected-note {{dereferenced pointer past the end of subobject of 's'}}
using IP3 = IntRef<s.n[3]>; // expected-error {{not a constant expression}} expected-note {{dereferenced pointer past the end of subobject of 's'}}
using IP3 = IntRef<*(s.n + 3)>; // expected-error {{not a constant expression}} expected-note {{dereferenced pointer past the end of subobject of 's'}}

// classes
template<S> struct Struct {};
Expand All @@ -48,12 +48,12 @@ using U1 = Union<U{.b = 1}>; // expected-error {{different types}}

// miscellaneous scalar types
template<_Complex int> struct ComplexInt {};
using CI = ComplexInt<1 + 3i>;
using CI = ComplexInt<3i + 1>;
using CI = ComplexInt<1 + 3i>; // FIXME: expected-error {{sorry}}
using CI = ComplexInt<1 + 3i>; // FIXME: expected-error {{sorry}}

template<_Complex float> struct ComplexFloat {};
using CF = ComplexFloat<1.0f + 3.0fi>;
using CF = ComplexFloat<3.0fi + 1.0f>;
using CF = ComplexFloat<1.0f + 3.0fi>; // FIXME: expected-error {{sorry}}
using CF = ComplexFloat<1.0f + 3.0fi>; // FIXME: expected-error {{sorry}}

namespace ClassNTTP {
struct A { // expected-note 2{{candidate}}
Expand Down Expand Up @@ -292,47 +292,3 @@ 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>();
else if constexpr (N < 30)
return S<&n>();
else if constexpr (N < 40)
return S<&vn.v>();
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>();
auto w = f<Base + 1>();
static_assert(!__is_same(decltype(v), decltype(w)));
static_assert(v != w);
}
template void check<0>();
template void check<10>();
template void check<20>();
template void check<30>();
template void check<40>();
template void check<50>();
template void check<60>();
template void check<70>();
}
Loading