forked from OSchip/llvm-project
Canonicalize implicit deduction guide parameter types when forming a deduction
guide from a constructor. The purpose of this change is to avoid triggering instantiation of the class when substituting back into the deduction guide if it uses a typedef member. We will still instantiate the class if the constructor (explicitly or implicitly, directly or indirectly) uses the current instantiation in a way that we can't canonicalize out, but that seems unavoidable. llvm-svn: 295016
This commit is contained in:
parent
b2bca7e309
commit
c27b3d7623
|
@ -1585,12 +1585,7 @@ private:
|
||||||
|
|
||||||
// -- The types of the function parameters are those of the constructor.
|
// -- The types of the function parameters are those of the constructor.
|
||||||
for (auto *OldParam : TL.getParams()) {
|
for (auto *OldParam : TL.getParams()) {
|
||||||
// If we're transforming a non-template constructor, just reuse its
|
ParmVarDecl *NewParam = transformFunctionTypeParam(OldParam, Args);
|
||||||
// parameters as the parameters of the deduction guide. Otherwise, we
|
|
||||||
// need to transform their references to constructor template parameters.
|
|
||||||
ParmVarDecl *NewParam = Args.getNumLevels()
|
|
||||||
? transformFunctionTypeParam(OldParam, Args)
|
|
||||||
: OldParam;
|
|
||||||
if (!NewParam)
|
if (!NewParam)
|
||||||
return QualType();
|
return QualType();
|
||||||
ParamTypes.push_back(NewParam->getType());
|
ParamTypes.push_back(NewParam->getType());
|
||||||
|
@ -1636,16 +1631,31 @@ private:
|
||||||
transformFunctionTypeParam(ParmVarDecl *OldParam,
|
transformFunctionTypeParam(ParmVarDecl *OldParam,
|
||||||
MultiLevelTemplateArgumentList &Args) {
|
MultiLevelTemplateArgumentList &Args) {
|
||||||
TypeSourceInfo *OldDI = OldParam->getTypeSourceInfo();
|
TypeSourceInfo *OldDI = OldParam->getTypeSourceInfo();
|
||||||
TypeSourceInfo *NewDI = SemaRef.SubstType(
|
TypeSourceInfo *NewDI =
|
||||||
OldDI, Args, OldParam->getLocation(), OldParam->getDeclName());
|
Args.getNumLevels()
|
||||||
|
? SemaRef.SubstType(OldDI, Args, OldParam->getLocation(),
|
||||||
|
OldParam->getDeclName())
|
||||||
|
: OldDI;
|
||||||
if (!NewDI)
|
if (!NewDI)
|
||||||
return nullptr;
|
return nullptr;
|
||||||
|
|
||||||
|
// Canonicalize the type. This (for instance) replaces references to
|
||||||
|
// typedef members of the current instantiations with the definitions of
|
||||||
|
// those typedefs, avoiding triggering instantiation of the deduced type
|
||||||
|
// during deduction.
|
||||||
|
// FIXME: It would be preferable to retain type sugar and source
|
||||||
|
// information here (and handle this in substitution instead).
|
||||||
|
NewDI = SemaRef.Context.getTrivialTypeSourceInfo(
|
||||||
|
SemaRef.Context.getCanonicalType(NewDI->getType()),
|
||||||
|
OldParam->getLocation());
|
||||||
|
|
||||||
// Resolving a wording defect, we also inherit default arguments from the
|
// Resolving a wording defect, we also inherit default arguments from the
|
||||||
// constructor.
|
// constructor.
|
||||||
ExprResult NewDefArg;
|
ExprResult NewDefArg;
|
||||||
if (OldParam->hasDefaultArg()) {
|
if (OldParam->hasDefaultArg()) {
|
||||||
NewDefArg = SemaRef.SubstExpr(OldParam->getDefaultArg(), Args);
|
NewDefArg = Args.getNumLevels()
|
||||||
|
? SemaRef.SubstExpr(OldParam->getDefaultArg(), Args)
|
||||||
|
: OldParam->getDefaultArg();
|
||||||
if (NewDefArg.isInvalid())
|
if (NewDefArg.isInvalid())
|
||||||
return nullptr;
|
return nullptr;
|
||||||
}
|
}
|
||||||
|
|
|
@ -136,4 +136,17 @@ namespace look_into_current_instantiation {
|
||||||
B(typename X::type); // expected-note {{couldn't infer template argument 'T'}}
|
B(typename X::type); // expected-note {{couldn't infer template argument 'T'}}
|
||||||
};
|
};
|
||||||
B b = 0; // expected-error {{no viable}}
|
B b = 0; // expected-error {{no viable}}
|
||||||
|
|
||||||
|
// We should have a substitution failure in the immediate context of
|
||||||
|
// deduction when using the C(T, U) constructor (probably; core wording
|
||||||
|
// unclear).
|
||||||
|
template<typename T> struct C {
|
||||||
|
using U = typename T::type;
|
||||||
|
C(T, U);
|
||||||
|
};
|
||||||
|
|
||||||
|
struct R { R(int); typedef R type; };
|
||||||
|
C(...) -> C<R>;
|
||||||
|
|
||||||
|
C c = {1, 2};
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in New Issue