[cfe-commits] r121833 - in /cfe/trunk: include/clang/AST/Decl.h lib/CodeGen/CodeGenModule.cpp lib/Sema/SemaDecl.cpp test/CodeGenCXX/inline-functions.cpp
John McCall
rjmccall at apple.com
Tue Dec 14 20:00:32 PST 2010
Author: rjmccall
Date: Tue Dec 14 22:00:32 2010
New Revision: 121833
URL: http://llvm.org/viewvc/llvm-project?rev=121833&view=rev
Log:
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.
Modified:
cfe/trunk/include/clang/AST/Decl.h
cfe/trunk/lib/CodeGen/CodeGenModule.cpp
cfe/trunk/lib/Sema/SemaDecl.cpp
cfe/trunk/test/CodeGenCXX/inline-functions.cpp
Modified: cfe/trunk/include/clang/AST/Decl.h
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/AST/Decl.h?rev=121833&r1=121832&r2=121833&view=diff
==============================================================================
--- cfe/trunk/include/clang/AST/Decl.h (original)
+++ cfe/trunk/include/clang/AST/Decl.h Tue Dec 14 22:00:32 2010
@@ -1503,11 +1503,16 @@
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
Modified: cfe/trunk/lib/CodeGen/CodeGenModule.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/CodeGen/CodeGenModule.cpp?rev=121833&r1=121832&r2=121833&view=diff
==============================================================================
--- cfe/trunk/lib/CodeGen/CodeGenModule.cpp (original)
+++ cfe/trunk/lib/CodeGen/CodeGenModule.cpp Tue Dec 14 22:00:32 2010
@@ -829,30 +829,31 @@
// 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.
Modified: cfe/trunk/lib/Sema/SemaDecl.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Sema/SemaDecl.cpp?rev=121833&r1=121832&r2=121833&view=diff
==============================================================================
--- cfe/trunk/lib/Sema/SemaDecl.cpp (original)
+++ cfe/trunk/lib/Sema/SemaDecl.cpp Tue Dec 14 22:00:32 2010
@@ -3735,6 +3735,12 @@
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:
Modified: cfe/trunk/test/CodeGenCXX/inline-functions.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/CodeGenCXX/inline-functions.cpp?rev=121833&r1=121832&r2=121833&view=diff
==============================================================================
--- cfe/trunk/test/CodeGenCXX/inline-functions.cpp (original)
+++ cfe/trunk/test/CodeGenCXX/inline-functions.cpp Tue Dec 14 22:00:32 2010
@@ -29,3 +29,27 @@
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();
+ }
+}
More information about the cfe-commits
mailing list