forked from OSchip/llvm-project
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:
parent
6b5897b4de
commit
5597ab4076
|
@ -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);
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
|
|
|
@ -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.
|
||||
|
|
|
@ -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.
|
||||
///
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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();
|
||||
|
|
|
@ -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;
|
Loading…
Reference in New Issue