From 5597ab4076e2bbd8972c9328f79cd1ca9fea17ce Mon Sep 17 00:00:00 2001 From: Douglas Gregor Date: Fri, 7 May 2010 23:12:07 +0000 Subject: [PATCH] When we encounter a non-dependent type during template instantiation, mark any declarations we see inside of that type as "referenced". Fixes PR7079. llvm-svn: 103323 --- clang/include/clang/AST/RecursiveASTVisitor.h | 9 +++- clang/lib/Frontend/BoostConAction.cpp | 6 +++ clang/lib/Sema/Sema.h | 1 + clang/lib/Sema/SemaExpr.cpp | 43 +++++++++++++++++++ clang/lib/Sema/SemaTemplateInstantiate.cpp | 15 +++++-- .../lib/Sema/SemaTemplateInstantiateDecl.cpp | 4 ++ .../instantiate-non-dependent-types.cpp | 14 ++++++ 7 files changed, 88 insertions(+), 4 deletions(-) create mode 100644 clang/test/SemaTemplate/instantiate-non-dependent-types.cpp diff --git a/clang/include/clang/AST/RecursiveASTVisitor.h b/clang/include/clang/AST/RecursiveASTVisitor.h index a3d639e94b40..27823694c759 100644 --- a/clang/include/clang/AST/RecursiveASTVisitor.h +++ b/clang/include/clang/AST/RecursiveASTVisitor.h @@ -257,6 +257,8 @@ case Stmt::CLASS ## Class: DISPATCH(CLASS, CLASS, S); case Type::Class: DISPATCH(Class##Type, Class##Type, T.getTypePtr()); #include "clang/AST/TypeNodes.def" } + + return false; } template @@ -291,6 +293,8 @@ case Stmt::CLASS ## Class: DISPATCH(CLASS, CLASS, S); case NestedNameSpecifier::TypeSpecWithTemplate: return Visit(QualType(NNS->getAsType(), 0)); } + + return false; } template @@ -327,6 +331,8 @@ case Stmt::CLASS ## Class: DISPATCH(CLASS, CLASS, S); return getDerived().VisitTemplateArguments(Arg.pack_begin(), Arg.pack_size()); } + + return false; } template @@ -614,7 +620,8 @@ case Stmt::CLASS ## Class: DISPATCH(CLASS, CLASS, S); return true; if (T->getTemplateId() && - getDerived().VisitTemplateSpecializationType(T->getTemplateId())) + getDerived().VisitTemplateSpecializationType( + const_cast(T->getTemplateId()))) return true; return getDerived().VisitType(T); diff --git a/clang/lib/Frontend/BoostConAction.cpp b/clang/lib/Frontend/BoostConAction.cpp index 6995969fdf97..ae150c6ec21e 100644 --- a/clang/lib/Frontend/BoostConAction.cpp +++ b/clang/lib/Frontend/BoostConAction.cpp @@ -10,6 +10,7 @@ #include "clang/AST/ASTConsumer.h" #include "clang/AST/RecursiveASTVisitor.h" #include +#include using namespace clang; namespace { @@ -19,6 +20,11 @@ namespace { /// HandleTranslationUnit - This method is called when the ASTs for entire /// translation unit have been parsed. virtual void HandleTranslationUnit(ASTContext &Ctx); + + bool VisitCXXRecordDecl(CXXRecordDecl *D) { + std::cout << D->getNameAsString() << std::endl; + return false; + } }; } diff --git a/clang/lib/Sema/Sema.h b/clang/lib/Sema/Sema.h index 1bc2a72179f2..24480fe81a08 100644 --- a/clang/lib/Sema/Sema.h +++ b/clang/lib/Sema/Sema.h @@ -1784,6 +1784,7 @@ public: virtual void PopExpressionEvaluationContext(); void MarkDeclarationReferenced(SourceLocation Loc, Decl *D); + void MarkDeclarationsReferencedInType(SourceLocation Loc, QualType T); bool DiagRuntimeBehavior(SourceLocation Loc, const PartialDiagnostic &PD); // Primary Expressions. diff --git a/clang/lib/Sema/SemaExpr.cpp b/clang/lib/Sema/SemaExpr.cpp index 03964587e9e8..73493b60662b 100644 --- a/clang/lib/Sema/SemaExpr.cpp +++ b/clang/lib/Sema/SemaExpr.cpp @@ -22,6 +22,7 @@ #include "clang/AST/Expr.h" #include "clang/AST/ExprCXX.h" #include "clang/AST/ExprObjC.h" +#include "clang/AST/RecursiveASTVisitor.h" #include "clang/AST/TypeLoc.h" #include "clang/Basic/PartialDiagnostic.h" #include "clang/Basic/SourceManager.h" @@ -7572,6 +7573,48 @@ void Sema::MarkDeclarationReferenced(SourceLocation Loc, Decl *D) { } } +namespace { + // Mark all of the declarations referenced + // FIXME: Not fully implemented yet! We need to have a better understanding + // of when we're entering + class MarkReferencedDecls : public RecursiveASTVisitor { + Sema &S; + SourceLocation Loc; + + public: + typedef RecursiveASTVisitor Inherited; + + MarkReferencedDecls(Sema &S, SourceLocation Loc) : S(S), Loc(Loc) { } + + bool VisitTemplateArgument(const TemplateArgument &Arg); + bool VisitRecordType(RecordType *T); + }; +} + +bool MarkReferencedDecls::VisitTemplateArgument(const TemplateArgument &Arg) { + if (Arg.getKind() == TemplateArgument::Declaration) { + S.MarkDeclarationReferenced(Loc, Arg.getAsDecl()); + } + + return Inherited::VisitTemplateArgument(Arg); +} + +bool MarkReferencedDecls::VisitRecordType(RecordType *T) { + if (ClassTemplateSpecializationDecl *Spec + = dyn_cast(T->getDecl())) { + const TemplateArgumentList &Args = Spec->getTemplateArgs(); + return VisitTemplateArguments(Args.getFlatArgumentList(), + Args.flat_size()); + } + + return false; +} + +void Sema::MarkDeclarationsReferencedInType(SourceLocation Loc, QualType T) { + MarkReferencedDecls Marker(*this, Loc); + Marker.Visit(Context.getCanonicalType(T)); +} + /// \brief Emit a diagnostic that describes an effect on the run-time behavior /// of the program being compiled. /// diff --git a/clang/lib/Sema/SemaTemplateInstantiate.cpp b/clang/lib/Sema/SemaTemplateInstantiate.cpp index c7489ad82107..7dab4bd8bd55 100644 --- a/clang/lib/Sema/SemaTemplateInstantiate.cpp +++ b/clang/lib/Sema/SemaTemplateInstantiate.cpp @@ -560,9 +560,7 @@ namespace { /// /// For the purposes of template instantiation, a type has already been /// transformed if it is NULL or if it is not dependent. - bool AlreadyTransformed(QualType T) { - return T.isNull() || !T->isDependentType(); - } + bool AlreadyTransformed(QualType T); /// \brief Returns the location of the entity being instantiated, if known. SourceLocation getBaseLocation() { return Loc; } @@ -624,6 +622,17 @@ namespace { }; } +bool TemplateInstantiator::AlreadyTransformed(QualType T) { + if (T.isNull()) + return true; + + if (T->isDependentType()) + return false; + + getSema().MarkDeclarationsReferencedInType(Loc, T); + return true; +} + Decl *TemplateInstantiator::TransformDecl(SourceLocation Loc, Decl *D) { if (!D) return 0; diff --git a/clang/lib/Sema/SemaTemplateInstantiateDecl.cpp b/clang/lib/Sema/SemaTemplateInstantiateDecl.cpp index 44bce7976c8e..a32c0e1ac32a 100644 --- a/clang/lib/Sema/SemaTemplateInstantiateDecl.cpp +++ b/clang/lib/Sema/SemaTemplateInstantiateDecl.cpp @@ -191,6 +191,8 @@ Decl *TemplateDeclInstantiator::VisitTypedefDecl(TypedefDecl *D) { Invalid = true; DI = SemaRef.Context.getTrivialTypeSourceInfo(SemaRef.Context.IntTy); } + } else { + SemaRef.MarkDeclarationsReferencedInType(D->getLocation(), DI->getType()); } // Create the new typedef @@ -440,6 +442,8 @@ Decl *TemplateDeclInstantiator::VisitFieldDecl(FieldDecl *D) { << DI->getType(); Invalid = true; } + } else { + SemaRef.MarkDeclarationsReferencedInType(D->getLocation(), DI->getType()); } Expr *BitWidth = D->getBitWidth(); diff --git a/clang/test/SemaTemplate/instantiate-non-dependent-types.cpp b/clang/test/SemaTemplate/instantiate-non-dependent-types.cpp new file mode 100644 index 000000000000..a0005c56675a --- /dev/null +++ b/clang/test/SemaTemplate/instantiate-non-dependent-types.cpp @@ -0,0 +1,14 @@ +// RUN: %clang_cc1 -fsyntax-only -verify %s +template +struct X1 { + static void member() { T* x = 1; } // expected-error{{cannot initialize a variable of type 'int *' with an rvalue of type 'int'}} +}; + +template struct instantiate { }; + +template +struct X2 { + typedef instantiate<&X1::member> i; // expected-note{{in instantiation of}} +}; + +X2 x;