зеркало из https://github.com/microsoft/clang-1.git
Set the "implicitly inline" bit on a method as soon as we see a definition
within the class. Teach IR gen to look for function definitions in record lexical contexts when deciding whether to emit a function whose address was taken. Fixes PR8789. git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@121833 91177308-0d34-0410-b5e6-96231b3b80d8
This commit is contained in:
Родитель
bebbe0d9b7
Коммит
bfdcdc8e26
|
@ -1503,11 +1503,16 @@ public:
|
|||
IsInline = I;
|
||||
}
|
||||
|
||||
/// Flag that this function is implicitly inline.
|
||||
void setImplicitlyInline() {
|
||||
IsInline = true;
|
||||
}
|
||||
|
||||
/// \brief Determine whether this function should be inlined, because it is
|
||||
/// either marked "inline" or is a member function of a C++ class that
|
||||
/// was defined in the class body.
|
||||
bool isInlined() const;
|
||||
|
||||
|
||||
bool isInlineDefinitionExternallyVisible() const;
|
||||
|
||||
/// isOverloadedOperator - Whether this function declaration
|
||||
|
|
|
@ -829,30 +829,31 @@ CodeGenModule::GetOrCreateLLVMFunction(llvm::StringRef MangledName,
|
|||
// list, and remove it from DeferredDecls (since we don't need it anymore).
|
||||
DeferredDeclsToEmit.push_back(DDI->second);
|
||||
DeferredDecls.erase(DDI);
|
||||
} else if (const FunctionDecl *FD = cast_or_null<FunctionDecl>(D.getDecl())) {
|
||||
// If this the first reference to a C++ inline function in a class, queue up
|
||||
// the deferred function body for emission. These are not seen as
|
||||
// top-level declarations.
|
||||
if (FD->isThisDeclarationADefinition() && MayDeferGeneration(FD)) {
|
||||
DeferredDeclsToEmit.push_back(D);
|
||||
// A called constructor which has no definition or declaration need be
|
||||
// synthesized.
|
||||
} else if (const CXXConstructorDecl *CD = dyn_cast<CXXConstructorDecl>(FD)) {
|
||||
if (CD->isImplicit()) {
|
||||
assert(CD->isUsed() && "Sema doesn't consider constructor as used.");
|
||||
DeferredDeclsToEmit.push_back(D);
|
||||
|
||||
// Otherwise, there are cases we have to worry about where we're
|
||||
// using a declaration for which we must emit a definition but where
|
||||
// we might not find a top-level definition:
|
||||
// - member functions defined inline in their classes
|
||||
// - friend functions defined inline in some class
|
||||
// - special member functions with implicit definitions
|
||||
// If we ever change our AST traversal to walk into class methods,
|
||||
// this will be unnecessary.
|
||||
} else if (getLangOptions().CPlusPlus && D.getDecl()) {
|
||||
// Look for a declaration that's lexically in a record.
|
||||
const FunctionDecl *FD = cast<FunctionDecl>(D.getDecl());
|
||||
do {
|
||||
if (isa<CXXRecordDecl>(FD->getLexicalDeclContext())) {
|
||||
if (FD->isImplicit()) {
|
||||
assert(FD->isUsed() && "Sema didn't mark implicit function as used!");
|
||||
DeferredDeclsToEmit.push_back(D);
|
||||
break;
|
||||
} else if (FD->isThisDeclarationADefinition()) {
|
||||
DeferredDeclsToEmit.push_back(D);
|
||||
break;
|
||||
}
|
||||
}
|
||||
} else if (const CXXDestructorDecl *DD = dyn_cast<CXXDestructorDecl>(FD)) {
|
||||
if (DD->isImplicit()) {
|
||||
assert(DD->isUsed() && "Sema doesn't consider destructor as used.");
|
||||
DeferredDeclsToEmit.push_back(D);
|
||||
}
|
||||
} else if (const CXXMethodDecl *MD = dyn_cast<CXXMethodDecl>(FD)) {
|
||||
if (MD->isImplicit() && MD->isCopyAssignmentOperator()) {
|
||||
assert(MD->isUsed() && "Sema doesn't consider CopyAssignment as used.");
|
||||
DeferredDeclsToEmit.push_back(D);
|
||||
}
|
||||
}
|
||||
FD = FD->getPreviousDeclaration();
|
||||
} while (FD);
|
||||
}
|
||||
|
||||
// Make sure the result is of the requested type.
|
||||
|
|
|
@ -3735,6 +3735,12 @@ Sema::ActOnFunctionDeclarator(Scope* S, Declarator& D, DeclContext* DC,
|
|||
NewFD->setAccess(AS_public);
|
||||
}
|
||||
|
||||
if (isa<CXXMethodDecl>(NewFD) && DC == CurContext && IsFunctionDefinition) {
|
||||
// A method is implicitly inline if it's defined in its class
|
||||
// definition.
|
||||
NewFD->setImplicitlyInline();
|
||||
}
|
||||
|
||||
if (SC == SC_Static && isa<CXXMethodDecl>(NewFD) &&
|
||||
!CurContext->isRecord()) {
|
||||
// C++ [class.static]p1:
|
||||
|
|
|
@ -29,3 +29,27 @@ inline void f1(int);
|
|||
void f1(int) { }
|
||||
|
||||
void test_f1() { f1(17); }
|
||||
|
||||
// PR8789
|
||||
namespace test1 {
|
||||
template <typename T> class ClassTemplate {
|
||||
private:
|
||||
friend void T::func();
|
||||
void g() {}
|
||||
};
|
||||
|
||||
// CHECK: define linkonce_odr void @_ZN5test11C4funcEv(
|
||||
|
||||
class C {
|
||||
public:
|
||||
void func() {
|
||||
ClassTemplate<C> ct;
|
||||
ct.g();
|
||||
}
|
||||
};
|
||||
|
||||
void f() {
|
||||
C c;
|
||||
c.func();
|
||||
}
|
||||
}
|
||||
|
|
Загрузка…
Ссылка в новой задаче