Skip to content
This repository has been archived by the owner on Apr 23, 2020. It is now read-only.

Commit

Permalink
Fix some subtle wrong partial ordering bugs particularly with C++1z a…
Browse files Browse the repository at this point in the history
…uto-typed

non-type template parameters.

During partial ordering, when checking the substituted deduced template
arguments match the original, check the types of non-type template arguments
match even if they're dependent. The only way we get dependent types here is if
they really represent types of the other template (which are supposed to be
modeled as being substituted for unique, non-dependent types).

In order to make this work for auto-typed non-type template arguments, we need
to be able to perform auto deduction even when the initializer and
(potentially) the auto type are dependent, support for which is the bulk of
this patch. (Note that this requires the ability to deduce only a single level
of a multi-level dependent type.)


git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@290511 91177308-0d34-0410-b5e6-96231b3b80d8
  • Loading branch information
zygoloid committed Dec 25, 2016
1 parent ee97307 commit 89014aa
Show file tree
Hide file tree
Showing 7 changed files with 189 additions and 93 deletions.
20 changes: 12 additions & 8 deletions include/clang/AST/Type.h
Expand Up @@ -4092,18 +4092,22 @@ class SubstTemplateTypeParmPackType : public Type, public llvm::FoldingSetNode {
/// \brief Represents a C++11 auto or C++14 decltype(auto) type.
///
/// These types are usually a placeholder for a deduced type. However, before
/// the initializer is attached, or if the initializer is type-dependent, there
/// is no deduced type and an auto type is canonical. In the latter case, it is
/// also a dependent type.
/// the initializer is attached, or (usually) if the initializer is
/// type-dependent, there is no deduced type and an auto type is canonical. In
/// the latter case, it is also a dependent type.
class AutoType : public Type, public llvm::FoldingSetNode {
AutoType(QualType DeducedType, AutoTypeKeyword Keyword, bool IsDependent)
: Type(Auto, DeducedType.isNull() ? QualType(this, 0) : DeducedType,
/*Dependent=*/IsDependent, /*InstantiationDependent=*/IsDependent,
/*VariablyModified=*/false,
/*ContainsParameterPack=*/DeducedType.isNull()
? false : DeducedType->containsUnexpandedParameterPack()) {
assert((DeducedType.isNull() || !IsDependent) &&
"auto deduced to dependent type");
/*VariablyModified=*/false, /*ContainsParameterPack=*/false) {
if (!DeducedType.isNull()) {
if (DeducedType->isDependentType())
setDependent();
if (DeducedType->isInstantiationDependentType())
setInstantiationDependent();
if (DeducedType->containsUnexpandedParameterPack())
setContainsUnexpandedParameterPack();
}
AutoTypeBits.Keyword = (unsigned)Keyword;
}

Expand Down
10 changes: 6 additions & 4 deletions include/clang/Sema/Sema.h
Expand Up @@ -6655,10 +6655,12 @@ class Sema {
DAR_FailedAlreadyDiagnosed
};

DeduceAutoResult DeduceAutoType(TypeSourceInfo *AutoType, Expr *&Initializer,
QualType &Result);
DeduceAutoResult DeduceAutoType(TypeLoc AutoTypeLoc, Expr *&Initializer,
QualType &Result);
DeduceAutoResult
DeduceAutoType(TypeSourceInfo *AutoType, Expr *&Initializer, QualType &Result,
Optional<unsigned> DependentDeductionDepth = None);
DeduceAutoResult
DeduceAutoType(TypeLoc AutoTypeLoc, Expr *&Initializer, QualType &Result,
Optional<unsigned> DependentDeductionDepth = None);
void DiagnoseAutoDeductionFailure(VarDecl *VDecl, Expr *Init);
bool DeduceReturnType(FunctionDecl *FD, SourceLocation Loc,
bool Diagnose = true);
Expand Down
13 changes: 11 additions & 2 deletions include/clang/Sema/TemplateDeduction.h
Expand Up @@ -40,6 +40,9 @@ class TemplateDeductionInfo {
/// \brief Have we suppressed an error during deduction?
bool HasSFINAEDiagnostic;

/// \brief The template parameter depth for which we're performing deduction.
unsigned DeducedDepth;

/// \brief Warnings (and follow-on notes) that were suppressed due to
/// SFINAE while performing template argument deduction.
SmallVector<PartialDiagnosticAt, 4> SuppressedDiagnostics;
Expand All @@ -48,16 +51,22 @@ class TemplateDeductionInfo {
void operator=(const TemplateDeductionInfo &) = delete;

public:
TemplateDeductionInfo(SourceLocation Loc)
TemplateDeductionInfo(SourceLocation Loc, unsigned DeducedDepth = 0)
: Deduced(nullptr), Loc(Loc), HasSFINAEDiagnostic(false),
Expression(nullptr) {}
DeducedDepth(DeducedDepth), Expression(nullptr) {}

/// \brief Returns the location at which template argument is
/// occurring.
SourceLocation getLocation() const {
return Loc;
}

/// \brief The depth of template parameters for which deduction is being
/// performed.
unsigned getDeducedDepth() const {
return DeducedDepth;
}

/// \brief Take ownership of the deduced template argument list.
TemplateArgumentList *take() {
TemplateArgumentList *Result = Deduced;
Expand Down
24 changes: 15 additions & 9 deletions lib/Sema/SemaTemplate.cpp
Expand Up @@ -5008,9 +5008,15 @@ ExprResult Sema::CheckTemplateArgument(NonTypeTemplateParmDecl *Param,

// If the parameter type somehow involves auto, deduce the type now.
if (getLangOpts().CPlusPlus1z && ParamType->isUndeducedType()) {
// When checking a deduced template argument, deduce from its type even if
// the type is dependent, in order to check the types of non-type template
// arguments line up properly in partial ordering.
Optional<unsigned> Depth;
if (CTAK != CTAK_Specified)
Depth = Param->getDepth() + 1;
if (DeduceAutoType(
Context.getTrivialTypeSourceInfo(ParamType, Param->getLocation()),
Arg, ParamType) == DAR_Failed) {
Arg, ParamType, Depth) == DAR_Failed) {
Diag(Arg->getExprLoc(),
diag::err_non_type_template_parm_type_deduction_failure)
<< Param->getDeclName() << Param->getType() << Arg->getType()
Expand All @@ -5029,14 +5035,6 @@ ExprResult Sema::CheckTemplateArgument(NonTypeTemplateParmDecl *Param,
}
}

// If either the parameter has a dependent type or the argument is
// type-dependent, there's nothing we can check now.
if (ParamType->isDependentType() || Arg->isTypeDependent()) {
// FIXME: Produce a cloned, canonical expression?
Converted = TemplateArgument(Arg);
return Arg;
}

// We should have already dropped all cv-qualifiers by now.
assert(!ParamType.hasQualifiers() &&
"non-type template parameter type cannot be qualified");
Expand All @@ -5058,6 +5056,14 @@ ExprResult Sema::CheckTemplateArgument(NonTypeTemplateParmDecl *Param,
return ExprError();
}

// If either the parameter has a dependent type or the argument is
// type-dependent, there's nothing we can check now.
if (ParamType->isDependentType() || Arg->isTypeDependent()) {
// FIXME: Produce a cloned, canonical expression?
Converted = TemplateArgument(Arg);
return Arg;
}

if (getLangOpts().CPlusPlus1z) {
// C++1z [temp.arg.nontype]p1:
// A template-argument for a non-type template parameter shall be
Expand Down

0 comments on commit 89014aa

Please sign in to comment.