Index: clang/include/clang/AST/ASTContext.h =================================================================== --- clang/include/clang/AST/ASTContext.h +++ clang/include/clang/AST/ASTContext.h @@ -2355,6 +2355,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); } Index: clang/include/clang/Basic/DiagnosticSemaKinds.td =================================================================== --- clang/include/clang/Basic/DiagnosticSemaKinds.td +++ clang/include/clang/Basic/DiagnosticSemaKinds.td @@ -5122,6 +5122,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">; Index: clang/lib/Sema/SemaTemplate.cpp =================================================================== --- clang/lib/Sema/SemaTemplate.cpp +++ clang/lib/Sema/SemaTemplate.cpp @@ -9992,6 +9992,7 @@ VarDecl *Prev = Previous.getAsSingle(); VarTemplateDecl *PrevTemplate = Previous.getAsSingle(); + bool IsStaticDataMemberInstantiation = false; if (!PrevTemplate) { if (!Prev || !Prev->isStaticDataMember()) { @@ -10013,6 +10014,8 @@ // FIXME: Can we provide a note showing where this was declared? return true; } + + IsStaticDataMemberInstantiation = true; } else { // Explicitly instantiate a variable template. @@ -10105,6 +10108,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; } Index: clang/test/SemaCXX/template-explicit-instant-type-mismatch.cpp =================================================================== --- /dev/null +++ clang/test/SemaCXX/template-explicit-instant-type-mismatch.cpp @@ -0,0 +1,15 @@ +// RUN: %clang_cc1 -verify -fsyntax-only %s + +template +class A +{ + static T a; //expected-note {{in instantiation of static data member 'A::a' requested here}} +}; + +template +T A::a; + +class B +{ }; + +template int A::a; //expected-error {{type 'int' of explicit instantiation of 'A::a' does not match expected type 'B'}}