From 91a5755ad73c5dc1dfb167e448fdd74e75a6df56 Mon Sep 17 00:00:00 2001 From: John McCall Date: Fri, 15 Jul 2011 05:09:51 +0000 Subject: [PATCH] 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 --- include/clang/AST/Expr.h | 16 +++- include/clang/AST/ExprCXX.h | 42 +++++++++ include/clang/AST/RecursiveASTVisitor.h | 1 + include/clang/Basic/StmtNodes.td | 1 + lib/AST/ExprClassification.cpp | 3 + lib/AST/ExprConstant.cpp | 6 ++ lib/AST/ItaniumMangle.cpp | 5 ++ lib/AST/StmtPrinter.cpp | 5 ++ lib/AST/StmtProfile.cpp | 6 ++ lib/CodeGen/CGExpr.cpp | 2 + lib/CodeGen/CGExprAgg.cpp | 3 + lib/CodeGen/CGExprComplex.cpp | 4 + lib/CodeGen/CGExprConstant.cpp | 5 ++ lib/CodeGen/CGExprScalar.cpp | 3 + lib/Sema/SemaTemplate.cpp | 54 +++++------- lib/Sema/SemaTemplateInstantiate.cpp | 111 ++++++++++++------------ lib/Sema/TreeTransform.h | 8 ++ lib/StaticAnalyzer/Core/ExprEngine.cpp | 1 + tools/libclang/CXCursor.cpp | 1 + 19 files changed, 189 insertions(+), 88 deletions(-) diff --git a/include/clang/AST/Expr.h b/include/clang/AST/Expr.h index 369820aa74..5445a9dae5 100644 --- a/include/clang/AST/Expr.h +++ b/include/clang/AST/Expr.h @@ -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(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(this)->IgnoreImpCasts(); + } const Expr *IgnoreParens() const { return const_cast(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(e)) + e = ice->getSubExpr(); + return e; +} + /// ExplicitCastExpr - An explicit cast written in the source /// code. /// diff --git a/include/clang/AST/ExprCXX.h b/include/clang/AST/ExprCXX.h index e23b02cae0..97b015fdd6 100644 --- a/include/clang/AST/ExprCXX.h +++ b/include/clang/AST/ExprCXX.h @@ -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(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. /// diff --git a/include/clang/AST/RecursiveASTVisitor.h b/include/clang/AST/RecursiveASTVisitor.h index 7cdb0adc65..85c5c08853 100644 --- a/include/clang/AST/RecursiveASTVisitor.h +++ b/include/clang/AST/RecursiveASTVisitor.h @@ -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. diff --git a/include/clang/Basic/StmtNodes.td b/include/clang/Basic/StmtNodes.td index c07953eeca..73996e43d5 100644 --- a/include/clang/Basic/StmtNodes.td +++ b/include/clang/Basic/StmtNodes.td @@ -120,6 +120,7 @@ def UnresolvedMemberExpr : DStmt; def CXXNoexceptExpr : DStmt; def PackExpansionExpr : DStmt; def SizeOfPackExpr : DStmt; +def SubstNonTypeTemplateParmExpr : DStmt; def SubstNonTypeTemplateParmPackExpr : DStmt; def MaterializeTemporaryExpr : DStmt; diff --git a/lib/AST/ExprClassification.cpp b/lib/AST/ExprClassification.cpp index f75a56c39e..e7888a6aa7 100644 --- a/lib/AST/ExprClassification.cpp +++ b/lib/AST/ExprClassification.cpp @@ -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(E)->getReplacement()); // C++ [expr.sub]p1: The result is an lvalue of type "T". // However, subscripting vector types is more like member access. diff --git a/lib/AST/ExprConstant.cpp b/lib/AST/ExprConstant.cpp index 9943222b1d..987b02bb8f 100644 --- a/lib/AST/ExprConstant.cpp +++ b/lib/AST/ExprConstant.cpp @@ -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(E)->getReplacement(), Ctx); + case Expr::ParenExprClass: return CheckICE(cast(E)->getSubExpr(), Ctx); case Expr::GenericSelectionExprClass: diff --git a/lib/AST/ItaniumMangle.cpp b/lib/AST/ItaniumMangle.cpp index b07e962871..ec9863b298 100644 --- a/lib/AST/ItaniumMangle.cpp +++ b/lib/AST/ItaniumMangle.cpp @@ -2279,6 +2279,11 @@ recurse: mangleExpression(cast(E)->getExpr(), Arity); break; + case Expr::SubstNonTypeTemplateParmExprClass: + mangleExpression(cast(E)->getReplacement(), + Arity); + break; + case Expr::CXXMemberCallExprClass: // fallthrough case Expr::CallExprClass: { const CallExpr *CE = cast(E); diff --git a/lib/AST/StmtPrinter.cpp b/lib/AST/StmtPrinter.cpp index f8edaf7ccf..f705a84c7c 100644 --- a/lib/AST/StmtPrinter.cpp +++ b/lib/AST/StmtPrinter.cpp @@ -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()); } diff --git a/lib/AST/StmtProfile.cpp b/lib/AST/StmtProfile.cpp index 661bb1e4e6..120c9e50a9 100644 --- a/lib/AST/StmtProfile.cpp +++ b/lib/AST/StmtProfile.cpp @@ -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); diff --git a/lib/CodeGen/CGExpr.cpp b/lib/CodeGen/CGExpr.cpp index ef2ac4277b..a7e8003eaa 100644 --- a/lib/CodeGen/CGExpr.cpp +++ b/lib/CodeGen/CGExpr.cpp @@ -705,6 +705,8 @@ LValue CodeGenFunction::EmitLValue(const Expr *E) { return EmitLValue(cast(E)->getChosenSubExpr(getContext())); case Expr::OpaqueValueExprClass: return EmitOpaqueValueLValue(cast(E)); + case Expr::SubstNonTypeTemplateParmExprClass: + return EmitLValue(cast(E)->getReplacement()); case Expr::ImplicitCastExprClass: case Expr::CStyleCastExprClass: case Expr::CXXFunctionalCastExprClass: diff --git a/lib/CodeGen/CGExprAgg.cpp b/lib/CodeGen/CGExprAgg.cpp index f4387cd0de..915ffd6034 100644 --- a/lib/CodeGen/CGExprAgg.cpp +++ b/lib/CodeGen/CGExprAgg.cpp @@ -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); } diff --git a/lib/CodeGen/CGExprComplex.cpp b/lib/CodeGen/CGExprComplex.cpp index a88f112a16..35cff1d727 100644 --- a/lib/CodeGen/CGExprComplex.cpp +++ b/lib/CodeGen/CGExprComplex.cpp @@ -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); } diff --git a/lib/CodeGen/CGExprConstant.cpp b/lib/CodeGen/CGExprConstant.cpp index 8f27a51474..45e44dda0f 100644 --- a/lib/CodeGen/CGExprConstant.cpp +++ b/lib/CodeGen/CGExprConstant.cpp @@ -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()); } diff --git a/lib/CodeGen/CGExprScalar.cpp b/lib/CodeGen/CGExprScalar.cpp index 17d40c3ef2..410e9a736b 100644 --- a/lib/CodeGen/CGExprScalar.cpp +++ b/lib/CodeGen/CGExprScalar.cpp @@ -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()); } diff --git a/lib/Sema/SemaTemplate.cpp b/lib/Sema/SemaTemplate.cpp index 2b3e10e661..2514b48de3 100644 --- a/lib/Sema/SemaTemplate.cpp +++ b/lib/Sema/SemaTemplate.cpp @@ -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(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(Arg)) + Arg = subst->getReplacement()->IgnoreImpCasts(); + bool AddressTaken = false; SourceLocation AddrOpLoc; if (UnaryOperator *UnOp = dyn_cast(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(UnOp->getSubExpr())) { - Converted = TemplateArgument(ArgIn); - return false; - } - - DRE = dyn_cast(UnOp->getSubExpr()); + Arg = UnOp->getSubExpr(); AddressTaken = true; AddrOpLoc = UnOp->getOperatorLoc(); } - } else { - if (S.getLangOptions().Microsoft && isa(Arg)) { - Converted = TemplateArgument(ArgIn); - return false; - } - DRE = dyn_cast(Arg); } + + if (S.getLangOptions().Microsoft && isa(Arg)) { + Converted = TemplateArgument(ArgIn); + return false; + } + + while (SubstNonTypeTemplateParmExpr *subst = + dyn_cast(Arg)) + Arg = subst->getReplacement()->IgnoreImpCasts(); + + DeclRefExpr *DRE = dyn_cast(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(Arg)) + Arg = subst->getReplacement()->IgnoreImpCasts(); + // A pointer-to-member constant written &Class::member. if (UnaryOperator *UnOp = dyn_cast(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. diff --git a/lib/Sema/SemaTemplateInstantiate.cpp b/lib/Sema/SemaTemplateInstantiate.cpp index edafb00c22..1988f14458 100644 --- a/lib/Sema/SemaTemplateInstantiate.cpp +++ b/lib/Sema/SemaTemplateInstantiate.cpp @@ -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(Arg.getAsDecl()); + } else if (arg.getKind() == TemplateArgument::Declaration) { + ValueDecl *VD = cast(arg.getAsDecl()); // Find the instantiation of the template argument. This is // required for nested templates. VD = cast_or_null( - 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(NTTP->getType())) { - TargetType = SemaRef.SubstType( - cast(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(parm->getType())) { + type = SemaRef.SubstType( + cast(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(Arg.getAsDecl()); - - // Find the instantiation of the template argument. This is - // required for nested templates. - VD = cast_or_null( - 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(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 diff --git a/lib/Sema/TreeTransform.h b/lib/Sema/TreeTransform.h index 040ba9ee12..0530b5a172 100644 --- a/lib/Sema/TreeTransform.h +++ b/lib/Sema/TreeTransform.h @@ -7663,6 +7663,14 @@ TreeTransform::TransformSubstNonTypeTemplateParmPackExpr( return SemaRef.Owned(E); } +template +ExprResult +TreeTransform::TransformSubstNonTypeTemplateParmExpr( + SubstNonTypeTemplateParmExpr *E) { + // Default behavior is to do nothing with this transformation. + return SemaRef.Owned(E); +} + template ExprResult TreeTransform::TransformMaterializeTemporaryExpr( diff --git a/lib/StaticAnalyzer/Core/ExprEngine.cpp b/lib/StaticAnalyzer/Core/ExprEngine.cpp index fbaa8490e9..cdf76bfa3e 100644 --- a/lib/StaticAnalyzer/Core/ExprEngine.cpp +++ b/lib/StaticAnalyzer/Core/ExprEngine.cpp @@ -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; diff --git a/tools/libclang/CXCursor.cpp b/tools/libclang/CXCursor.cpp index 86997d6701..b3c57dc934 100644 --- a/tools/libclang/CXCursor.cpp +++ b/tools/libclang/CXCursor.cpp @@ -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?