forked from OSchip/llvm-project
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:
parent
45b12f1835
commit
32b615c2a1
|
@ -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
|
||||
|
|
|
@ -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();
|
||||
|
|
|
@ -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;
|
||||
|
||||
|
|
|
@ -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>()); }
|
Loading…
Reference in New Issue