summaryrefslogtreecommitdiffstats
path: root/clang/lib
diff options
context:
space:
mode:
authorRichard Smith <richard-llvm@metafoo.co.uk>2014-05-29 03:15:31 +0000
committerRichard Smith <richard-llvm@metafoo.co.uk>2014-05-29 03:15:31 +0000
commit195d8ef452a0712105a88194848db736d415f3c2 (patch)
treea696475a249bdebaa8281cae38f33eefb4361c87 /clang/lib
parent086e5816b034754897e9c91713bdbc98633adea7 (diff)
downloadbcm5719-llvm-195d8ef452a0712105a88194848db736d415f3c2.tar.gz
bcm5719-llvm-195d8ef452a0712105a88194848db736d415f3c2.zip
When merging functions across modules (and in particular, instantiations of
member functions), ensure that the redecl chain never transitions from 'inline' to 'not inline', since that violates an AST invariant. llvm-svn: 209794
Diffstat (limited to 'clang/lib')
-rw-r--r--clang/lib/Sema/SemaTemplateInstantiateDecl.cpp12
-rw-r--r--clang/lib/Serialization/ASTReaderDecl.cpp39
2 files changed, 47 insertions, 4 deletions
diff --git a/clang/lib/Sema/SemaTemplateInstantiateDecl.cpp b/clang/lib/Sema/SemaTemplateInstantiateDecl.cpp
index be2db41efd8..40177457c14 100644
--- a/clang/lib/Sema/SemaTemplateInstantiateDecl.cpp
+++ b/clang/lib/Sema/SemaTemplateInstantiateDecl.cpp
@@ -3377,8 +3377,16 @@ void Sema::InstantiateFunctionDefinition(SourceLocation PointOfInstantiation,
!PatternDecl->getReturnType()->getContainedAutoType())
return;
- if (PatternDecl->isInlined())
- Function->setImplicitlyInline();
+ if (PatternDecl->isInlined()) {
+ // Function, and all later redeclarations of it (from imported modules,
+ // for instance), are now implicitly inline.
+ for (auto *D = Function->getMostRecentDecl(); /**/;
+ D = D->getPreviousDecl()) {
+ D->setImplicitlyInline();
+ if (D == Function)
+ break;
+ }
+ }
InstantiatingTemplate Inst(*this, PointOfInstantiation, Function);
if (Inst.isInvalid())
diff --git a/clang/lib/Serialization/ASTReaderDecl.cpp b/clang/lib/Serialization/ASTReaderDecl.cpp
index 8a0849cb909..7e652c47181 100644
--- a/clang/lib/Serialization/ASTReaderDecl.cpp
+++ b/clang/lib/Serialization/ASTReaderDecl.cpp
@@ -2491,6 +2491,32 @@ void ASTDeclReader::attachPreviousDecl(Decl *D, Decl *Previous) {
D->IdentifierNamespace |=
Previous->IdentifierNamespace &
(Decl::IDNS_Ordinary | Decl::IDNS_Tag | Decl::IDNS_Type);
+
+ // If the previous declaration is an inline function declaration, then this
+ // declaration is too.
+ if (auto *FD = dyn_cast<FunctionDecl>(D)) {
+ if (cast<FunctionDecl>(Previous)->IsInline != FD->IsInline) {
+ // FIXME: [dcl.fct.spec]p4:
+ // If a function with external linkage is declared inline in one
+ // translation unit, it shall be declared inline in all translation
+ // units in which it appears.
+ //
+ // Be careful of this case:
+ //
+ // module A:
+ // template<typename T> struct X { void f(); };
+ // template<typename T> inline void X<T>::f() {}
+ //
+ // module B instantiates the declaration of X<int>::f
+ // module C instantiates the definition of X<int>::f
+ //
+ // If module B and C are merged, we do not have a violation of this rule.
+ //
+ //if (!FD->IsInline || Previous->getOwningModule())
+ // Diag(FD->getLocation(), diag::err_odr_differing_inline);
+ FD->IsInline = true;
+ }
+ }
}
template<typename DeclT>
@@ -3162,8 +3188,17 @@ void ASTDeclReader::UpdateDecl(Decl *D, ModuleFile &ModuleFile,
return;
}
- if (Record[Idx++])
- FD->setImplicitlyInline();
+ if (Record[Idx++]) {
+ // Maintain AST consistency: any later redeclarations of this function
+ // are inline if this one is. (We might have merged another declaration
+ // into this one.)
+ for (auto *D = FD->getMostRecentDecl(); /**/;
+ D = D->getPreviousDecl()) {
+ D->setImplicitlyInline();
+ if (D == FD)
+ break;
+ }
+ }
FD->setInnerLocStart(Reader.ReadSourceLocation(ModuleFile, Record, Idx));
if (auto *CD = dyn_cast<CXXConstructorDecl>(FD))
std::tie(CD->CtorInitializers, CD->NumCtorInitializers) =
OpenPOWER on IntegriCloud