diff options
| author | Reid Kleckner <reid@kleckner.net> | 2014-05-14 16:02:09 +0000 |
|---|---|---|
| committer | Reid Kleckner <reid@kleckner.net> | 2014-05-14 16:02:09 +0000 |
| commit | cf87e10f9db91f0c4eed6c3f49e7b83ea2126660 (patch) | |
| tree | ad80663fb850439ea0c5b42f2b96b52dfa7253c1 /clang/lib/CodeGen/CGCXXABI.cpp | |
| parent | e92ab94d4a291fedd7de6b47d801a9e937d5928a (diff) | |
| download | bcm5719-llvm-cf87e10f9db91f0c4eed6c3f49e7b83ea2126660.tar.gz bcm5719-llvm-cf87e10f9db91f0c4eed6c3f49e7b83ea2126660.zip | |
Don't copy objects with trivial, deleted copy ctors
This affects both the Itanium and Microsoft C++ ABIs.
This is in anticipation of a change to the Itanium C++ ABI, and should
match GCC's current behavior. The new text will likely be:
"""
Pass an object of class type by value if every copy constructor and
move constructor is deleted or trivial and at least one of them is not
deleted, and the destructor is trivial.
"""
http://sourcerytools.com/pipermail/cxx-abi-dev/2014-May/002728.html
On x86 Windows, we can mostly use the same logic, where we use inalloca
instead of passing by address. However, on Win64, there are register
parameters, and we have to do what MSVC does. MSVC ignores the presence
of non-trivial move constructors and only considers the presence of
non-trivial or deleted copy constructors. If a non-trivial or deleted
copy ctor is present, it passes the argument indirectly.
This change fixes bugs and makes us more ABI compatible with both GCC
and MSVC.
Fixes PR19668.
Reviewers: rsmith
Differential Revision: http://reviews.llvm.org/D3660
llvm-svn: 208786
Diffstat (limited to 'clang/lib/CodeGen/CGCXXABI.cpp')
| -rw-r--r-- | clang/lib/CodeGen/CGCXXABI.cpp | 31 |
1 files changed, 31 insertions, 0 deletions
diff --git a/clang/lib/CodeGen/CGCXXABI.cpp b/clang/lib/CodeGen/CGCXXABI.cpp index 2bb3907ef06..933fe2db208 100644 --- a/clang/lib/CodeGen/CGCXXABI.cpp +++ b/clang/lib/CodeGen/CGCXXABI.cpp @@ -28,6 +28,37 @@ void CGCXXABI::ErrorUnsupportedABI(CodeGenFunction &CGF, StringRef S) { << S; } +bool CGCXXABI::canCopyArgument(const CXXRecordDecl *RD) const { + // If RD has a non-trivial move or copy constructor, we cannot copy the + // argument. + if (RD->hasNonTrivialCopyConstructor() || RD->hasNonTrivialMoveConstructor()) + return false; + + // If RD has a non-trivial destructor, we cannot copy the argument. + if (RD->hasNonTrivialDestructor()) + return false; + + // We can only copy the argument if there exists at least one trivial, + // non-deleted copy or move constructor. + // FIXME: This assumes that all lazily declared copy and move constructors are + // not deleted. This assumption might not be true in some corner cases. + bool CopyOrMoveDeleted = false; + for (const CXXConstructorDecl *CD : RD->ctors()) { + if (CD->isCopyConstructor() || CD->isMoveConstructor()) { + assert(CD->isTrivial()); + // We had at least one undeleted trivial copy or move ctor. Return + // directly. + if (!CD->isDeleted()) + return true; + CopyOrMoveDeleted = true; + } + } + + // If all trivial copy and move constructors are deleted, we cannot copy the + // argument. + return !CopyOrMoveDeleted; +} + llvm::Constant *CGCXXABI::GetBogusMemberPointer(QualType T) { return llvm::Constant::getNullValue(CGM.getTypes().ConvertType(T)); } |

