diff options
author | Aaron Ballman <aaron@aaronballman.com> | 2012-12-09 17:45:41 +0000 |
---|---|---|
committer | Aaron Ballman <aaron@aaronballman.com> | 2012-12-09 17:45:41 +0000 |
commit | fff3248e69c478cfb4d1a1ffdefb808d5885535b (patch) | |
tree | 4d0810b453c6b57e7b4bedb1c70c0aab7c35a12b /lib/Sema | |
parent | baab683a5a95fff67439dd069e004487a2c1bc8c (diff) |
Virtual method overrides can no longer have mismatched calling conventions. This fixes PR14339.
git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@169705 91177308-0d34-0410-b5e6-96231b3b80d8
Diffstat (limited to 'lib/Sema')
-rw-r--r-- | lib/Sema/SemaDecl.cpp | 1 | ||||
-rw-r--r-- | lib/Sema/SemaDeclAttr.cpp | 13 | ||||
-rw-r--r-- | lib/Sema/SemaDeclCXX.cpp | 35 |
3 files changed, 46 insertions, 3 deletions
diff --git a/lib/Sema/SemaDecl.cpp b/lib/Sema/SemaDecl.cpp index be300539eb..aa0b41bc7a 100644 --- a/lib/Sema/SemaDecl.cpp +++ b/lib/Sema/SemaDecl.cpp @@ -4846,6 +4846,7 @@ bool Sema::AddOverriddenMethods(CXXRecordDecl *DC, CXXMethodDecl *MD) { if (CXXMethodDecl *OldMD = dyn_cast<CXXMethodDecl>(*I)) { MD->addOverriddenMethod(OldMD->getCanonicalDecl()); if (!CheckOverridingFunctionReturnType(MD, OldMD) && + !CheckOverridingFunctionAttributes(MD, OldMD) && !CheckOverridingFunctionExceptionSpec(MD, OldMD) && !CheckIfOverriddenFunctionIsMarkedFinal(MD, OldMD)) { hasDeletedOverridenMethods |= OldMD->isDeleted(); diff --git a/lib/Sema/SemaDeclAttr.cpp b/lib/Sema/SemaDeclAttr.cpp index e36ba2a457..502b358315 100644 --- a/lib/Sema/SemaDeclAttr.cpp +++ b/lib/Sema/SemaDeclAttr.cpp @@ -3557,10 +3557,11 @@ static void handleGNUInlineAttr(Sema &S, Decl *D, const AttributeList &Attr) { static void handleCallConvAttr(Sema &S, Decl *D, const AttributeList &Attr) { if (hasDeclarator(D)) return; + const FunctionDecl *FD = dyn_cast<FunctionDecl>(D); // Diagnostic is emitted elsewhere: here we store the (valid) Attr // in the Decl node for syntactic reasoning, e.g., pretty-printing. CallingConv CC; - if (S.CheckCallingConvAttr(Attr, CC)) + if (S.CheckCallingConvAttr(Attr, CC, FD)) return; if (!isa<ObjCMethodDecl>(D)) { @@ -3615,7 +3616,8 @@ static void handleOpenCLKernelAttr(Sema &S, Decl *D, const AttributeList &Attr){ D->addAttr(::new (S.Context) OpenCLKernelAttr(Attr.getRange(), S.Context)); } -bool Sema::CheckCallingConvAttr(const AttributeList &attr, CallingConv &CC) { +bool Sema::CheckCallingConvAttr(const AttributeList &attr, CallingConv &CC, + const FunctionDecl *FD) { if (attr.isInvalid()) return true; @@ -3665,7 +3667,12 @@ bool Sema::CheckCallingConvAttr(const AttributeList &attr, CallingConv &CC) { TargetInfo::CallingConvCheckResult A = TI.checkCallingConvention(CC); if (A == TargetInfo::CCCR_Warning) { Diag(attr.getLoc(), diag::warn_cconv_ignored) << attr.getName(); - CC = TI.getDefaultCallingConv(); + + TargetInfo::CallingConvMethodType MT = TargetInfo::CCMT_Unknown; + if (FD) + MT = FD->isCXXInstanceMember() ? TargetInfo::CCMT_Member : + TargetInfo::CCMT_NonMember; + CC = TI.getDefaultCallingConv(MT); } return false; diff --git a/lib/Sema/SemaDeclCXX.cpp b/lib/Sema/SemaDeclCXX.cpp index 6f1b489a2d..2fae8c9f91 100644 --- a/lib/Sema/SemaDeclCXX.cpp +++ b/lib/Sema/SemaDeclCXX.cpp @@ -26,6 +26,7 @@ #include "clang/AST/TypeLoc.h" #include "clang/AST/TypeOrdering.h" #include "clang/Basic/PartialDiagnostic.h" +#include "clang/Basic/TargetInfo.h" #include "clang/Lex/Preprocessor.h" #include "clang/Sema/CXXFieldCollector.h" #include "clang/Sema/DeclSpec.h" @@ -10950,6 +10951,40 @@ void Sema::DiagnoseReturnInConstructorExceptionHandler(CXXTryStmt *TryBlock) { } } +bool Sema::CheckOverridingFunctionAttributes(const CXXMethodDecl *New,
+ const CXXMethodDecl *Old) { + const FunctionType *NewFT = New->getType()->getAs<FunctionType>(); + const FunctionType *OldFT = Old->getType()->getAs<FunctionType>(); + + CallingConv NewCC = NewFT->getCallConv(), OldCC = OldFT->getCallConv(); + + // If the calling conventions match, everything is fine + if (NewCC == OldCC) + return false; + + // If either of the calling conventions are set to "default", we need to pick + // something more sensible based on the target. This supports code where the + // one method explicitly sets thiscall, and another has no explicit calling + // convention. + CallingConv Default = + Context.getTargetInfo().getDefaultCallingConv(TargetInfo::CCMT_Member); + if (NewCC == CC_Default) + NewCC = Default; + if (OldCC == CC_Default) + OldCC = Default; + + // If the calling conventions still don't match, then report the error + if (NewCC != OldCC) { + Diag(New->getLocation(),
+ diag::err_conflicting_overriding_cc_attributes)
+ << New->getDeclName() << New->getType() << Old->getType();
+ Diag(Old->getLocation(), diag::note_overridden_virtual_function);
+ return true;
+ } + + return false; +} + bool Sema::CheckOverridingFunctionReturnType(const CXXMethodDecl *New, const CXXMethodDecl *Old) { QualType NewTy = New->getType()->getAs<FunctionType>()->getResultType(); |