PR36181: Teach CodeGen to properly ignore requests to emit dependent entities.

Previously, friend function definitions within class templates slipped through
the gaps and caused the MS mangler to assert.

llvm-svn: 323935
This commit is contained in:
Richard Smith 2018-02-01 00:28:36 +00:00
parent 45b12f1835
commit 32b615c2a1
4 changed files with 29 additions and 17 deletions

View File

@ -836,6 +836,10 @@ public:
void setLexicalDeclContext(DeclContext *DC);
/// Determine whether this declaration is a templated entity (whether it is
// within the scope of a template parameter).
bool isTemplated() const;
/// isDefinedOutsideFunctionOrMethod - This predicate returns true if this
/// scoped decl is defined outside the current function or method. This is
/// roughly global variables and functions, but also handles enums (which

View File

@ -236,10 +236,23 @@ TemplateDecl *Decl::getDescribedTemplate() const {
return RD->getDescribedClassTemplate();
else if (auto *VD = dyn_cast<VarDecl>(this))
return VD->getDescribedVarTemplate();
else if (auto *AD = dyn_cast<TypeAliasDecl>(this))
return AD->getDescribedAliasTemplate();
return nullptr;
}
bool Decl::isTemplated() const {
// A declaration is dependent if it is a template or a template pattern, or
// is within (lexcially for a friend, semantically otherwise) a dependent
// context.
// FIXME: Should local extern declarations be treated like friends?
if (auto *AsDC = dyn_cast<DeclContext>(this))
return AsDC->isDependentContext();
auto *DC = getFriendObjectKind() ? getLexicalDeclContext() : getDeclContext();
return DC->isDependentContext() || isTemplateDecl() || getDescribedTemplate();
}
const DeclContext *Decl::getParentFunctionOrMethod() const {
for (const DeclContext *DC = getDeclContext();
DC && !DC->isTranslationUnit() && !DC->isNamespace();

View File

@ -4190,18 +4190,13 @@ void CodeGenModule::EmitDeclContext(const DeclContext *DC) {
/// EmitTopLevelDecl - Emit code for a single top level declaration.
void CodeGenModule::EmitTopLevelDecl(Decl *D) {
// Ignore dependent declarations.
if (D->getDeclContext() && D->getDeclContext()->isDependentContext())
if (D->isTemplated())
return;
switch (D->getKind()) {
case Decl::CXXConversion:
case Decl::CXXMethod:
case Decl::Function:
// Skip function templates
if (cast<FunctionDecl>(D)->getDescribedFunctionTemplate() ||
cast<FunctionDecl>(D)->isLateTemplateParsed())
return;
EmitGlobal(cast<FunctionDecl>(D));
// Always provide some coverage mapping
// even for the functions that aren't emitted.
@ -4214,10 +4209,6 @@ void CodeGenModule::EmitTopLevelDecl(Decl *D) {
case Decl::Var:
case Decl::Decomposition:
// Skip variable templates
if (cast<VarDecl>(D)->getDescribedVarTemplate())
return;
LLVM_FALLTHROUGH;
case Decl::VarTemplateSpecialization:
EmitGlobal(cast<VarDecl>(D));
if (auto *DD = dyn_cast<DecompositionDecl>(D))
@ -4276,16 +4267,9 @@ void CodeGenModule::EmitTopLevelDecl(Decl *D) {
DI->EmitUsingDirective(cast<UsingDirectiveDecl>(*D));
return;
case Decl::CXXConstructor:
// Skip function templates
if (cast<FunctionDecl>(D)->getDescribedFunctionTemplate() ||
cast<FunctionDecl>(D)->isLateTemplateParsed())
return;
getCXXABI().EmitCXXConstructors(cast<CXXConstructorDecl>(D));
break;
case Decl::CXXDestructor:
if (cast<FunctionDecl>(D)->isLateTemplateParsed())
return;
getCXXABI().EmitCXXDestructors(cast<CXXDestructorDecl>(D));
break;

View File

@ -0,0 +1,11 @@
// RUN: %clang_cc1 -emit-llvm-only -fmodules -triple x86_64-windows %s
// PR36181
#pragma clang module build foo
module foo {}
#pragma clang module contents
template <typename T> struct A {
friend void f(A<T>) {}
};
#pragma clang module endbuild
#pragma clang module import foo
void g() { f(A<int>()); }