aboutsummaryrefslogtreecommitdiff
path: root/lib/CodeGen
diff options
context:
space:
mode:
authorJohn McCall <rjmccall@apple.com>2010-12-15 04:00:32 +0000
committerJohn McCall <rjmccall@apple.com>2010-12-15 04:00:32 +0000
commitbfdcdc8e26097c9dbb4c40d78296f6ccc3e6684c (patch)
tree80b57258c03700b50172959830acf7fc36398940 /lib/CodeGen
parentbebbe0d9b7568ce43a464286bee49429489ef483 (diff)
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
Diffstat (limited to 'lib/CodeGen')
-rw-r--r--lib/CodeGen/CodeGenModule.cpp47
1 files changed, 24 insertions, 23 deletions
diff --git a/lib/CodeGen/CodeGenModule.cpp b/lib/CodeGen/CodeGenModule.cpp
index 1dab027455..142f29820e 100644
--- a/lib/CodeGen/CodeGenModule.cpp
+++ b/lib/CodeGen/CodeGenModule.cpp
@@ -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);
- }
- } 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);
+
+ // 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;
+ }
}
- }
+ FD = FD->getPreviousDeclaration();
+ } while (FD);
}
// Make sure the result is of the requested type.