diff options
author | Hans Wennborg <hans@hanshq.net> | 2015-08-15 01:18:16 +0000 |
---|---|---|
committer | Hans Wennborg <hans@hanshq.net> | 2015-08-15 01:18:16 +0000 |
commit | 99000c24c9c08773bb74fede3ed07d6bfd95d538 (patch) | |
tree | d7d4dbba37c6c7bf562f6416cae8cb8d4f902eac /clang/lib/Sema/SemaDeclCXX.cpp | |
parent | 3a4a60cba5faf2691403206b48b26fca4f666d7c (diff) | |
download | bcm5719-llvm-99000c24c9c08773bb74fede3ed07d6bfd95d538.tar.gz bcm5719-llvm-99000c24c9c08773bb74fede3ed07d6bfd95d538.zip |
Delay emitting members of dllexport classes until the class is fully parsed (PR23542)
This enables Clang to correctly handle code such as:
struct __declspec(dllexport) S {
int x = 42;
};
where it would otherwise error due to trying to generate the default
constructor before the in-class initializer for x has been parsed.
Differential Revision: http://reviews.llvm.org/D11850
llvm-svn: 245139
Diffstat (limited to 'clang/lib/Sema/SemaDeclCXX.cpp')
-rw-r--r-- | clang/lib/Sema/SemaDeclCXX.cpp | 106 |
1 files changed, 67 insertions, 39 deletions
diff --git a/clang/lib/Sema/SemaDeclCXX.cpp b/clang/lib/Sema/SemaDeclCXX.cpp index 3bd4a23eee7..8afa3324661 100644 --- a/clang/lib/Sema/SemaDeclCXX.cpp +++ b/clang/lib/Sema/SemaDeclCXX.cpp @@ -4682,6 +4682,60 @@ static void CheckAbstractClassUsage(AbstractUsageInfo &Info, } } +static void ReferenceDllExportedMethods(Sema &S, CXXRecordDecl *Class) { + Attr *ClassAttr = getDLLAttr(Class); + if (!ClassAttr) + return; + + assert(ClassAttr->getKind() == attr::DLLExport); + + TemplateSpecializationKind TSK = Class->getTemplateSpecializationKind(); + + if (TSK == TSK_ExplicitInstantiationDeclaration) + // Don't go any further if this is just an explicit instantiation + // declaration. + return; + + for (Decl *Member : Class->decls()) { + auto *MD = dyn_cast<CXXMethodDecl>(Member); + if (!MD) + continue; + + if (Member->getAttr<DLLExportAttr>()) { + if (MD->isUserProvided()) { + // Instantiate non-default class member functions ... + + // .. except for certain kinds of template specializations. + if (TSK == TSK_ImplicitInstantiation && !ClassAttr->isInherited()) + continue; + + S.MarkFunctionReferenced(Class->getLocation(), MD); + + // The function will be passed to the consumer when its definition is + // encountered. + } else if (!MD->isTrivial() || MD->isExplicitlyDefaulted() || + MD->isCopyAssignmentOperator() || + MD->isMoveAssignmentOperator()) { + // Synthesize and instantiate non-trivial implicit methods, explicitly + // defaulted methods, and the copy and move assignment operators. The + // latter are exported even if they are trivial, because the address of + // an operator can be taken and should compare equal accross libraries. + DiagnosticErrorTrap Trap(S.Diags); + S.MarkFunctionReferenced(Class->getLocation(), MD); + if (Trap.hasErrorOccurred()) { + S.Diag(ClassAttr->getLocation(), diag::note_due_to_dllexported_class) + << Class->getName() << !S.getLangOpts().CPlusPlus11; + break; + } + + // There is no later point when we will see the definition of this + // function, so pass it to the consumer now. + S.Consumer.HandleTopLevelDecl(DeclGroupRef(MD)); + } + } + } +} + /// \brief Check class-level dllimport/dllexport attribute. void Sema::checkClassLevelDLLAttribute(CXXRecordDecl *Class) { Attr *ClassAttr = getDLLAttr(Class); @@ -4783,45 +4837,10 @@ void Sema::checkClassLevelDLLAttribute(CXXRecordDecl *Class) { NewAttr->setInherited(true); Member->addAttr(NewAttr); } - - if (MD && ClassExported) { - if (TSK == TSK_ExplicitInstantiationDeclaration) - // Don't go any further if this is just an explicit instantiation - // declaration. - continue; - - if (MD->isUserProvided()) { - // Instantiate non-default class member functions ... - - // .. except for certain kinds of template specializations. - if (TSK == TSK_ImplicitInstantiation && !ClassAttr->isInherited()) - continue; - - MarkFunctionReferenced(Class->getLocation(), MD); - - // The function will be passed to the consumer when its definition is - // encountered. - } else if (!MD->isTrivial() || MD->isExplicitlyDefaulted() || - MD->isCopyAssignmentOperator() || - MD->isMoveAssignmentOperator()) { - // Synthesize and instantiate non-trivial implicit methods, explicitly - // defaulted methods, and the copy and move assignment operators. The - // latter are exported even if they are trivial, because the address of - // an operator can be taken and should compare equal accross libraries. - DiagnosticErrorTrap Trap(Diags); - MarkFunctionReferenced(Class->getLocation(), MD); - if (Trap.hasErrorOccurred()) { - Diag(ClassAttr->getLocation(), diag::note_due_to_dllexported_class) - << Class->getName() << !getLangOpts().CPlusPlus11; - break; - } - - // There is no later point when we will see the definition of this - // function, so pass it to the consumer now. - Consumer.HandleTopLevelDecl(DeclGroupRef(MD)); - } - } } + + if (ClassExported) + DelayedDllExportClasses.push_back(Class); } /// \brief Perform propagation of DLL attributes from a derived class to a @@ -9479,7 +9498,7 @@ static void getDefaultArgExprsForConstructors(Sema &S, CXXRecordDecl *Class) { } } -void Sema::ActOnFinishCXXMemberDefaultArgs(Decl *D) { +void Sema::ActOnFinishCXXNonNestedClass(Decl *D) { auto *RD = dyn_cast<CXXRecordDecl>(D); // Default constructors that are annotated with __declspec(dllexport) which @@ -9487,6 +9506,15 @@ void Sema::ActOnFinishCXXMemberDefaultArgs(Decl *D) { // wrapped with a thunk called the default constructor closure. if (RD && Context.getTargetInfo().getCXXABI().isMicrosoft()) getDefaultArgExprsForConstructors(*this, RD); + + if (!DelayedDllExportClasses.empty()) { + // Calling ReferenceDllExportedMethods might cause the current function to + // be called again, so use a local copy of DelayedDllExportClasses. + SmallVector<CXXRecordDecl *, 4> WorkList; + std::swap(DelayedDllExportClasses, WorkList); + for (CXXRecordDecl *Class : WorkList) + ReferenceDllExportedMethods(*this, Class); + } } void Sema::AdjustDestructorExceptionSpec(CXXRecordDecl *ClassDecl, |