diff --git a/clang/include/clang/AST/ASTContext.h b/clang/include/clang/AST/ASTContext.h --- a/clang/include/clang/AST/ASTContext.h +++ b/clang/include/clang/AST/ASTContext.h @@ -2343,6 +2343,20 @@ bool hasSameType(QualType T1, QualType T2) const { return getCanonicalType(T1) == getCanonicalType(T2); } + + /// Determine whether the given types \p T1 and \p T2 are equivalent with + /// lifetime qualifiers ignored. We want this because with option -fobjc-arc, + /// the compiler automatically adds Objective C lifetime qualifiers for + /// static data members. Sometimes, this will make two types not equal while + /// they should be. + bool hasSameTypeIgnoreLifetime(QualType T1, QualType T2) const { + SplitQualType ST1 = getCanonicalType(T1).split(); + SplitQualType ST2 = getCanonicalType(T2).split(); + ST1.Quals.removeObjCLifetime(); + ST2.Quals.removeObjCLifetime(); + return ST1 == ST2; + } + bool hasSameType(const Type *T1, const Type *T2) const { return getCanonicalType(T1) == getCanonicalType(T2); } diff --git a/clang/include/clang/Basic/DiagnosticSemaKinds.td b/clang/include/clang/Basic/DiagnosticSemaKinds.td --- a/clang/include/clang/Basic/DiagnosticSemaKinds.td +++ b/clang/include/clang/Basic/DiagnosticSemaKinds.td @@ -5056,6 +5056,8 @@ "of %select{explicit instantiation|explicit specialization|" "partial specialization|redeclaration}0 of %1 does not match" " expected type %3">; +def err_invalid_template_static_data_member_spec_type : Error<"type %1 " + "of explicit instantiation of %q0 does not match expected type %2">; def err_mismatched_exception_spec_explicit_instantiation : Error< "exception specification in explicit instantiation does not match " "instantiated one">; diff --git a/clang/lib/Sema/SemaTemplate.cpp b/clang/lib/Sema/SemaTemplate.cpp --- a/clang/lib/Sema/SemaTemplate.cpp +++ b/clang/lib/Sema/SemaTemplate.cpp @@ -10027,6 +10027,7 @@ VarDecl *Prev = Previous.getAsSingle(); VarTemplateDecl *PrevTemplate = Previous.getAsSingle(); + bool IsStaticDataMemberInstantiation = false; if (!PrevTemplate) { if (!Prev || !Prev->isStaticDataMember()) { @@ -10048,6 +10049,8 @@ // FIXME: Can we provide a note showing where this was declared? return true; } + + IsStaticDataMemberInstantiation = true; } else { // Explicitly instantiate a variable template. @@ -10140,6 +10143,21 @@ return true; } + // Check the static member's type given in the explicit instantiation + // definition against the one in the class template. This won't happen in + // explicit instantiation declaration because the instantiated code won't + // be generated in that case. + if (IsStaticDataMemberInstantiation && + TSK == TSK_ExplicitInstantiationDefinition && Prev && + !Context.hasSameTypeIgnoreLifetime(Prev->getType(), R)) { + Diag(T->getTypeLoc().getBeginLoc(), + diag::err_invalid_template_static_data_member_spec_type) + << Prev << R << Prev->getType(); + Diag(Prev->getLocation(), diag::note_template_static_data_member_def_here) + << Prev; + return true; + } + // FIXME: Create an ExplicitInstantiation node? return (Decl*) nullptr; }