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
This commit is contained in:
Douglas Gregor 2010-05-07 23:12:07 +00:00
parent 6b5897b4de
commit 5597ab4076
7 changed files with 88 additions and 4 deletions

View File

@ -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<typename Derived>
@ -291,6 +293,8 @@ case Stmt::CLASS ## Class: DISPATCH(CLASS, CLASS, S);
case NestedNameSpecifier::TypeSpecWithTemplate:
return Visit(QualType(NNS->getAsType(), 0));
}
return false;
}
template<typename Derived>
@ -327,6 +331,8 @@ case Stmt::CLASS ## Class: DISPATCH(CLASS, CLASS, S);
return getDerived().VisitTemplateArguments(Arg.pack_begin(),
Arg.pack_size());
}
return false;
}
template<typename Derived>
@ -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<TemplateSpecializationType *>(T->getTemplateId())))
return true;
return getDerived().VisitType(T);

View File

@ -10,6 +10,7 @@
#include "clang/AST/ASTConsumer.h"
#include "clang/AST/RecursiveASTVisitor.h"
#include <cstdio>
#include <iostream>
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;
}
};
}

View File

@ -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.

View File

@ -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<MarkReferencedDecls> {
Sema &S;
SourceLocation Loc;
public:
typedef RecursiveASTVisitor<MarkReferencedDecls> 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<ClassTemplateSpecializationDecl>(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.
///

View File

@ -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;

View File

@ -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();

View File

@ -0,0 +1,14 @@
// RUN: %clang_cc1 -fsyntax-only -verify %s
template<typename T>
struct X1 {
static void member() { T* x = 1; } // expected-error{{cannot initialize a variable of type 'int *' with an rvalue of type 'int'}}
};
template<void(*)()> struct instantiate { };
template<typename T>
struct X2 {
typedef instantiate<&X1<int>::member> i; // expected-note{{in instantiation of}}
};
X2<int> x;