Create a new expression node, SubstNonTypeTemplateParmExpr,

to represent a fully-substituted non-type template parameter.
This should improve source fidelity, as well as being generically
useful for diagnostics and such.



git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@135243 91177308-0d34-0410-b5e6-96231b3b80d8
This commit is contained in:
John McCall 2011-07-15 05:09:51 +00:00
Родитель 165622faa4
Коммит 91a5755ad7
19 изменённых файлов: 189 добавлений и 88 удалений

Просмотреть файл

@ -538,6 +538,10 @@ public:
/// the rules of C++ [expr.unary.noexcept].
CanThrowResult CanThrow(ASTContext &C) const;
/// IgnoreImpCasts - Skip past any implicit casts which might
/// surround this expression. Only skips ImplicitCastExprs.
Expr *IgnoreImpCasts();
/// IgnoreImplicit - Skip past any implicit AST nodes which might
/// surround this expression.
Expr *IgnoreImplicit() { return cast<Expr>(Stmt::IgnoreImplicit()); }
@ -596,7 +600,10 @@ public:
/// \brief Whether this expression is an implicit reference to 'this' in C++.
bool isImplicitCXXThis() const;
const Expr *IgnoreImpCasts() const {
return const_cast<Expr*>(this)->IgnoreImpCasts();
}
const Expr *IgnoreParens() const {
return const_cast<Expr*>(this)->IgnoreParens();
}
@ -2487,6 +2494,13 @@ public:
static bool classof(const ImplicitCastExpr *) { return true; }
};
inline Expr *Expr::IgnoreImpCasts() {
Expr *e = this;
while (ImplicitCastExpr *ice = dyn_cast<ImplicitCastExpr>(e))
e = ice->getSubExpr();
return e;
}
/// ExplicitCastExpr - An explicit cast written in the source
/// code.
///

Просмотреть файл

@ -2957,6 +2957,48 @@ public:
child_range children() { return child_range(); }
};
/// \brief Represents a reference to a non-type template parameter
/// that has been substituted with a template argument.
class SubstNonTypeTemplateParmExpr : public Expr {
/// \brief The replaced parameter.
NonTypeTemplateParmDecl *Param;
/// \brief The replacement expression.
Stmt *Replacement;
/// \brief The location of the non-type template parameter reference.
SourceLocation NameLoc;
public:
SubstNonTypeTemplateParmExpr(QualType type,
ExprValueKind valueKind,
SourceLocation loc,
NonTypeTemplateParmDecl *param,
Expr *replacement)
: Expr(SubstNonTypeTemplateParmExprClass, type, valueKind, OK_Ordinary,
replacement->isTypeDependent(), replacement->isValueDependent(),
replacement->isInstantiationDependent(),
replacement->containsUnexpandedParameterPack()),
Param(param), Replacement(replacement), NameLoc(loc) {}
SourceLocation getNameLoc() const { return NameLoc; }
SourceRange getSourceRange() const { return NameLoc; }
Expr *getReplacement() const { return cast<Expr>(Replacement); }
NonTypeTemplateParmDecl *getParameter() const { return Param; }
static bool classof(const Stmt *s) {
return s->getStmtClass() == SubstNonTypeTemplateParmExprClass;
}
static bool classof(const SubstNonTypeTemplateParmExpr *) {
return true;
}
// Iterators
child_range children() { return child_range(&Replacement, &Replacement+1); }
};
/// \brief Represents a reference to a non-type template parameter pack that
/// has been substituted with a non-template argument pack.
///

Просмотреть файл

@ -1978,6 +1978,7 @@ DEF_TRAVERSE_STMT(CXXNoexceptExpr, { })
DEF_TRAVERSE_STMT(PackExpansionExpr, { })
DEF_TRAVERSE_STMT(SizeOfPackExpr, { })
DEF_TRAVERSE_STMT(SubstNonTypeTemplateParmPackExpr, { })
DEF_TRAVERSE_STMT(SubstNonTypeTemplateParmExpr, { })
DEF_TRAVERSE_STMT(MaterializeTemporaryExpr, { })
// These literals (all of them) do not need any action.

Просмотреть файл

@ -120,6 +120,7 @@ def UnresolvedMemberExpr : DStmt<OverloadExpr>;
def CXXNoexceptExpr : DStmt<Expr>;
def PackExpansionExpr : DStmt<Expr>;
def SizeOfPackExpr : DStmt<Expr>;
def SubstNonTypeTemplateParmExpr : DStmt<Expr>;
def SubstNonTypeTemplateParmPackExpr : DStmt<Expr>;
def MaterializeTemporaryExpr : DStmt<Expr>;

Просмотреть файл

@ -165,6 +165,9 @@ static Cl::Kinds ClassifyInternal(ASTContext &Ctx, const Expr *E) {
return Cl::CL_PRValue;
// Next come the complicated cases.
case Expr::SubstNonTypeTemplateParmExprClass:
return ClassifyInternal(Ctx,
cast<SubstNonTypeTemplateParmExpr>(E)->getReplacement());
// C++ [expr.sub]p1: The result is an lvalue of type "T".
// However, subscripting vector types is more like member access.

Просмотреть файл

@ -406,6 +406,8 @@ public:
{ return StmtVisitorTy::Visit(E->getChosenSubExpr(Info.Ctx)); }
RetTy VisitGenericSelectionExpr(const GenericSelectionExpr *E)
{ return StmtVisitorTy::Visit(E->getResultExpr()); }
RetTy VisitSubstNonTypeTemplateParmExpr(const SubstNonTypeTemplateParmExpr *E)
{ return StmtVisitorTy::Visit(E->getReplacement()); }
RetTy VisitBinaryConditionalOperator(const BinaryConditionalOperator *E) {
OpaqueValueEvaluation opaque(Info, E->getOpaqueValue(), E->getCommon());
@ -2806,6 +2808,10 @@ static ICEDiag CheckICE(const Expr* E, ASTContext &Ctx) {
// GCC considers the GNU __null value to be an integral constant expression.
return NoDiag();
case Expr::SubstNonTypeTemplateParmExprClass:
return
CheckICE(cast<SubstNonTypeTemplateParmExpr>(E)->getReplacement(), Ctx);
case Expr::ParenExprClass:
return CheckICE(cast<ParenExpr>(E)->getSubExpr(), Ctx);
case Expr::GenericSelectionExprClass:

Просмотреть файл

@ -2279,6 +2279,11 @@ recurse:
mangleExpression(cast<CXXDefaultArgExpr>(E)->getExpr(), Arity);
break;
case Expr::SubstNonTypeTemplateParmExprClass:
mangleExpression(cast<SubstNonTypeTemplateParmExpr>(E)->getReplacement(),
Arity);
break;
case Expr::CXXMemberCallExprClass: // fallthrough
case Expr::CallExprClass: {
const CallExpr *CE = cast<CallExpr>(E);

Просмотреть файл

@ -1413,6 +1413,11 @@ void StmtPrinter::VisitSubstNonTypeTemplateParmPackExpr(
OS << Node->getParameterPack()->getNameAsString();
}
void StmtPrinter::VisitSubstNonTypeTemplateParmExpr(
SubstNonTypeTemplateParmExpr *Node) {
Visit(Node->getReplacement());
}
void StmtPrinter::VisitMaterializeTemporaryExpr(MaterializeTemporaryExpr *Node){
PrintExpr(Node->GetTemporaryExpr());
}

Просмотреть файл

@ -911,6 +911,12 @@ void StmtProfiler::VisitSubstNonTypeTemplateParmPackExpr(
VisitTemplateArgument(S->getArgumentPack());
}
void StmtProfiler::VisitSubstNonTypeTemplateParmExpr(
const SubstNonTypeTemplateParmExpr *E) {
// Profile exactly as the replacement expression.
Visit(E->getReplacement());
}
void StmtProfiler::VisitMaterializeTemporaryExpr(
const MaterializeTemporaryExpr *S) {
VisitExpr(S);

Просмотреть файл

@ -705,6 +705,8 @@ LValue CodeGenFunction::EmitLValue(const Expr *E) {
return EmitLValue(cast<ChooseExpr>(E)->getChosenSubExpr(getContext()));
case Expr::OpaqueValueExprClass:
return EmitOpaqueValueLValue(cast<OpaqueValueExpr>(E));
case Expr::SubstNonTypeTemplateParmExprClass:
return EmitLValue(cast<SubstNonTypeTemplateParmExpr>(E)->getReplacement());
case Expr::ImplicitCastExprClass:
case Expr::CStyleCastExprClass:
case Expr::CXXFunctionalCastExprClass:

Просмотреть файл

@ -85,6 +85,9 @@ public:
Visit(GE->getResultExpr());
}
void VisitUnaryExtension(UnaryOperator *E) { Visit(E->getSubExpr()); }
void VisitSubstNonTypeTemplateParmExpr(SubstNonTypeTemplateParmExpr *E) {
return Visit(E->getReplacement());
}
// l-values.
void VisitDeclRefExpr(DeclRefExpr *DRE) { EmitAggLoadOfLValue(DRE); }

Просмотреть файл

@ -112,6 +112,10 @@ public:
return Visit(GE->getResultExpr());
}
ComplexPairTy VisitImaginaryLiteral(const ImaginaryLiteral *IL);
ComplexPairTy
VisitSubstNonTypeTemplateParmExpr(SubstNonTypeTemplateParmExpr *PE) {
return Visit(PE->getReplacement());
}
// l-values.
ComplexPairTy VisitDeclRefExpr(const Expr *E) { return EmitLoadOfLValue(E); }

Просмотреть файл

@ -481,6 +481,11 @@ public:
return Visit(PE->getSubExpr());
}
llvm::Constant *
VisitSubstNonTypeTemplateParmExpr(SubstNonTypeTemplateParmExpr *PE) {
return Visit(PE->getReplacement());
}
llvm::Constant *VisitGenericSelectionExpr(GenericSelectionExpr *GE) {
return Visit(GE->getResultExpr());
}

Просмотреть файл

@ -161,6 +161,9 @@ public:
Value *VisitParenExpr(ParenExpr *PE) {
return Visit(PE->getSubExpr());
}
Value *VisitSubstNonTypeTemplateParmExpr(SubstNonTypeTemplateParmExpr *E) {
return Visit(E->getReplacement());
}
Value *VisitGenericSelectionExpr(GenericSelectionExpr *GE) {
return Visit(GE->getResultExpr());
}

Просмотреть файл

@ -3316,8 +3316,7 @@ CheckTemplateArgumentAddressOfObjectOrFunction(Sema &S,
QualType ArgType = Arg->getType();
// See through any implicit casts we added to fix the type.
while (ImplicitCastExpr *Cast = dyn_cast<ImplicitCastExpr>(Arg))
Arg = Cast->getSubExpr();
Arg = Arg->IgnoreImpCasts();
// C++ [temp.arg.nontype]p1:
//
@ -3330,7 +3329,6 @@ CheckTemplateArgumentAddressOfObjectOrFunction(Sema &S,
// expressed as & id-expression where the & is optional if
// the name refers to a function or array, or if the
// corresponding template-parameter is a reference; or
DeclRefExpr *DRE = 0;
// In C++98/03 mode, give an extension warning on any extra parentheses.
// See http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_defects.html#773
@ -3346,29 +3344,30 @@ CheckTemplateArgumentAddressOfObjectOrFunction(Sema &S,
Arg = Parens->getSubExpr();
}
while (SubstNonTypeTemplateParmExpr *subst =
dyn_cast<SubstNonTypeTemplateParmExpr>(Arg))
Arg = subst->getReplacement()->IgnoreImpCasts();
bool AddressTaken = false;
SourceLocation AddrOpLoc;
if (UnaryOperator *UnOp = dyn_cast<UnaryOperator>(Arg)) {
if (UnOp->getOpcode() == UO_AddrOf) {
// Support &__uuidof(class_with_uuid) as a non-type template argument.
// Very common in Microsoft COM headers.
if (S.getLangOptions().Microsoft &&
isa<CXXUuidofExpr>(UnOp->getSubExpr())) {
Converted = TemplateArgument(ArgIn);
return false;
}
DRE = dyn_cast<DeclRefExpr>(UnOp->getSubExpr());
Arg = UnOp->getSubExpr();
AddressTaken = true;
AddrOpLoc = UnOp->getOperatorLoc();
}
} else {
if (S.getLangOptions().Microsoft && isa<CXXUuidofExpr>(Arg)) {
Converted = TemplateArgument(ArgIn);
return false;
}
DRE = dyn_cast<DeclRefExpr>(Arg);
}
if (S.getLangOptions().Microsoft && isa<CXXUuidofExpr>(Arg)) {
Converted = TemplateArgument(ArgIn);
return false;
}
while (SubstNonTypeTemplateParmExpr *subst =
dyn_cast<SubstNonTypeTemplateParmExpr>(Arg))
Arg = subst->getReplacement()->IgnoreImpCasts();
DeclRefExpr *DRE = dyn_cast<DeclRefExpr>(Arg);
if (!DRE) {
S.Diag(Arg->getLocStart(), diag::err_template_arg_not_decl_ref)
<< Arg->getSourceRange();
@ -3563,10 +3562,10 @@ CheckTemplateArgumentAddressOfObjectOrFunction(Sema &S,
// We can't perform this conversion or binding.
if (ParamType->isReferenceType())
S.Diag(Arg->getLocStart(), diag::err_template_arg_no_ref_bind)
<< ParamType << Arg->getType() << Arg->getSourceRange();
<< ParamType << ArgIn->getType() << Arg->getSourceRange();
else
S.Diag(Arg->getLocStart(), diag::err_template_arg_not_convertible)
<< Arg->getType() << ParamType << Arg->getSourceRange();
<< ArgIn->getType() << ParamType << Arg->getSourceRange();
S.Diag(Param->getLocation(), diag::note_template_param_here);
return true;
}
@ -3610,6 +3609,10 @@ bool Sema::CheckTemplateArgumentPointerToMember(Expr *Arg,
Arg = Parens->getSubExpr();
}
while (SubstNonTypeTemplateParmExpr *subst =
dyn_cast<SubstNonTypeTemplateParmExpr>(Arg))
Arg = subst->getReplacement()->IgnoreImpCasts();
// A pointer-to-member constant written &Class::member.
if (UnaryOperator *UnOp = dyn_cast<UnaryOperator>(Arg)) {
if (UnOp->getOpcode() == UO_AddrOf) {
@ -4149,16 +4152,7 @@ Sema::BuildExpressionFromIntegralTemplateArgument(const TemplateArgument &Arg,
else
BT = T;
Expr *E = IntegerLiteral::Create(Context, *Arg.getAsIntegral(), BT, Loc);
if (T->isEnumeralType()) {
// FIXME: This is a hack. We need a better way to handle substituted
// non-type template parameters.
E = CStyleCastExpr::Create(Context, T, VK_RValue, CK_IntegralCast, E, 0,
Context.getTrivialTypeSourceInfo(T, Loc),
Loc, Loc);
}
return Owned(E);
return Owned(IntegerLiteral::Create(Context, *Arg.getAsIntegral(), BT, Loc));
}
/// \brief Match two template parameters within template parameter lists.

Просмотреть файл

@ -800,6 +800,11 @@ namespace {
getSema().CallsUndergoingInstantiation.pop_back();
return move(Result);
}
private:
ExprResult transformNonTypeTemplateParmRef(NonTypeTemplateParmDecl *parm,
SourceLocation loc,
const TemplateArgument &arg);
};
}
@ -1078,46 +1083,65 @@ TemplateInstantiator::TransformTemplateParmRefExpr(DeclRefExpr *E,
Arg = Arg.pack_begin()[getSema().ArgumentPackSubstitutionIndex];
}
return transformNonTypeTemplateParmRef(NTTP, E->getLocation(), Arg);
}
ExprResult TemplateInstantiator::transformNonTypeTemplateParmRef(
NonTypeTemplateParmDecl *parm,
SourceLocation loc,
const TemplateArgument &arg) {
ExprResult result;
QualType type;
// The template argument itself might be an expression, in which
// case we just return that expression.
if (Arg.getKind() == TemplateArgument::Expression)
return SemaRef.Owned(Arg.getAsExpr());
if (arg.getKind() == TemplateArgument::Expression) {
Expr *argExpr = arg.getAsExpr();
result = SemaRef.Owned(argExpr);
type = argExpr->getType();
if (Arg.getKind() == TemplateArgument::Declaration) {
ValueDecl *VD = cast<ValueDecl>(Arg.getAsDecl());
} else if (arg.getKind() == TemplateArgument::Declaration) {
ValueDecl *VD = cast<ValueDecl>(arg.getAsDecl());
// Find the instantiation of the template argument. This is
// required for nested templates.
VD = cast_or_null<ValueDecl>(
getSema().FindInstantiatedDecl(E->getLocation(),
VD, TemplateArgs));
getSema().FindInstantiatedDecl(loc, VD, TemplateArgs));
if (!VD)
return ExprError();
// Derive the type we want the substituted decl to have. This had
// better be non-dependent, or these checks will have serious problems.
QualType TargetType;
if (NTTP->isExpandedParameterPack())
TargetType = NTTP->getExpansionType(
getSema().ArgumentPackSubstitutionIndex);
else if (NTTP->isParameterPack() &&
isa<PackExpansionType>(NTTP->getType())) {
TargetType = SemaRef.SubstType(
cast<PackExpansionType>(NTTP->getType())->getPattern(),
TemplateArgs, E->getLocation(),
NTTP->getDeclName());
} else
TargetType = SemaRef.SubstType(NTTP->getType(), TemplateArgs,
E->getLocation(), NTTP->getDeclName());
assert(!TargetType.isNull() && "type substitution failed for param type");
assert(!TargetType->isDependentType() && "param type still dependent");
return SemaRef.BuildExpressionFromDeclTemplateArgument(Arg,
TargetType,
E->getLocation());
}
if (parm->isExpandedParameterPack()) {
type = parm->getExpansionType(SemaRef.ArgumentPackSubstitutionIndex);
} else if (parm->isParameterPack() &&
isa<PackExpansionType>(parm->getType())) {
type = SemaRef.SubstType(
cast<PackExpansionType>(parm->getType())->getPattern(),
TemplateArgs, loc, parm->getDeclName());
} else {
type = SemaRef.SubstType(parm->getType(), TemplateArgs,
loc, parm->getDeclName());
}
assert(!type.isNull() && "type substitution failed for param type");
assert(!type->isDependentType() && "param type still dependent");
result = SemaRef.BuildExpressionFromDeclTemplateArgument(arg, type, loc);
return SemaRef.BuildExpressionFromIntegralTemplateArgument(Arg,
E->getSourceRange().getBegin());
if (!result.isInvalid()) type = result.get()->getType();
} else {
result = SemaRef.BuildExpressionFromIntegralTemplateArgument(arg, loc);
// Note that this type can be different from the type of 'result',
// e.g. if it's an enum type.
type = arg.getIntegralType();
}
if (result.isInvalid()) return ExprError();
Expr *resultExpr = result.take();
return SemaRef.Owned(new (SemaRef.Context)
SubstNonTypeTemplateParmExpr(type,
resultExpr->getValueKind(),
loc, parm, resultExpr));
}
ExprResult
@ -1133,36 +1157,9 @@ TemplateInstantiator::TransformSubstNonTypeTemplateParmPackExpr(
assert(Index < ArgPack.pack_size() && "Substitution index out-of-range");
const TemplateArgument &Arg = ArgPack.pack_begin()[Index];
if (Arg.getKind() == TemplateArgument::Expression)
return SemaRef.Owned(Arg.getAsExpr());
if (Arg.getKind() == TemplateArgument::Declaration) {
ValueDecl *VD = cast<ValueDecl>(Arg.getAsDecl());
// Find the instantiation of the template argument. This is
// required for nested templates.
VD = cast_or_null<ValueDecl>(
getSema().FindInstantiatedDecl(E->getParameterPackLocation(),
VD, TemplateArgs));
if (!VD)
return ExprError();
QualType T;
NonTypeTemplateParmDecl *NTTP = E->getParameterPack();
if (NTTP->isExpandedParameterPack())
T = NTTP->getExpansionType(getSema().ArgumentPackSubstitutionIndex);
else if (const PackExpansionType *Expansion
= dyn_cast<PackExpansionType>(NTTP->getType()))
T = SemaRef.SubstType(Expansion->getPattern(), TemplateArgs,
E->getParameterPackLocation(), NTTP->getDeclName());
else
T = E->getType();
return SemaRef.BuildExpressionFromDeclTemplateArgument(Arg, T,
E->getParameterPackLocation());
}
return SemaRef.BuildExpressionFromIntegralTemplateArgument(Arg,
E->getParameterPackLocation());
return transformNonTypeTemplateParmRef(E->getParameterPack(),
E->getParameterPackLocation(),
Arg);
}
ExprResult

Просмотреть файл

@ -7663,6 +7663,14 @@ TreeTransform<Derived>::TransformSubstNonTypeTemplateParmPackExpr(
return SemaRef.Owned(E);
}
template<typename Derived>
ExprResult
TreeTransform<Derived>::TransformSubstNonTypeTemplateParmExpr(
SubstNonTypeTemplateParmExpr *E) {
// Default behavior is to do nothing with this transformation.
return SemaRef.Owned(E);
}
template<typename Derived>
ExprResult
TreeTransform<Derived>::TransformMaterializeTemporaryExpr(

Просмотреть файл

@ -479,6 +479,7 @@ void ExprEngine::Visit(const Stmt* S, ExplodedNode* Pred,
// We don't handle default arguments either yet, but we can fake it
// for now by just skipping them.
case Stmt::SubstNonTypeTemplateParmExprClass:
case Stmt::CXXDefaultArgExprClass: {
Dst.Add(Pred);
break;

Просмотреть файл

@ -183,6 +183,7 @@ CXCursor cxcursor::MakeCXCursor(Stmt *S, Decl *Parent,
case Stmt::DeclRefExprClass:
case Stmt::BlockDeclRefExprClass:
case Stmt::SubstNonTypeTemplateParmExprClass:
case Stmt::SubstNonTypeTemplateParmPackExprClass:
// FIXME: UnresolvedLookupExpr?
// FIXME: DependentScopeDeclRefExpr?