diff options
-rw-r--r-- | clang/include/clang/AST/DeclCXX.h | 3 | ||||
-rw-r--r-- | clang/include/clang/AST/DeclNodes.def | 6 | ||||
-rw-r--r-- | clang/include/clang/AST/DeclTemplate.h | 75 | ||||
-rw-r--r-- | clang/include/clang/Basic/DiagnosticSemaKinds.td | 5 | ||||
-rw-r--r-- | clang/lib/AST/DeclBase.cpp | 4 | ||||
-rw-r--r-- | clang/lib/AST/DeclTemplate.cpp | 29 | ||||
-rw-r--r-- | clang/lib/Sema/Sema.h | 12 | ||||
-rw-r--r-- | clang/lib/Sema/SemaTemplate.cpp | 145 | ||||
-rw-r--r-- | clang/lib/Sema/SemaTemplateInstantiate.cpp | 35 | ||||
-rw-r--r-- | clang/test/SemaTemplate/class-template-spec.cpp | 3 | ||||
-rw-r--r-- | clang/test/SemaTemplate/instantiation-default-1.cpp | 2 | ||||
-rw-r--r-- | clang/test/SemaTemplate/temp_class_spec.cpp | 20 |
12 files changed, 301 insertions, 38 deletions
diff --git a/clang/include/clang/AST/DeclCXX.h b/clang/include/clang/AST/DeclCXX.h index 36c461bf52e..4a74a2c2cbc 100644 --- a/clang/include/clang/AST/DeclCXX.h +++ b/clang/include/clang/AST/DeclCXX.h @@ -449,7 +449,8 @@ public: static bool classof(const Decl *D) { return D->getKind() == CXXRecord || - D->getKind() == ClassTemplateSpecialization; + D->getKind() == ClassTemplateSpecialization || + D->getKind() == ClassTemplatePartialSpecialization; } static bool classof(const CXXRecordDecl *D) { return true; } static bool classof(const ClassTemplateSpecializationDecl *D) { diff --git a/clang/include/clang/AST/DeclNodes.def b/clang/include/clang/AST/DeclNodes.def index a82d26a20c0..d1b921a4cb6 100644 --- a/clang/include/clang/AST/DeclNodes.def +++ b/clang/include/clang/AST/DeclNodes.def @@ -86,6 +86,8 @@ ABSTRACT_DECL(Named, Decl) DECL(Record, TagDecl) DECL(CXXRecord, RecordDecl) DECL(ClassTemplateSpecialization, CXXRecordDecl) + DECL(ClassTemplatePartialSpecialization, + ClassTemplateSpecializationDecl) DECL(TemplateTypeParm, TypeDecl) ABSTRACT_DECL(Value, NamedDecl) DECL(EnumConstant, ValueDecl) @@ -141,8 +143,8 @@ DECL_RANGE(Named, OverloadedFunction, ObjCImplementation) DECL_RANGE(ObjCContainer, ObjCContainer, ObjCInterface) DECL_RANGE(Field, Field, ObjCAtDefsField) DECL_RANGE(Type, Typedef, TemplateTypeParm) -DECL_RANGE(Tag, Enum, ClassTemplateSpecialization) -DECL_RANGE(Record, Record, ClassTemplateSpecialization) +DECL_RANGE(Tag, Enum, ClassTemplatePartialSpecialization) +DECL_RANGE(Record, Record, ClassTemplatePartialSpecialization) DECL_RANGE(Value, EnumConstant, NonTypeTemplateParm) DECL_RANGE(Function, Function, CXXConversion) DECL_RANGE(Template, Template, TemplateTemplateParm) diff --git a/clang/include/clang/AST/DeclTemplate.h b/clang/include/clang/AST/DeclTemplate.h index b68b46f56d0..226af3411d5 100644 --- a/clang/include/clang/AST/DeclTemplate.h +++ b/clang/include/clang/AST/DeclTemplate.h @@ -24,6 +24,7 @@ class TemplateParameterList; class TemplateDecl; class FunctionTemplateDecl; class ClassTemplateDecl; +class ClassTemplatePartialSpecializationDecl; class TemplateTypeParmDecl; class NonTypeTemplateParmDecl; class TemplateTemplateParmDecl; @@ -619,7 +620,8 @@ enum TemplateSpecializationKind { /// has not yet been declared, defined, or instantiated. TSK_Undeclared = 0, /// This template specialization was declared or defined by an - /// explicit specialization (C++ [temp.expl.spec]). + /// explicit specialization (C++ [temp.expl.spec]) or partial + /// specialization (C++ [temp.class.spec]). TSK_ExplicitSpecialization, /// This template specialization was implicitly instantiated from a /// template. (C++ [temp.inst]). @@ -654,7 +656,8 @@ class ClassTemplateSpecializationDecl /// Really a value of type TemplateSpecializationKind. unsigned SpecializationKind : 2; - ClassTemplateSpecializationDecl(ASTContext &Context, +protected: + ClassTemplateSpecializationDecl(ASTContext &Context, Kind DK, DeclContext *DC, SourceLocation L, ClassTemplateDecl *SpecializedTemplate, TemplateArgument *TemplateArgs, @@ -686,16 +689,16 @@ public: SpecializationKind = TSK; } - void Profile(llvm::FoldingSetNodeID &ID) const { - Profile(ID, TemplateArgs.getFlatArgumentList(), TemplateArgs.flat_size()); - } - /// \brief Sets the type of this specialization as it was written by /// the user. This will be a class template specialization type. void setTypeAsWritten(QualType T) { TypeForDecl = T.getTypePtr(); } + void Profile(llvm::FoldingSetNodeID &ID) const { + Profile(ID, TemplateArgs.getFlatArgumentList(), TemplateArgs.flat_size()); + } + static void Profile(llvm::FoldingSetNodeID &ID, const TemplateArgument *TemplateArgs, unsigned NumTemplateArgs) { @@ -704,12 +707,58 @@ public: } static bool classof(const Decl *D) { - return D->getKind() == ClassTemplateSpecialization; + return D->getKind() == ClassTemplateSpecialization || + D->getKind() == ClassTemplatePartialSpecialization; } static bool classof(const ClassTemplateSpecializationDecl *) { return true; } + + static bool classof(const ClassTemplatePartialSpecializationDecl *) { + return true; + } +}; + +class ClassTemplatePartialSpecializationDecl + : public ClassTemplateSpecializationDecl +{ + /// \brief The list of template parameters + TemplateParameterList* TemplateParams; + + ClassTemplatePartialSpecializationDecl(ASTContext &Context, + DeclContext *DC, SourceLocation L, + TemplateParameterList *Params, + ClassTemplateDecl *SpecializedTemplate, + TemplateArgument *TemplateArgs, + unsigned NumTemplateArgs) + : ClassTemplateSpecializationDecl(Context, ClassTemplatePartialSpecialization, + DC, L, SpecializedTemplate, TemplateArgs, + NumTemplateArgs), + TemplateParams(Params) { } + +public: + static ClassTemplatePartialSpecializationDecl * + Create(ASTContext &Context, DeclContext *DC, SourceLocation L, + TemplateParameterList *Params, + ClassTemplateDecl *SpecializedTemplate, + TemplateArgument *TemplateArgs, unsigned NumTemplateArgs, + ClassTemplatePartialSpecializationDecl *PrevDecl); + + /// Get the list of template parameters + TemplateParameterList *getTemplateParameters() const { + return TemplateParams; + } + + // FIXME: Add Profile support! + + static bool classof(const Decl *D) { + return D->getKind() == ClassTemplatePartialSpecialization; + } + + static bool classof(const ClassTemplatePartialSpecializationDecl *) { + return true; + } }; /// Declaration of a class template. @@ -722,6 +771,11 @@ protected: /// template, including explicit specializations and instantiations. llvm::FoldingSet<ClassTemplateSpecializationDecl> Specializations; + /// \brief The class template partial specializations for this class + /// template. + llvm::FoldingSet<ClassTemplatePartialSpecializationDecl> + PartialSpecializations; + /// \brief The injected-class-name type for this class template. QualType InjectedClassNameType; }; @@ -768,6 +822,13 @@ public: return CommonPtr->Specializations; } + /// \brief Retrieve the set of partial specializations of this class + /// template. + llvm::FoldingSet<ClassTemplatePartialSpecializationDecl> & + getPartialSpecializations() { + return CommonPtr->PartialSpecializations; + } + /// \brief Retrieve the type of the injected-class-name for this /// class template. /// diff --git a/clang/include/clang/Basic/DiagnosticSemaKinds.td b/clang/include/clang/Basic/DiagnosticSemaKinds.td index 946b8003bea..1f72c249635 100644 --- a/clang/include/clang/Basic/DiagnosticSemaKinds.td +++ b/clang/include/clang/Basic/DiagnosticSemaKinds.td @@ -733,8 +733,9 @@ def err_template_spec_needs_header : Error< "template specialization requires 'template<>'">; def err_template_spec_extra_headers : Error< "template specialization must have a single 'template<>' header">; -def unsup_template_partial_spec : Error< - "class template partial specialization is not yet supported">; +def unsup_template_partial_spec_ordering : Error< + "partial ordering of class template partial specializations is not yet " + "supported">; def err_template_spec_decl_out_of_scope_global : Error< "class template specialization of %0 must occur in the global scope">; def err_template_spec_decl_out_of_scope : Error< diff --git a/clang/lib/AST/DeclBase.cpp b/clang/lib/AST/DeclBase.cpp index 80b422e7538..fd7de715db7 100644 --- a/clang/lib/AST/DeclBase.cpp +++ b/clang/lib/AST/DeclBase.cpp @@ -212,6 +212,7 @@ unsigned Decl::getIdentifierNamespaceForKind(Kind DeclKind) { // Aren't looked up? case UsingDirective: case ClassTemplateSpecialization: + case ClassTemplatePartialSpecialization: return 0; } } @@ -399,6 +400,9 @@ bool DeclContext::isDependentContext() const { if (isFileContext()) return false; + if (isa<ClassTemplatePartialSpecializationDecl>(this)) + return true; + if (const CXXRecordDecl *Record = dyn_cast<CXXRecordDecl>(this)) if (Record->getDescribedClassTemplate()) return true; diff --git a/clang/lib/AST/DeclTemplate.cpp b/clang/lib/AST/DeclTemplate.cpp index f1979c4bed6..f38ee825106 100644 --- a/clang/lib/AST/DeclTemplate.cpp +++ b/clang/lib/AST/DeclTemplate.cpp @@ -268,12 +268,12 @@ TemplateArgumentList::~TemplateArgumentList() { // ClassTemplateSpecializationDecl Implementation //===----------------------------------------------------------------------===// ClassTemplateSpecializationDecl:: -ClassTemplateSpecializationDecl(ASTContext &Context, +ClassTemplateSpecializationDecl(ASTContext &Context, Kind DK, DeclContext *DC, SourceLocation L, ClassTemplateDecl *SpecializedTemplate, TemplateArgument *TemplateArgs, unsigned NumTemplateArgs) - : CXXRecordDecl(ClassTemplateSpecialization, + : CXXRecordDecl(DK, SpecializedTemplate->getTemplatedDecl()->getTagKind(), DC, L, // FIXME: Should we use DeclarationName for the name of @@ -292,10 +292,33 @@ ClassTemplateSpecializationDecl::Create(ASTContext &Context, unsigned NumTemplateArgs, ClassTemplateSpecializationDecl *PrevDecl) { ClassTemplateSpecializationDecl *Result - = new (Context)ClassTemplateSpecializationDecl(Context, DC, L, + = new (Context)ClassTemplateSpecializationDecl(Context, + ClassTemplateSpecialization, + DC, L, SpecializedTemplate, TemplateArgs, NumTemplateArgs); Context.getTypeDeclType(Result, PrevDecl); return Result; } + +//===----------------------------------------------------------------------===// +// ClassTemplatePartialSpecializationDecl Implementation +//===----------------------------------------------------------------------===// +ClassTemplatePartialSpecializationDecl * +ClassTemplatePartialSpecializationDecl:: +Create(ASTContext &Context, DeclContext *DC, SourceLocation L, + TemplateParameterList *Params, + ClassTemplateDecl *SpecializedTemplate, + TemplateArgument *TemplateArgs, unsigned NumTemplateArgs, + ClassTemplatePartialSpecializationDecl *PrevDecl) { + ClassTemplatePartialSpecializationDecl *Result + = new (Context)ClassTemplatePartialSpecializationDecl(Context, + DC, L, Params, + SpecializedTemplate, + TemplateArgs, + NumTemplateArgs); + Result->setSpecializationKind(TSK_ExplicitSpecialization); + Context.getTypeDeclType(Result, PrevDecl); + return Result; +} diff --git a/clang/lib/Sema/Sema.h b/clang/lib/Sema/Sema.h index d926fa9c4bd..c428d29367d 100644 --- a/clang/lib/Sema/Sema.h +++ b/clang/lib/Sema/Sema.h @@ -68,6 +68,7 @@ namespace clang { class TemplateArgumentList; class TemplateParameterList; class TemplateTemplateParmDecl; + class ClassTemplatePartialSpecializationDecl; class ClassTemplateDecl; class ObjCInterfaceDecl; class ObjCCompatibleAliasDecl; @@ -2017,6 +2018,17 @@ public: QualType CheckTypenameType(NestedNameSpecifier *NNS, const IdentifierInfo &II, SourceRange Range); + + bool DeduceTemplateArguments(QualType Param, QualType Arg, + llvm::SmallVectorImpl<TemplateArgument> &Deduced); + bool DeduceTemplateArguments(const TemplateArgument &Param, + const TemplateArgument &Arg, + llvm::SmallVectorImpl<TemplateArgument> &Deduced); + bool DeduceTemplateArguments(const TemplateArgumentList &ParamList, + const TemplateArgumentList &ArgList, + llvm::SmallVectorImpl<TemplateArgument> &Deduced); + bool DeduceTemplateArguments(ClassTemplatePartialSpecializationDecl *Partial, + const TemplateArgumentList &TemplateArgs); //===--------------------------------------------------------------------===// // C++ Template Instantiation diff --git a/clang/lib/Sema/SemaTemplate.cpp b/clang/lib/Sema/SemaTemplate.cpp index 179e27d8b7a..782a0d87d89 100644 --- a/clang/lib/Sema/SemaTemplate.cpp +++ b/clang/lib/Sema/SemaTemplate.cpp @@ -2000,6 +2000,8 @@ Sema::ActOnClassTemplateSpecialization(Scope *S, unsigned TagSpec, TagKind TK, ClassTemplateDecl *ClassTemplate = cast<ClassTemplateDecl>(Name.getAsTemplateDecl()); + bool isPartialSpecialization = false; + // Check the validity of the template headers that introduce this // template. // FIXME: Once we have member templates, we'll need to check @@ -2017,11 +2019,9 @@ Sema::ActOnClassTemplateSpecialization(Scope *S, unsigned TagSpec, TagKind TK, return true; } - if (TemplateParams->size() > 0) { - // FIXME: No support for class template partial specialization. - Diag(TemplateParams->getTemplateLoc(), diag::unsup_template_partial_spec); - return true; - } + // FIXME: We'll need more checks, here! + if (TemplateParams->size() > 0) + isPartialSpecialization = true; } // Check that the specialization uses the same tag kind as the @@ -2061,14 +2061,26 @@ Sema::ActOnClassTemplateSpecialization(Scope *S, unsigned TagSpec, TagKind TK, ClassTemplate->getTemplateParameters()->size()) && "Converted template argument list is too short!"); - // Find the class template specialization declaration that + // Find the class template (partial) specialization declaration that // corresponds to these arguments. llvm::FoldingSetNodeID ID; - ClassTemplateSpecializationDecl::Profile(ID, &ConvertedTemplateArgs[0], - ConvertedTemplateArgs.size()); + if (isPartialSpecialization) + // FIXME: Template parameter list matters, too + ClassTemplatePartialSpecializationDecl::Profile(ID, &ConvertedTemplateArgs[0], + ConvertedTemplateArgs.size()); + else + ClassTemplateSpecializationDecl::Profile(ID, &ConvertedTemplateArgs[0], + ConvertedTemplateArgs.size()); void *InsertPos = 0; - ClassTemplateSpecializationDecl *PrevDecl - = ClassTemplate->getSpecializations().FindNodeOrInsertPos(ID, InsertPos); + ClassTemplateSpecializationDecl *PrevDecl = 0; + + if (isPartialSpecialization) + PrevDecl + = ClassTemplate->getPartialSpecializations().FindNodeOrInsertPos(ID, + InsertPos); + else + PrevDecl + = ClassTemplate->getSpecializations().FindNodeOrInsertPos(ID, InsertPos); ClassTemplateSpecializationDecl *Specialization = 0; @@ -2088,6 +2100,31 @@ Sema::ActOnClassTemplateSpecialization(Scope *S, unsigned TagSpec, TagKind TK, Specialization = PrevDecl; Specialization->setLocation(TemplateNameLoc); PrevDecl = 0; + } else if (isPartialSpecialization) { + // FIXME: extra checking for partial specializations + + // Create a new class template partial specialization declaration node. + TemplateParameterList *TemplateParams + = static_cast<TemplateParameterList*>(*TemplateParameterLists.get()); + ClassTemplatePartialSpecializationDecl *PrevPartial + = cast_or_null<ClassTemplatePartialSpecializationDecl>(PrevDecl); + ClassTemplatePartialSpecializationDecl *Partial + = ClassTemplatePartialSpecializationDecl::Create(Context, + ClassTemplate->getDeclContext(), + TemplateNameLoc, + TemplateParams, + ClassTemplate, + &ConvertedTemplateArgs[0], + ConvertedTemplateArgs.size(), + PrevPartial); + + if (PrevPartial) { + ClassTemplate->getPartialSpecializations().RemoveNode(PrevPartial); + ClassTemplate->getPartialSpecializations().GetOrInsertNode(Partial); + } else { + ClassTemplate->getPartialSpecializations().InsertNode(Partial, InsertPos); + } + Specialization = Partial; } else { // Create a new class template specialization declaration node for // this explicit specialization. @@ -2119,7 +2156,7 @@ Sema::ActOnClassTemplateSpecialization(Scope *S, unsigned TagSpec, TagKind TK, // instantiation with a special diagnostic. SourceRange Range(TemplateNameLoc, RAngleLoc); Diag(TemplateNameLoc, diag::err_redefinition) - << Specialization << Range; + << Context.getTypeDeclType(Specialization) << Range; Diag(Def->getLocation(), diag::note_previous_definition); Specialization->setInvalidDecl(); return true; @@ -2526,3 +2563,89 @@ Sema::CheckTypenameType(NestedNameSpecifier *NNS, const IdentifierInfo &II, << Name; return QualType(); } + +// FIXME: Move to SemaTemplateDeduction.cpp +bool +Sema::DeduceTemplateArguments(QualType Param, QualType Arg, + llvm::SmallVectorImpl<TemplateArgument> &Deduced) { + // We only want to look at the canonical types, since typedefs and + // sugar are not part of template argument deduction. + Param = Context.getCanonicalType(Param); + Arg = Context.getCanonicalType(Arg); + + // If the parameter type is not dependent, just compare the types + // directly. + if (!Param->isDependentType()) + return Param == Arg; + + // FIXME: Use a visitor or switch to handle all of the kinds of + // types that the parameter may be. + if (const TemplateTypeParmType *TemplateTypeParm + = Param->getAsTemplateTypeParmType()) { + (void)TemplateTypeParm; // FIXME: use this + // The argument type can not be less qualified than the parameter + // type. + if (Param.isMoreQualifiedThan(Arg)) + return false; + + unsigned Quals = Arg.getCVRQualifiers() & ~Param.getCVRQualifiers(); + QualType DeducedType = Arg.getQualifiedType(Quals); + // FIXME: actually save the deduced type, and check that this + // deduction is consistent. + return true; + } + + if (Param.getCVRQualifiers() != Arg.getCVRQualifiers()) + return false; + + if (const PointerType *PointerParam = Param->getAsPointerType()) { + const PointerType *PointerArg = Arg->getAsPointerType(); + if (!PointerArg) + return false; + + return DeduceTemplateArguments(PointerParam->getPointeeType(), + PointerArg->getPointeeType(), + Deduced); + } + + // FIXME: Many more cases to go (to go). + return false; +} + +bool +Sema::DeduceTemplateArguments(const TemplateArgument &Param, + const TemplateArgument &Arg, + llvm::SmallVectorImpl<TemplateArgument> &Deduced) { + assert(Param.getKind() == Arg.getKind() && + "Template argument kind mismatch during deduction"); + switch (Param.getKind()) { + case TemplateArgument::Type: + return DeduceTemplateArguments(Param.getAsType(), Arg.getAsType(), + Deduced); + + default: + return false; + } +} + +bool +Sema::DeduceTemplateArguments(const TemplateArgumentList &ParamList, + const TemplateArgumentList &ArgList, + llvm::SmallVectorImpl<TemplateArgument> &Deduced) { + assert(ParamList.size() == ArgList.size()); + for (unsigned I = 0, N = ParamList.size(); I != N; ++I) { + if (!DeduceTemplateArguments(ParamList[I], ArgList[I], Deduced)) + return false; + } + return true; +} + + +bool +Sema::DeduceTemplateArguments(ClassTemplatePartialSpecializationDecl *Partial, + const TemplateArgumentList &TemplateArgs) { + llvm::SmallVector<TemplateArgument, 4> Deduced; + Deduced.resize(Partial->getTemplateParameters()->size()); + return DeduceTemplateArguments(Partial->getTemplateArgs(), TemplateArgs, + Deduced); +} diff --git a/clang/lib/Sema/SemaTemplateInstantiate.cpp b/clang/lib/Sema/SemaTemplateInstantiate.cpp index 3cac7398181..d3d771b0ebb 100644 --- a/clang/lib/Sema/SemaTemplateInstantiate.cpp +++ b/clang/lib/Sema/SemaTemplateInstantiate.cpp @@ -822,14 +822,34 @@ Sema::InstantiateClassTemplateSpecialization( if (ClassTemplateSpec->getSpecializationKind() != TSK_Undeclared) return true; - // FIXME: Push this class template instantiation onto the instantiation stack, - // checking for recursion that exceeds a certain depth. - - // FIXME: Perform class template partial specialization to select the best - // template. ClassTemplateDecl *Template = ClassTemplateSpec->getSpecializedTemplate(); - CXXRecordDecl *Pattern = Template->getTemplatedDecl(); + const TemplateArgumentList *TemplateArgs + = &ClassTemplateSpec->getTemplateArgs(); + + // Determine whether any class template partial specializations + // match the given template arguments. + llvm::SmallVector<ClassTemplatePartialSpecializationDecl *, 4> Matched; + for (llvm::FoldingSet<ClassTemplatePartialSpecializationDecl>::iterator + Partial = Template->getPartialSpecializations().begin(), + PartialEnd = Template->getPartialSpecializations().end(); + Partial != PartialEnd; + ++Partial) { + if (DeduceTemplateArguments(&*Partial, ClassTemplateSpec->getTemplateArgs())) + Matched.push_back(&*Partial); + } + + if (Matched.size() == 1) { + Pattern = Matched[0]; + // FIXME: set TemplateArgs to the template arguments of the + // partial specialization, instantiated with the deduced template + // arguments. + } else if (Matched.size() > 1) { + // FIXME: Implement partial ordering of class template partial + // specializations. + Diag(ClassTemplateSpec->getLocation(), + diag::unsup_template_partial_spec_ordering); + } // Note that this is an instantiation. ClassTemplateSpec->setSpecializationKind( @@ -837,8 +857,7 @@ Sema::InstantiateClassTemplateSpecialization( : TSK_ImplicitInstantiation); return InstantiateClass(ClassTemplateSpec->getLocation(), - ClassTemplateSpec, Pattern, - ClassTemplateSpec->getTemplateArgs(), + ClassTemplateSpec, Pattern, *TemplateArgs, ExplicitInstantiation); } diff --git a/clang/test/SemaTemplate/class-template-spec.cpp b/clang/test/SemaTemplate/class-template-spec.cpp index b3dc3b2dca2..71d8ea14be6 100644 --- a/clang/test/SemaTemplate/class-template-spec.cpp +++ b/clang/test/SemaTemplate/class-template-spec.cpp @@ -52,9 +52,6 @@ A<char>::A() { } // Diagnose specialization errors struct A<double> { }; // expected-error{{template specialization requires 'template<>'}} -template<typename T> // expected-error{{class template partial specialization is not yet supported}} -struct A<T*> { }; - template<> struct ::A<double>; namespace N { diff --git a/clang/test/SemaTemplate/instantiation-default-1.cpp b/clang/test/SemaTemplate/instantiation-default-1.cpp index ecb1fb73f90..f0ce0d3cc66 100644 --- a/clang/test/SemaTemplate/instantiation-default-1.cpp +++ b/clang/test/SemaTemplate/instantiation-default-1.cpp @@ -36,7 +36,7 @@ typedef int& int_ref_t; Def2<int_ref_t> *d2; // expected-note{{in instantiation of default argument for 'Def2<int &>' required here}} -template<> struct Def1<const int, const int> { }; // expected-error{{redefinition of 'Def1'}} +template<> struct Def1<const int, const int> { }; // expected-error{{redefinition of 'Def1<int const>'}} template<typename T, typename T2 = T&> struct Def3; diff --git a/clang/test/SemaTemplate/temp_class_spec.cpp b/clang/test/SemaTemplate/temp_class_spec.cpp new file mode 100644 index 00000000000..df652b5ba38 --- /dev/null +++ b/clang/test/SemaTemplate/temp_class_spec.cpp @@ -0,0 +1,20 @@ +// RUN: clang-cc -fsyntax-only -verify %s +template<typename T> +struct is_pointer { + static const bool value = false; +}; + +template<typename T> +struct is_pointer<T*> { + static const bool value = true; +}; + +template<typename T> +struct is_pointer<const T*> { + static const bool value = true; +}; + +int array0[is_pointer<int>::value? -1 : 1]; +int array1[is_pointer<int*>::value? 1 : -1]; +int array2[is_pointer<const int*>::value? 1 : -1]; // expected-error{{partial ordering}} \ +// expected-error{{negative}} |