Typically, template types are made canonical when deducing template arguments.
However, using canonical types also means diagnostic messages will have
canonical types when sugared types would be preferred. As an example:
#include <string>
#include <vector>
using std::vector;
using std::string;
template<typename T>
T getVector(T a) {
return T();
}
void foo() {
std::vector<std::string> V;
int s = getVector(V);
}
produces the error:
error: no viable conversion from 'std::vector<std::basic_string<char>,
std::allocator<std::basic_string<char> > >' to 'int'
int s = getVector(V);
^ ~~~~~~~~~~~~
With this patch, it gives this more readable message:
error: no viable conversion from 'std::vector<std::string>' to 'int'
int s = getVector(V);
^ ~~~~~~~~~~~~
In addition, this favors printing the parameter name instead of printing
something like "type-parameter-0-0"
Changes made to template deduction:
1) Remove the type canonicalization steps
2) Remove assertions that checked for canonical types
3) Use the type as provided, or used the desugared type.
4) For some cases, fallback to using canonical types.
Other changes:
1) Change SubstTemplateTypeParmType to store the replacement type instead of
using the canonical type.
2) Change AutoType to store the deduced type instead of using the canonical type
3) Canonicalize the types above in their Profile functions, as well as in
TemplateArgument's Profile function
4) Fix up tests.
http://llvm-reviews.chandlerc.com/D562
Files:
lib/Sema/SemaTemplateDeduction.cpp
lib/Sema/SemaTemplate.cpp
lib/AST/ASTContext.cpp
lib/AST/TemplateBase.cpp
test/CodeGenObjCXX/encode.mm
test/Misc/diag-template-diffing.cpp
test/CXX/temp/temp.fct.spec/temp.deduct/temp.deduct.call/p1-0x.cpp
test/CXX/temp/temp.fct.spec/temp.deduct/temp.deduct.call/p3-0x.cpp
test/CXX/temp/temp.arg/temp.arg.type/p2.cpp
test/CXX/temp/temp.arg/temp.arg.template/p3-0x.cpp
test/SemaTemplate/operator-template.cpp
test/SemaTemplate/instantiate-declref.cpp
test/SemaTemplate/instantiation-default-1.cpp
test/SemaTemplate/instantiate-init.cpp
test/SemaTemplate/default-expr-arguments.cpp
include/clang/AST/Type.h
Index: lib/Sema/SemaTemplateDeduction.cpp
===================================================================
--- lib/Sema/SemaTemplateDeduction.cpp
+++ lib/Sema/SemaTemplateDeduction.cpp
@@ -457,37 +457,46 @@
static Sema::TemplateDeductionResult
DeduceTemplateArguments(Sema &S,
TemplateParameterList *TemplateParams,
- const TemplateSpecializationType *Param,
+ QualType ParamIn,
QualType Arg,
TemplateDeductionInfo &Info,
SmallVectorImpl<DeducedTemplateArgument> &Deduced) {
- assert(Arg.isCanonical() && "Argument type must be canonical");
+ const TemplateSpecializationType *Param =
+ dyn_cast<TemplateSpecializationType>(ParamIn);
+ if (!Param)
+ Param =
+ cast<TemplateSpecializationType>(ParamIn.getDesugaredType(S.Context));
// Check whether the template argument is a dependent template-id.
- if (const TemplateSpecializationType *SpecArg
- = dyn_cast<TemplateSpecializationType>(Arg)) {
- // Perform template argument deduction for the template name.
- if (Sema::TemplateDeductionResult Result
- = DeduceTemplateArguments(S, TemplateParams,
- Param->getTemplateName(),
- SpecArg->getTemplateName(),
- Info, Deduced))
- return Result;
+ if (Arg->isDependentType()) {
+ if (const TemplateSpecializationType *SpecArg
+ = dyn_cast<TemplateSpecializationType>(Arg)) {
+ // Perform template argument deduction for the template name.
+ if (Sema::TemplateDeductionResult Result
+ = DeduceTemplateArguments(S, TemplateParams,
+ Param->getTemplateName(),
+ SpecArg->getTemplateName(),
+ Info, Deduced))
+ return Result;
- // Perform template argument deduction on each template
- // argument. Ignore any missing/extra arguments, since they could be
- // filled in by default arguments.
- return DeduceTemplateArguments(S, TemplateParams,
- Param->getArgs(), Param->getNumArgs(),
- SpecArg->getArgs(), SpecArg->getNumArgs(),
- Info, Deduced);
+ // Perform template argument deduction on each template
+ // argument. Ignore any missing/extra arguments, since they could be
+ // filled in by default arguments.
+ return DeduceTemplateArguments(S, TemplateParams,
+ Param->getArgs(), Param->getNumArgs(),
+ SpecArg->getArgs(), SpecArg->getNumArgs(),
+ Info, Deduced);
+ }
}
// If the argument type is a class template specialization, we
// perform template argument deduction using its template
// arguments.
const RecordType *RecordArg = dyn_cast<RecordType>(Arg);
+ if (!RecordArg)
+ RecordArg = dyn_cast<RecordType>(Arg.getDesugaredType(S.Context));
+
if (!RecordArg) {
Info.FirstArg = TemplateArgument(QualType(Param, 0));
Info.SecondArg = TemplateArgument(Arg);
@@ -508,8 +517,16 @@
TemplateParams,
Param->getTemplateName(),
TemplateName(SpecArg->getSpecializedTemplate()),
- Info, Deduced))
- return Result;
+ Info, Deduced)) {
+ if (ParamIn.isCanonical() && Arg.isCanonical())
+ return Result;
+
+ // Call this function with canonical types.
+ return DeduceTemplateArguments(S, TemplateParams,
+ S.Context.getCanonicalType(ParamIn),
+ S.Context.getCanonicalType(Arg),
+ Info, Deduced);
+ }
// Perform template argument deduction for the template arguments.
return DeduceTemplateArguments(S, TemplateParams,
@@ -874,9 +891,9 @@
///
/// \param TemplateParams the template parameters that we are deducing
///
-/// \param ParamIn the parameter type
+/// \param Param the parameter type
///
-/// \param ArgIn the argument type
+/// \param Arg the argument type
///
/// \param Info information about the template argument deduction itself
///
@@ -897,18 +914,13 @@
static Sema::TemplateDeductionResult
DeduceTemplateArgumentsByTypeMatch(Sema &S,
TemplateParameterList *TemplateParams,
- QualType ParamIn, QualType ArgIn,
+ QualType Param, QualType Arg,
TemplateDeductionInfo &Info,
SmallVectorImpl<DeducedTemplateArgument> &Deduced,
unsigned TDF,
bool PartialOrdering,
SmallVectorImpl<RefParamPartialOrderingComparison> *
RefParamComparisons) {
- // We only want to look at the canonical types, since typedefs and
- // sugar are not part of template argument deduction.
- QualType Param = S.Context.getCanonicalType(ParamIn);
- QualType Arg = S.Context.getCanonicalType(ArgIn);
-
// If the argument type is a pack expansion, look at its pattern.
// This isn't explicitly called out
if (const PackExpansionType *ArgExpansion
@@ -1092,8 +1104,8 @@
}
// Set up the template argument deduction information for a failure.
- Info.FirstArg = TemplateArgument(ParamIn);
- Info.SecondArg = TemplateArgument(ArgIn);
+ Info.FirstArg = TemplateArgument(Param);
+ Info.SecondArg = TemplateArgument(Arg);
// If the parameter is an already-substituted template parameter
// pack, do nothing: we don't know which of its arguments to look
@@ -1114,16 +1126,18 @@
// If the parameter type is not dependent, there is nothing to deduce.
if (!Param->isDependentType()) {
- if (!(TDF & TDF_SkipNonDependent) && Param != Arg)
+ if (!(TDF & TDF_SkipNonDependent) && !S.Context.hasSameType(Param, Arg))
return Sema::TDK_NonDeducedMismatch;
return Sema::TDK_Success;
}
} else if (!Param->isDependentType() &&
- Param.getUnqualifiedType() == Arg.getUnqualifiedType()) {
+ S.Context.hasSameType(Param.getUnqualifiedType(),
+ Arg.getUnqualifiedType())) {
return Sema::TDK_Success;
}
+ Param = Param.getDesugaredType(S.Context);
switch (Param->getTypeClass()) {
// Non-canonical types cannot appear here.
#define NON_CANONICAL_TYPE(Class, Base) \
@@ -1154,7 +1168,8 @@
Arg = Arg.getUnqualifiedType();
}
- return Param == Arg? Sema::TDK_Success : Sema::TDK_NonDeducedMismatch;
+ return S.Context.hasSameType(Param, Arg) ? Sema::TDK_Success
+ : Sema::TDK_NonDeducedMismatch;
}
// _Complex T [placeholder extension]
@@ -1307,10 +1322,16 @@
const FunctionProtoType *FunctionProtoArg =
dyn_cast<FunctionProtoType>(Arg);
if (!FunctionProtoArg)
+ FunctionProtoArg =
+ dyn_cast<FunctionProtoType>(Arg.getDesugaredType(S.Context));
+ if (!FunctionProtoArg)
return Sema::TDK_NonDeducedMismatch;
const FunctionProtoType *FunctionProtoParam =
- cast<FunctionProtoType>(Param);
+ dyn_cast<FunctionProtoType>(Param);
+ if (!FunctionProtoParam)
+ FunctionProtoParam =
+ cast<FunctionProtoType>(Param.getDesugaredType(S.Context));
if (FunctionProtoParam->getTypeQuals()
!= FunctionProtoArg->getTypeQuals() ||
@@ -1351,12 +1372,9 @@
// TT<i>
// TT<>
case Type::TemplateSpecialization: {
- const TemplateSpecializationType *SpecParam
- = cast<TemplateSpecializationType>(Param);
-
// Try to deduce template arguments from the template-id.
Sema::TemplateDeductionResult Result
- = DeduceTemplateArguments(S, TemplateParams, SpecParam, Arg,
+ = DeduceTemplateArguments(S, TemplateParams, Param, Arg,
Info, Deduced);
if (Result && (TDF & TDF_DerivedClass)) {
@@ -1399,7 +1417,7 @@
if (NextT != RecordT) {
TemplateDeductionInfo BaseInfo(Info.getLocation());
Sema::TemplateDeductionResult BaseResult
- = DeduceTemplateArguments(S, TemplateParams, SpecParam,
+ = DeduceTemplateArguments(S, TemplateParams, Param,
QualType(NextT, 0), BaseInfo,
Deduced);
@@ -1451,6 +1469,9 @@
const MemberPointerType *MemPtrParam = cast<MemberPointerType>(Param);
const MemberPointerType *MemPtrArg = dyn_cast<MemberPointerType>(Arg);
if (!MemPtrArg)
+ MemPtrArg =
+ dyn_cast<MemberPointerType>(Arg.getDesugaredType(S.Context));
+ if (!MemPtrArg)
return Sema::TDK_NonDeducedMismatch;
if (Sema::TemplateDeductionResult Result
@@ -1478,6 +1499,9 @@
const BlockPointerType *BlockPtrArg = dyn_cast<BlockPointerType>(Arg);
if (!BlockPtrArg)
+ BlockPtrArg =
+ dyn_cast<BlockPointerType>(Arg.getDesugaredType(S.Context));
+ if (!BlockPtrArg)
return Sema::TDK_NonDeducedMismatch;
return DeduceTemplateArgumentsByTypeMatch(S, TemplateParams,
@@ -1491,7 +1515,10 @@
// T __attribute__(((ext_vector_type(<integral constant>))))
case Type::ExtVector: {
const ExtVectorType *VectorParam = cast<ExtVectorType>(Param);
- if (const ExtVectorType *VectorArg = dyn_cast<ExtVectorType>(Arg)) {
+ const ExtVectorType *VectorArg = dyn_cast<ExtVectorType>(Arg);
+ if (!VectorArg)
+ VectorArg = dyn_cast<ExtVectorType>(Arg.getDesugaredType(S.Context));
+ if (VectorArg) {
// Make sure that the vectors have the same number of elements.
if (VectorParam->getNumElements() != VectorArg->getNumElements())
return Sema::TDK_NonDeducedMismatch;
@@ -1526,7 +1553,10 @@
const DependentSizedExtVectorType *VectorParam
= cast<DependentSizedExtVectorType>(Param);
- if (const ExtVectorType *VectorArg = dyn_cast<ExtVectorType>(Arg)) {
+ const ExtVectorType *VectorArg = dyn_cast<ExtVectorType>(Arg);
+ if (!VectorArg)
+ VectorArg = dyn_cast<ExtVectorType>(Arg.getDesugaredType(S.Context));
+ if (VectorArg) {
// Perform deduction on the element types.
if (Sema::TemplateDeductionResult Result
= DeduceTemplateArgumentsByTypeMatch(S, TemplateParams,
@@ -3166,8 +3196,17 @@
if (TemplateDeductionResult Result
= DeduceTemplateArgumentsByTypeMatch(*this, TemplateParams,
ParamType, ArgType,
- Info, Deduced, TDF))
- return Result;
+ Info, Deduced, TDF)) {
+ if (ArgType.isCanonical())
+ return Result;
+
+ ArgType = Context.getCanonicalType(ArgType);
+ Result = DeduceTemplateArgumentsByTypeMatch(*this, TemplateParams,
+ ParamType, ArgType,
+ Info, Deduced, TDF);
+ if (Result)
+ return Result;
+ }
continue;
}
Index: lib/Sema/SemaTemplate.cpp
===================================================================
--- lib/Sema/SemaTemplate.cpp
+++ lib/Sema/SemaTemplate.cpp
@@ -2514,7 +2514,7 @@
return true;
// Add the converted template type argument.
- QualType ArgType = Context.getCanonicalType(Arg.getAsType());
+ QualType ArgType = Arg.getAsType();
// Objective-C ARC:
// If an explicitly-specified template argument type is a lifetime type
Index: lib/AST/ASTContext.cpp
===================================================================
--- lib/AST/ASTContext.cpp
+++ lib/AST/ASTContext.cpp
@@ -2864,9 +2864,6 @@
QualType
ASTContext::getSubstTemplateTypeParmType(const TemplateTypeParmType *Parm,
QualType Replacement) const {
- assert(Replacement.isCanonical()
- && "replacement types must always be canonical");
-
llvm::FoldingSetNodeID ID;
SubstTemplateTypeParmType::Profile(ID, Parm, Replacement);
void *InsertPos = 0;
Index: lib/AST/TemplateBase.cpp
===================================================================
--- lib/AST/TemplateBase.cpp
+++ lib/AST/TemplateBase.cpp
@@ -240,7 +240,7 @@
break;
case Type:
- getAsType().Profile(ID);
+ getAsType().getCanonicalType().Profile(ID);
break;
case Declaration:
Index: test/CodeGenObjCXX/encode.mm
===================================================================
--- test/CodeGenObjCXX/encode.mm
+++ test/CodeGenObjCXX/encode.mm
@@ -87,7 +87,7 @@
typedef vector< float, fixed<4> > vector4f;
- // CHECK: @_ZN11rdar93574002ggE = constant [49 x i8] c"{vector<float, rdar9357400::fixed<4, -1> >=[4f]}\00"
+ // CHECK: @_ZN11rdar93574002ggE = constant [32 x i8] c"{vector<float, fixed<4> >=[4f]}\00"
extern const char gg[] = @encode(vector4f);
}
Index: test/Misc/diag-template-diffing.cpp
===================================================================
--- test/Misc/diag-template-diffing.cpp
+++ test/Misc/diag-template-diffing.cpp
@@ -257,24 +257,21 @@
int k9 = f9(V9<double>());
// CHECK-ELIDE-NOTREE: no matching function for call to 'f9'
-// CHECK-ELIDE-NOTREE: candidate function not viable: no known conversion from 'S9<[2 * ...], S9<[2 * ...], double>>' to 'S9<[2 * ...], S9<[2 * ...], const double>>' for 1st argument
+// CHECK-ELIDE-NOTREE: candidate function not viable: no known conversion from 'S9<[2 * ...], U9<double>>' to 'S9<[2 * ...], U9<const double>>' for 1st argument
// CHECK-NOELIDE-NOTREE: no matching function for call to 'f9'
-// CHECK-NOELIDE-NOTREE: candidate function not viable: no known conversion from 'S9<int, char, S9<int, char, double>>' to 'S9<int, char, S9<int, char, const double>>' for 1st argument
+// CHECK-NOELIDE-NOTREE: candidate function not viable: no known conversion from 'S9<int, char, U9<double>>' to 'S9<int, char, U9<const double>>' for 1st argument
// CHECK-ELIDE-TREE: no matching function for call to 'f9'
// CHECK-ELIDE-TREE: candidate function not viable: no known conversion from argument type to parameter type for 1st argument
// CHECK-ELIDE-TREE: S9<
// CHECK-ELIDE-TREE: [2 * ...],
-// CHECK-ELIDE-TREE: S9<
-// CHECK-ELIDE-TREE: [2 * ...],
+// CHECK-ELIDE-TREE: U9<
// CHECK-ELIDE-TREE: [double != const double]>>
// CHECK-NOELIDE-TREE: no matching function for call to 'f9'
// CHECK-NOELIDE-TREE: candidate function not viable: no known conversion from argument type to parameter type for 1st argument
// CHECK-NOELIDE-TREE: S9<
// CHECK-NOELIDE-TREE: int,
// CHECK-NOELIDE-TREE: char,
-// CHECK-NOELIDE-TREE: S9<
-// CHECK-NOELIDE-TREE: int,
-// CHECK-NOELIDE-TREE: char,
+// CHECK-NOELIDE-TREE: U9<
// CHECK-NOELIDE-TREE: [double != const double]>>
template<typename ...A> class class_types {};
Index: test/CXX/temp/temp.fct.spec/temp.deduct/temp.deduct.call/p1-0x.cpp
===================================================================
--- test/CXX/temp/temp.fct.spec/temp.deduct/temp.deduct.call/p1-0x.cpp
+++ test/CXX/temp/temp.fct.spec/temp.deduct/temp.deduct.call/p1-0x.cpp
@@ -53,9 +53,8 @@
}
-// FIXME: Use the template parameter names in this diagnostic.
template<typename ...Args1, typename ...Args2>
-typename get_nth_type<0, Args1...>::type first_arg_pair(pair<Args1, Args2>...); // expected-note{{candidate template ignored: could not match 'pair<type-parameter-0-0, type-parameter-0-1>' against 'int'}}
+typename get_nth_type<0, Args1...>::type first_arg_pair(pair<Args1, Args2>...); // expected-note{{candidate template ignored: could not match 'pair<Args1, Args2>' against 'int'}}
template<typename ...Args1, typename ...Args2>
typename get_nth_type<1, Args1...>::type second_arg_pair(pair<Args1, Args2>...);
Index: test/CXX/temp/temp.fct.spec/temp.deduct/temp.deduct.call/p3-0x.cpp
===================================================================
--- test/CXX/temp/temp.fct.spec/temp.deduct/temp.deduct.call/p3-0x.cpp
+++ test/CXX/temp/temp.fct.spec/temp.deduct/temp.deduct.call/p3-0x.cpp
@@ -23,8 +23,8 @@
X<Y&> xy2 = f0(lvalue<Y>());
}
-template<typename T> X<T> f1(const T&&); // expected-note{{candidate function [with T = int] not viable: no known conversion from 'int' to 'const int &&' for 1st argument}} \
-// expected-note{{candidate function [with T = Y] not viable: no known conversion from 'Y' to 'const Y &&' for 1st argument}}
+template<typename T> X<T> f1(const T&&); // expected-note{{candidate function [with T = int] not viable: no known conversion from 'int' to 'int const &&' for 1st argument}} \
+// expected-note{{candidate function [with T = Y] not viable: no known conversion from 'Y' to 'Y const &&' for 1st argument}}
void test_f1() {
X<int> xi0 = f1(prvalue<int>());
Index: test/CXX/temp/temp.arg/temp.arg.type/p2.cpp
===================================================================
--- test/CXX/temp/temp.arg/temp.arg.type/p2.cpp
+++ test/CXX/temp/temp.arg/temp.arg.type/p2.cpp
@@ -1,12 +1,12 @@
// RUN: %clang_cc1 -fsyntax-only -verify %s
template<class T> struct A {
- static T t; // expected-error{{static data member instantiated with function type 'int ()'}}
+ static T t; // expected-error{{static data member instantiated with function type 'function' (aka 'int ()')}}
};
typedef int function();
A<function> a; // expected-note{{instantiation of}}
template<typename T> struct B {
- B() { T t; } // expected-error{{variable instantiated with function type 'int ()'}}
+ B() { T t; } // expected-error{{variable instantiated with function type 'function' (aka 'int ()')}}
};
B<function> b; // expected-note{{instantiation of}}
Index: test/CXX/temp/temp.arg/temp.arg.template/p3-0x.cpp
===================================================================
--- test/CXX/temp/temp.arg/temp.arg.template/p3-0x.cpp
+++ test/CXX/temp/temp.arg/temp.arg.template/p3-0x.cpp
@@ -15,7 +15,7 @@
eval<B<int, float>> eB;
eval<C<17>> eC; // expected-error{{implicit instantiation of undefined template 'eval<C<17> >'}}
eval<D<int, 17>> eD; // expected-error{{implicit instantiation of undefined template 'eval<D<int, 17> >'}}
-eval<E<int, float>> eE; // expected-error{{implicit instantiation of undefined template 'eval<E<int, float, 17> >}}
+eval<E<int, float>> eE; // expected-error{{implicit instantiation of undefined template 'eval<E<int, float> >}}
template<template <int ...N> class TT> struct X0 { }; // expected-note{{previous non-type template parameter with type 'int' is here}}
template<int I, int J, int ...Rest> struct X0a;
Index: test/SemaTemplate/operator-template.cpp
===================================================================
--- test/SemaTemplate/operator-template.cpp
+++ test/SemaTemplate/operator-template.cpp
@@ -2,7 +2,7 @@
// Make sure we accept this
template<class X>struct A{typedef X Y;};
-template<class X>bool operator==(A<X>,typename A<X>::Y); // expected-note{{candidate template ignored: could not match 'A<type-parameter-0-0>' against 'B<int> *'}}
+template<class X>bool operator==(A<X>,typename A<X>::Y); // expected-note{{candidate template ignored: could not match 'A<X>' against 'B<int> *'}}
int a(A<int> x) { return operator==(x,1); }
Index: test/SemaTemplate/instantiate-declref.cpp
===================================================================
--- test/SemaTemplate/instantiate-declref.cpp
+++ test/SemaTemplate/instantiate-declref.cpp
@@ -36,7 +36,7 @@
typedef int INT;
template struct N::Outer::Inner::InnerTemplate<INT>::VeryInner;
-template struct N::Outer::Inner::InnerTemplate<INT>::UeberInner; // expected-error{{no struct named 'UeberInner' in 'N::Outer::Inner::InnerTemplate<int>'}}
+template struct N::Outer::Inner::InnerTemplate<INT>::UeberInner; // expected-error{{no struct named 'UeberInner' in 'N::Outer::Inner::InnerTemplate<INT>'}}
namespace N2 {
struct Outer2 {
Index: test/SemaTemplate/instantiation-default-1.cpp
===================================================================
--- test/SemaTemplate/instantiation-default-1.cpp
+++ test/SemaTemplate/instantiation-default-1.cpp
@@ -33,7 +33,7 @@
}
typedef int& int_ref_t;
-Def2<int_ref_t> *d2; // expected-note{{in instantiation of default argument for 'Def2<int &>' required here}}
+Def2<int_ref_t> *d2; // expected-note{{in instantiation of default argument for 'Def2<int_ref_t>' required here}}
template<> struct Def1<const int, const int> { }; // expected-error{{redefinition of 'Def1<const int>'}}
Index: test/SemaTemplate/instantiate-init.cpp
===================================================================
--- test/SemaTemplate/instantiate-init.cpp
+++ test/SemaTemplate/instantiate-init.cpp
@@ -78,7 +78,7 @@
template<int N> struct integral_c { };
template <typename T, int N>
- integral_c<N> array_lengthof(T (&x)[N]) { return integral_c<N>(); } // expected-note 2{{candidate template ignored: could not match 'T [N]' against 'const Data<}}
+ integral_c<N> array_lengthof(T (&x)[N]) { return integral_c<N>(); } // expected-note 2{{candidate template ignored: could not match 'T [N]' against 'PR7985::Data<}}
template<typename T>
struct Data {
Index: test/SemaTemplate/default-expr-arguments.cpp
===================================================================
--- test/SemaTemplate/default-expr-arguments.cpp
+++ test/SemaTemplate/default-expr-arguments.cpp
@@ -41,10 +41,10 @@
void g3(F<int> f, F<struct S> s) {
f.f();
- s.f(); // expected-note{{in instantiation of default function argument expression for 'f<S>' required here}}
+ s.f(); // expected-note{{in instantiation of default function argument expression for 'f<struct S>' required here}}
F<int> f2;
- F<S> s2; // expected-note{{in instantiation of default function argument expression for 'F<S>' required here}}
+ F<S> s2; // expected-note{{in instantiation of default function argument expression for 'F<struct S>' required here}}
}
template<typename T> struct G {
Index: include/clang/AST/Type.h
===================================================================
--- include/clang/AST/Type.h
+++ include/clang/AST/Type.h
@@ -3448,13 +3448,16 @@
class SubstTemplateTypeParmType : public Type, public llvm::FoldingSetNode {
// The original type parameter.
const TemplateTypeParmType *Replaced;
+ QualType ReplacementType;
- SubstTemplateTypeParmType(const TemplateTypeParmType *Param, QualType Canon)
- : Type(SubstTemplateTypeParm, Canon, Canon->isDependentType(),
- Canon->isInstantiationDependentType(),
- Canon->isVariablyModifiedType(),
- Canon->containsUnexpandedParameterPack()),
- Replaced(Param) { }
+ SubstTemplateTypeParmType(const TemplateTypeParmType *Param,
+ QualType Replacement)
+ : Type(SubstTemplateTypeParm, Replacement.getCanonicalType(),
+ Replacement->isDependentType(),
+ Replacement->isInstantiationDependentType(),
+ Replacement->isVariablyModifiedType(),
+ Replacement->containsUnexpandedParameterPack()),
+ Replaced(Param), ReplacementType(Replacement) { }
friend class ASTContext;
@@ -3467,7 +3470,7 @@
/// Gets the type that was substituted for the template
/// parameter.
QualType getReplacementType() const {
- return getCanonicalTypeInternal();
+ return ReplacementType;
}
bool isSugared() const { return true; }
@@ -3480,7 +3483,7 @@
const TemplateTypeParmType *Replaced,
QualType Replacement) {
ID.AddPointer(Replaced);
- ID.AddPointer(Replacement.getAsOpaquePtr());
+ ID.AddPointer(Replacement.getCanonicalType().getAsOpaquePtr());
}
static bool classof(const Type *T) {
@@ -3546,11 +3549,15 @@
/// templates and before the initializer is attached, there is no deduced type
/// and an auto type is type-dependent and canonical.
class AutoType : public Type, public llvm::FoldingSetNode {
+ QualType Deduced;
+
AutoType(QualType DeducedType)
- : Type(Auto, DeducedType.isNull() ? QualType(this, 0) : DeducedType,
+ : Type(Auto, DeducedType.isNull() ? QualType(this, 0)
+ : DeducedType.getCanonicalType(),
/*Dependent=*/DeducedType.isNull(),
/*InstantiationDependent=*/DeducedType.isNull(),
- /*VariablyModified=*/false, /*ContainsParameterPack=*/false) {
+ /*VariablyModified=*/false, /*ContainsParameterPack=*/false),
+ Deduced(DeducedType) {
assert((DeducedType.isNull() || !DeducedType->isDependentType()) &&
"deduced a dependent type for auto");
}
@@ -3562,7 +3569,7 @@
QualType desugar() const { return getCanonicalTypeInternal(); }
QualType getDeducedType() const {
- return isDeduced() ? getCanonicalTypeInternal() : QualType();
+ return isDeduced() ? Deduced : QualType();
}
bool isDeduced() const {
return !isDependentType();
@@ -3574,7 +3581,7 @@
static void Profile(llvm::FoldingSetNodeID &ID,
QualType Deduced) {
- ID.AddPointer(Deduced.getAsOpaquePtr());
+ ID.AddPointer(Deduced.getCanonicalType().getAsOpaquePtr());
}
static bool classof(const Type *T) {
_______________________________________________
cfe-commits mailing list
[email protected]
http://lists.cs.uiuc.edu/mailman/listinfo/cfe-commits