r209794 - When merging functions across modules (and in particular, instantiations of
Richard Smith
richard-llvm at metafoo.co.uk
Wed May 28 20:15:32 PDT 2014
Author: rsmith
Date: Wed May 28 22:15:31 2014
New Revision: 209794
URL: http://llvm.org/viewvc/llvm-project?rev=209794&view=rev
Log:
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.
Modified:
cfe/trunk/lib/Sema/SemaTemplateInstantiateDecl.cpp
cfe/trunk/lib/Serialization/ASTReaderDecl.cpp
cfe/trunk/test/Modules/Inputs/templates-left.h
cfe/trunk/test/Modules/Inputs/templates-right.h
cfe/trunk/test/Modules/Inputs/templates-top.h
cfe/trunk/test/Modules/templates.mm
Modified: cfe/trunk/lib/Sema/SemaTemplateInstantiateDecl.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Sema/SemaTemplateInstantiateDecl.cpp?rev=209794&r1=209793&r2=209794&view=diff
==============================================================================
--- cfe/trunk/lib/Sema/SemaTemplateInstantiateDecl.cpp (original)
+++ cfe/trunk/lib/Sema/SemaTemplateInstantiateDecl.cpp Wed May 28 22:15:31 2014
@@ -3377,8 +3377,16 @@ void Sema::InstantiateFunctionDefinition
!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())
Modified: cfe/trunk/lib/Serialization/ASTReaderDecl.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Serialization/ASTReaderDecl.cpp?rev=209794&r1=209793&r2=209794&view=diff
==============================================================================
--- cfe/trunk/lib/Serialization/ASTReaderDecl.cpp (original)
+++ cfe/trunk/lib/Serialization/ASTReaderDecl.cpp Wed May 28 22:15:31 2014
@@ -2491,6 +2491,32 @@ void ASTDeclReader::attachPreviousDecl(D
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,
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) =
Modified: cfe/trunk/test/Modules/Inputs/templates-left.h
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/Modules/Inputs/templates-left.h?rev=209794&r1=209793&r2=209794&view=diff
==============================================================================
--- cfe/trunk/test/Modules/Inputs/templates-left.h (original)
+++ cfe/trunk/test/Modules/Inputs/templates-left.h Wed May 28 22:15:31 2014
@@ -56,3 +56,7 @@ template<typename> struct DelayUpdates;
template<> struct DelayUpdates<int>;
template<typename T> struct DelayUpdates<T*>;
template<typename T> void testDelayUpdates(DelayUpdates<T> *p = 0) {}
+
+void outOfLineInlineUseLeftF(void (OutOfLineInline<int>::*)() = &OutOfLineInline<int>::f);
+void outOfLineInlineUseLeftG(void (OutOfLineInline<int>::*)() = &OutOfLineInline<int>::g);
+void outOfLineInlineUseLeftH(void (OutOfLineInline<int>::*)() = &OutOfLineInline<int>::h);
Modified: cfe/trunk/test/Modules/Inputs/templates-right.h
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/Modules/Inputs/templates-right.h?rev=209794&r1=209793&r2=209794&view=diff
==============================================================================
--- cfe/trunk/test/Modules/Inputs/templates-right.h (original)
+++ cfe/trunk/test/Modules/Inputs/templates-right.h Wed May 28 22:15:31 2014
@@ -39,3 +39,7 @@ int defineListDoubleRight() {
}
template<typename T> struct MergePatternDecl;
+
+void outOfLineInlineUseRightF(void (OutOfLineInline<int>::*)() = &OutOfLineInline<int>::f);
+void outOfLineInlineUseRightG(void (OutOfLineInline<int>::*)() = &OutOfLineInline<int>::g);
+void outOfLineInlineUseRightH(void (OutOfLineInline<int>::*)() = &OutOfLineInline<int>::h);
Modified: cfe/trunk/test/Modules/Inputs/templates-top.h
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/Modules/Inputs/templates-top.h?rev=209794&r1=209793&r2=209794&view=diff
==============================================================================
--- cfe/trunk/test/Modules/Inputs/templates-top.h (original)
+++ cfe/trunk/test/Modules/Inputs/templates-top.h Wed May 28 22:15:31 2014
@@ -31,3 +31,12 @@ template<bool, bool> struct ExplicitInst
};
template<typename> struct DelayUpdates {};
+
+template<typename T> struct OutOfLineInline {
+ void f();
+ void g();
+ void h();
+};
+template<typename T> inline void OutOfLineInline<T>::f() {}
+template<typename T> inline void OutOfLineInline<T>::g() {}
+template<typename T> inline void OutOfLineInline<T>::h() {}
Modified: cfe/trunk/test/Modules/templates.mm
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/Modules/templates.mm?rev=209794&r1=209793&r2=209794&view=diff
==============================================================================
--- cfe/trunk/test/Modules/templates.mm (original)
+++ cfe/trunk/test/Modules/templates.mm Wed May 28 22:15:31 2014
@@ -4,6 +4,12 @@
// expected-no-diagnostics
@import templates_left;
+
+void testInlineRedeclEarly() {
+ // instantiate definition now, we'll add another declaration in _right.
+ OutOfLineInline<int>().h();
+}
+
@import templates_right;
// CHECK: @list_left = global { %{{.*}}*, i32, [4 x i8] } { %{{.*}}* null, i32 8,
@@ -39,6 +45,14 @@ void testRedeclDefinition() {
redeclDefinitionEmit();
}
+void testInlineRedecl() {
+ outOfLineInlineUseLeftF();
+ outOfLineInlineUseRightG();
+
+ outOfLineInlineUseRightF();
+ outOfLineInlineUseLeftG();
+}
+
// CHECK-NOT: @_ZN21ExplicitInstantiationILb0ELb0EE1fEv(
// CHECK: declare {{.*}}@_ZN21ExplicitInstantiationILb1ELb0EE1fEv(
// CHECK: define {{.*}}@_ZN21ExplicitInstantiationILb1ELb1EE1fEv(
More information about the cfe-commits
mailing list