Index: clang/include/clang/AST/ASTContext.h =================================================================== --- clang/include/clang/AST/ASTContext.h +++ clang/include/clang/AST/ASTContext.h @@ -2337,8 +2337,19 @@ CanQualType getCanonicalParamType(QualType T) const; /// Determine whether the given types \p T1 and \p T2 are equivalent. - bool hasSameType(QualType T1, QualType T2) const { - return getCanonicalType(T1) == getCanonicalType(T2); + /// The lifetime qualifier of Objective C can be chosen to be ignored because + /// sometimes we don't want to take this into consideration. + bool hasSameType(QualType T1, QualType T2, + bool IgnoreObjCLifetimeQual = false) const { + if (!IgnoreObjCLifetimeQual) { + return getCanonicalType(T1) == getCanonicalType(T2); + } else { + 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 @@ -5034,6 +5034,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 @@ -9977,6 +9977,7 @@ VarDecl *Prev = Previous.getAsSingle(); VarTemplateDecl *PrevTemplate = Previous.getAsSingle(); + bool IsStaticDataMemberInstantiation = false; if (!PrevTemplate) { if (!Prev || !Prev->isStaticDataMember()) { @@ -9998,6 +9999,8 @@ // FIXME: Can we provide a note showing where this was declared? return true; } + + IsStaticDataMemberInstantiation = true; } else { // Explicitly instantiate a variable template. @@ -10090,6 +10093,23 @@ 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. Objective C lifetime qualifiers will be + // automatically added by compiler with option -fobjc-arc so it should be + // ignored when comparing types. + if (IsStaticDataMemberInstantiation && + TSK==TSK_ExplicitInstantiationDefinition && Prev && + !Context.hasSameType(Prev->getType(), R, true)) { + 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) + < +class A +{ + static T a; //expected-note {{in instantiation of static data member 'A::a' requested here}} +}; + +template +T A::a; + +class B +{ }; + +template T c; //expected-note {{variable template 'c' declared here}} + +template int c; //expected-error {{type 'int' of explicit instantiation of 'c' does not match expected type 'B'}} + +template int A::a; //expected-error {{type 'int' of explicit instantiation of 'A::a' does not match expected type 'B'}}