diff options
Diffstat (limited to 'clang/lib/Sema/SemaDecl.cpp')
-rw-r--r-- | clang/lib/Sema/SemaDecl.cpp | 26 |
1 files changed, 24 insertions, 2 deletions
diff --git a/clang/lib/Sema/SemaDecl.cpp b/clang/lib/Sema/SemaDecl.cpp index 9efcb52d148..d584ed85710 100644 --- a/clang/lib/Sema/SemaDecl.cpp +++ b/clang/lib/Sema/SemaDecl.cpp @@ -6362,9 +6362,31 @@ bool Sema::CheckFunctionDeclaration(Scope *S, FunctionDecl *NewFD, } } else { - if (isa<CXXMethodDecl>(NewFD)) // Set access for out-of-line definitions - NewFD->setAccess(OldDecl->getAccess()); + // This needs to happen first so that 'inline' propagates. NewFD->setPreviousDeclaration(cast<FunctionDecl>(OldDecl)); + + if (isa<CXXMethodDecl>(NewFD)) { + // A valid redeclaration of a C++ method must be out-of-line, + // but (unfortunately) it's not necessarily a definition + // because of templates, which means that the previous + // declaration is not necessarily from the class definition. + + // For just setting the access, that doesn't matter. + CXXMethodDecl *oldMethod = cast<CXXMethodDecl>(OldDecl); + NewFD->setAccess(oldMethod->getAccess()); + + // Update the key-function state if necessary for this ABI. + if (NewFD->isInlined() && + !Context.getTargetInfo().getCXXABI().canKeyFunctionBeInline()) { + // setNonKeyFunction needs to work with the original + // declaration from the class definition, and isVirtual() is + // just faster in that case, so map back to that now. + oldMethod = cast<CXXMethodDecl>(oldMethod->getFirstDeclaration()); + if (oldMethod->isVirtual()) { + Context.setNonKeyFunction(oldMethod); + } + } + } } } |