[libcxx-commits] [libcxx] c9e4621 - [clang] retain type sugar in auto / template argument deduction
Matheus Izvekov via libcxx-commits
libcxx-commits at lists.llvm.org
Mon Nov 15 14:07:59 PST 2021
Author: Matheus Izvekov
Date: 2021-11-15T23:07:45+01:00
New Revision: c9e46219f38da5c3fbfe41012173dc893516826e
URL: https://github.com/llvm/llvm-project/commit/c9e46219f38da5c3fbfe41012173dc893516826e
DIFF: https://github.com/llvm/llvm-project/commit/c9e46219f38da5c3fbfe41012173dc893516826e.diff
LOG: [clang] retain type sugar in auto / template argument deduction
This implements the following changes:
* AutoType retains sugared deduced-as-type.
* Template argument deduction machinery analyses the sugared type all the way
down. It would previously lose the sugar on first recursion.
* Undeduced AutoType will be properly canonicalized, including the constraint
template arguments.
* Remove the decltype node created from the decltype(auto) deduction.
As a result, we start seeing sugared types in a lot more test cases,
including some which showed very unfriendly `type-parameter-*-*` types.
Signed-off-by: Matheus Izvekov <mizvekov at gmail.com>
Reviewed By: rsmith, #libc, ldionne
Differential Revision: https://reviews.llvm.org/D110216
Added:
clang/test/SemaCXX/sugared-auto.cpp
libcxx/test/std/utilities/any/any.nonmembers/any.cast/const_correctness.verify.cpp
libcxx/test/std/utilities/any/any.nonmembers/any.cast/not_copy_constructible.verify.cpp
Modified:
clang-tools-extra/clang-tidy/cppcoreguidelines/OwningMemoryCheck.cpp
clang-tools-extra/clang-tidy/cppcoreguidelines/ProBoundsPointerArithmeticCheck.cpp
clang-tools-extra/clang-tidy/readability/QualifiedAutoCheck.cpp
clang-tools-extra/clangd/FindTarget.cpp
clang-tools-extra/clangd/InlayHints.cpp
clang-tools-extra/clangd/unittests/ASTTests.cpp
clang-tools-extra/clangd/unittests/HoverTests.cpp
clang-tools-extra/clangd/unittests/InlayHintTests.cpp
clang-tools-extra/clangd/unittests/tweaks/ExpandAutoTypeTests.cpp
clang-tools-extra/test/clang-tidy/checkers/cppcoreguidelines-owning-memory.cpp
clang/include/clang/AST/ASTContext.h
clang/include/clang/AST/Type.h
clang/include/clang/ASTMatchers/ASTMatchersInternal.h
clang/include/clang/Sema/Sema.h
clang/lib/AST/ASTContext.cpp
clang/lib/AST/ASTImporter.cpp
clang/lib/AST/Type.cpp
clang/lib/Sema/SemaCXXScopeSpec.cpp
clang/lib/Sema/SemaDecl.cpp
clang/lib/Sema/SemaDeclCXX.cpp
clang/lib/Sema/SemaExprCXX.cpp
clang/lib/Sema/SemaInit.cpp
clang/lib/Sema/SemaLambda.cpp
clang/lib/Sema/SemaStmt.cpp
clang/lib/Sema/SemaTemplate.cpp
clang/lib/Sema/SemaTemplateDeduction.cpp
clang/lib/Sema/SemaType.cpp
clang/lib/Sema/TreeTransform.h
clang/test/CXX/over/over.match/over.match.funcs/over.match.class.deduct/p2.cpp
clang/test/CXX/stmt.stmt/stmt.iter/stmt.ranged/p1.cpp
clang/test/CXX/temp/temp.decls/temp.variadic/multi-level-substitution.cpp
clang/test/CXX/temp/temp.fct.spec/temp.deduct/temp.deduct.call/p1-0x.cpp
clang/test/CXX/temp/temp.fct.spec/temp.deduct/temp.deduct.call/p4.cpp
clang/test/Index/print-type.cpp
clang/test/SemaCXX/cxx1z-class-template-argument-deduction.cpp
clang/test/SemaCXX/cxx1z-decomposition.cpp
clang/test/SemaCXX/deduced-return-type-cxx14.cpp
clang/test/SemaCXX/friend.cpp
clang/test/SemaCXX/recovery-expr-type.cpp
clang/test/SemaCXX/sizeless-1.cpp
clang/test/SemaTemplate/attributes.cpp
clang/test/SemaTemplate/deduction.cpp
clang/test/SemaTemplate/friend.cpp
clang/test/SemaTemplate/operator-template.cpp
lldb/test/Shell/SymbolFile/NativePDB/function-types-builtins.cpp
Removed:
libcxx/test/std/utilities/any/any.nonmembers/any.cast/const_correctness.fail.cpp
libcxx/test/std/utilities/any/any.nonmembers/any.cast/not_copy_constructible.fail.cpp
################################################################################
diff --git a/clang-tools-extra/clang-tidy/cppcoreguidelines/OwningMemoryCheck.cpp b/clang-tools-extra/clang-tidy/cppcoreguidelines/OwningMemoryCheck.cpp
index 13bb7246fd43a..b87c33dd10bda 100644
--- a/clang-tools-extra/clang-tidy/cppcoreguidelines/OwningMemoryCheck.cpp
+++ b/clang-tools-extra/clang-tidy/cppcoreguidelines/OwningMemoryCheck.cpp
@@ -134,14 +134,9 @@ void OwningMemoryCheck::registerMatchers(MatchFinder *Finder) {
// Matching on initialization operations where the initial value is a newly
// created owner, but the LHS is not an owner.
Finder->addMatcher(
- traverse(
- TK_AsIs,
- namedDecl(
- varDecl(eachOf(allOf(hasInitializer(CreatesOwner),
- unless(IsOwnerType)),
- allOf(hasInitializer(ConsideredOwner),
- hasType(autoType().bind("deduced_type")))))
- .bind("bad_owner_creation_variable"))),
+ traverse(TK_AsIs, namedDecl(varDecl(allOf(hasInitializer(CreatesOwner),
+ unless(IsOwnerType)))
+ .bind("bad_owner_creation_variable"))),
this);
// Match on all function calls that expect owners as arguments, but didn't
@@ -324,13 +319,6 @@ bool OwningMemoryCheck::handleAssignmentFromNewOwner(const BoundNodes &Nodes) {
// FIXME: FixitHint to rewrite the type of the initialized variable
// as 'gsl::owner<OriginalType>'
-
- // If the type of the variable was deduced, the wrapping owner typedef is
- // eliminated, therefore the check emits a special note for that case.
- if (Nodes.getNodeAs<AutoType>("deduced_type")) {
- diag(BadOwnerInitialization->getBeginLoc(),
- "type deduction did not result in an owner", DiagnosticIDs::Note);
- }
return true;
}
diff --git a/clang-tools-extra/clang-tidy/cppcoreguidelines/ProBoundsPointerArithmeticCheck.cpp b/clang-tools-extra/clang-tidy/cppcoreguidelines/ProBoundsPointerArithmeticCheck.cpp
index 680b337874460..5b88da658f082 100644
--- a/clang-tools-extra/clang-tidy/cppcoreguidelines/ProBoundsPointerArithmeticCheck.cpp
+++ b/clang-tools-extra/clang-tidy/cppcoreguidelines/ProBoundsPointerArithmeticCheck.cpp
@@ -20,9 +20,11 @@ void ProBoundsPointerArithmeticCheck::registerMatchers(MatchFinder *Finder) {
if (!getLangOpts().CPlusPlus)
return;
- const auto AllPointerTypes = anyOf(
- hasType(pointerType()), hasType(autoType(hasDeducedType(pointerType()))),
- hasType(decltypeType(hasUnderlyingType(pointerType()))));
+ const auto AllPointerTypes =
+ anyOf(hasType(pointerType()),
+ hasType(autoType(
+ hasDeducedType(hasUnqualifiedDesugaredType(pointerType())))),
+ hasType(decltypeType(hasUnderlyingType(pointerType()))));
// Flag all operators +, -, +=, -=, ++, -- that result in a pointer
Finder->addMatcher(
diff --git a/clang-tools-extra/clang-tidy/readability/QualifiedAutoCheck.cpp b/clang-tools-extra/clang-tidy/readability/QualifiedAutoCheck.cpp
index 95380069f5274..c564b5adcbbf8 100644
--- a/clang-tools-extra/clang-tidy/readability/QualifiedAutoCheck.cpp
+++ b/clang-tools-extra/clang-tidy/readability/QualifiedAutoCheck.cpp
@@ -125,18 +125,22 @@ void QualifiedAutoCheck::registerMatchers(MatchFinder *Finder) {
};
auto IsBoundToType = refersToType(equalsBoundNode("type"));
+ auto UnlessFunctionType = unless(hasUnqualifiedDesugaredType(functionType()));
+ auto IsAutoDeducedToPointer = [](const auto &...InnerMatchers) {
+ return autoType(hasDeducedType(
+ hasUnqualifiedDesugaredType(pointerType(pointee(InnerMatchers...)))));
+ };
Finder->addMatcher(
- ExplicitSingleVarDecl(hasType(autoType(hasDeducedType(
- pointerType(pointee(unless(functionType())))))),
+ ExplicitSingleVarDecl(hasType(IsAutoDeducedToPointer(UnlessFunctionType)),
"auto"),
this);
Finder->addMatcher(
ExplicitSingleVarDeclInTemplate(
- allOf(hasType(autoType(hasDeducedType(pointerType(
- pointee(hasUnqualifiedType(qualType().bind("type")),
- unless(functionType())))))),
+ allOf(hasType(IsAutoDeducedToPointer(
+ hasUnqualifiedType(qualType().bind("type")),
+ UnlessFunctionType)),
anyOf(hasAncestor(
functionDecl(hasAnyTemplateArgument(IsBoundToType))),
hasAncestor(classTemplateSpecializationDecl(
diff --git a/clang-tools-extra/clangd/FindTarget.cpp b/clang-tools-extra/clangd/FindTarget.cpp
index 82e4dfeccf43d..70e1d423f5422 100644
--- a/clang-tools-extra/clangd/FindTarget.cpp
+++ b/clang-tools-extra/clangd/FindTarget.cpp
@@ -374,7 +374,7 @@ struct TargetFinder {
void VisitDeducedType(const DeducedType *DT) {
// FIXME: In practice this doesn't work: the AutoType you find inside
// TypeLoc never has a deduced type. https://llvm.org/PR42914
- Outer.add(DT->getDeducedType(), Flags | Rel::Underlying);
+ Outer.add(DT->getDeducedType(), Flags);
}
void VisitDeducedTemplateSpecializationType(
const DeducedTemplateSpecializationType *DTST) {
diff --git a/clang-tools-extra/clangd/InlayHints.cpp b/clang-tools-extra/clangd/InlayHints.cpp
index 73864b7849345..6b9c8b1eee54f 100644
--- a/clang-tools-extra/clangd/InlayHints.cpp
+++ b/clang-tools-extra/clangd/InlayHints.cpp
@@ -38,10 +38,9 @@ class InlayHintVisitor : public RecursiveASTVisitor<InlayHintVisitor> {
// For structured bindings, print canonical types. This is important because
// for bindings that use the tuple_element protocol, the non-canonical types
// would be "tuple_element<I, A>::type".
- // For "auto", we often prefer sugared types, but the AST doesn't currently
- // retain them in DeducedType. However, not setting PrintCanonicalTypes for
- // "auto" at least allows SuppressDefaultTemplateArgs (set by default) to
- // have an effect.
+ // For "auto", we often prefer sugared types.
+ // Not setting PrintCanonicalTypes for "auto" allows
+ // SuppressDefaultTemplateArgs (set by default) to have an effect.
StructuredBindingPolicy = TypeHintPolicy;
StructuredBindingPolicy.PrintCanonicalTypes = true;
}
diff --git a/clang-tools-extra/clangd/unittests/ASTTests.cpp b/clang-tools-extra/clangd/unittests/ASTTests.cpp
index df42a28d5ebe2..44dc8f0c69cf5 100644
--- a/clang-tools-extra/clangd/unittests/ASTTests.cpp
+++ b/clang-tools-extra/clangd/unittests/ASTTests.cpp
@@ -43,7 +43,7 @@ TEST(GetDeducedType, KwAutoKwDecltypeExpansion) {
namespace ns1 { struct S {}; }
^auto v = ns1::S{};
)cpp",
- "struct ns1::S",
+ "ns1::S",
},
{
R"cpp( // decltype on struct
@@ -63,7 +63,7 @@ TEST(GetDeducedType, KwAutoKwDecltypeExpansion) {
ns1::S& j = i;
^decltype(auto) k = j;
)cpp",
- "struct ns1::S &",
+ "ns1::S &",
},
{
R"cpp( // auto on template class
@@ -71,7 +71,7 @@ TEST(GetDeducedType, KwAutoKwDecltypeExpansion) {
template<typename T> class Foo {};
^auto v = Foo<X>();
)cpp",
- "class Foo<class X>",
+ "Foo<class X>",
},
{
R"cpp( // auto on initializer list.
@@ -177,8 +177,7 @@ TEST(GetDeducedType, KwAutoKwDecltypeExpansion) {
using Bar = Foo;
^auto x = Bar();
)cpp",
- // FIXME: it'd be nice if this resolved to the alias instead
- "struct Foo",
+ "Bar",
},
};
for (Test T : Tests) {
diff --git a/clang-tools-extra/clangd/unittests/HoverTests.cpp b/clang-tools-extra/clangd/unittests/HoverTests.cpp
index 53df965fef2fa..79510ceefa1b3 100644
--- a/clang-tools-extra/clangd/unittests/HoverTests.cpp
+++ b/clang-tools-extra/clangd/unittests/HoverTests.cpp
@@ -461,7 +461,7 @@ class Foo {})cpp";
[](HoverInfo &HI) {
HI.Name = "auto";
HI.Kind = index::SymbolKind::TypeAlias;
- HI.Definition = "class Foo<int>";
+ HI.Definition = "Foo<int>";
}},
// auto on specialized template
{R"cpp(
@@ -474,7 +474,7 @@ class Foo {})cpp";
[](HoverInfo &HI) {
HI.Name = "auto";
HI.Kind = index::SymbolKind::TypeAlias;
- HI.Definition = "class Foo<int>";
+ HI.Definition = "Foo<int>";
}},
// macro
@@ -648,7 +648,7 @@ class Foo {})cpp";
[](HoverInfo &HI) {
HI.Name = "auto";
HI.Kind = index::SymbolKind::TypeAlias;
- HI.Definition = "class Foo<X>";
+ HI.Definition = "Foo<X>";
}},
{// Falls back to primary template, when the type is not instantiated.
R"cpp(
@@ -2024,7 +2024,7 @@ TEST(Hover, All) {
[](HoverInfo &HI) {
HI.Name = "auto";
HI.Kind = index::SymbolKind::TypeAlias;
- HI.Definition = "int";
+ HI.Definition = "int_type";
}},
{
R"cpp(// auto on alias
@@ -2035,7 +2035,7 @@ TEST(Hover, All) {
[](HoverInfo &HI) {
HI.Name = "auto";
HI.Kind = index::SymbolKind::TypeAlias;
- HI.Definition = "struct cls";
+ HI.Definition = "cls_type";
HI.Documentation = "auto on alias";
}},
{
@@ -2047,7 +2047,7 @@ TEST(Hover, All) {
[](HoverInfo &HI) {
HI.Name = "auto";
HI.Kind = index::SymbolKind::TypeAlias;
- HI.Definition = "struct templ<int>";
+ HI.Definition = "templ<int>";
HI.Documentation = "auto on alias";
}},
{
diff --git a/clang-tools-extra/clangd/unittests/InlayHintTests.cpp b/clang-tools-extra/clangd/unittests/InlayHintTests.cpp
index 1c69d504ec6dc..b6c6dd17dbe3b 100644
--- a/clang-tools-extra/clangd/unittests/InlayHintTests.cpp
+++ b/clang-tools-extra/clangd/unittests/InlayHintTests.cpp
@@ -466,7 +466,14 @@ TEST(TypeHints, NoQualifiers) {
}
}
)cpp",
- ExpectedHint{": S1", "x"}, ExpectedHint{": Inner<int>", "y"});
+ ExpectedHint{": S1", "x"},
+ // FIXME: We want to suppress scope specifiers
+ // here because we are into the whole
+ // brevity thing, but the ElaboratedType
+ // printer does not honor the SuppressScope
+ // flag by design, so we need to extend the
+ // PrintingPolicy to support this use case.
+ ExpectedHint{": S2::Inner<int>", "y"});
}
TEST(TypeHints, Lambda) {
diff --git a/clang-tools-extra/clangd/unittests/tweaks/ExpandAutoTypeTests.cpp b/clang-tools-extra/clangd/unittests/tweaks/ExpandAutoTypeTests.cpp
index 1b784f63f59cf..96574a67b5a46 100644
--- a/clang-tools-extra/clangd/unittests/tweaks/ExpandAutoTypeTests.cpp
+++ b/clang-tools-extra/clangd/unittests/tweaks/ExpandAutoTypeTests.cpp
@@ -57,7 +57,7 @@ TEST_F(ExpandAutoTypeTest, Test) {
EXPECT_UNAVAILABLE("au^to x = []{};");
// inline namespaces
EXPECT_EQ(apply("au^to x = inl_ns::Visible();"),
- "Visible x = inl_ns::Visible();");
+ "inl_ns::Visible x = inl_ns::Visible();");
// local class
EXPECT_EQ(apply("namespace x { void y() { struct S{}; ^auto z = S(); } }"),
"namespace x { void y() { struct S{}; S z = S(); } }");
@@ -67,8 +67,9 @@ TEST_F(ExpandAutoTypeTest, Test) {
EXPECT_EQ(apply("ns::Class * foo() { au^to c = foo(); }"),
"ns::Class * foo() { ns::Class * c = foo(); }");
- EXPECT_EQ(apply("void ns::Func() { au^to x = new ns::Class::Nested{}; }"),
- "void ns::Func() { Class::Nested * x = new ns::Class::Nested{}; }");
+ EXPECT_EQ(
+ apply("void ns::Func() { au^to x = new ns::Class::Nested{}; }"),
+ "void ns::Func() { ns::Class::Nested * x = new ns::Class::Nested{}; }");
EXPECT_UNAVAILABLE("dec^ltype(au^to) x = 10;");
// expanding types in structured bindings is syntactically invalid.
diff --git a/clang-tools-extra/test/clang-tidy/checkers/cppcoreguidelines-owning-memory.cpp b/clang-tools-extra/test/clang-tidy/checkers/cppcoreguidelines-owning-memory.cpp
index 72b13801cf1eb..2669d66627a50 100644
--- a/clang-tools-extra/test/clang-tidy/checkers/cppcoreguidelines-owning-memory.cpp
+++ b/clang-tools-extra/test/clang-tidy/checkers/cppcoreguidelines-owning-memory.cpp
@@ -91,13 +91,9 @@ void test_assignment_and_initialization() {
// FIXME:, flow analysis for the case of reassignment. Value must be released before
owned_int6 = owned_int3; // BAD, because reassignment without resource release
- auto owned_int7 = returns_owner1(); // Bad, since type deduction eliminates the owner wrapper
- // CHECK-NOTES: [[@LINE-1]]:3: warning: initializing non-owner 'int *' with a newly created 'gsl::owner<>'
- // CHECK-NOTES: [[@LINE-2]]:3: note: type deduction did not result in an owner
+ auto owned_int7 = returns_owner1(); // Ok, since type deduction does not eliminate the owner wrapper
- const auto owned_int8 = returns_owner2(); // Bad, since type deduction eliminates the owner wrapper
- // CHECK-NOTES: [[@LINE-1]]:3: warning: initializing non-owner 'int *const' with a newly created 'gsl::owner<>'
- // CHECK-NOTES: [[@LINE-2]]:3: note: type deduction did not result in an owner
+ const auto owned_int8 = returns_owner2(); // Ok, since type deduction does not eliminate the owner wrapper
gsl::owner<int *> owned_int9 = returns_owner1(); // Ok
int *unowned_int3 = returns_owner1(); // Bad
@@ -285,15 +281,12 @@ void test_class_with_owner() {
ClassWithOwner C2{A}; // Bad, since the owner would be initialized with an non-owner, but catched in the class
ClassWithOwner C3{gsl::owner<ArbitraryClass *>(new ArbitraryClass)}; // Ok
- const auto Owner1 = C3.buggy_but_returns_owner(); // BAD, deduces Owner1 to ArbitraryClass *const
- // CHECK-NOTES: [[@LINE-1]]:3: warning: initializing non-owner 'ArbitraryClass *const' with a newly created 'gsl::owner<>'
- // CHECK-NOTES: [[@LINE-2]]:3: note: type deduction did not result in an owner
+ const auto Owner1 = C3.buggy_but_returns_owner(); // Ok, deduces Owner1 to owner<ArbitraryClass *> const
- auto Owner2 = C2.buggy_but_returns_owner(); // BAD, deduces Owner2 to ArbitraryClass *
- // CHECK-NOTES: [[@LINE-1]]:3: warning: initializing non-owner 'ArbitraryClass *' with a newly created 'gsl::owner<>'
- // CHECK-NOTES: [[@LINE-2]]:3: note: type deduction did not result in an owner
+ auto Owner2 = C2.buggy_but_returns_owner(); // Ok, deduces Owner2 to owner<ArbitraryClass *>
- Owner2 = &A; // Ok, since type deduction did NOT result in owner<int*>
+ Owner2 = &A; // BAD, since type deduction resulted in owner<ArbitraryClass *>
+ // CHECK-NOTES: [[@LINE-1]]:3: warning: expected assignment source to be of type 'gsl::owner<>'; got 'ArbitraryClass *'
gsl::owner<ArbitraryClass *> Owner3 = C1.buggy_but_returns_owner(); // Ok, still an owner
Owner3 = &A; // Bad, since assignment of non-owner to owner
diff --git a/clang/include/clang/AST/ASTContext.h b/clang/include/clang/AST/ASTContext.h
index b9aa2d2cfadb5..d336342e4cda6 100644
--- a/clang/include/clang/AST/ASTContext.h
+++ b/clang/include/clang/AST/ASTContext.h
@@ -1531,6 +1531,12 @@ class ASTContext : public RefCountedBase<ASTContext> {
QualType getFunctionTypeInternal(QualType ResultTy, ArrayRef<QualType> Args,
const FunctionProtoType::ExtProtoInfo &EPI,
bool OnlyWantCanonical) const;
+ QualType
+ getAutoTypeInternal(QualType DeducedType, AutoTypeKeyword Keyword,
+ bool IsDependent, bool IsPack = false,
+ ConceptDecl *TypeConstraintConcept = nullptr,
+ ArrayRef<TemplateArgument> TypeConstraintArgs = {},
+ bool IsCanon = false) const;
public:
/// Return the unique reference to the type for the specified type
diff --git a/clang/include/clang/AST/Type.h b/clang/include/clang/AST/Type.h
index 722add6cd8777..fd25ec25d4f21 100644
--- a/clang/include/clang/AST/Type.h
+++ b/clang/include/clang/AST/Type.h
@@ -4944,29 +4944,29 @@ class SubstTemplateTypeParmPackType : public Type, public llvm::FoldingSetNode {
/// type-dependent, there is no deduced type and the type is canonical. In
/// the latter case, it is also a dependent type.
class DeducedType : public Type {
+ QualType DeducedAsType;
+
protected:
DeducedType(TypeClass TC, QualType DeducedAsType,
- TypeDependence ExtraDependence)
- : Type(TC,
- // FIXME: Retain the sugared deduced type?
- DeducedAsType.isNull() ? QualType(this, 0)
- : DeducedAsType.getCanonicalType(),
+ TypeDependence ExtraDependence, QualType Canon)
+ : Type(TC, Canon,
ExtraDependence | (DeducedAsType.isNull()
? TypeDependence::None
: DeducedAsType->getDependence() &
- ~TypeDependence::VariablyModified)) {}
+ ~TypeDependence::VariablyModified)),
+ DeducedAsType(DeducedAsType) {}
public:
- bool isSugared() const { return !isCanonicalUnqualified(); }
- QualType desugar() const { return getCanonicalTypeInternal(); }
-
- /// Get the type deduced for this placeholder type, or null if it's
- /// either not been deduced or was deduced to a dependent type.
- QualType getDeducedType() const {
- return !isCanonicalUnqualified() ? getCanonicalTypeInternal() : QualType();
+ bool isSugared() const { return !DeducedAsType.isNull(); }
+ QualType desugar() const {
+ return isSugared() ? DeducedAsType : QualType(this, 0);
}
+
+ /// Get the type deduced for this placeholder type, or null if it
+ /// has not been deduced.
+ QualType getDeducedType() const { return DeducedAsType; }
bool isDeduced() const {
- return !isCanonicalUnqualified() || isDependentType();
+ return !DeducedAsType.isNull() || isDependentType();
}
static bool classof(const Type *T) {
@@ -4983,7 +4983,7 @@ class alignas(8) AutoType : public DeducedType, public llvm::FoldingSetNode {
ConceptDecl *TypeConstraintConcept;
AutoType(QualType DeducedAsType, AutoTypeKeyword Keyword,
- TypeDependence ExtraDependence, ConceptDecl *CD,
+ TypeDependence ExtraDependence, QualType Canon, ConceptDecl *CD,
ArrayRef<TemplateArgument> TypeConstraintArgs);
const TemplateArgument *getArgBuffer() const {
@@ -5057,7 +5057,9 @@ class DeducedTemplateSpecializationType : public DeducedType,
toTypeDependence(Template.getDependence()) |
(IsDeducedAsDependent
? TypeDependence::DependentInstantiation
- : TypeDependence::None)),
+ : TypeDependence::None),
+ DeducedAsType.isNull() ? QualType(this, 0)
+ : DeducedAsType.getCanonicalType()),
Template(Template) {}
public:
diff --git a/clang/include/clang/ASTMatchers/ASTMatchersInternal.h b/clang/include/clang/ASTMatchers/ASTMatchersInternal.h
index f84582c06f780..a77611001fb14 100644
--- a/clang/include/clang/ASTMatchers/ASTMatchersInternal.h
+++ b/clang/include/clang/ASTMatchers/ASTMatchersInternal.h
@@ -1027,31 +1027,29 @@ class HasDeclarationMatcher : public MatcherInterface<T> {
BoundNodesTreeBuilder *Builder) const {
// DeducedType does not have declarations of its own, so
// match the deduced type instead.
- const Type *EffectiveType = &Node;
if (const auto *S = dyn_cast<DeducedType>(&Node)) {
- EffectiveType = S->getDeducedType().getTypePtrOrNull();
- if (!EffectiveType)
- return false;
+ QualType DT = S->getDeducedType();
+ return !DT.isNull() ? matchesSpecialized(*DT, Finder, Builder) : false;
}
// First, for any types that have a declaration, extract the declaration and
// match on it.
- if (const auto *S = dyn_cast<TagType>(EffectiveType)) {
+ if (const auto *S = dyn_cast<TagType>(&Node)) {
return matchesDecl(S->getDecl(), Finder, Builder);
}
- if (const auto *S = dyn_cast<InjectedClassNameType>(EffectiveType)) {
+ if (const auto *S = dyn_cast<InjectedClassNameType>(&Node)) {
return matchesDecl(S->getDecl(), Finder, Builder);
}
- if (const auto *S = dyn_cast<TemplateTypeParmType>(EffectiveType)) {
+ if (const auto *S = dyn_cast<TemplateTypeParmType>(&Node)) {
return matchesDecl(S->getDecl(), Finder, Builder);
}
- if (const auto *S = dyn_cast<TypedefType>(EffectiveType)) {
+ if (const auto *S = dyn_cast<TypedefType>(&Node)) {
return matchesDecl(S->getDecl(), Finder, Builder);
}
- if (const auto *S = dyn_cast<UnresolvedUsingType>(EffectiveType)) {
+ if (const auto *S = dyn_cast<UnresolvedUsingType>(&Node)) {
return matchesDecl(S->getDecl(), Finder, Builder);
}
- if (const auto *S = dyn_cast<ObjCObjectType>(EffectiveType)) {
+ if (const auto *S = dyn_cast<ObjCObjectType>(&Node)) {
return matchesDecl(S->getInterface(), Finder, Builder);
}
@@ -1063,14 +1061,14 @@ class HasDeclarationMatcher : public MatcherInterface<T> {
// template<typename T> struct X { T t; } class A {}; X<A> a;
// The following matcher will match, which otherwise would not:
// fieldDecl(hasType(pointerType())).
- if (const auto *S = dyn_cast<SubstTemplateTypeParmType>(EffectiveType)) {
+ if (const auto *S = dyn_cast<SubstTemplateTypeParmType>(&Node)) {
return matchesSpecialized(S->getReplacementType(), Finder, Builder);
}
// For template specialization types, we want to match the template
// declaration, as long as the type is still dependent, and otherwise the
// declaration of the instantiated tag type.
- if (const auto *S = dyn_cast<TemplateSpecializationType>(EffectiveType)) {
+ if (const auto *S = dyn_cast<TemplateSpecializationType>(&Node)) {
if (!S->isTypeAlias() && S->isSugared()) {
// If the template is non-dependent, we want to match the instantiated
// tag type.
@@ -1089,7 +1087,7 @@ class HasDeclarationMatcher : public MatcherInterface<T> {
// FIXME: We desugar elaborated types. This makes the assumption that users
// do never want to match on whether a type is elaborated - there are
// arguments for both sides; for now, continue desugaring.
- if (const auto *S = dyn_cast<ElaboratedType>(EffectiveType)) {
+ if (const auto *S = dyn_cast<ElaboratedType>(&Node)) {
return matchesSpecialized(S->desugar(), Finder, Builder);
}
return false;
diff --git a/clang/include/clang/Sema/Sema.h b/clang/include/clang/Sema/Sema.h
index c7a6d04ce8f8c..5f5755ef13435 100644
--- a/clang/include/clang/Sema/Sema.h
+++ b/clang/include/clang/Sema/Sema.h
@@ -2359,11 +2359,13 @@ class Sema final {
const CXXScopeSpec &SS, QualType T,
TagDecl *OwnedTagDecl = nullptr);
- QualType BuildTypeofExprType(Expr *E, SourceLocation Loc);
+ // Returns the underlying type of a decltype with the given expression.
+ QualType getDecltypeForExpr(Expr *E);
+
+ QualType BuildTypeofExprType(Expr *E);
/// If AsUnevaluated is false, E is treated as though it were an evaluated
/// context, such as when building a type for decltype(auto).
- QualType BuildDecltypeType(Expr *E, SourceLocation Loc,
- bool AsUnevaluated = true);
+ QualType BuildDecltypeType(Expr *E, bool AsUnevaluated = true);
QualType BuildUnaryTransformType(QualType BaseType,
UnaryTransformType::UTTKind UKind,
SourceLocation Loc);
@@ -3502,7 +3504,7 @@ class Sema final {
bool IsFunctionConversion(QualType FromType, QualType ToType,
QualType &ResultTy);
bool DiagnoseMultipleUserDefinedConversion(Expr *From, QualType ToType);
- bool isSameOrCompatibleFunctionType(CanQualType Param, CanQualType Arg);
+ bool isSameOrCompatibleFunctionType(QualType Param, QualType Arg);
bool CanPerformAggregateInitializationForOverloadResolution(
const InitializedEntity &Entity, InitListExpr *From);
@@ -8565,6 +8567,14 @@ class Sema final {
/// Substitute Replacement for auto in TypeWithAuto
TypeSourceInfo* SubstAutoTypeSourceInfo(TypeSourceInfo *TypeWithAuto,
QualType Replacement);
+
+ // Substitute auto in TypeWithAuto for a Dependent auto type
+ QualType SubstAutoTypeDependent(QualType TypeWithAuto);
+
+ // Substitute auto in TypeWithAuto for a Dependent auto type
+ TypeSourceInfo *
+ SubstAutoTypeSourceInfoDependent(TypeSourceInfo *TypeWithAuto);
+
/// Completely replace the \c auto in \p TypeWithAuto by
/// \p Replacement. This does not retain any \c auto type sugar.
QualType ReplaceAutoType(QualType TypeWithAuto, QualType Replacement);
diff --git a/clang/lib/AST/ASTContext.cpp b/clang/lib/AST/ASTContext.cpp
index 391a0c0b338e6..f0b931bdc9050 100644
--- a/clang/lib/AST/ASTContext.cpp
+++ b/clang/lib/AST/ASTContext.cpp
@@ -4815,6 +4815,23 @@ ASTContext::getTemplateSpecializationType(TemplateName Template,
return QualType(Spec, 0);
}
+static bool
+getCanonicalTemplateArguments(const ASTContext &C,
+ ArrayRef<TemplateArgument> OrigArgs,
+ SmallVectorImpl<TemplateArgument> &CanonArgs) {
+ bool AnyNonCanonArgs = false;
+ unsigned NumArgs = OrigArgs.size();
+ CanonArgs.resize(NumArgs);
+ for (unsigned I = 0; I != NumArgs; ++I) {
+ const TemplateArgument &OrigArg = OrigArgs[I];
+ TemplateArgument &CanonArg = CanonArgs[I];
+ CanonArg = C.getCanonicalTemplateArgument(OrigArg);
+ if (!CanonArg.structurallyEquals(OrigArg))
+ AnyNonCanonArgs = true;
+ }
+ return AnyNonCanonArgs;
+}
+
QualType ASTContext::getCanonicalTemplateSpecializationType(
TemplateName Template, ArrayRef<TemplateArgument> Args) const {
assert(!Template.getAsDependentTemplateName() &&
@@ -4827,10 +4844,7 @@ QualType ASTContext::getCanonicalTemplateSpecializationType(
// Build the canonical template specialization type.
TemplateName CanonTemplate = getCanonicalTemplateName(Template);
SmallVector<TemplateArgument, 4> CanonArgs;
- unsigned NumArgs = Args.size();
- CanonArgs.reserve(NumArgs);
- for (const TemplateArgument &Arg : Args)
- CanonArgs.push_back(getCanonicalTemplateArgument(Arg));
+ ::getCanonicalTemplateArguments(*this, Args, CanonArgs);
// Determine whether this canonical template specialization type already
// exists.
@@ -4845,7 +4859,7 @@ QualType ASTContext::getCanonicalTemplateSpecializationType(
if (!Spec) {
// Allocate a new canonical template specialization type.
void *Mem = Allocate((sizeof(TemplateSpecializationType) +
- sizeof(TemplateArgument) * NumArgs),
+ sizeof(TemplateArgument) * CanonArgs.size()),
TypeAlignment);
Spec = new (Mem) TemplateSpecializationType(CanonTemplate,
CanonArgs,
@@ -4987,14 +5001,9 @@ ASTContext::getDependentTemplateSpecializationType(
ElaboratedTypeKeyword CanonKeyword = Keyword;
if (Keyword == ETK_None) CanonKeyword = ETK_Typename;
- bool AnyNonCanonArgs = false;
- unsigned NumArgs = Args.size();
- SmallVector<TemplateArgument, 16> CanonArgs(NumArgs);
- for (unsigned I = 0; I != NumArgs; ++I) {
- CanonArgs[I] = getCanonicalTemplateArgument(Args[I]);
- if (!CanonArgs[I].structurallyEquals(Args[I]))
- AnyNonCanonArgs = true;
- }
+ SmallVector<TemplateArgument, 16> CanonArgs;
+ bool AnyNonCanonArgs =
+ ::getCanonicalTemplateArguments(*this, Args, CanonArgs);
QualType Canon;
if (AnyNonCanonArgs || CanonNNS != NNS || CanonKeyword != Keyword) {
@@ -5007,7 +5016,7 @@ ASTContext::getDependentTemplateSpecializationType(
}
void *Mem = Allocate((sizeof(DependentTemplateSpecializationType) +
- sizeof(TemplateArgument) * NumArgs),
+ sizeof(TemplateArgument) * Args.size()),
TypeAlignment);
T = new (Mem) DependentTemplateSpecializationType(Keyword, NNS,
Name, Args, Canon);
@@ -5589,15 +5598,10 @@ QualType ASTContext::getUnaryTransformType(QualType BaseType,
return QualType(ut, 0);
}
-/// getAutoType - Return the uniqued reference to the 'auto' type which has been
-/// deduced to the given type, or to the canonical undeduced 'auto' type, or the
-/// canonical deduced-but-dependent 'auto' type.
-QualType
-ASTContext::getAutoType(QualType DeducedType, AutoTypeKeyword Keyword,
- bool IsDependent, bool IsPack,
- ConceptDecl *TypeConstraintConcept,
- ArrayRef<TemplateArgument> TypeConstraintArgs) const {
- assert((!IsPack || IsDependent) && "only use IsPack for a dependent pack");
+QualType ASTContext::getAutoTypeInternal(
+ QualType DeducedType, AutoTypeKeyword Keyword, bool IsDependent,
+ bool IsPack, ConceptDecl *TypeConstraintConcept,
+ ArrayRef<TemplateArgument> TypeConstraintArgs, bool IsCanon) const {
if (DeducedType.isNull() && Keyword == AutoTypeKeyword::Auto &&
!TypeConstraintConcept && !IsDependent)
return getAutoDeductType();
@@ -5610,21 +5614,52 @@ ASTContext::getAutoType(QualType DeducedType, AutoTypeKeyword Keyword,
if (AutoType *AT = AutoTypes.FindNodeOrInsertPos(ID, InsertPos))
return QualType(AT, 0);
+ QualType Canon;
+ if (!IsCanon) {
+ if (DeducedType.isNull()) {
+ SmallVector<TemplateArgument, 4> CanonArgs;
+ bool AnyNonCanonArgs =
+ ::getCanonicalTemplateArguments(*this, TypeConstraintArgs, CanonArgs);
+ if (AnyNonCanonArgs) {
+ Canon = getAutoTypeInternal(QualType(), Keyword, IsDependent, IsPack,
+ TypeConstraintConcept, CanonArgs, true);
+ // Find the insert position again.
+ AutoTypes.FindNodeOrInsertPos(ID, InsertPos);
+ }
+ } else {
+ Canon = DeducedType.getCanonicalType();
+ }
+ }
+
void *Mem = Allocate(sizeof(AutoType) +
- sizeof(TemplateArgument) * TypeConstraintArgs.size(),
+ sizeof(TemplateArgument) * TypeConstraintArgs.size(),
TypeAlignment);
auto *AT = new (Mem) AutoType(
DeducedType, Keyword,
(IsDependent ? TypeDependence::DependentInstantiation
: TypeDependence::None) |
(IsPack ? TypeDependence::UnexpandedPack : TypeDependence::None),
- TypeConstraintConcept, TypeConstraintArgs);
+ Canon, TypeConstraintConcept, TypeConstraintArgs);
Types.push_back(AT);
- if (InsertPos)
- AutoTypes.InsertNode(AT, InsertPos);
+ AutoTypes.InsertNode(AT, InsertPos);
return QualType(AT, 0);
}
+/// getAutoType - Return the uniqued reference to the 'auto' type which has been
+/// deduced to the given type, or to the canonical undeduced 'auto' type, or the
+/// canonical deduced-but-dependent 'auto' type.
+QualType
+ASTContext::getAutoType(QualType DeducedType, AutoTypeKeyword Keyword,
+ bool IsDependent, bool IsPack,
+ ConceptDecl *TypeConstraintConcept,
+ ArrayRef<TemplateArgument> TypeConstraintArgs) const {
+ assert((!IsPack || IsDependent) && "only use IsPack for a dependent pack");
+ assert((!IsDependent || DeducedType.isNull()) &&
+ "A dependent auto should be undeduced");
+ return getAutoTypeInternal(DeducedType, Keyword, IsDependent, IsPack,
+ TypeConstraintConcept, TypeConstraintArgs);
+}
+
/// Return the uniqued reference to the deduced template specialization type
/// which has been deduced to the given type, or to the canonical undeduced
/// such type, or the canonical deduced-but-dependent such type.
@@ -5642,8 +5677,7 @@ QualType ASTContext::getDeducedTemplateSpecializationType(
auto *DTST = new (*this, TypeAlignment)
DeducedTemplateSpecializationType(Template, DeducedType, IsDependent);
Types.push_back(DTST);
- if (InsertPos)
- DeducedTemplateSpecializationTypes.InsertNode(DTST, InsertPos);
+ DeducedTemplateSpecializationTypes.InsertNode(DTST, InsertPos);
return QualType(DTST, 0);
}
@@ -5680,7 +5714,7 @@ QualType ASTContext::getAutoDeductType() const {
if (AutoDeductTy.isNull())
AutoDeductTy = QualType(new (*this, TypeAlignment)
AutoType(QualType(), AutoTypeKeyword::Auto,
- TypeDependence::None,
+ TypeDependence::None, QualType(),
/*concept*/ nullptr, /*args*/ {}),
0);
return AutoDeductTy;
diff --git a/clang/lib/AST/ASTImporter.cpp b/clang/lib/AST/ASTImporter.cpp
index 8062b4fcab532..710e40bbb4b72 100644
--- a/clang/lib/AST/ASTImporter.cpp
+++ b/clang/lib/AST/ASTImporter.cpp
@@ -3172,13 +3172,14 @@ static bool isAncestorDeclContextOf(const DeclContext *DC, const Decl *D) {
bool ASTNodeImporter::hasAutoReturnTypeDeclaredInside(FunctionDecl *D) {
QualType FromTy = D->getType();
- const FunctionProtoType *FromFPT = FromTy->getAs<FunctionProtoType>();
+ const auto *FromFPT = FromTy->getAs<FunctionProtoType>();
assert(FromFPT && "Must be called on FunctionProtoType");
- if (AutoType *AutoT = FromFPT->getReturnType()->getContainedAutoType()) {
+ if (const AutoType *AutoT =
+ FromFPT->getReturnType()->getContainedAutoType()) {
QualType DeducedT = AutoT->getDeducedType();
- if (const RecordType *RecordT =
- DeducedT.isNull() ? nullptr : dyn_cast<RecordType>(DeducedT)) {
- RecordDecl *RD = RecordT->getDecl();
+ if (const auto *RecordT =
+ !DeducedT.isNull() ? DeducedT->getAs<RecordType>() : nullptr) {
+ const RecordDecl *RD = RecordT->getDecl();
assert(RD);
if (isAncestorDeclContextOf(D, RD)) {
assert(RD->getLexicalDeclContext() == RD->getDeclContext());
@@ -3186,9 +3187,8 @@ bool ASTNodeImporter::hasAutoReturnTypeDeclaredInside(FunctionDecl *D) {
}
}
}
- if (const TypedefType *TypedefT =
- dyn_cast<TypedefType>(FromFPT->getReturnType())) {
- TypedefNameDecl *TD = TypedefT->getDecl();
+ if (const auto *TypedefT = FromFPT->getReturnType()->getAs<TypedefType>()) {
+ const TypedefNameDecl *TD = TypedefT->getDecl();
assert(TD);
if (isAncestorDeclContextOf(D, TD)) {
assert(TD->getLexicalDeclContext() == TD->getDeclContext());
diff --git a/clang/lib/AST/Type.cpp b/clang/lib/AST/Type.cpp
index a48df089ea86f..e0ac3f5b1351d 100644
--- a/clang/lib/AST/Type.cpp
+++ b/clang/lib/AST/Type.cpp
@@ -4400,10 +4400,10 @@ void clang::FixedPointValueToString(SmallVectorImpl<char> &Str,
}
AutoType::AutoType(QualType DeducedAsType, AutoTypeKeyword Keyword,
- TypeDependence ExtraDependence,
+ TypeDependence ExtraDependence, QualType Canon,
ConceptDecl *TypeConstraintConcept,
ArrayRef<TemplateArgument> TypeConstraintArgs)
- : DeducedType(Auto, DeducedAsType, ExtraDependence) {
+ : DeducedType(Auto, DeducedAsType, ExtraDependence, Canon) {
AutoTypeBits.Keyword = (unsigned)Keyword;
AutoTypeBits.NumArgs = TypeConstraintArgs.size();
this->TypeConstraintConcept = TypeConstraintConcept;
diff --git a/clang/lib/Sema/SemaCXXScopeSpec.cpp b/clang/lib/Sema/SemaCXXScopeSpec.cpp
index 7f8d030081592..c4826b5a6e8f9 100644
--- a/clang/lib/Sema/SemaCXXScopeSpec.cpp
+++ b/clang/lib/Sema/SemaCXXScopeSpec.cpp
@@ -865,7 +865,7 @@ bool Sema::ActOnCXXNestedNameSpecifierDecltype(CXXScopeSpec &SS,
assert(DS.getTypeSpecType() == DeclSpec::TST_decltype);
- QualType T = BuildDecltypeType(DS.getRepAsExpr(), DS.getTypeSpecTypeLoc());
+ QualType T = BuildDecltypeType(DS.getRepAsExpr());
if (T.isNull())
return true;
diff --git a/clang/lib/Sema/SemaDecl.cpp b/clang/lib/Sema/SemaDecl.cpp
index d16ec45e7c416..4fcc01012d44d 100644
--- a/clang/lib/Sema/SemaDecl.cpp
+++ b/clang/lib/Sema/SemaDecl.cpp
@@ -3613,14 +3613,14 @@ bool Sema::MergeFunctionDecl(FunctionDecl *New, NamedDecl *&OldD,
// defined, copy the deduced value from the old declaration.
AutoType *OldAT = Old->getReturnType()->getContainedAutoType();
if (OldAT && OldAT->isDeduced()) {
- New->setType(
- SubstAutoType(New->getType(),
- OldAT->isDependentType() ? Context.DependentTy
- : OldAT->getDeducedType()));
- NewQType = Context.getCanonicalType(
- SubstAutoType(NewQType,
- OldAT->isDependentType() ? Context.DependentTy
- : OldAT->getDeducedType()));
+ QualType DT = OldAT->getDeducedType();
+ if (DT.isNull()) {
+ New->setType(SubstAutoTypeDependent(New->getType()));
+ NewQType = Context.getCanonicalType(SubstAutoTypeDependent(NewQType));
+ } else {
+ New->setType(SubstAutoType(New->getType(), DT));
+ NewQType = Context.getCanonicalType(SubstAutoType(NewQType, DT));
+ }
}
}
@@ -9258,8 +9258,7 @@ Sema::ActOnFunctionDeclarator(Scope *S, Declarator &D, DeclContext *DC,
// a friend yet, so 'isDependentContext' on the FD doesn't work.
const FunctionProtoType *FPT =
NewFD->getType()->castAs<FunctionProtoType>();
- QualType Result =
- SubstAutoType(FPT->getReturnType(), Context.DependentTy);
+ QualType Result = SubstAutoTypeDependent(FPT->getReturnType());
NewFD->setType(Context.getFunctionType(Result, FPT->getParamTypes(),
FPT->getExtProtoInfo()));
}
@@ -12350,7 +12349,7 @@ void Sema::AddInitializerToDecl(Decl *RealDecl, Expr *Init, bool DirectInit) {
/*TreatUnavailableAsInvalid=*/false);
ExprResult Result = InitSeq.Perform(*this, Entity, Kind, Args, &DclT);
if (Result.isInvalid()) {
- // If the provied initializer fails to initialize the var decl,
+ // If the provided initializer fails to initialize the var decl,
// we attach a recovery expr for better recovery.
auto RecoveryExpr =
CreateRecoveryExpr(Init->getBeginLoc(), Init->getEndLoc(), Args);
diff --git a/clang/lib/Sema/SemaDeclCXX.cpp b/clang/lib/Sema/SemaDeclCXX.cpp
index d67e039dd26cc..46b41a7b0f430 100644
--- a/clang/lib/Sema/SemaDeclCXX.cpp
+++ b/clang/lib/Sema/SemaDeclCXX.cpp
@@ -4219,7 +4219,7 @@ Sema::BuildMemInitializer(Decl *ConstructorD,
if (BaseType.isNull())
return true;
} else if (DS.getTypeSpecType() == TST_decltype) {
- BaseType = BuildDecltypeType(DS.getRepAsExpr(), DS.getTypeSpecTypeLoc());
+ BaseType = BuildDecltypeType(DS.getRepAsExpr());
} else if (DS.getTypeSpecType() == TST_decltype_auto) {
Diag(DS.getTypeSpecTypeLoc(), diag::err_decltype_auto_invalid);
return true;
diff --git a/clang/lib/Sema/SemaExprCXX.cpp b/clang/lib/Sema/SemaExprCXX.cpp
index 571b790b31eaa..891909c443ccd 100644
--- a/clang/lib/Sema/SemaExprCXX.cpp
+++ b/clang/lib/Sema/SemaExprCXX.cpp
@@ -468,7 +468,7 @@ ParsedType Sema::getDestructorTypeForDecltype(const DeclSpec &DS,
assert(DS.getTypeSpecType() == DeclSpec::TST_decltype &&
"unexpected type in getDestructorType");
- QualType T = BuildDecltypeType(DS.getRepAsExpr(), DS.getTypeSpecTypeLoc());
+ QualType T = BuildDecltypeType(DS.getRepAsExpr());
// If we know the type of the object, check that the correct destructor
// type was named now; we can give better diagnostics this way.
@@ -7761,8 +7761,7 @@ ExprResult Sema::ActOnPseudoDestructorExpr(Scope *S, Expr *Base,
return true;
}
- QualType T = BuildDecltypeType(DS.getRepAsExpr(), DS.getTypeSpecTypeLoc(),
- false);
+ QualType T = BuildDecltypeType(DS.getRepAsExpr(), /*AsUnevaluated=*/false);
TypeLocBuilder TLB;
DecltypeTypeLoc DecltypeTL = TLB.push<DecltypeTypeLoc>(T);
diff --git a/clang/lib/Sema/SemaInit.cpp b/clang/lib/Sema/SemaInit.cpp
index 75686e2947041..8e435d9cb41f5 100644
--- a/clang/lib/Sema/SemaInit.cpp
+++ b/clang/lib/Sema/SemaInit.cpp
@@ -9972,7 +9972,7 @@ QualType Sema::DeduceTemplateSpecializationFromInitializer(
auto TemplateName = DeducedTST->getTemplateName();
if (TemplateName.isDependent())
- return SubstAutoType(TSInfo->getType(), Context.DependentTy);
+ return SubstAutoTypeDependent(TSInfo->getType());
// We can only perform deduction for class templates.
auto *Template =
@@ -9991,7 +9991,7 @@ QualType Sema::DeduceTemplateSpecializationFromInitializer(
Diag(TSInfo->getTypeLoc().getBeginLoc(),
diag::warn_cxx14_compat_class_template_argument_deduction)
<< TSInfo->getTypeLoc().getSourceRange() << 0;
- return SubstAutoType(TSInfo->getType(), Context.DependentTy);
+ return SubstAutoTypeDependent(TSInfo->getType());
}
// FIXME: Perform "exact type" matching first, per CWG discussion?
diff --git a/clang/lib/Sema/SemaLambda.cpp b/clang/lib/Sema/SemaLambda.cpp
index c4a8b3487ab98..b05e0b5cc0f12 100644
--- a/clang/lib/Sema/SemaLambda.cpp
+++ b/clang/lib/Sema/SemaLambda.cpp
@@ -373,7 +373,7 @@ CXXMethodDecl *Sema::startLambdaDefinition(CXXRecordDecl *Class,
const FunctionProtoType *FPT = MethodType->castAs<FunctionProtoType>();
QualType Result = FPT->getReturnType();
if (Result->isUndeducedType()) {
- Result = SubstAutoType(Result, Context.DependentTy);
+ Result = SubstAutoTypeDependent(Result);
MethodType = Context.getFunctionType(Result, FPT->getParamTypes(),
FPT->getExtProtoInfo());
}
diff --git a/clang/lib/Sema/SemaStmt.cpp b/clang/lib/Sema/SemaStmt.cpp
index dc564e318d82d..3c820829864d0 100644
--- a/clang/lib/Sema/SemaStmt.cpp
+++ b/clang/lib/Sema/SemaStmt.cpp
@@ -2759,7 +2759,7 @@ StmtResult Sema::BuildCXXForRangeStmt(SourceLocation ForLoc,
if (auto *DD = dyn_cast<DecompositionDecl>(LoopVar))
for (auto *Binding : DD->bindings())
Binding->setType(Context.DependentTy);
- LoopVar->setType(SubstAutoType(LoopVar->getType(), Context.DependentTy));
+ LoopVar->setType(SubstAutoTypeDependent(LoopVar->getType()));
}
} else if (!BeginDeclStmt.get()) {
SourceLocation RangeLoc = RangeVar->getLocation();
diff --git a/clang/lib/Sema/SemaTemplate.cpp b/clang/lib/Sema/SemaTemplate.cpp
index e682dc7da66e9..f4fd2ea5aa8e9 100644
--- a/clang/lib/Sema/SemaTemplate.cpp
+++ b/clang/lib/Sema/SemaTemplate.cpp
@@ -1259,15 +1259,15 @@ bool Sema::AttachTypeConstraint(AutoTypeLoc TL, NonTypeTemplateParmDecl *NTTP,
BuildDeclRefExpr(NTTP, NTTP->getType(), VK_PRValue, NTTP->getLocation());
if (!Ref)
return true;
- ExprResult ImmediatelyDeclaredConstraint =
- formImmediatelyDeclaredConstraint(
- *this, TL.getNestedNameSpecifierLoc(), TL.getConceptNameInfo(),
- TL.getNamedConcept(), TL.getLAngleLoc(), TL.getRAngleLoc(),
- BuildDecltypeType(Ref, NTTP->getLocation()), NTTP->getLocation(),
- [&] (TemplateArgumentListInfo &ConstraintArgs) {
- for (unsigned I = 0, C = TL.getNumArgs(); I != C; ++I)
- ConstraintArgs.addArgument(TL.getArgLoc(I));
- }, EllipsisLoc);
+ ExprResult ImmediatelyDeclaredConstraint = formImmediatelyDeclaredConstraint(
+ *this, TL.getNestedNameSpecifierLoc(), TL.getConceptNameInfo(),
+ TL.getNamedConcept(), TL.getLAngleLoc(), TL.getRAngleLoc(),
+ BuildDecltypeType(Ref), NTTP->getLocation(),
+ [&](TemplateArgumentListInfo &ConstraintArgs) {
+ for (unsigned I = 0, C = TL.getNumArgs(); I != C; ++I)
+ ConstraintArgs.addArgument(TL.getArgLoc(I));
+ },
+ EllipsisLoc);
if (ImmediatelyDeclaredConstraint.isInvalid() ||
!ImmediatelyDeclaredConstraint.isUsable())
return true;
@@ -1289,7 +1289,7 @@ QualType Sema::CheckNonTypeTemplateParameterType(TypeSourceInfo *&TSI,
// - an identifier associated by name lookup with a non-type
// template-parameter declared with a type that contains a
// placeholder type (7.1.7.4),
- TSI = SubstAutoTypeSourceInfo(TSI, Context.DependentTy);
+ TSI = SubstAutoTypeSourceInfoDependent(TSI);
}
return CheckNonTypeTemplateParameterType(TSI->getType(), Loc);
@@ -10873,7 +10873,7 @@ bool Sema::RebuildTemplateParamsInCurrentInstantiation(
// - an identifier associated by name lookup with a non-type
// template-parameter declared with a type that contains a
// placeholder type (7.1.7.4),
- NewTSI = SubstAutoTypeSourceInfo(NewTSI, Context.DependentTy);
+ NewTSI = SubstAutoTypeSourceInfoDependent(NewTSI);
}
if (NewTSI != NTTP->getTypeSourceInfo()) {
diff --git a/clang/lib/Sema/SemaTemplateDeduction.cpp b/clang/lib/Sema/SemaTemplateDeduction.cpp
index facd3e0998e8f..a1722c45b632b 100644
--- a/clang/lib/Sema/SemaTemplateDeduction.cpp
+++ b/clang/lib/Sema/SemaTemplateDeduction.cpp
@@ -131,30 +131,16 @@ static bool hasSameExtendedValue(llvm::APSInt X, llvm::APSInt Y) {
return X == Y;
}
-static Sema::TemplateDeductionResult
-DeduceTemplateArguments(Sema &S,
- TemplateParameterList *TemplateParams,
- const TemplateArgument &Param,
- TemplateArgument Arg,
- TemplateDeductionInfo &Info,
- SmallVectorImpl<DeducedTemplateArgument> &Deduced);
-
-static Sema::TemplateDeductionResult
-DeduceTemplateArgumentsByTypeMatch(Sema &S,
- TemplateParameterList *TemplateParams,
- QualType Param,
- QualType Arg,
- TemplateDeductionInfo &Info,
- SmallVectorImpl<DeducedTemplateArgument> &
- Deduced,
- unsigned TDF,
- bool PartialOrdering = false,
- bool DeducedFromArrayBound = false);
+static Sema::TemplateDeductionResult DeduceTemplateArgumentsByTypeMatch(
+ Sema &S, TemplateParameterList *TemplateParams, QualType Param,
+ QualType Arg, TemplateDeductionInfo &Info,
+ SmallVectorImpl<DeducedTemplateArgument> &Deduced, unsigned TDF,
+ bool PartialOrdering = false, bool DeducedFromArrayBound = false);
static Sema::TemplateDeductionResult
DeduceTemplateArguments(Sema &S, TemplateParameterList *TemplateParams,
- ArrayRef<TemplateArgument> Params,
- ArrayRef<TemplateArgument> Args,
+ ArrayRef<TemplateArgument> Ps,
+ ArrayRef<TemplateArgument> As,
TemplateDeductionInfo &Info,
SmallVectorImpl<DeducedTemplateArgument> &Deduced,
bool NumberOfArgumentsMustMatch);
@@ -559,75 +545,67 @@ DeduceTemplateArguments(Sema &S,
/// "success" result means that template argument deduction has not yet failed,
/// but it may still fail, later, for other reasons.
static Sema::TemplateDeductionResult
-DeduceTemplateArguments(Sema &S,
- TemplateParameterList *TemplateParams,
- const TemplateSpecializationType *Param,
- QualType Arg,
- TemplateDeductionInfo &Info,
- SmallVectorImpl<DeducedTemplateArgument> &Deduced) {
- assert(Arg.isCanonical() && "Argument type must be canonical");
-
+DeduceTemplateSpecArguments(Sema &S, TemplateParameterList *TemplateParams,
+ const QualType P, QualType A,
+ TemplateDeductionInfo &Info,
+ SmallVectorImpl<DeducedTemplateArgument> &Deduced) {
+ QualType UP = P;
+ if (const auto *IP = P->getAs<InjectedClassNameType>())
+ UP = IP->getInjectedSpecializationType();
+ // FIXME: Try to preserve type sugar here, which is hard
+ // because of the unresolved template arguments.
+ const auto *TP = UP.getCanonicalType()->castAs<TemplateSpecializationType>();
+ ArrayRef<TemplateArgument> PResolved = TP->template_arguments();
+
+ QualType UA = A;
// Treat an injected-class-name as its underlying template-id.
- if (auto *Injected = dyn_cast<InjectedClassNameType>(Arg))
- Arg = Injected->getInjectedSpecializationType();
+ if (const auto *Injected = A->getAs<InjectedClassNameType>())
+ UA = Injected->getInjectedSpecializationType();
// Check whether the template argument is a dependent template-id.
- if (const TemplateSpecializationType *SpecArg
- = dyn_cast<TemplateSpecializationType>(Arg)) {
+ // FIXME: Should not lose sugar here.
+ if (const auto *SA =
+ dyn_cast<TemplateSpecializationType>(UA.getCanonicalType())) {
// Perform template argument deduction for the template name.
- if (Sema::TemplateDeductionResult Result
- = DeduceTemplateArguments(S, TemplateParams,
- Param->getTemplateName(),
- SpecArg->getTemplateName(),
- Info, Deduced))
+ if (auto Result =
+ DeduceTemplateArguments(S, TemplateParams, TP->getTemplateName(),
+ SA->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->template_arguments(),
- SpecArg->template_arguments(), Info, Deduced,
+ return DeduceTemplateArguments(S, TemplateParams, PResolved,
+ SA->template_arguments(), Info, Deduced,
/*NumberOfArgumentsMustMatch=*/false);
}
// 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) {
- Info.FirstArg = TemplateArgument(QualType(Param, 0));
- Info.SecondArg = TemplateArgument(Arg);
- return Sema::TDK_NonDeducedMismatch;
- }
-
- ClassTemplateSpecializationDecl *SpecArg
- = dyn_cast<ClassTemplateSpecializationDecl>(RecordArg->getDecl());
- if (!SpecArg) {
- Info.FirstArg = TemplateArgument(QualType(Param, 0));
- Info.SecondArg = TemplateArgument(Arg);
+ const auto *RA = UA->getAs<RecordType>();
+ const auto *SA =
+ RA ? dyn_cast<ClassTemplateSpecializationDecl>(RA->getDecl()) : nullptr;
+ if (!SA) {
+ Info.FirstArg = TemplateArgument(P);
+ Info.SecondArg = TemplateArgument(A);
return Sema::TDK_NonDeducedMismatch;
}
// Perform template argument deduction for the template name.
- if (Sema::TemplateDeductionResult Result
- = DeduceTemplateArguments(S,
- TemplateParams,
- Param->getTemplateName(),
- TemplateName(SpecArg->getSpecializedTemplate()),
- Info, Deduced))
+ if (auto Result = DeduceTemplateArguments(
+ S, TemplateParams, TP->getTemplateName(),
+ TemplateName(SA->getSpecializedTemplate()), Info, Deduced))
return Result;
// Perform template argument deduction for the template arguments.
- return DeduceTemplateArguments(S, TemplateParams, Param->template_arguments(),
- SpecArg->getTemplateArgs().asArray(), Info,
- Deduced, /*NumberOfArgumentsMustMatch=*/true);
+ return DeduceTemplateArguments(S, TemplateParams, PResolved,
+ SA->getTemplateArgs().asArray(), Info, Deduced,
+ /*NumberOfArgumentsMustMatch=*/true);
}
-/// Determines whether the given type is an opaque type that
-/// might be more qualified when instantiated.
-static bool IsPossiblyOpaquelyQualifiedType(QualType T) {
+static bool IsPossiblyOpaquelyQualifiedType(const Type *T) {
+ assert(T->isCanonicalUnqualified());
+
switch (T->getTypeClass()) {
case Type::TypeOfExpr:
case Type::TypeOf:
@@ -642,13 +620,20 @@ static bool IsPossiblyOpaquelyQualifiedType(QualType T) {
case Type::VariableArray:
case Type::DependentSizedArray:
return IsPossiblyOpaquelyQualifiedType(
- cast<ArrayType>(T)->getElementType());
+ cast<ArrayType>(T)->getElementType().getTypePtr());
default:
return false;
}
}
+/// Determines whether the given type is an opaque type that
+/// might be more qualified when instantiated.
+static bool IsPossiblyOpaquelyQualifiedType(QualType T) {
+ return IsPossiblyOpaquelyQualifiedType(
+ T->getCanonicalTypeInternal().getTypePtr());
+}
+
/// Helper function to build a TemplateParameter when we don't
/// know its type statically.
static TemplateParameter makeTemplateParameter(Decl *D) {
@@ -1047,11 +1032,12 @@ DeduceTemplateArguments(Sema &S,
return Sema::TDK_MiscellaneousDeductionFailure;
}
- if (Sema::TemplateDeductionResult Result
- = DeduceTemplateArgumentsByTypeMatch(S, TemplateParams,
- Params[ParamIdx], Args[ArgIdx],
- Info, Deduced, TDF,
- PartialOrdering))
+ if (Sema::TemplateDeductionResult Result =
+ DeduceTemplateArgumentsByTypeMatch(
+ S, TemplateParams, Params[ParamIdx].getUnqualifiedType(),
+ Args[ArgIdx].getUnqualifiedType(), Info, Deduced, TDF,
+ PartialOrdering,
+ /*DeducedFromArrayBound=*/false))
return Result;
++ArgIdx;
@@ -1073,10 +1059,11 @@ DeduceTemplateArguments(Sema &S,
if (ParamIdx + 1 == NumParams || PackScope.hasFixedArity()) {
for (; ArgIdx < NumArgs && PackScope.hasNextElement(); ++ArgIdx) {
// Deduce template arguments from the pattern.
- if (Sema::TemplateDeductionResult Result
- = DeduceTemplateArgumentsByTypeMatch(S, TemplateParams, Pattern,
- Args[ArgIdx], Info, Deduced,
- TDF, PartialOrdering))
+ if (Sema::TemplateDeductionResult Result =
+ DeduceTemplateArgumentsByTypeMatch(
+ S, TemplateParams, Pattern.getUnqualifiedType(),
+ Args[ArgIdx].getUnqualifiedType(), Info, Deduced, TDF,
+ PartialOrdering, /*DeducedFromArrayBound=*/false))
return Result;
PackScope.nextPackElement();
@@ -1155,26 +1142,25 @@ static bool hasInconsistentOrSupersetQualifiersOf(QualType ParamType,
/// function types (noreturn adjustment, implicit calling conventions). If any
/// of parameter and argument is not a function, just perform type comparison.
///
-/// \param Param the template parameter type.
+/// \param P the template parameter type.
///
-/// \param Arg the argument type.
-bool Sema::isSameOrCompatibleFunctionType(CanQualType Param,
- CanQualType Arg) {
- const FunctionType *ParamFunction = Param->getAs<FunctionType>(),
- *ArgFunction = Arg->getAs<FunctionType>();
+/// \param A the argument type.
+bool Sema::isSameOrCompatibleFunctionType(QualType P, QualType A) {
+ const FunctionType *PF = P->getAs<FunctionType>(),
+ *AF = A->getAs<FunctionType>();
// Just compare if not functions.
- if (!ParamFunction || !ArgFunction)
- return Param == Arg;
+ if (!PF || !AF)
+ return Context.hasSameType(P, A);
// Noreturn and noexcept adjustment.
QualType AdjustedParam;
- if (IsFunctionConversion(Param, Arg, AdjustedParam))
- return Arg == Context.getCanonicalType(AdjustedParam);
+ if (IsFunctionConversion(P, A, AdjustedParam))
+ return Context.hasSameType(AdjustedParam, A);
// FIXME: Compatible calling conventions.
- return Param == Arg;
+ return Context.hasSameType(P, A);
}
/// Get the index of the first template parameter that was originally from the
@@ -1203,6 +1189,11 @@ static bool isForwardingReference(QualType Param, unsigned FirstInnerIndex) {
return false;
}
+static CXXRecordDecl *getCanonicalRD(QualType T) {
+ return cast<CXXRecordDecl>(
+ T->castAs<RecordType>()->getDecl()->getCanonicalDecl());
+}
+
/// Attempt to deduce the template arguments by checking the base types
/// according to (C++20 [temp.deduct.call] p4b3.
///
@@ -1221,10 +1212,11 @@ static bool isForwardingReference(QualType Param, unsigned FirstInnerIndex) {
/// \returns the result of template argument deduction with the bases. "invalid"
/// means no matches, "success" found a single item, and the
/// "MiscellaneousDeductionFailure" result happens when the match is ambiguous.
-static Sema::TemplateDeductionResult DeduceTemplateBases(
- Sema &S, const RecordType *RecordT, TemplateParameterList *TemplateParams,
- const TemplateSpecializationType *SpecParam, TemplateDeductionInfo &Info,
- SmallVectorImpl<DeducedTemplateArgument> &Deduced) {
+static Sema::TemplateDeductionResult
+DeduceTemplateBases(Sema &S, const CXXRecordDecl *RD,
+ TemplateParameterList *TemplateParams, QualType P,
+ TemplateDeductionInfo &Info,
+ SmallVectorImpl<DeducedTemplateArgument> &Deduced) {
// C++14 [temp.deduct.call] p4b3:
// If P is a class and P has the form simple-template-id, then the
// transformed A can be a derived class of the deduced A. Likewise if
@@ -1244,45 +1236,44 @@ static Sema::TemplateDeductionResult DeduceTemplateBases(
// visited, while ToVisit is our stack of records that we still need to
// visit. Matches contains a list of matches that have yet to be
// disqualified.
- llvm::SmallPtrSet<const RecordType *, 8> Visited;
- SmallVector<const RecordType *, 8> ToVisit;
+ llvm::SmallPtrSet<const CXXRecordDecl *, 8> Visited;
+ SmallVector<QualType, 8> ToVisit;
// We iterate over this later, so we have to use MapVector to ensure
// determinism.
- llvm::MapVector<const RecordType *, SmallVector<DeducedTemplateArgument, 8>>
+ llvm::MapVector<const CXXRecordDecl *,
+ SmallVector<DeducedTemplateArgument, 8>>
Matches;
- auto AddBases = [&Visited, &ToVisit](const RecordType *RT) {
- CXXRecordDecl *RD = cast<CXXRecordDecl>(RT->getDecl());
+ auto AddBases = [&Visited, &ToVisit](const CXXRecordDecl *RD) {
for (const auto &Base : RD->bases()) {
- assert(Base.getType()->isRecordType() &&
- "Base class that isn't a record?");
- const RecordType *RT = Base.getType()->getAs<RecordType>();
- if (Visited.insert(RT).second)
- ToVisit.push_back(Base.getType()->getAs<RecordType>());
+ QualType T = Base.getType();
+ assert(T->isRecordType() && "Base class that isn't a record?");
+ if (Visited.insert(::getCanonicalRD(T)).second)
+ ToVisit.push_back(T);
}
};
// Set up the loop by adding all the bases.
- AddBases(RecordT);
+ AddBases(RD);
// Search each path of bases until we either run into a successful match
// (where all bases of it are invalid), or we run out of bases.
while (!ToVisit.empty()) {
- const RecordType *NextT = ToVisit.pop_back_val();
+ QualType NextT = ToVisit.pop_back_val();
SmallVector<DeducedTemplateArgument, 8> DeducedCopy(Deduced.begin(),
Deduced.end());
TemplateDeductionInfo BaseInfo(TemplateDeductionInfo::ForBase, Info);
- Sema::TemplateDeductionResult BaseResult =
- DeduceTemplateArguments(S, TemplateParams, SpecParam,
- QualType(NextT, 0), BaseInfo, DeducedCopy);
+ Sema::TemplateDeductionResult BaseResult = DeduceTemplateSpecArguments(
+ S, TemplateParams, P, NextT, BaseInfo, DeducedCopy);
// If this was a successful deduction, add it to the list of matches,
// otherwise we need to continue searching its bases.
+ const CXXRecordDecl *RD = ::getCanonicalRD(NextT);
if (BaseResult == Sema::TDK_Success)
- Matches.insert({NextT, DeducedCopy});
+ Matches.insert({RD, DeducedCopy});
else
- AddBases(NextT);
+ AddBases(RD);
}
// At this point, 'Matches' contains a list of seemingly valid bases, however
@@ -1299,12 +1290,12 @@ static Sema::TemplateDeductionResult DeduceTemplateBases(
// We can give up once we have a single item (or have run out of things to
// search) since cyclical inheritance isn't valid.
while (Matches.size() > 1 && !ToVisit.empty()) {
- const RecordType *NextT = ToVisit.pop_back_val();
- Matches.erase(NextT);
+ const CXXRecordDecl *RD = ::getCanonicalRD(ToVisit.pop_back_val());
+ Matches.erase(RD);
// Always add all bases, since the inheritance tree can contain
// disqualifications for multiple matches.
- AddBases(NextT);
+ AddBases(RD);
}
}
@@ -1341,41 +1332,26 @@ static Sema::TemplateDeductionResult DeduceTemplateBases(
/// \returns the result of template argument deduction so far. Note that a
/// "success" result means that template argument deduction has not yet failed,
/// but it may still fail, later, for other reasons.
-static Sema::TemplateDeductionResult
-DeduceTemplateArgumentsByTypeMatch(Sema &S,
- TemplateParameterList *TemplateParams,
- QualType ParamIn, QualType ArgIn,
- TemplateDeductionInfo &Info,
- SmallVectorImpl<DeducedTemplateArgument> &Deduced,
- unsigned TDF,
- bool PartialOrdering,
- bool DeducedFromArrayBound) {
- // 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
- = dyn_cast<PackExpansionType>(Arg))
- Arg = ArgExpansion->getPattern();
-
+static Sema::TemplateDeductionResult DeduceTemplateArgumentsByTypeMatch(
+ Sema &S, TemplateParameterList *TemplateParams, QualType P, QualType A,
+ TemplateDeductionInfo &Info,
+ SmallVectorImpl<DeducedTemplateArgument> &Deduced, unsigned TDF,
+ bool PartialOrdering, bool DeducedFromArrayBound) {
if (PartialOrdering) {
// C++11 [temp.deduct.partial]p5:
// Before the partial ordering is done, certain transformations are
// performed on the types used for partial ordering:
// - If P is a reference type, P is replaced by the type referred to.
- const ReferenceType *ParamRef = Param->getAs<ReferenceType>();
- if (ParamRef)
- Param = ParamRef->getPointeeType();
+ const ReferenceType *PRef = P->getAs<ReferenceType>();
+ if (PRef)
+ P = PRef->getPointeeType();
// - If A is a reference type, A is replaced by the type referred to.
- const ReferenceType *ArgRef = Arg->getAs<ReferenceType>();
- if (ArgRef)
- Arg = ArgRef->getPointeeType();
+ const ReferenceType *ARef = A->getAs<ReferenceType>();
+ if (ARef)
+ A = A->getPointeeType();
- if (ParamRef && ArgRef && S.Context.hasSameUnqualifiedType(Param, Arg)) {
+ if (PRef && ARef && S.Context.hasSameUnqualifiedType(P, A)) {
// C++11 [temp.deduct.partial]p9:
// If, for a given type, deduction succeeds in both directions (i.e.,
// the types are identical after the transformations above) and both
@@ -1395,29 +1371,26 @@ DeduceTemplateArgumentsByTypeMatch(Sema &S,
// succeeds, so we model this as a deduction failure. Note that
// [the first type] is P and [the other type] is A here; the standard
// gets this backwards.
- Qualifiers ParamQuals = Param.getQualifiers();
- Qualifiers ArgQuals = Arg.getQualifiers();
- if ((ParamRef->isLValueReferenceType() &&
- !ArgRef->isLValueReferenceType()) ||
- ParamQuals.isStrictSupersetOf(ArgQuals) ||
- (ParamQuals.hasNonTrivialObjCLifetime() &&
- ArgQuals.getObjCLifetime() == Qualifiers::OCL_ExplicitNone &&
- ParamQuals.withoutObjCLifetime() ==
- ArgQuals.withoutObjCLifetime())) {
- Info.FirstArg = TemplateArgument(ParamIn);
- Info.SecondArg = TemplateArgument(ArgIn);
+ Qualifiers PQuals = P.getQualifiers(), AQuals = A.getQualifiers();
+ if ((PRef->isLValueReferenceType() && !ARef->isLValueReferenceType()) ||
+ PQuals.isStrictSupersetOf(AQuals) ||
+ (PQuals.hasNonTrivialObjCLifetime() &&
+ AQuals.getObjCLifetime() == Qualifiers::OCL_ExplicitNone &&
+ PQuals.withoutObjCLifetime() == AQuals.withoutObjCLifetime())) {
+ Info.FirstArg = TemplateArgument(P);
+ Info.SecondArg = TemplateArgument(A);
return Sema::TDK_NonDeducedMismatch;
}
}
-
+ Qualifiers DiscardedQuals;
// C++11 [temp.deduct.partial]p7:
// Remove any top-level cv-qualifiers:
// - If P is a cv-qualified type, P is replaced by the cv-unqualified
// version of P.
- Param = Param.getUnqualifiedType();
+ P = S.Context.getUnqualifiedArrayType(P, DiscardedQuals);
// - If A is a cv-qualified type, A is replaced by the cv-unqualified
// version of A.
- Arg = Arg.getUnqualifiedType();
+ A = S.Context.getUnqualifiedArrayType(A, DiscardedQuals);
} else {
// C++0x [temp.deduct.call]p4 bullet 1:
// - If the original P is a reference type, the deduced A (i.e., the type
@@ -1425,13 +1398,12 @@ DeduceTemplateArgumentsByTypeMatch(Sema &S,
// transformed A.
if (TDF & TDF_ParamWithReferenceType) {
Qualifiers Quals;
- QualType UnqualParam = S.Context.getUnqualifiedArrayType(Param, Quals);
- Quals.setCVRQualifiers(Quals.getCVRQualifiers() &
- Arg.getCVRQualifiers());
- Param = S.Context.getQualifiedType(UnqualParam, Quals);
+ QualType UnqualP = S.Context.getUnqualifiedArrayType(P, Quals);
+ Quals.setCVRQualifiers(Quals.getCVRQualifiers() & A.getCVRQualifiers());
+ P = S.Context.getQualifiedType(UnqualP, Quals);
}
- if ((TDF & TDF_TopLevelParameterTypeList) && !Param->isFunctionType()) {
+ if ((TDF & TDF_TopLevelParameterTypeList) && !P->isFunctionType()) {
// C++0x [temp.deduct.type]p10:
// If P and A are function types that originated from deduction when
// taking the address of a function template (14.8.2.2) or when deducing
@@ -1444,8 +1416,9 @@ DeduceTemplateArgumentsByTypeMatch(Sema &S,
// Pi is T&& and Ai is X&, the adjusted Pi will be T, causing T to be
// deduced as X&. - end note ]
TDF &= ~TDF_TopLevelParameterTypeList;
- if (isForwardingReference(Param, 0) && Arg->isLValueReferenceType())
- Param = Param->getPointeeType();
+ if (isForwardingReference(P, /*FirstInnerIndex=*/0) &&
+ A->isLValueReferenceType())
+ P = P->getPointeeType();
}
}
@@ -1456,53 +1429,48 @@ DeduceTemplateArgumentsByTypeMatch(Sema &S,
//
// T
// cv-list T
- if (const TemplateTypeParmType *TemplateTypeParm
- = Param->getAs<TemplateTypeParmType>()) {
+ if (const auto *TTP = P->getAs<TemplateTypeParmType>()) {
// Just skip any attempts to deduce from a placeholder type or a parameter
// at a
diff erent depth.
- if (Arg->isPlaceholderType() ||
- Info.getDeducedDepth() != TemplateTypeParm->getDepth())
+ if (A->isPlaceholderType() || Info.getDeducedDepth() != TTP->getDepth())
return Sema::TDK_Success;
- unsigned Index = TemplateTypeParm->getIndex();
- bool RecanonicalizeArg = false;
+ unsigned Index = TTP->getIndex();
// If the argument type is an array type, move the qualifiers up to the
// top level, so they can be matched with the qualifiers on the parameter.
- if (isa<ArrayType>(Arg)) {
+ if (A->isArrayType()) {
Qualifiers Quals;
- Arg = S.Context.getUnqualifiedArrayType(Arg, Quals);
- if (Quals) {
- Arg = S.Context.getQualifiedType(Arg, Quals);
- RecanonicalizeArg = true;
- }
+ A = S.Context.getUnqualifiedArrayType(A, Quals);
+ if (Quals)
+ A = S.Context.getQualifiedType(A, Quals);
}
// The argument type can not be less qualified than the parameter
// type.
if (!(TDF & TDF_IgnoreQualifiers) &&
- hasInconsistentOrSupersetQualifiersOf(Param, Arg)) {
+ hasInconsistentOrSupersetQualifiersOf(P, A)) {
Info.Param = cast<TemplateTypeParmDecl>(TemplateParams->getParam(Index));
- Info.FirstArg = TemplateArgument(Param);
- Info.SecondArg = TemplateArgument(Arg);
+ Info.FirstArg = TemplateArgument(P);
+ Info.SecondArg = TemplateArgument(A);
return Sema::TDK_Underqualified;
}
// Do not match a function type with a cv-qualified type.
// http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_active.html#1584
- if (Arg->isFunctionType() && Param.hasQualifiers()) {
+ if (A->isFunctionType() && P.hasQualifiers())
return Sema::TDK_NonDeducedMismatch;
- }
- assert(TemplateTypeParm->getDepth() == Info.getDeducedDepth() &&
+ assert(TTP->getDepth() == Info.getDeducedDepth() &&
"saw template type parameter with wrong depth");
- assert(Arg != S.Context.OverloadTy && "Unresolved overloaded function");
- QualType DeducedType = Arg;
+ assert(A->getCanonicalTypeInternal() != S.Context.OverloadTy &&
+ "Unresolved overloaded function");
+ QualType DeducedType = A;
// Remove any qualifiers on the parameter from the deduced type.
// We checked the qualifiers for consistency above.
Qualifiers DeducedQs = DeducedType.getQualifiers();
- Qualifiers ParamQs = Param.getQualifiers();
+ Qualifiers ParamQs = P.getQualifiers();
DeducedQs.removeCVRQualifiers(ParamQs.getCVRQualifiers());
if (ParamQs.hasObjCGCAttr())
DeducedQs.removeObjCGCAttr();
@@ -1517,29 +1485,24 @@ DeduceTemplateArgumentsByTypeMatch(Sema &S,
if (ParamQs.hasObjCLifetime() && !DeducedType->isObjCLifetimeType() &&
!DeducedType->isDependentType()) {
Info.Param = cast<TemplateTypeParmDecl>(TemplateParams->getParam(Index));
- Info.FirstArg = TemplateArgument(Param);
- Info.SecondArg = TemplateArgument(Arg);
+ Info.FirstArg = TemplateArgument(P);
+ Info.SecondArg = TemplateArgument(A);
return Sema::TDK_Underqualified;
}
// Objective-C ARC:
// If template deduction would produce an argument type with lifetime type
// but no lifetime qualifier, the __strong lifetime qualifier is inferred.
- if (S.getLangOpts().ObjCAutoRefCount &&
- DeducedType->isObjCLifetimeType() &&
+ if (S.getLangOpts().ObjCAutoRefCount && DeducedType->isObjCLifetimeType() &&
!DeducedQs.hasObjCLifetime())
DeducedQs.setObjCLifetime(Qualifiers::OCL_Strong);
- DeducedType = S.Context.getQualifiedType(DeducedType.getUnqualifiedType(),
- DeducedQs);
-
- if (RecanonicalizeArg)
- DeducedType = S.Context.getCanonicalType(DeducedType);
+ DeducedType =
+ S.Context.getQualifiedType(DeducedType.getUnqualifiedType(), DeducedQs);
DeducedTemplateArgument NewDeduced(DeducedType, DeducedFromArrayBound);
- DeducedTemplateArgument Result = checkDeducedTemplateArguments(S.Context,
- Deduced[Index],
- NewDeduced);
+ DeducedTemplateArgument Result =
+ checkDeducedTemplateArguments(S.Context, Deduced[Index], NewDeduced);
if (Result.isNull()) {
Info.Param = cast<TemplateTypeParmDecl>(TemplateParams->getParam(Index));
Info.FirstArg = Deduced[Index];
@@ -1552,69 +1515,57 @@ DeduceTemplateArgumentsByTypeMatch(Sema &S,
}
// Set up the template argument deduction information for a failure.
- Info.FirstArg = TemplateArgument(ParamIn);
- Info.SecondArg = TemplateArgument(ArgIn);
+ Info.FirstArg = TemplateArgument(P);
+ Info.SecondArg = TemplateArgument(A);
// If the parameter is an already-substituted template parameter
// pack, do nothing: we don't know which of its arguments to look
// at, so we have to wait until all of the parameter packs in this
// expansion have arguments.
- if (isa<SubstTemplateTypeParmPackType>(Param))
+ if (P->getAs<SubstTemplateTypeParmPackType>())
return Sema::TDK_Success;
// Check the cv-qualifiers on the parameter and argument types.
- CanQualType CanParam = S.Context.getCanonicalType(Param);
- CanQualType CanArg = S.Context.getCanonicalType(Arg);
if (!(TDF & TDF_IgnoreQualifiers)) {
if (TDF & TDF_ParamWithReferenceType) {
- if (hasInconsistentOrSupersetQualifiersOf(Param, Arg))
+ if (hasInconsistentOrSupersetQualifiersOf(P, A))
return Sema::TDK_NonDeducedMismatch;
} else if (TDF & TDF_ArgWithReferenceType) {
// C++ [temp.deduct.conv]p4:
// If the original A is a reference type, A can be more cv-qualified
// than the deduced A
- if (!Arg.getQualifiers().compatiblyIncludes(Param.getQualifiers()))
+ if (!A.getQualifiers().compatiblyIncludes(P.getQualifiers()))
return Sema::TDK_NonDeducedMismatch;
// Strip out all extra qualifiers from the argument to figure out the
// type we're converting to, prior to the qualification conversion.
Qualifiers Quals;
- Arg = S.Context.getUnqualifiedArrayType(Arg, Quals);
- Arg = S.Context.getQualifiedType(Arg, Param.getQualifiers());
- } else if (!IsPossiblyOpaquelyQualifiedType(Param)) {
- if (Param.getCVRQualifiers() != Arg.getCVRQualifiers())
+ A = S.Context.getUnqualifiedArrayType(A, Quals);
+ A = S.Context.getQualifiedType(A, P.getQualifiers());
+ } else if (!IsPossiblyOpaquelyQualifiedType(P)) {
+ if (P.getCVRQualifiers() != A.getCVRQualifiers())
return Sema::TDK_NonDeducedMismatch;
}
+ }
- // If the parameter type is not dependent, there is nothing to deduce.
- if (!Param->isDependentType()) {
- if (!(TDF & TDF_SkipNonDependent)) {
- bool NonDeduced =
- (TDF & TDF_AllowCompatibleFunctionType)
- ? !S.isSameOrCompatibleFunctionType(CanParam, CanArg)
- : Param != Arg;
- if (NonDeduced) {
- return Sema::TDK_NonDeducedMismatch;
- }
- }
+ // If the parameter type is not dependent, there is nothing to deduce.
+ if (!P->isDependentType()) {
+ if (TDF & TDF_SkipNonDependent)
return Sema::TDK_Success;
- }
- } else if (!Param->isDependentType()) {
- if (!(TDF & TDF_SkipNonDependent)) {
- CanQualType ParamUnqualType = CanParam.getUnqualifiedType(),
- ArgUnqualType = CanArg.getUnqualifiedType();
- bool Success =
- (TDF & TDF_AllowCompatibleFunctionType)
- ? S.isSameOrCompatibleFunctionType(ParamUnqualType, ArgUnqualType)
- : ParamUnqualType == ArgUnqualType;
- if (Success)
- return Sema::TDK_Success;
- } else {
+ if ((TDF & TDF_IgnoreQualifiers) ? S.Context.hasSameUnqualifiedType(P, A)
+ : S.Context.hasSameType(P, A))
return Sema::TDK_Success;
- }
+ if (TDF & TDF_AllowCompatibleFunctionType &&
+ S.isSameOrCompatibleFunctionType(P, A))
+ return Sema::TDK_Success;
+ if (!(TDF & TDF_IgnoreQualifiers))
+ return Sema::TDK_NonDeducedMismatch;
+ // Otherwise, when ignoring qualifiers, the types not having the same
+ // unqualified type does not mean they do not match, so in this case we
+ // must keep going and analyze with a non-dependent parameter type.
}
- switch (Param->getTypeClass()) {
+ switch (P.getCanonicalType()->getTypeClass()) {
// Non-canonical types cannot appear here.
#define NON_CANONICAL_TYPE(Class, Base) \
case Type::Class: llvm_unreachable("deducing non-canonical type: " #Class);
@@ -1625,8 +1576,11 @@ DeduceTemplateArgumentsByTypeMatch(Sema &S,
case Type::SubstTemplateTypeParmPack:
llvm_unreachable("Type nodes handled above");
- // These types cannot be dependent, so simply check whether the types are
- // the same.
+ case Type::Auto:
+ // FIXME: Implement deduction in dependent case.
+ if (P->isDependentType())
+ return Sema::TDK_Success;
+ LLVM_FALLTHROUGH;
case Type::Builtin:
case Type::VariableArray:
case Type::Vector:
@@ -1637,134 +1591,115 @@ DeduceTemplateArgumentsByTypeMatch(Sema &S,
case Type::ObjCInterface:
case Type::ObjCObjectPointer:
case Type::ExtInt:
- if (TDF & TDF_SkipNonDependent)
- return Sema::TDK_Success;
-
- if (TDF & TDF_IgnoreQualifiers) {
- Param = Param.getUnqualifiedType();
- Arg = Arg.getUnqualifiedType();
- }
-
- return Param == Arg? Sema::TDK_Success : Sema::TDK_NonDeducedMismatch;
+ return (TDF & TDF_SkipNonDependent) ||
+ ((TDF & TDF_IgnoreQualifiers)
+ ? S.Context.hasSameUnqualifiedType(P, A)
+ : S.Context.hasSameType(P, A))
+ ? Sema::TDK_Success
+ : Sema::TDK_NonDeducedMismatch;
// _Complex T [placeholder extension]
- case Type::Complex:
- if (const ComplexType *ComplexArg = Arg->getAs<ComplexType>())
- return DeduceTemplateArgumentsByTypeMatch(S, TemplateParams,
- cast<ComplexType>(Param)->getElementType(),
- ComplexArg->getElementType(),
- Info, Deduced, TDF);
-
- return Sema::TDK_NonDeducedMismatch;
+ case Type::Complex: {
+ const auto *CP = P->castAs<ComplexType>(), *CA = A->getAs<ComplexType>();
+ if (!CA)
+ return Sema::TDK_NonDeducedMismatch;
+ return DeduceTemplateArgumentsByTypeMatch(
+ S, TemplateParams, CP->getElementType(), CA->getElementType(), Info,
+ Deduced, TDF);
+ }
// _Atomic T [extension]
- case Type::Atomic:
- if (const AtomicType *AtomicArg = Arg->getAs<AtomicType>())
- return DeduceTemplateArgumentsByTypeMatch(S, TemplateParams,
- cast<AtomicType>(Param)->getValueType(),
- AtomicArg->getValueType(),
- Info, Deduced, TDF);
-
- return Sema::TDK_NonDeducedMismatch;
+ case Type::Atomic: {
+ const auto *PA = P->castAs<AtomicType>(), *AA = A->getAs<AtomicType>();
+ if (!AA)
+ return Sema::TDK_NonDeducedMismatch;
+ return DeduceTemplateArgumentsByTypeMatch(
+ S, TemplateParams, PA->getValueType(), AA->getValueType(), Info,
+ Deduced, TDF);
+ }
// T *
case Type::Pointer: {
QualType PointeeType;
- if (const PointerType *PointerArg = Arg->getAs<PointerType>()) {
- PointeeType = PointerArg->getPointeeType();
- } else if (const ObjCObjectPointerType *PointerArg
- = Arg->getAs<ObjCObjectPointerType>()) {
- PointeeType = PointerArg->getPointeeType();
+ if (const auto *PA = A->getAs<PointerType>()) {
+ PointeeType = PA->getPointeeType();
+ } else if (const auto *PA = A->getAs<ObjCObjectPointerType>()) {
+ PointeeType = PA->getPointeeType();
} else {
return Sema::TDK_NonDeducedMismatch;
}
-
- unsigned SubTDF = TDF & (TDF_IgnoreQualifiers | TDF_DerivedClass);
- return DeduceTemplateArgumentsByTypeMatch(S, TemplateParams,
- cast<PointerType>(Param)->getPointeeType(),
- PointeeType,
- Info, Deduced, SubTDF);
+ return DeduceTemplateArgumentsByTypeMatch(
+ S, TemplateParams, P->castAs<PointerType>()->getPointeeType(),
+ PointeeType, Info, Deduced,
+ TDF & (TDF_IgnoreQualifiers | TDF_DerivedClass));
}
// T &
case Type::LValueReference: {
- const LValueReferenceType *ReferenceArg =
- Arg->getAs<LValueReferenceType>();
- if (!ReferenceArg)
+ const auto *RP = P->castAs<LValueReferenceType>(),
+ *RA = A->getAs<LValueReferenceType>();
+ if (!RA)
return Sema::TDK_NonDeducedMismatch;
- return DeduceTemplateArgumentsByTypeMatch(S, TemplateParams,
- cast<LValueReferenceType>(Param)->getPointeeType(),
- ReferenceArg->getPointeeType(), Info, Deduced, 0);
+ return DeduceTemplateArgumentsByTypeMatch(
+ S, TemplateParams, RP->getPointeeType(), RA->getPointeeType(), Info,
+ Deduced, 0);
}
// T && [C++0x]
case Type::RValueReference: {
- const RValueReferenceType *ReferenceArg =
- Arg->getAs<RValueReferenceType>();
- if (!ReferenceArg)
+ const auto *RP = P->castAs<RValueReferenceType>(),
+ *RA = A->getAs<RValueReferenceType>();
+ if (!RA)
return Sema::TDK_NonDeducedMismatch;
- return DeduceTemplateArgumentsByTypeMatch(S, TemplateParams,
- cast<RValueReferenceType>(Param)->getPointeeType(),
- ReferenceArg->getPointeeType(),
- Info, Deduced, 0);
+ return DeduceTemplateArgumentsByTypeMatch(
+ S, TemplateParams, RP->getPointeeType(), RA->getPointeeType(), Info,
+ Deduced, 0);
}
// T [] (implied, but not stated explicitly)
case Type::IncompleteArray: {
- const IncompleteArrayType *IncompleteArrayArg =
- S.Context.getAsIncompleteArrayType(Arg);
- if (!IncompleteArrayArg)
+ const auto *IAA = S.Context.getAsIncompleteArrayType(A);
+ if (!IAA)
return Sema::TDK_NonDeducedMismatch;
- unsigned SubTDF = TDF & TDF_IgnoreQualifiers;
- return DeduceTemplateArgumentsByTypeMatch(S, TemplateParams,
- S.Context.getAsIncompleteArrayType(Param)->getElementType(),
- IncompleteArrayArg->getElementType(),
- Info, Deduced, SubTDF);
+ return DeduceTemplateArgumentsByTypeMatch(
+ S, TemplateParams,
+ S.Context.getAsIncompleteArrayType(P)->getElementType(),
+ IAA->getElementType(), Info, Deduced, TDF & TDF_IgnoreQualifiers);
}
// T [integer-constant]
case Type::ConstantArray: {
- const ConstantArrayType *ConstantArrayArg =
- S.Context.getAsConstantArrayType(Arg);
- if (!ConstantArrayArg)
+ const auto *CAA = S.Context.getAsConstantArrayType(A),
+ *CAP = S.Context.getAsConstantArrayType(P);
+ assert(CAP);
+ if (!CAA || CAA->getSize() != CAP->getSize())
return Sema::TDK_NonDeducedMismatch;
- const ConstantArrayType *ConstantArrayParm =
- S.Context.getAsConstantArrayType(Param);
- if (ConstantArrayArg->getSize() != ConstantArrayParm->getSize())
- return Sema::TDK_NonDeducedMismatch;
-
- unsigned SubTDF = TDF & TDF_IgnoreQualifiers;
- return DeduceTemplateArgumentsByTypeMatch(S, TemplateParams,
- ConstantArrayParm->getElementType(),
- ConstantArrayArg->getElementType(),
- Info, Deduced, SubTDF);
+ return DeduceTemplateArgumentsByTypeMatch(
+ S, TemplateParams, CAP->getElementType(), CAA->getElementType(), Info,
+ Deduced, TDF & TDF_IgnoreQualifiers);
}
// type [i]
case Type::DependentSizedArray: {
- const ArrayType *ArrayArg = S.Context.getAsArrayType(Arg);
- if (!ArrayArg)
+ const auto *AA = S.Context.getAsArrayType(A);
+ if (!AA)
return Sema::TDK_NonDeducedMismatch;
- unsigned SubTDF = TDF & TDF_IgnoreQualifiers;
-
// Check the element type of the arrays
- const DependentSizedArrayType *DependentArrayParm
- = S.Context.getAsDependentSizedArrayType(Param);
- if (Sema::TemplateDeductionResult Result
- = DeduceTemplateArgumentsByTypeMatch(S, TemplateParams,
- DependentArrayParm->getElementType(),
- ArrayArg->getElementType(),
- Info, Deduced, SubTDF))
+ const auto *DAP = S.Context.getAsDependentSizedArrayType(P);
+ assert(DAP);
+ if (auto Result = DeduceTemplateArgumentsByTypeMatch(
+ S, TemplateParams, DAP->getElementType(), AA->getElementType(),
+ Info, Deduced, TDF & TDF_IgnoreQualifiers))
return Result;
// Determine the array bound is something we can deduce.
- const NonTypeTemplateParmDecl *NTTP
- = getDeducedParameterFromExpr(Info, DependentArrayParm->getSizeExpr());
+ const NonTypeTemplateParmDecl *NTTP =
+ getDeducedParameterFromExpr(Info, DAP->getSizeExpr());
if (!NTTP)
return Sema::TDK_Success;
@@ -1772,20 +1707,16 @@ DeduceTemplateArgumentsByTypeMatch(Sema &S,
// template parameter.
assert(NTTP->getDepth() == Info.getDeducedDepth() &&
"saw non-type template parameter with wrong depth");
- if (const ConstantArrayType *ConstantArrayArg
- = dyn_cast<ConstantArrayType>(ArrayArg)) {
- llvm::APSInt Size(ConstantArrayArg->getSize());
- return DeduceNonTypeTemplateArgument(S, TemplateParams, NTTP, Size,
- S.Context.getSizeType(),
- /*ArrayBound=*/true,
- Info, Deduced);
+ if (const auto *CAA = dyn_cast<ConstantArrayType>(AA)) {
+ llvm::APSInt Size(CAA->getSize());
+ return DeduceNonTypeTemplateArgument(
+ S, TemplateParams, NTTP, Size, S.Context.getSizeType(),
+ /*ArrayBound=*/true, Info, Deduced);
}
- if (const DependentSizedArrayType *DependentArrayArg
- = dyn_cast<DependentSizedArrayType>(ArrayArg))
- if (DependentArrayArg->getSizeExpr())
- return DeduceNonTypeTemplateArgument(S, TemplateParams, NTTP,
- DependentArrayArg->getSizeExpr(),
- Info, Deduced);
+ if (const auto *DAA = dyn_cast<DependentSizedArrayType>(AA))
+ if (DAA->getSizeExpr())
+ return DeduceNonTypeTemplateArgument(
+ S, TemplateParams, NTTP, DAA->getSizeExpr(), Info, Deduced);
// Incomplete type does not match a dependently-sized array type
return Sema::TDK_NonDeducedMismatch;
@@ -1795,34 +1726,29 @@ DeduceTemplateArgumentsByTypeMatch(Sema &S,
// T(*)()
// T(*)(T)
case Type::FunctionProto: {
- unsigned SubTDF = TDF & TDF_TopLevelParameterTypeList;
- const FunctionProtoType *FunctionProtoArg =
- dyn_cast<FunctionProtoType>(Arg);
- if (!FunctionProtoArg)
+ const auto *FPP = P->castAs<FunctionProtoType>(),
+ *FPA = A->getAs<FunctionProtoType>();
+ if (!FPA)
return Sema::TDK_NonDeducedMismatch;
- const FunctionProtoType *FunctionProtoParam =
- cast<FunctionProtoType>(Param);
-
- if (FunctionProtoParam->getMethodQuals()
- != FunctionProtoArg->getMethodQuals() ||
- FunctionProtoParam->getRefQualifier()
- != FunctionProtoArg->getRefQualifier() ||
- FunctionProtoParam->isVariadic() != FunctionProtoArg->isVariadic())
+ if (FPP->getMethodQuals() != FPA->getMethodQuals() ||
+ FPP->getRefQualifier() != FPA->getRefQualifier() ||
+ FPP->isVariadic() != FPA->isVariadic())
return Sema::TDK_NonDeducedMismatch;
// Check return types.
if (auto Result = DeduceTemplateArgumentsByTypeMatch(
- S, TemplateParams, FunctionProtoParam->getReturnType(),
- FunctionProtoArg->getReturnType(), Info, Deduced, 0))
+ S, TemplateParams, FPP->getReturnType(), FPA->getReturnType(),
+ Info, Deduced, 0,
+ /*PartialOrdering=*/false,
+ /*DeducedFromArrayBound=*/false))
return Result;
// Check parameter types.
if (auto Result = DeduceTemplateArguments(
- S, TemplateParams, FunctionProtoParam->param_type_begin(),
- FunctionProtoParam->getNumParams(),
- FunctionProtoArg->param_type_begin(),
- FunctionProtoArg->getNumParams(), Info, Deduced, SubTDF))
+ S, TemplateParams, FPP->param_type_begin(), FPP->getNumParams(),
+ FPA->param_type_begin(), FPA->getNumParams(), Info, Deduced,
+ TDF & TDF_TopLevelParameterTypeList))
return Result;
if (TDF & TDF_AllowCompatibleFunctionType)
@@ -1831,15 +1757,15 @@ DeduceTemplateArgumentsByTypeMatch(Sema &S,
// FIXME: Per core-2016/10/1019 (no corresponding core issue yet), permit
// deducing through the noexcept-specifier if it's part of the canonical
// type. libstdc++ relies on this.
- Expr *NoexceptExpr = FunctionProtoParam->getNoexceptExpr();
+ Expr *NoexceptExpr = FPP->getNoexceptExpr();
if (const NonTypeTemplateParmDecl *NTTP =
- NoexceptExpr ? getDeducedParameterFromExpr(Info, NoexceptExpr)
- : nullptr) {
+ NoexceptExpr ? getDeducedParameterFromExpr(Info, NoexceptExpr)
+ : nullptr) {
assert(NTTP->getDepth() == Info.getDeducedDepth() &&
"saw non-type template parameter with wrong depth");
llvm::APSInt Noexcept(1);
- switch (FunctionProtoArg->canThrow()) {
+ switch (FPA->canThrow()) {
case CT_Cannot:
Noexcept = 1;
LLVM_FALLTHROUGH;
@@ -1849,10 +1775,10 @@ DeduceTemplateArgumentsByTypeMatch(Sema &S,
// FIXME: Should we?
return DeduceNonTypeTemplateArgument(
S, TemplateParams, NTTP, Noexcept, S.Context.BoolTy,
- /*ArrayBound*/true, Info, Deduced);
+ /*DeducedFromArrayBound=*/true, Info, Deduced);
case CT_Dependent:
- if (Expr *ArgNoexceptExpr = FunctionProtoArg->getNoexceptExpr())
+ if (Expr *ArgNoexceptExpr = FPA->getNoexceptExpr())
return DeduceNonTypeTemplateArgument(
S, TemplateParams, NTTP, ArgNoexceptExpr, Info, Deduced);
// Can't deduce anything from throw(T...).
@@ -1870,11 +1796,6 @@ DeduceTemplateArgumentsByTypeMatch(Sema &S,
case Type::InjectedClassName:
// Treat a template's injected-class-name as if the template
// specialization type had been used.
- Param = cast<InjectedClassNameType>(Param)
- ->getInjectedSpecializationType();
- assert(isa<TemplateSpecializationType>(Param) &&
- "injected class name is not a template specialization type");
- LLVM_FALLTHROUGH;
// template-name<T> (where template-name refers to a class template)
// template-name<i>
@@ -1882,41 +1803,33 @@ DeduceTemplateArgumentsByTypeMatch(Sema &S,
// TT<i>
// TT<>
case Type::TemplateSpecialization: {
- const TemplateSpecializationType *SpecParam =
- cast<TemplateSpecializationType>(Param);
-
// When Arg cannot be a derived class, we can just try to deduce template
// arguments from the template-id.
- const RecordType *RecordT = Arg->getAs<RecordType>();
- if (!(TDF & TDF_DerivedClass) || !RecordT)
- return DeduceTemplateArguments(S, TemplateParams, SpecParam, Arg, Info,
- Deduced);
+ if (!(TDF & TDF_DerivedClass) || !A->isRecordType())
+ return DeduceTemplateSpecArguments(S, TemplateParams, P, A, Info,
+ Deduced);
SmallVector<DeducedTemplateArgument, 8> DeducedOrig(Deduced.begin(),
Deduced.end());
- Sema::TemplateDeductionResult Result = DeduceTemplateArguments(
- S, TemplateParams, SpecParam, Arg, Info, Deduced);
-
+ auto Result =
+ DeduceTemplateSpecArguments(S, TemplateParams, P, A, Info, Deduced);
if (Result == Sema::TDK_Success)
return Result;
// We cannot inspect base classes as part of deduction when the type
// is incomplete, so either instantiate any templates necessary to
// complete the type, or skip over it if it cannot be completed.
- if (!S.isCompleteType(Info.getLocation(), Arg))
+ if (!S.isCompleteType(Info.getLocation(), A))
return Result;
// Reset the incorrectly deduced argument from above.
Deduced = DeducedOrig;
// Check bases according to C++14 [temp.deduct.call] p4b3:
- Sema::TemplateDeductionResult BaseResult = DeduceTemplateBases(
- S, RecordT, TemplateParams, SpecParam, Info, Deduced);
-
- if (BaseResult != Sema::TDK_Invalid)
- return BaseResult;
- return Result;
+ auto BaseResult = DeduceTemplateBases(S, getCanonicalRD(A),
+ TemplateParams, P, Info, Deduced);
+ return BaseResult != Sema::TDK_Invalid ? BaseResult : Result;
}
// T type::*
@@ -1929,33 +1842,27 @@ DeduceTemplateArgumentsByTypeMatch(Sema &S,
// T (T::*)()
// T (T::*)(T)
case Type::MemberPointer: {
- const MemberPointerType *MemPtrParam = cast<MemberPointerType>(Param);
- const MemberPointerType *MemPtrArg = dyn_cast<MemberPointerType>(Arg);
- if (!MemPtrArg)
+ const auto *MPP = P->castAs<MemberPointerType>(),
+ *MPA = A->getAs<MemberPointerType>();
+ if (!MPA)
return Sema::TDK_NonDeducedMismatch;
- QualType ParamPointeeType = MemPtrParam->getPointeeType();
- if (ParamPointeeType->isFunctionType())
- S.adjustMemberFunctionCC(ParamPointeeType, /*IsStatic=*/true,
+ QualType PPT = MPP->getPointeeType();
+ if (PPT->isFunctionType())
+ S.adjustMemberFunctionCC(PPT, /*IsStatic=*/true,
/*IsCtorOrDtor=*/false, Info.getLocation());
- QualType ArgPointeeType = MemPtrArg->getPointeeType();
- if (ArgPointeeType->isFunctionType())
- S.adjustMemberFunctionCC(ArgPointeeType, /*IsStatic=*/true,
+ QualType APT = MPA->getPointeeType();
+ if (APT->isFunctionType())
+ S.adjustMemberFunctionCC(APT, /*IsStatic=*/true,
/*IsCtorOrDtor=*/false, Info.getLocation());
- if (Sema::TemplateDeductionResult Result
- = DeduceTemplateArgumentsByTypeMatch(S, TemplateParams,
- ParamPointeeType,
- ArgPointeeType,
- Info, Deduced,
- TDF & TDF_IgnoreQualifiers))
+ unsigned SubTDF = TDF & TDF_IgnoreQualifiers;
+ if (auto Result = DeduceTemplateArgumentsByTypeMatch(
+ S, TemplateParams, PPT, APT, Info, Deduced, SubTDF))
return Result;
-
- return DeduceTemplateArgumentsByTypeMatch(S, TemplateParams,
- QualType(MemPtrParam->getClass(), 0),
- QualType(MemPtrArg->getClass(), 0),
- Info, Deduced,
- TDF & TDF_IgnoreQualifiers);
+ return DeduceTemplateArgumentsByTypeMatch(
+ S, TemplateParams, QualType(MPP->getClass(), 0),
+ QualType(MPA->getClass(), 0), Info, Deduced, SubTDF);
}
// (clang extension)
@@ -1964,70 +1871,58 @@ DeduceTemplateArgumentsByTypeMatch(Sema &S,
// T(^)()
// T(^)(T)
case Type::BlockPointer: {
- const BlockPointerType *BlockPtrParam = cast<BlockPointerType>(Param);
- const BlockPointerType *BlockPtrArg = dyn_cast<BlockPointerType>(Arg);
-
- if (!BlockPtrArg)
+ const auto *BPP = P->castAs<BlockPointerType>(),
+ *BPA = A->getAs<BlockPointerType>();
+ if (!BPA)
return Sema::TDK_NonDeducedMismatch;
-
- return DeduceTemplateArgumentsByTypeMatch(S, TemplateParams,
- BlockPtrParam->getPointeeType(),
- BlockPtrArg->getPointeeType(),
- Info, Deduced, 0);
+ return DeduceTemplateArgumentsByTypeMatch(
+ S, TemplateParams, BPP->getPointeeType(), BPA->getPointeeType(), Info,
+ Deduced, 0);
}
// (clang extension)
//
// 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 auto *VP = P->castAs<ExtVectorType>();
+ QualType ElementType;
+ if (const auto *VA = A->getAs<ExtVectorType>()) {
// Make sure that the vectors have the same number of elements.
- if (VectorParam->getNumElements() != VectorArg->getNumElements())
+ if (VP->getNumElements() != VA->getNumElements())
return Sema::TDK_NonDeducedMismatch;
-
- // Perform deduction on the element types.
- return DeduceTemplateArgumentsByTypeMatch(S, TemplateParams,
- VectorParam->getElementType(),
- VectorArg->getElementType(),
- Info, Deduced, TDF);
- }
-
- if (const DependentSizedExtVectorType *VectorArg
- = dyn_cast<DependentSizedExtVectorType>(Arg)) {
+ ElementType = VA->getElementType();
+ } else if (const auto *VA = A->getAs<DependentSizedExtVectorType>()) {
// We can't check the number of elements, since the argument has a
// dependent number of elements. This can only occur during partial
// ordering.
-
- // Perform deduction on the element types.
- return DeduceTemplateArgumentsByTypeMatch(S, TemplateParams,
- VectorParam->getElementType(),
- VectorArg->getElementType(),
- Info, Deduced, TDF);
+ ElementType = VA->getElementType();
+ } else {
+ return Sema::TDK_NonDeducedMismatch;
}
-
- return Sema::TDK_NonDeducedMismatch;
+ // Perform deduction on the element types.
+ return DeduceTemplateArgumentsByTypeMatch(
+ S, TemplateParams, VP->getElementType(), ElementType, Info, Deduced,
+ TDF);
}
case Type::DependentVector: {
- const auto *VectorParam = cast<DependentVectorType>(Param);
+ const auto *VP = P->castAs<DependentVectorType>();
- if (const auto *VectorArg = dyn_cast<VectorType>(Arg)) {
+ if (const auto *VA = A->getAs<VectorType>()) {
// Perform deduction on the element types.
- if (Sema::TemplateDeductionResult Result =
- DeduceTemplateArgumentsByTypeMatch(
- S, TemplateParams, VectorParam->getElementType(),
- VectorArg->getElementType(), Info, Deduced, TDF))
+ if (auto Result = DeduceTemplateArgumentsByTypeMatch(
+ S, TemplateParams, VP->getElementType(), VA->getElementType(),
+ Info, Deduced, TDF))
return Result;
// Perform deduction on the vector size, if we can.
const NonTypeTemplateParmDecl *NTTP =
- getDeducedParameterFromExpr(Info, VectorParam->getSizeExpr());
+ getDeducedParameterFromExpr(Info, VP->getSizeExpr());
if (!NTTP)
return Sema::TDK_Success;
llvm::APSInt ArgSize(S.Context.getTypeSize(S.Context.IntTy), false);
- ArgSize = VectorArg->getNumElements();
+ ArgSize = VA->getNumElements();
// Note that we use the "array bound" rules here; just like in that
// case, we don't have any particular type for the vector size, but
// we can provide one if necessary.
@@ -2036,22 +1931,21 @@ DeduceTemplateArgumentsByTypeMatch(Sema &S,
Info, Deduced);
}
- if (const auto *VectorArg = dyn_cast<DependentVectorType>(Arg)) {
+ if (const auto *VA = A->getAs<DependentVectorType>()) {
// Perform deduction on the element types.
- if (Sema::TemplateDeductionResult Result =
- DeduceTemplateArgumentsByTypeMatch(
- S, TemplateParams, VectorParam->getElementType(),
- VectorArg->getElementType(), Info, Deduced, TDF))
+ if (auto Result = DeduceTemplateArgumentsByTypeMatch(
+ S, TemplateParams, VP->getElementType(), VA->getElementType(),
+ Info, Deduced, TDF))
return Result;
// Perform deduction on the vector size, if we can.
- const NonTypeTemplateParmDecl *NTTP = getDeducedParameterFromExpr(
- Info, VectorParam->getSizeExpr());
+ const NonTypeTemplateParmDecl *NTTP =
+ getDeducedParameterFromExpr(Info, VP->getSizeExpr());
if (!NTTP)
return Sema::TDK_Success;
- return DeduceNonTypeTemplateArgument(
- S, TemplateParams, NTTP, VectorArg->getSizeExpr(), Info, Deduced);
+ return DeduceNonTypeTemplateArgument(S, TemplateParams, NTTP,
+ VA->getSizeExpr(), Info, Deduced);
}
return Sema::TDK_NonDeducedMismatch;
@@ -2061,26 +1955,23 @@ DeduceTemplateArgumentsByTypeMatch(Sema &S,
//
// T __attribute__(((ext_vector_type(N))))
case Type::DependentSizedExtVector: {
- const DependentSizedExtVectorType *VectorParam
- = cast<DependentSizedExtVectorType>(Param);
+ const auto *VP = P->castAs<DependentSizedExtVectorType>();
- if (const ExtVectorType *VectorArg = dyn_cast<ExtVectorType>(Arg)) {
+ if (const auto *VA = A->getAs<ExtVectorType>()) {
// Perform deduction on the element types.
- if (Sema::TemplateDeductionResult Result
- = DeduceTemplateArgumentsByTypeMatch(S, TemplateParams,
- VectorParam->getElementType(),
- VectorArg->getElementType(),
- Info, Deduced, TDF))
+ if (auto Result = DeduceTemplateArgumentsByTypeMatch(
+ S, TemplateParams, VP->getElementType(), VA->getElementType(),
+ Info, Deduced, TDF))
return Result;
// Perform deduction on the vector size, if we can.
const NonTypeTemplateParmDecl *NTTP =
- getDeducedParameterFromExpr(Info, VectorParam->getSizeExpr());
+ getDeducedParameterFromExpr(Info, VP->getSizeExpr());
if (!NTTP)
return Sema::TDK_Success;
llvm::APSInt ArgSize(S.Context.getTypeSize(S.Context.IntTy), false);
- ArgSize = VectorArg->getNumElements();
+ ArgSize = VA->getNumElements();
// Note that we use the "array bound" rules here; just like in that
// case, we don't have any particular type for the vector size, but
// we can provide one if necessary.
@@ -2089,25 +1980,21 @@ DeduceTemplateArgumentsByTypeMatch(Sema &S,
Deduced);
}
- if (const DependentSizedExtVectorType *VectorArg
- = dyn_cast<DependentSizedExtVectorType>(Arg)) {
+ if (const auto *VA = A->getAs<DependentSizedExtVectorType>()) {
// Perform deduction on the element types.
- if (Sema::TemplateDeductionResult Result
- = DeduceTemplateArgumentsByTypeMatch(S, TemplateParams,
- VectorParam->getElementType(),
- VectorArg->getElementType(),
- Info, Deduced, TDF))
+ if (auto Result = DeduceTemplateArgumentsByTypeMatch(
+ S, TemplateParams, VP->getElementType(), VA->getElementType(),
+ Info, Deduced, TDF))
return Result;
// Perform deduction on the vector size, if we can.
const NonTypeTemplateParmDecl *NTTP =
- getDeducedParameterFromExpr(Info, VectorParam->getSizeExpr());
+ getDeducedParameterFromExpr(Info, VP->getSizeExpr());
if (!NTTP)
return Sema::TDK_Success;
return DeduceNonTypeTemplateArgument(S, TemplateParams, NTTP,
- VectorArg->getSizeExpr(),
- Info, Deduced);
+ VA->getSizeExpr(), Info, Deduced);
}
return Sema::TDK_NonDeducedMismatch;
@@ -2118,57 +2005,55 @@ DeduceTemplateArgumentsByTypeMatch(Sema &S,
// T __attribute__((matrix_type(<integral constant>,
// <integral constant>)))
case Type::ConstantMatrix: {
- const ConstantMatrixType *MatrixArg = dyn_cast<ConstantMatrixType>(Arg);
- if (!MatrixArg)
+ const auto *MP = P->castAs<ConstantMatrixType>(),
+ *MA = A->getAs<ConstantMatrixType>();
+ if (!MA)
return Sema::TDK_NonDeducedMismatch;
- const ConstantMatrixType *MatrixParam = cast<ConstantMatrixType>(Param);
// Check that the dimensions are the same
- if (MatrixParam->getNumRows() != MatrixArg->getNumRows() ||
- MatrixParam->getNumColumns() != MatrixArg->getNumColumns()) {
+ if (MP->getNumRows() != MA->getNumRows() ||
+ MP->getNumColumns() != MA->getNumColumns()) {
return Sema::TDK_NonDeducedMismatch;
}
// Perform deduction on element types.
return DeduceTemplateArgumentsByTypeMatch(
- S, TemplateParams, MatrixParam->getElementType(),
- MatrixArg->getElementType(), Info, Deduced, TDF);
+ S, TemplateParams, MP->getElementType(), MA->getElementType(), Info,
+ Deduced, TDF);
}
case Type::DependentSizedMatrix: {
- const MatrixType *MatrixArg = dyn_cast<MatrixType>(Arg);
- if (!MatrixArg)
+ const auto *MP = P->castAs<DependentSizedMatrixType>();
+ const auto *MA = A->getAs<MatrixType>();
+ if (!MA)
return Sema::TDK_NonDeducedMismatch;
// Check the element type of the matrixes.
- const DependentSizedMatrixType *MatrixParam =
- cast<DependentSizedMatrixType>(Param);
- if (Sema::TemplateDeductionResult Result =
- DeduceTemplateArgumentsByTypeMatch(
- S, TemplateParams, MatrixParam->getElementType(),
- MatrixArg->getElementType(), Info, Deduced, TDF))
+ if (auto Result = DeduceTemplateArgumentsByTypeMatch(
+ S, TemplateParams, MP->getElementType(), MA->getElementType(),
+ Info, Deduced, TDF))
return Result;
// Try to deduce a matrix dimension.
auto DeduceMatrixArg =
[&S, &Info, &Deduced, &TemplateParams](
- Expr *ParamExpr, const MatrixType *Arg,
+ Expr *ParamExpr, const MatrixType *A,
unsigned (ConstantMatrixType::*GetArgDimension)() const,
Expr *(DependentSizedMatrixType::*GetArgDimensionExpr)() const) {
- const auto *ArgConstMatrix = dyn_cast<ConstantMatrixType>(Arg);
- const auto *ArgDepMatrix = dyn_cast<DependentSizedMatrixType>(Arg);
+ const auto *ACM = dyn_cast<ConstantMatrixType>(A);
+ const auto *ADM = dyn_cast<DependentSizedMatrixType>(A);
if (!ParamExpr->isValueDependent()) {
Optional<llvm::APSInt> ParamConst =
ParamExpr->getIntegerConstantExpr(S.Context);
if (!ParamConst)
return Sema::TDK_NonDeducedMismatch;
- if (ArgConstMatrix) {
- if ((ArgConstMatrix->*GetArgDimension)() == *ParamConst)
+ if (ACM) {
+ if ((ACM->*GetArgDimension)() == *ParamConst)
return Sema::TDK_Success;
return Sema::TDK_NonDeducedMismatch;
}
- Expr *ArgExpr = (ArgDepMatrix->*GetArgDimensionExpr)();
+ Expr *ArgExpr = (ADM->*GetArgDimensionExpr)();
if (Optional<llvm::APSInt> ArgConst =
ArgExpr->getIntegerConstantExpr(S.Context))
if (*ArgConst == *ParamConst)
@@ -2181,27 +2066,26 @@ DeduceTemplateArgumentsByTypeMatch(Sema &S,
if (!NTTP)
return Sema::TDK_Success;
- if (ArgConstMatrix) {
+ if (ACM) {
llvm::APSInt ArgConst(
S.Context.getTypeSize(S.Context.getSizeType()));
- ArgConst = (ArgConstMatrix->*GetArgDimension)();
+ ArgConst = (ACM->*GetArgDimension)();
return DeduceNonTypeTemplateArgument(
S, TemplateParams, NTTP, ArgConst, S.Context.getSizeType(),
/*ArrayBound=*/true, Info, Deduced);
}
- return DeduceNonTypeTemplateArgument(
- S, TemplateParams, NTTP, (ArgDepMatrix->*GetArgDimensionExpr)(),
- Info, Deduced);
+ return DeduceNonTypeTemplateArgument(S, TemplateParams, NTTP,
+ (ADM->*GetArgDimensionExpr)(),
+ Info, Deduced);
};
- auto Result = DeduceMatrixArg(MatrixParam->getRowExpr(), MatrixArg,
- &ConstantMatrixType::getNumRows,
- &DependentSizedMatrixType::getRowExpr);
- if (Result)
+ if (auto Result = DeduceMatrixArg(MP->getRowExpr(), MA,
+ &ConstantMatrixType::getNumRows,
+ &DependentSizedMatrixType::getRowExpr))
return Result;
- return DeduceMatrixArg(MatrixParam->getColumnExpr(), MatrixArg,
+ return DeduceMatrixArg(MP->getColumnExpr(), MA,
&ConstantMatrixType::getNumColumns,
&DependentSizedMatrixType::getColumnExpr);
}
@@ -2210,44 +2094,39 @@ DeduceTemplateArgumentsByTypeMatch(Sema &S,
//
// T __attribute__(((address_space(N))))
case Type::DependentAddressSpace: {
- const DependentAddressSpaceType *AddressSpaceParam =
- cast<DependentAddressSpaceType>(Param);
+ const auto *ASP = P->castAs<DependentAddressSpaceType>();
- if (const DependentAddressSpaceType *AddressSpaceArg =
- dyn_cast<DependentAddressSpaceType>(Arg)) {
+ if (const auto *ASA = A->getAs<DependentAddressSpaceType>()) {
// Perform deduction on the pointer type.
- if (Sema::TemplateDeductionResult Result =
- DeduceTemplateArgumentsByTypeMatch(
- S, TemplateParams, AddressSpaceParam->getPointeeType(),
- AddressSpaceArg->getPointeeType(), Info, Deduced, TDF))
+ if (auto Result = DeduceTemplateArgumentsByTypeMatch(
+ S, TemplateParams, ASP->getPointeeType(), ASA->getPointeeType(),
+ Info, Deduced, TDF))
return Result;
// Perform deduction on the address space, if we can.
- const NonTypeTemplateParmDecl *NTTP = getDeducedParameterFromExpr(
- Info, AddressSpaceParam->getAddrSpaceExpr());
+ const NonTypeTemplateParmDecl *NTTP =
+ getDeducedParameterFromExpr(Info, ASP->getAddrSpaceExpr());
if (!NTTP)
return Sema::TDK_Success;
return DeduceNonTypeTemplateArgument(
- S, TemplateParams, NTTP, AddressSpaceArg->getAddrSpaceExpr(), Info,
- Deduced);
+ S, TemplateParams, NTTP, ASA->getAddrSpaceExpr(), Info, Deduced);
}
- if (isTargetAddressSpace(Arg.getAddressSpace())) {
+ if (isTargetAddressSpace(A.getAddressSpace())) {
llvm::APSInt ArgAddressSpace(S.Context.getTypeSize(S.Context.IntTy),
false);
- ArgAddressSpace = toTargetAddressSpace(Arg.getAddressSpace());
+ ArgAddressSpace = toTargetAddressSpace(A.getAddressSpace());
// Perform deduction on the pointer types.
- if (Sema::TemplateDeductionResult Result =
- DeduceTemplateArgumentsByTypeMatch(
- S, TemplateParams, AddressSpaceParam->getPointeeType(),
- S.Context.removeAddrSpaceQualType(Arg), Info, Deduced, TDF))
+ if (auto Result = DeduceTemplateArgumentsByTypeMatch(
+ S, TemplateParams, ASP->getPointeeType(),
+ S.Context.removeAddrSpaceQualType(A), Info, Deduced, TDF))
return Result;
// Perform deduction on the address space, if we can.
- const NonTypeTemplateParmDecl *NTTP = getDeducedParameterFromExpr(
- Info, AddressSpaceParam->getAddrSpaceExpr());
+ const NonTypeTemplateParmDecl *NTTP =
+ getDeducedParameterFromExpr(Info, ASP->getAddrSpaceExpr());
if (!NTTP)
return Sema::TDK_Success;
@@ -2259,30 +2138,31 @@ DeduceTemplateArgumentsByTypeMatch(Sema &S,
return Sema::TDK_NonDeducedMismatch;
}
case Type::DependentExtInt: {
- const auto *IntParam = cast<DependentExtIntType>(Param);
+ const auto *IP = P->castAs<DependentExtIntType>();
- if (const auto *IntArg = dyn_cast<ExtIntType>(Arg)){
- if (IntParam->isUnsigned() != IntArg->isUnsigned())
+ if (const auto *IA = A->getAs<ExtIntType>()) {
+ if (IP->isUnsigned() != IA->isUnsigned())
return Sema::TDK_NonDeducedMismatch;
const NonTypeTemplateParmDecl *NTTP =
- getDeducedParameterFromExpr(Info, IntParam->getNumBitsExpr());
+ getDeducedParameterFromExpr(Info, IP->getNumBitsExpr());
if (!NTTP)
return Sema::TDK_Success;
llvm::APSInt ArgSize(S.Context.getTypeSize(S.Context.IntTy), false);
- ArgSize = IntArg->getNumBits();
+ ArgSize = IA->getNumBits();
return DeduceNonTypeTemplateArgument(S, TemplateParams, NTTP, ArgSize,
S.Context.IntTy, true, Info,
Deduced);
}
- if (const auto *IntArg = dyn_cast<DependentExtIntType>(Arg)) {
- if (IntParam->isUnsigned() != IntArg->isUnsigned())
+ if (const auto *IA = A->getAs<DependentExtIntType>()) {
+ if (IP->isUnsigned() != IA->isUnsigned())
return Sema::TDK_NonDeducedMismatch;
return Sema::TDK_Success;
}
+
return Sema::TDK_NonDeducedMismatch;
}
@@ -2292,125 +2172,103 @@ DeduceTemplateArgumentsByTypeMatch(Sema &S,
case Type::UnresolvedUsing:
case Type::Decltype:
case Type::UnaryTransform:
- case Type::Auto:
case Type::DeducedTemplateSpecialization:
case Type::DependentTemplateSpecialization:
case Type::PackExpansion:
case Type::Pipe:
// No template argument deduction for these types
return Sema::TDK_Success;
- }
+ }
llvm_unreachable("Invalid Type Class!");
}
static Sema::TemplateDeductionResult
-DeduceTemplateArguments(Sema &S,
- TemplateParameterList *TemplateParams,
- const TemplateArgument &Param,
- TemplateArgument Arg,
+DeduceTemplateArguments(Sema &S, TemplateParameterList *TemplateParams,
+ const TemplateArgument &P, TemplateArgument A,
TemplateDeductionInfo &Info,
SmallVectorImpl<DeducedTemplateArgument> &Deduced) {
// If the template argument is a pack expansion, perform template argument
// deduction against the pattern of that expansion. This only occurs during
// partial ordering.
- if (Arg.isPackExpansion())
- Arg = Arg.getPackExpansionPattern();
+ if (A.isPackExpansion())
+ A = A.getPackExpansionPattern();
- switch (Param.getKind()) {
+ switch (P.getKind()) {
case TemplateArgument::Null:
llvm_unreachable("Null template argument in parameter list");
case TemplateArgument::Type:
- if (Arg.getKind() == TemplateArgument::Type)
- return DeduceTemplateArgumentsByTypeMatch(S, TemplateParams,
- Param.getAsType(),
- Arg.getAsType(),
- Info, Deduced, 0);
- Info.FirstArg = Param;
- Info.SecondArg = Arg;
+ if (A.getKind() == TemplateArgument::Type)
+ return DeduceTemplateArgumentsByTypeMatch(
+ S, TemplateParams, P.getAsType(), A.getAsType(), Info, Deduced, 0);
+ Info.FirstArg = P;
+ Info.SecondArg = A;
return Sema::TDK_NonDeducedMismatch;
case TemplateArgument::Template:
- if (Arg.getKind() == TemplateArgument::Template)
- return DeduceTemplateArguments(S, TemplateParams,
- Param.getAsTemplate(),
- Arg.getAsTemplate(), Info, Deduced);
- Info.FirstArg = Param;
- Info.SecondArg = Arg;
+ if (A.getKind() == TemplateArgument::Template)
+ return DeduceTemplateArguments(S, TemplateParams, P.getAsTemplate(),
+ A.getAsTemplate(), Info, Deduced);
+ Info.FirstArg = P;
+ Info.SecondArg = A;
return Sema::TDK_NonDeducedMismatch;
case TemplateArgument::TemplateExpansion:
llvm_unreachable("caller should handle pack expansions");
case TemplateArgument::Declaration:
- if (Arg.getKind() == TemplateArgument::Declaration &&
- isSameDeclaration(Param.getAsDecl(), Arg.getAsDecl()))
+ if (A.getKind() == TemplateArgument::Declaration &&
+ isSameDeclaration(P.getAsDecl(), A.getAsDecl()))
return Sema::TDK_Success;
- Info.FirstArg = Param;
- Info.SecondArg = Arg;
+ Info.FirstArg = P;
+ Info.SecondArg = A;
return Sema::TDK_NonDeducedMismatch;
case TemplateArgument::NullPtr:
- if (Arg.getKind() == TemplateArgument::NullPtr &&
- S.Context.hasSameType(Param.getNullPtrType(), Arg.getNullPtrType()))
+ if (A.getKind() == TemplateArgument::NullPtr &&
+ S.Context.hasSameType(P.getNullPtrType(), A.getNullPtrType()))
return Sema::TDK_Success;
- Info.FirstArg = Param;
- Info.SecondArg = Arg;
+ Info.FirstArg = P;
+ Info.SecondArg = A;
return Sema::TDK_NonDeducedMismatch;
case TemplateArgument::Integral:
- if (Arg.getKind() == TemplateArgument::Integral) {
- if (hasSameExtendedValue(Param.getAsIntegral(), Arg.getAsIntegral()))
+ if (A.getKind() == TemplateArgument::Integral) {
+ if (hasSameExtendedValue(P.getAsIntegral(), A.getAsIntegral()))
return Sema::TDK_Success;
-
- Info.FirstArg = Param;
- Info.SecondArg = Arg;
- return Sema::TDK_NonDeducedMismatch;
- }
-
- if (Arg.getKind() == TemplateArgument::Expression) {
- Info.FirstArg = Param;
- Info.SecondArg = Arg;
- return Sema::TDK_NonDeducedMismatch;
}
-
- Info.FirstArg = Param;
- Info.SecondArg = Arg;
+ Info.FirstArg = P;
+ Info.SecondArg = A;
return Sema::TDK_NonDeducedMismatch;
case TemplateArgument::Expression:
if (const NonTypeTemplateParmDecl *NTTP =
- getDeducedParameterFromExpr(Info, Param.getAsExpr())) {
- if (Arg.getKind() == TemplateArgument::Integral)
- return DeduceNonTypeTemplateArgument(S, TemplateParams, NTTP,
- Arg.getAsIntegral(),
- Arg.getIntegralType(),
- /*ArrayBound=*/false,
- Info, Deduced);
- if (Arg.getKind() == TemplateArgument::NullPtr)
+ getDeducedParameterFromExpr(Info, P.getAsExpr())) {
+ if (A.getKind() == TemplateArgument::Integral)
+ return DeduceNonTypeTemplateArgument(
+ S, TemplateParams, NTTP, A.getAsIntegral(), A.getIntegralType(),
+ /*ArrayBound=*/false, Info, Deduced);
+ if (A.getKind() == TemplateArgument::NullPtr)
return DeduceNullPtrTemplateArgument(S, TemplateParams, NTTP,
- Arg.getNullPtrType(),
- Info, Deduced);
- if (Arg.getKind() == TemplateArgument::Expression)
+ A.getNullPtrType(), Info, Deduced);
+ if (A.getKind() == TemplateArgument::Expression)
return DeduceNonTypeTemplateArgument(S, TemplateParams, NTTP,
- Arg.getAsExpr(), Info, Deduced);
- if (Arg.getKind() == TemplateArgument::Declaration)
- return DeduceNonTypeTemplateArgument(S, TemplateParams, NTTP,
- Arg.getAsDecl(),
- Arg.getParamTypeForDecl(),
- Info, Deduced);
+ A.getAsExpr(), Info, Deduced);
+ if (A.getKind() == TemplateArgument::Declaration)
+ return DeduceNonTypeTemplateArgument(
+ S, TemplateParams, NTTP, A.getAsDecl(), A.getParamTypeForDecl(),
+ Info, Deduced);
- Info.FirstArg = Param;
- Info.SecondArg = Arg;
+ Info.FirstArg = P;
+ Info.SecondArg = A;
return Sema::TDK_NonDeducedMismatch;
}
// Can't deduce anything, but that's okay.
return Sema::TDK_Success;
-
case TemplateArgument::Pack:
llvm_unreachable("Argument packs should be expanded by the caller!");
}
@@ -2463,8 +2321,8 @@ static bool hasPackExpansionBeforeEnd(ArrayRef<TemplateArgument> Args) {
static Sema::TemplateDeductionResult
DeduceTemplateArguments(Sema &S, TemplateParameterList *TemplateParams,
- ArrayRef<TemplateArgument> Params,
- ArrayRef<TemplateArgument> Args,
+ ArrayRef<TemplateArgument> Ps,
+ ArrayRef<TemplateArgument> As,
TemplateDeductionInfo &Info,
SmallVectorImpl<DeducedTemplateArgument> &Deduced,
bool NumberOfArgumentsMustMatch) {
@@ -2472,7 +2330,7 @@ DeduceTemplateArguments(Sema &S, TemplateParameterList *TemplateParams,
// If the template argument list of P contains a pack expansion that is not
// the last template argument, the entire template argument list is a
// non-deduced context.
- if (hasPackExpansionBeforeEnd(Params))
+ if (hasPackExpansionBeforeEnd(Ps))
return Sema::TDK_Success;
// C++0x [temp.deduct.type]p9:
@@ -2480,12 +2338,13 @@ DeduceTemplateArguments(Sema &S, TemplateParameterList *TemplateParams,
// respective template argument list P is compared with the corresponding
// argument Ai of the corresponding template argument list of A.
unsigned ArgIdx = 0, ParamIdx = 0;
- for (; hasTemplateArgumentForDeduction(Params, ParamIdx); ++ParamIdx) {
- if (!Params[ParamIdx].isPackExpansion()) {
+ for (; hasTemplateArgumentForDeduction(Ps, ParamIdx); ++ParamIdx) {
+ const TemplateArgument &P = Ps[ParamIdx];
+ if (!P.isPackExpansion()) {
// The simple case: deduce template arguments by matching Pi and Ai.
// Check whether we have enough arguments.
- if (!hasTemplateArgumentForDeduction(Args, ArgIdx))
+ if (!hasTemplateArgumentForDeduction(As, ArgIdx))
return NumberOfArgumentsMustMatch
? Sema::TDK_MiscellaneousDeductionFailure
: Sema::TDK_Success;
@@ -2493,14 +2352,12 @@ DeduceTemplateArguments(Sema &S, TemplateParameterList *TemplateParams,
// C++1z [temp.deduct.type]p9:
// During partial ordering, if Ai was originally a pack expansion [and]
// Pi is not a pack expansion, template argument deduction fails.
- if (Args[ArgIdx].isPackExpansion())
+ if (As[ArgIdx].isPackExpansion())
return Sema::TDK_MiscellaneousDeductionFailure;
// Perform deduction for this Pi/Ai pair.
- if (Sema::TemplateDeductionResult Result
- = DeduceTemplateArguments(S, TemplateParams,
- Params[ParamIdx], Args[ArgIdx],
- Info, Deduced))
+ if (auto Result = DeduceTemplateArguments(S, TemplateParams, P,
+ As[ArgIdx], Info, Deduced))
return Result;
// Move to the next argument.
@@ -2515,7 +2372,7 @@ DeduceTemplateArguments(Sema &S, TemplateParameterList *TemplateParams,
// each remaining argument in the template argument list of A. Each
// comparison deduces template arguments for subsequent positions in the
// template parameter packs expanded by Pi.
- TemplateArgument Pattern = Params[ParamIdx].getPackExpansionPattern();
+ TemplateArgument Pattern = P.getPackExpansionPattern();
// Prepare to deduce the packs within the pattern.
PackDeductionScope PackScope(S, TemplateParams, Deduced, Info, Pattern);
@@ -2523,13 +2380,12 @@ DeduceTemplateArguments(Sema &S, TemplateParameterList *TemplateParams,
// Keep track of the deduced template arguments for each parameter pack
// expanded by this pack expansion (the outer index) and for each
// template argument (the inner SmallVectors).
- for (; hasTemplateArgumentForDeduction(Args, ArgIdx) &&
+ for (; hasTemplateArgumentForDeduction(As, ArgIdx) &&
PackScope.hasNextElement();
++ArgIdx) {
// Deduce template arguments from the pattern.
- if (Sema::TemplateDeductionResult Result
- = DeduceTemplateArguments(S, TemplateParams, Pattern, Args[ArgIdx],
- Info, Deduced))
+ if (auto Result = DeduceTemplateArguments(S, TemplateParams, Pattern,
+ As[ArgIdx], Info, Deduced))
return Result;
PackScope.nextPackElement();
@@ -2545,15 +2401,14 @@ DeduceTemplateArguments(Sema &S, TemplateParameterList *TemplateParams,
}
static Sema::TemplateDeductionResult
-DeduceTemplateArguments(Sema &S,
- TemplateParameterList *TemplateParams,
+DeduceTemplateArguments(Sema &S, TemplateParameterList *TemplateParams,
const TemplateArgumentList &ParamList,
const TemplateArgumentList &ArgList,
TemplateDeductionInfo &Info,
SmallVectorImpl<DeducedTemplateArgument> &Deduced) {
return DeduceTemplateArguments(S, TemplateParams, ParamList.asArray(),
ArgList.asArray(), Info, Deduced,
- /*NumberOfArgumentsMustMatch*/false);
+ /*NumberOfArgumentsMustMatch=*/false);
}
/// Determine whether two template arguments are the same.
@@ -4356,7 +4211,7 @@ Sema::TemplateDeductionResult Sema::DeduceTemplateArguments(
bool HasDeducedReturnType = false;
if (getLangOpts().CPlusPlus14 && IsAddressOfFunction &&
Function->getReturnType()->getContainedAutoType()) {
- FunctionType = SubstAutoType(FunctionType, Context.DependentTy);
+ FunctionType = SubstAutoTypeDependent(FunctionType);
HasDeducedReturnType = true;
}
@@ -4790,12 +4645,8 @@ Sema::DeduceAutoType(TypeLoc Type, Expr *&Init, QualType &Result,
ExprResult ER = CheckPlaceholderExpr(Init);
if (ER.isInvalid())
return DAR_FailedAlreadyDiagnosed;
- Init = ER.get();
- QualType Deduced = BuildDecltypeType(Init, Init->getBeginLoc(), false);
- if (Deduced.isNull())
- return DAR_FailedAlreadyDiagnosed;
- // FIXME: Support a non-canonical deduced type for 'auto'.
- Deduced = Context.getCanonicalType(Deduced);
+ QualType Deduced = getDecltypeForExpr(ER.get());
+ assert(!Deduced.isNull());
if (AT->isConstrained() && !IgnoreConstraints) {
auto ConstraintsResult =
CheckDeducedPlaceholderConstraints(*this, *AT,
@@ -4830,7 +4681,7 @@ Sema::DeduceAutoType(TypeLoc Type, Expr *&Init, QualType &Result,
Context, Loc, Loc, TemplParamPtr, Loc, nullptr);
QualType FuncParam =
- SubstituteDeducedTypeTransform(*this, TemplArg, /*UseTypeSugar*/false)
+ SubstituteDeducedTypeTransform(*this, TemplArg, /*UseTypeSugar*/ true)
.Apply(Type);
assert(!FuncParam.isNull() &&
"substituting template parameter for 'auto' failed");
@@ -4944,27 +4795,29 @@ Sema::DeduceAutoType(TypeLoc Type, Expr *&Init, QualType &Result,
QualType Sema::SubstAutoType(QualType TypeWithAuto,
QualType TypeToReplaceAuto) {
- if (TypeToReplaceAuto->isDependentType())
- return SubstituteDeducedTypeTransform(
- *this, DependentAuto{
- TypeToReplaceAuto->containsUnexpandedParameterPack()})
- .TransformType(TypeWithAuto);
+ assert(TypeToReplaceAuto != Context.DependentTy);
return SubstituteDeducedTypeTransform(*this, TypeToReplaceAuto)
.TransformType(TypeWithAuto);
}
TypeSourceInfo *Sema::SubstAutoTypeSourceInfo(TypeSourceInfo *TypeWithAuto,
QualType TypeToReplaceAuto) {
- if (TypeToReplaceAuto->isDependentType())
- return SubstituteDeducedTypeTransform(
- *this,
- DependentAuto{
- TypeToReplaceAuto->containsUnexpandedParameterPack()})
- .TransformType(TypeWithAuto);
+ assert(TypeToReplaceAuto != Context.DependentTy);
return SubstituteDeducedTypeTransform(*this, TypeToReplaceAuto)
.TransformType(TypeWithAuto);
}
+QualType Sema::SubstAutoTypeDependent(QualType TypeWithAuto) {
+ return SubstituteDeducedTypeTransform(*this, DependentAuto{false})
+ .TransformType(TypeWithAuto);
+}
+
+TypeSourceInfo *
+Sema::SubstAutoTypeSourceInfoDependent(TypeSourceInfo *TypeWithAuto) {
+ return SubstituteDeducedTypeTransform(*this, DependentAuto{false})
+ .TransformType(TypeWithAuto);
+}
+
QualType Sema::ReplaceAutoType(QualType TypeWithAuto,
QualType TypeToReplaceAuto) {
return SubstituteDeducedTypeTransform(*this, TypeToReplaceAuto,
@@ -5159,6 +5012,7 @@ static bool isAtLeastAsSpecializedAs(Sema &S,
Args2.resize(NumComparedArguments);
if (Reversed)
std::reverse(Args2.begin(), Args2.end());
+
if (DeduceTemplateArguments(S, TemplateParams, Args2.data(), Args2.size(),
Args1.data(), Args1.size(), Info, Deduced,
TDF_None, /*PartialOrdering=*/true))
diff --git a/clang/lib/Sema/SemaType.cpp b/clang/lib/Sema/SemaType.cpp
index 32ee61cc58659..d2ee669debd0c 100644
--- a/clang/lib/Sema/SemaType.cpp
+++ b/clang/lib/Sema/SemaType.cpp
@@ -1622,7 +1622,7 @@ static QualType ConvertDeclSpecToType(TypeProcessingState &state) {
Expr *E = DS.getRepAsExpr();
assert(E && "Didn't get an expression for typeof?");
// TypeQuals handled by caller.
- Result = S.BuildTypeofExprType(E, DS.getTypeSpecTypeLoc());
+ Result = S.BuildTypeofExprType(E);
if (Result.isNull()) {
Result = Context.IntTy;
declarator.setInvalidType(true);
@@ -1633,7 +1633,7 @@ static QualType ConvertDeclSpecToType(TypeProcessingState &state) {
Expr *E = DS.getRepAsExpr();
assert(E && "Didn't get an expression for decltype?");
// TypeQuals handled by caller.
- Result = S.BuildDecltypeType(E, DS.getTypeSpecTypeLoc());
+ Result = S.BuildDecltypeType(E);
if (Result.isNull()) {
Result = Context.IntTy;
declarator.setInvalidType(true);
@@ -8925,7 +8925,7 @@ QualType Sema::getElaboratedType(ElaboratedTypeKeyword Keyword,
return Context.getElaboratedType(Keyword, NNS, T, OwnedTagDecl);
}
-QualType Sema::BuildTypeofExprType(Expr *E, SourceLocation Loc) {
+QualType Sema::BuildTypeofExprType(Expr *E) {
assert(!E->hasPlaceholderType() && "unexpected placeholder");
if (!getLangOpts().CPlusPlus && E->refersToBitField())
@@ -8942,9 +8942,9 @@ QualType Sema::BuildTypeofExprType(Expr *E, SourceLocation Loc) {
/// getDecltypeForExpr - Given an expr, will return the decltype for
/// that expression, according to the rules in C++11
/// [dcl.type.simple]p4 and C++11 [expr.lambda.prim]p18.
-static QualType getDecltypeForExpr(Sema &S, Expr *E) {
+QualType Sema::getDecltypeForExpr(Expr *E) {
if (E->isTypeDependent())
- return S.Context.DependentTy;
+ return Context.DependentTy;
Expr *IDExpr = E;
if (auto *ImplCastExpr = dyn_cast<ImplicitCastExpr>(E))
@@ -8961,7 +8961,7 @@ static QualType getDecltypeForExpr(Sema &S, Expr *E) {
// parameter object. This rule makes no
diff erence before C++20 so we apply
// it unconditionally.
if (const auto *SNTTPE = dyn_cast<SubstNonTypeTemplateParmExpr>(IDExpr))
- return SNTTPE->getParameterType(S.Context);
+ return SNTTPE->getParameterType(Context);
// - if e is an unparenthesized id-expression or an unparenthesized class
// member access (5.2.5), decltype(e) is the type of the entity named
@@ -8969,22 +8969,21 @@ static QualType getDecltypeForExpr(Sema &S, Expr *E) {
// functions, the program is ill-formed;
//
// We apply the same rules for Objective-C ivar and property references.
- if (const DeclRefExpr *DRE = dyn_cast<DeclRefExpr>(IDExpr)) {
+ if (const auto *DRE = dyn_cast<DeclRefExpr>(IDExpr)) {
const ValueDecl *VD = DRE->getDecl();
- if (auto *TPO = dyn_cast<TemplateParamObjectDecl>(VD))
- return TPO->getType().getUnqualifiedType();
- return VD->getType();
- } else if (const MemberExpr *ME = dyn_cast<MemberExpr>(IDExpr)) {
- if (const ValueDecl *VD = ME->getMemberDecl())
+ QualType T = VD->getType();
+ return isa<TemplateParamObjectDecl>(VD) ? T.getUnqualifiedType() : T;
+ }
+ if (const auto *ME = dyn_cast<MemberExpr>(IDExpr)) {
+ if (const auto *VD = ME->getMemberDecl())
if (isa<FieldDecl>(VD) || isa<VarDecl>(VD))
return VD->getType();
- } else if (const ObjCIvarRefExpr *IR = dyn_cast<ObjCIvarRefExpr>(IDExpr)) {
+ } else if (const auto *IR = dyn_cast<ObjCIvarRefExpr>(IDExpr)) {
return IR->getDecl()->getType();
- } else if (const ObjCPropertyRefExpr *PR =
- dyn_cast<ObjCPropertyRefExpr>(IDExpr)) {
+ } else if (const auto *PR = dyn_cast<ObjCPropertyRefExpr>(IDExpr)) {
if (PR->isExplicitProperty())
return PR->getExplicitProperty()->getType();
- } else if (auto *PE = dyn_cast<PredefinedExpr>(IDExpr)) {
+ } else if (const auto *PE = dyn_cast<PredefinedExpr>(IDExpr)) {
return PE->getType();
}
@@ -8995,24 +8994,20 @@ static QualType getDecltypeForExpr(Sema &S, Expr *E) {
// access to a corresponding data member of the closure type that
// would have been declared if x were an odr-use of the denoted
// entity.
- using namespace sema;
- if (S.getCurLambda()) {
- if (isa<ParenExpr>(IDExpr)) {
- if (DeclRefExpr *DRE = dyn_cast<DeclRefExpr>(IDExpr->IgnoreParens())) {
- if (VarDecl *Var = dyn_cast<VarDecl>(DRE->getDecl())) {
- QualType T = S.getCapturedDeclRefType(Var, DRE->getLocation());
- if (!T.isNull())
- return S.Context.getLValueReferenceType(T);
- }
+ if (getCurLambda() && isa<ParenExpr>(IDExpr)) {
+ if (auto *DRE = dyn_cast<DeclRefExpr>(IDExpr->IgnoreParens())) {
+ if (auto *Var = dyn_cast<VarDecl>(DRE->getDecl())) {
+ QualType T = getCapturedDeclRefType(Var, DRE->getLocation());
+ if (!T.isNull())
+ return Context.getLValueReferenceType(T);
}
}
}
- return S.Context.getReferenceQualifiedType(E);
+ return Context.getReferenceQualifiedType(E);
}
-QualType Sema::BuildDecltypeType(Expr *E, SourceLocation Loc,
- bool AsUnevaluated) {
+QualType Sema::BuildDecltypeType(Expr *E, bool AsUnevaluated) {
assert(!E->hasPlaceholderType() && "unexpected placeholder");
if (AsUnevaluated && CodeSynthesisContexts.empty() &&
@@ -9023,8 +9018,7 @@ QualType Sema::BuildDecltypeType(Expr *E, SourceLocation Loc,
// used to build SFINAE gadgets.
Diag(E->getExprLoc(), diag::warn_side_effects_unevaluated_context);
}
-
- return Context.getDecltypeType(E, getDecltypeForExpr(*this, E));
+ return Context.getDecltypeType(E, getDecltypeForExpr(E));
}
QualType Sema::BuildUnaryTransformType(QualType BaseType,
diff --git a/clang/lib/Sema/TreeTransform.h b/clang/lib/Sema/TreeTransform.h
index c1e9890094fde..442b4819b808c 100644
--- a/clang/lib/Sema/TreeTransform.h
+++ b/clang/lib/Sema/TreeTransform.h
@@ -6586,7 +6586,7 @@ QualType TreeTransform<Derived>::TransformAutoType(TypeLocBuilder &TLB,
T->isDependentType() || T->isConstrained()) {
// FIXME: Maybe don't rebuild if all template arguments are the same.
llvm::SmallVector<TemplateArgument, 4> NewArgList;
- NewArgList.reserve(NewArgList.size());
+ NewArgList.reserve(NewTemplateArgs.size());
for (const auto &ArgLoc : NewTemplateArgs.arguments())
NewArgList.push_back(ArgLoc.getArgument());
Result = getDerived().RebuildAutoType(NewDeduced, T->getKeyword(), NewCD,
@@ -14501,10 +14501,10 @@ QualType TreeTransform<Derived>::RebuildUnresolvedUsingType(SourceLocation Loc,
return SemaRef.Context.getTypeDeclType(Ty);
}
-template<typename Derived>
+template <typename Derived>
QualType TreeTransform<Derived>::RebuildTypeOfExprType(Expr *E,
- SourceLocation Loc) {
- return SemaRef.BuildTypeofExprType(E, Loc);
+ SourceLocation) {
+ return SemaRef.BuildTypeofExprType(E);
}
template<typename Derived>
@@ -14512,10 +14512,9 @@ QualType TreeTransform<Derived>::RebuildTypeOfType(QualType Underlying) {
return SemaRef.Context.getTypeOfType(Underlying);
}
-template<typename Derived>
-QualType TreeTransform<Derived>::RebuildDecltypeType(Expr *E,
- SourceLocation Loc) {
- return SemaRef.BuildDecltypeType(E, Loc);
+template <typename Derived>
+QualType TreeTransform<Derived>::RebuildDecltypeType(Expr *E, SourceLocation) {
+ return SemaRef.BuildDecltypeType(E);
}
template<typename Derived>
diff --git a/clang/test/CXX/over/over.match/over.match.funcs/over.match.class.deduct/p2.cpp b/clang/test/CXX/over/over.match/over.match.funcs/over.match.class.deduct/p2.cpp
index cb9407b1db88b..594654730d071 100644
--- a/clang/test/CXX/over/over.match/over.match.funcs/over.match.class.deduct/p2.cpp
+++ b/clang/test/CXX/over/over.match/over.match.funcs/over.match.class.deduct/p2.cpp
@@ -36,7 +36,7 @@ namespace std {
namespace p0702r1 {
template<typename T> struct X { // expected-note {{candidate}}
- X(std::initializer_list<T>); // expected-note {{candidate template ignored: could not match 'initializer_list<type-parameter-0-0>' against 'p0702r1::Z'}}
+ X(std::initializer_list<T>); // expected-note {{candidate template ignored: could not match 'std::initializer_list<T>' against 'p0702r1::Z'}}
};
X xi = {0};
diff --git a/clang/test/CXX/stmt.stmt/stmt.iter/stmt.ranged/p1.cpp b/clang/test/CXX/stmt.stmt/stmt.iter/stmt.ranged/p1.cpp
index 0963dd23724a8..751ad58ad820b 100644
--- a/clang/test/CXX/stmt.stmt/stmt.iter/stmt.ranged/p1.cpp
+++ b/clang/test/CXX/stmt.stmt/stmt.iter/stmt.ranged/p1.cpp
@@ -321,14 +321,14 @@ namespace p0962r1 {
namespace NE {
struct E {
- void begin(); // expected-note {{member is not a candidate because range type 'p0962r1::NE::E' has no 'end' member}}
+ void begin(); // expected-note {{member is not a candidate because range type 'NE::E' has no 'end' member}}
};
int *end(E);
}
namespace NF {
struct F {
- void end(); // expected-note {{member is not a candidate because range type 'p0962r1::NF::F' has no 'begin' member}}
+ void end(); // expected-note {{member is not a candidate because range type 'NF::F' has no 'begin' member}}
};
int *begin(F);
}
@@ -336,9 +336,9 @@ namespace p0962r1 {
void use(NA::A a, NB::B b, NC::C c, ND::D d, NE::E e, NF::F f) {
for (auto x : a) {}
for (auto x : b) {}
- for (auto x : c) {} // expected-error {{invalid range expression of type 'p0962r1::NC::C'; no viable 'end' function available}}
- for (auto x : d) {} // expected-error {{invalid range expression of type 'p0962r1::ND::D'; no viable 'begin' function available}}
- for (auto x : e) {} // expected-error {{invalid range expression of type 'p0962r1::NE::E'; no viable 'begin' function available}}
- for (auto x : f) {} // expected-error {{invalid range expression of type 'p0962r1::NF::F'; no viable 'end' function available}}
+ for (auto x : c) {} // expected-error {{invalid range expression of type 'NC::C'; no viable 'end' function available}}
+ for (auto x : d) {} // expected-error {{invalid range expression of type 'ND::D'; no viable 'begin' function available}}
+ for (auto x : e) {} // expected-error {{invalid range expression of type 'NE::E'; no viable 'begin' function available}}
+ for (auto x : f) {} // expected-error {{invalid range expression of type 'NF::F'; no viable 'end' function available}}
}
}
diff --git a/clang/test/CXX/temp/temp.decls/temp.variadic/multi-level-substitution.cpp b/clang/test/CXX/temp/temp.decls/temp.variadic/multi-level-substitution.cpp
index 46fc91325880c..30e7c65dac91c 100644
--- a/clang/test/CXX/temp/temp.decls/temp.variadic/multi-level-substitution.cpp
+++ b/clang/test/CXX/temp/temp.decls/temp.variadic/multi-level-substitution.cpp
@@ -284,7 +284,7 @@ namespace PR13386 {
void g(U &&...u, T &&...t) {} // expected-note {{candidate}}
template<typename...U>
void h(tuple<T, U> &&...) {}
- // expected-note at -1 {{candidate template ignored: could not match 'tuple<type-parameter-0-0, type-parameter-0-0>' against 'int'}}
+ // expected-note at -1 {{candidate template ignored: could not match 'tuple<T, U>' against 'int'}}
// expected-note at -2 {{candidate template ignored: substitution failure: deduced incomplete pack <(no value)> for template parameter 'U'}}
template<typename...U>
diff --git a/clang/test/CXX/temp/temp.fct.spec/temp.deduct/temp.deduct.call/p1-0x.cpp b/clang/test/CXX/temp/temp.fct.spec/temp.deduct/temp.deduct.call/p1-0x.cpp
index 081bba2b8dffc..1da599ed3c27a 100644
--- a/clang/test/CXX/temp/temp.fct.spec/temp.deduct/temp.deduct.call/p1-0x.cpp
+++ b/clang/test/CXX/temp/temp.fct.spec/temp.deduct/temp.deduct.call/p1-0x.cpp
@@ -53,9 +53,8 @@ void test_simple_ref_deduction(int *ip, float *fp, double *dp) {
}
-// 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>...);
diff --git a/clang/test/CXX/temp/temp.fct.spec/temp.deduct/temp.deduct.call/p4.cpp b/clang/test/CXX/temp/temp.fct.spec/temp.deduct/temp.deduct.call/p4.cpp
index 357ea664037df..fe0af399f7b9c 100644
--- a/clang/test/CXX/temp/temp.fct.spec/temp.deduct/temp.deduct.call/p4.cpp
+++ b/clang/test/CXX/temp/temp.fct.spec/temp.deduct/temp.deduct.call/p4.cpp
@@ -18,6 +18,12 @@ namespace PR12132 {
void foo() {
fun(&A::x);
}
+ struct B { char* x; };
+ void bar() {
+ fun(&B::x);
+ // expected-error at -1 {{no matching function for call to 'fun'}}
+ // expected-note at -9 {{candidate template ignored: could not match 'const int' against 'char'}}
+ }
}
#if __cplusplus > 201402L
@@ -52,6 +58,4 @@ namespace noexcept_conversion {
int i1 = i(g1);
int i2 = i(g2);
}
-#else
-// expected-no-diagnostics
#endif
diff --git a/clang/test/Index/print-type.cpp b/clang/test/Index/print-type.cpp
index f52ee8092e8f3..458acc42ef3e0 100644
--- a/clang/test/Index/print-type.cpp
+++ b/clang/test/Index/print-type.cpp
@@ -199,7 +199,7 @@ inline namespace InlineNS {}
// CHECK: UnexposedExpr=templRefParam:71:40 [type=const Specialization<Specialization<bool> &>] [typekind=Record] const [templateargs/1= [type=Specialization<bool> &] [typekind=LValueReference]] [isPOD=1]
// CHECK: DeclRefExpr=templRefParam:71:40 [type=Specialization<Specialization<bool> &>] [typekind=Unexposed] [templateargs/1= [type=Specialization<bool> &] [typekind=LValueReference]] [canonicaltype=Specialization<Specialization<bool> &>] [canonicaltypekind=Record] [canonicaltemplateargs/1= [type=Specialization<bool> &] [typekind=LValueReference]] [isPOD=1]
// CHECK: TypeAliasDecl=baz:76:7 (Definition) [type=baz] [typekind=Typedef] [templateargs/1= [type=A<void>] [typekind=Unexposed]] [canonicaltype=A<void>] [canonicaltypekind=Record] [canonicaltemplateargs/1= [type=void] [typekind=Void]] [isPOD=0]
-// CHECK: VarDecl=autoTemplPointer:78:6 (Definition) [type=Specialization<Specialization<bool> &> *] [typekind=Auto] [canonicaltype=Specialization<Specialization<bool> &> *] [canonicaltypekind=Pointer] [isPOD=1] [pointeetype=Specialization<Specialization<bool> &>] [pointeekind=Record]
+// CHECK: VarDecl=autoTemplPointer:78:6 (Definition) [type=Specialization<Specialization<bool> &> *] [typekind=Auto] [canonicaltype=Specialization<Specialization<bool> &> *] [canonicaltypekind=Pointer] [isPOD=1] [pointeetype=Specialization<Specialization<bool> &>] [pointeekind=Auto]
// CHECK: CallExpr=Bar:17:3 [type=outer::inner::Bar] [typekind=Elaborated] [canonicaltype=outer::inner::Bar] [canonicaltypekind=Record] [args= [outer::Foo<bool> *] [Pointer]] [isPOD=0] [nbFields=3]
// CHECK: StructDecl=:84:3 (Definition) [type=X::(anonymous struct at {{.*}}print-type.cpp:84:3)] [typekind=Record] [isPOD=1] [nbFields=1] [isAnon=1]
// CHECK: ClassDecl=:85:3 (Definition) [type=X::(anonymous class at {{.*}}print-type.cpp:85:3)] [typekind=Record] [isPOD=1] [nbFields=1] [isAnon=1]
diff --git a/clang/test/SemaCXX/cxx1z-class-template-argument-deduction.cpp b/clang/test/SemaCXX/cxx1z-class-template-argument-deduction.cpp
index 84b3a542dcaad..5a49f28ef9a1d 100644
--- a/clang/test/SemaCXX/cxx1z-class-template-argument-deduction.cpp
+++ b/clang/test/SemaCXX/cxx1z-class-template-argument-deduction.cpp
@@ -569,6 +569,52 @@ namespace PR52139 {
virtual void f() = 0;
};
}
+
+namespace function_prototypes {
+ template<class T> using fptr1 = void (*) (T);
+ template<class T> using fptr2 = fptr1<fptr1<T>>;
+
+ template<class T> void foo0(fptr1<T>) {
+ static_assert(__is_same(T, const char*));
+ }
+ void bar0(const char *const volatile __restrict);
+ void t0() { foo0(&bar0); }
+
+ template<class T> void foo1(fptr1<const T *>) {
+ static_assert(__is_same(T, char));
+ }
+ void bar1(const char * __restrict);
+ void t1() { foo1(&bar1); }
+
+ template<class T> void foo2(fptr2<const T *>) {
+ static_assert(__is_same(T, char));
+ }
+ void bar2(fptr1<const char * __restrict>);
+ void t2() { foo2(&bar2); }
+
+ template<class T> void foo3(fptr1<const T *>) {}
+ void bar3(char * __restrict);
+ void t3() { foo3(&bar3); }
+ // expected-error at -1 {{no matching function for call to 'foo3'}}
+ // expected-note at -4 {{candidate template ignored: cannot deduce a type for 'T' that would make 'const T' equal 'char'}}
+
+ template<class T> void foo4(fptr2<const T *>) {}
+ void bar4(fptr1<char * __restrict>);
+ void t4() { foo4(&bar4); }
+ // expected-error at -1 {{no matching function for call to 'foo4'}}
+ // expected-note at -4 {{candidate template ignored: cannot deduce a type for 'T' that would make 'const T' equal 'char'}}
+
+ template<typename T> void foo5(T(T)) {}
+ const int bar5(int);
+ void t5() { foo5(bar5); }
+ // expected-error at -1 {{no matching function for call to 'foo5'}}
+ // expected-note at -4 {{candidate template ignored: deduced conflicting types for parameter 'T' ('const int' vs. 'int')}}
+
+ struct Foo6 {};
+ template<typename T> void foo6(void(*)(struct Foo6, T)) {}
+ void bar6(Foo6, int);
+ void t6() { foo6(bar6); }
+}
#else
// expected-no-diagnostics
diff --git a/clang/test/SemaCXX/cxx1z-decomposition.cpp b/clang/test/SemaCXX/cxx1z-decomposition.cpp
index f97c5b033e9c7..4c8c64177ed13 100644
--- a/clang/test/SemaCXX/cxx1z-decomposition.cpp
+++ b/clang/test/SemaCXX/cxx1z-decomposition.cpp
@@ -9,7 +9,7 @@ void num_elems() {
int a1[1], a2[2];
auto [] = a0; // expected-warning {{does not allow a decomposition group to be empty}}
- auto [v1] = a0; // expected-error {{type 'A0' decomposes into 0 elements, but 1 name was provided}}
+ auto [v1] = a0; // expected-error {{type 'struct A0' decomposes into 0 elements, but 1 name was provided}}
auto [] = a1; // expected-error {{type 'int[1]' decomposes into 1 element, but no names were provided}} expected-warning {{empty}}
auto [v2] = a1;
auto [v3, v4] = a1; // expected-error {{type 'int[1]' decomposes into 1 element, but 2 names were provided}}
@@ -70,7 +70,7 @@ void enclosing() {
void bitfield() {
struct { int a : 3, : 4, b : 5; } a;
auto &[x, y] = a;
- auto &[p, q, r] = a; // expected-error-re {{type '(unnamed struct at {{.*}})' decomposes into 2 elements, but 3 names were provided}}
+ auto &[p, q, r] = a; // expected-error-re {{type 'struct (unnamed struct at {{.*}})' decomposes into 2 elements, but 3 names were provided}}
}
void for_range() {
diff --git a/clang/test/SemaCXX/deduced-return-type-cxx14.cpp b/clang/test/SemaCXX/deduced-return-type-cxx14.cpp
index 030a329697efc..da2f5f54b2476 100644
--- a/clang/test/SemaCXX/deduced-return-type-cxx14.cpp
+++ b/clang/test/SemaCXX/deduced-return-type-cxx14.cpp
@@ -300,7 +300,7 @@ namespace Constexpr {
}
struct NonLiteral { ~NonLiteral(); } nl; // cxx14-note {{user-provided destructor}}
// cxx20_2b-note at -1 {{'NonLiteral' is not literal because its destructor is not constexpr}}
- constexpr auto f2(int n) { return nl; } // expected-error {{return type 'Constexpr::NonLiteral' is not a literal type}}
+ constexpr auto f2(int n) { return nl; } // expected-error {{return type 'struct NonLiteral' is not a literal type}}
}
// It's not really clear whether these are valid, but this matches g++.
diff --git a/clang/test/SemaCXX/friend.cpp b/clang/test/SemaCXX/friend.cpp
index 822b1de39a1e3..367d6a6c1807c 100644
--- a/clang/test/SemaCXX/friend.cpp
+++ b/clang/test/SemaCXX/friend.cpp
@@ -415,7 +415,7 @@ namespace PR33222 {
namespace qualified_friend_no_match {
void f(int); // expected-note {{type mismatch at 1st parameter}}
- template<typename T> void f(T*); // expected-note {{could not match 'type-parameter-0-0 *' against 'double'}}
+ template<typename T> void f(T*); // expected-note {{could not match 'T *' against 'double'}}
struct X {
friend void qualified_friend_no_match::f(double); // expected-error {{friend declaration of 'f' does not match any declaration in namespace 'qualified_friend_no_match'}}
friend void qualified_friend_no_match::g(); // expected-error {{friend declaration of 'g' does not match any declaration in namespace 'qualified_friend_no_match'}}
@@ -423,7 +423,7 @@ namespace qualified_friend_no_match {
struct Y {
void f(int); // expected-note {{type mismatch at 1st parameter}}
- template<typename T> void f(T*); // expected-note {{could not match 'type-parameter-0-0 *' against 'double'}}
+ template<typename T> void f(T*); // expected-note {{could not match 'T *' against 'double'}}
};
struct Z {
friend void Y::f(double); // expected-error {{friend declaration of 'f' does not match any declaration in 'qualified_friend_no_match::Y'}}
diff --git a/clang/test/SemaCXX/recovery-expr-type.cpp b/clang/test/SemaCXX/recovery-expr-type.cpp
index 2fdbd0d3b6c30..94b275c9a362f 100644
--- a/clang/test/SemaCXX/recovery-expr-type.cpp
+++ b/clang/test/SemaCXX/recovery-expr-type.cpp
@@ -133,7 +133,7 @@ struct S { // expected-note {{candidate}}
template <typename T> S(T t) -> S<void *>;
void baz() {
- bar(S(123)); // expected-error {{no matching conversion for functional-style cast from 'int' to 'test11::S<>'}}
+ bar(S(123)); // expected-error {{no matching conversion for functional-style cast from 'int' to 'S<void *>'}}
}
} // namespace test11
diff --git a/clang/test/SemaCXX/sizeless-1.cpp b/clang/test/SemaCXX/sizeless-1.cpp
index ee3ef51435d53..026c610a60e17 100644
--- a/clang/test/SemaCXX/sizeless-1.cpp
+++ b/clang/test/SemaCXX/sizeless-1.cpp
@@ -581,7 +581,7 @@ void cxx_only(int sel) {
auto auto_int8 = local_int8;
auto auto_int16 = local_int16;
#if __cplusplus >= 201703L
- auto [auto_int8_a] = local_int8; // expected-error {{cannot decompose non-class, non-array type '__SVInt8_t'}}
+ auto [auto_int8_a] = local_int8; // expected-error {{cannot decompose non-class, non-array type 'svint8_t' (aka '__SVInt8_t')}}
#endif
#endif
@@ -600,7 +600,7 @@ void cxx_only(int sel) {
auto fn1 = [&local_int8](svint8_t x) { local_int8 = x; };
auto fn2 = [&local_int8](svint8_t *ptr) { *ptr = local_int8; };
#if __cplusplus >= 201703L
- auto fn3 = [a(return_int8())] {}; // expected-error {{field has sizeless type '__SVInt8_t'}}
+ auto fn3 = [a(return_int8())] {}; // expected-error {{field has sizeless type 'svint8_t' (aka '__SVInt8_t')}}
#endif
auto fn4 = [local_int8](svint8_t *ptr) { *ptr = local_int8; }; // expected-error {{by-copy capture of variable 'local_int8' with sizeless type 'svint8_t'}}
diff --git a/clang/test/SemaCXX/sugared-auto.cpp b/clang/test/SemaCXX/sugared-auto.cpp
new file mode 100644
index 0000000000000..d63b0bccb2ed1
--- /dev/null
+++ b/clang/test/SemaCXX/sugared-auto.cpp
@@ -0,0 +1,43 @@
+// RUN: %clang_cc1 -fsyntax-only -verify %s -std=c++20
+
+enum class N {};
+
+using Animal = int;
+
+using AnimalPtr = Animal *;
+
+using Man = Animal;
+using Dog = Animal;
+
+namespace variable {
+
+auto x1 = Animal();
+N t1 = x1; // expected-error {{lvalue of type 'Animal' (aka 'int')}}
+
+auto x2 = AnimalPtr();
+N t2 = x2; // expected-error {{lvalue of type 'AnimalPtr' (aka 'int *')}}
+
+auto *x3 = AnimalPtr();
+N t3 = x3; // expected-error {{lvalue of type 'Animal *' (aka 'int *')}}
+
+// Each variable deduces separately.
+auto x4 = Man(), x5 = Dog();
+N t4 = x4; // expected-error {{lvalue of type 'Man' (aka 'int')}}
+N t5 = x5; // expected-error {{lvalue of type 'Dog' (aka 'int')}}
+
+} // namespace variable
+
+namespace function_basic {
+
+auto f1() { return Animal(); }
+auto x1 = f1();
+N t1 = x1; // expected-error {{lvalue of type 'Animal' (aka 'int')}}
+
+decltype(auto) f2() { return Animal(); }
+auto x2 = f2();
+N t2 = x2; // expected-error {{lvalue of type 'Animal' (aka 'int')}}
+
+auto x3 = [a = Animal()] { return a; }();
+N t3 = x3; // expected-error {{lvalue of type 'Animal' (aka 'int')}}
+
+} // namespace function_basic
diff --git a/clang/test/SemaTemplate/attributes.cpp b/clang/test/SemaTemplate/attributes.cpp
index b0bcca566dd9b..b34794968ae89 100644
--- a/clang/test/SemaTemplate/attributes.cpp
+++ b/clang/test/SemaTemplate/attributes.cpp
@@ -124,7 +124,8 @@ namespace preferred_name {
struct [[clang::preferred_name(iterator),
clang::preferred_name(const_iterator)]] Iter {};
};
- auto it = MemberTemplate<int>::Iter<const int>();
+ template<typename T> T desugar(T);
+ auto it = desugar(MemberTemplate<int>::Iter<const int>());
int n = it; // expected-error {{no viable conversion from 'preferred_name::MemberTemplate<int>::const_iterator' to 'int'}}
template<int A, int B, typename ...T> struct Foo;
diff --git a/clang/test/SemaTemplate/deduction.cpp b/clang/test/SemaTemplate/deduction.cpp
index 9c75595bc74a5..17ccc9c1dc458 100644
--- a/clang/test/SemaTemplate/deduction.cpp
+++ b/clang/test/SemaTemplate/deduction.cpp
@@ -152,6 +152,16 @@ namespace test3 {
};
}
+namespace test4 {
+
+template <class> struct a { using b = const float; };
+template <class c> using d = typename a<c>::b;
+
+template <class c> void e(d<c> *, c) {}
+template void e(const float *, int);
+
+} // namespace test4
+
// Verify that we can deduce enum-typed arguments correctly.
namespace test14 {
enum E { E0, E1 };
diff --git a/clang/test/SemaTemplate/friend.cpp b/clang/test/SemaTemplate/friend.cpp
index fc6cd42a3ba26..1427db093ec94 100644
--- a/clang/test/SemaTemplate/friend.cpp
+++ b/clang/test/SemaTemplate/friend.cpp
@@ -50,7 +50,7 @@ C<int> c;
namespace qualified_friend {
void f(int); // expected-note 2{{type mismatch at 1st parameter}}
- template<typename T> void f(T*); // expected-note 2{{could not match 'type-parameter-0-0 *' against 'double'}}
+ template<typename T> void f(T*); // expected-note 2{{could not match 'T *' against 'double'}}
template<typename T> void nondep();
template<typename> struct X1 {
@@ -66,7 +66,7 @@ namespace qualified_friend {
struct Y {
void f(int); // expected-note 2{{type mismatch at 1st parameter}}
- template<typename T> void f(T*); // expected-note 2{{could not match 'type-parameter-0-0 *' against 'double'}}
+ template<typename T> void f(T*); // expected-note 2{{could not match 'T *' against 'double'}}
template<typename T> void nondep();
};
diff --git a/clang/test/SemaTemplate/operator-template.cpp b/clang/test/SemaTemplate/operator-template.cpp
index e60216ff96319..cf604691b943c 100644
--- a/clang/test/SemaTemplate/operator-template.cpp
+++ b/clang/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); }
diff --git a/libcxx/test/std/utilities/any/any.nonmembers/any.cast/const_correctness.fail.cpp b/libcxx/test/std/utilities/any/any.nonmembers/any.cast/const_correctness.verify.cpp
similarity index 81%
rename from libcxx/test/std/utilities/any/any.nonmembers/any.cast/const_correctness.fail.cpp
rename to libcxx/test/std/utilities/any/any.nonmembers/any.cast/const_correctness.verify.cpp
index 234efc83423bb..a28e3fc9d1d78 100644
--- a/libcxx/test/std/utilities/any/any.nonmembers/any.cast/const_correctness.fail.cpp
+++ b/libcxx/test/std/utilities/any/any.nonmembers/any.cast/const_correctness.verify.cpp
@@ -18,6 +18,13 @@
// Try and cast away const.
+// This test only checks that we static_assert in any_cast when the
+// constraints are not respected, however Clang will sometimes emit
+// additional errors while trying to instantiate the rest of any_cast
+// following the static_assert. We ignore unexpected errors in
+// clang-verify to make the test more robust to changes in Clang.
+// ADDITIONAL_COMPILE_FLAGS: -Xclang -verify-ignore-unexpected=error
+
#include <any>
struct TestType {};
@@ -30,19 +37,15 @@ int main(int, char**)
any a;
- // expected-error at any:* {{drops 'const' qualifier}}
// expected-error-re at any:* {{static_assert failed{{.*}} "ValueType is required to be a const lvalue reference or a CopyConstructible type"}}
any_cast<TestType &>(static_cast<any const&>(a)); // expected-note {{requested here}}
- // expected-error at any:* {{cannot cast from lvalue of type 'const TestType' to rvalue reference type 'TestType &&'; types are not compatible}}
// expected-error-re at any:* {{static_assert failed{{.*}} "ValueType is required to be a const lvalue reference or a CopyConstructible type"}}
any_cast<TestType &&>(static_cast<any const&>(a)); // expected-note {{requested here}}
- // expected-error at any:* {{drops 'const' qualifier}}
// expected-error-re at any:* {{static_assert failed{{.*}} "ValueType is required to be a const lvalue reference or a CopyConstructible type"}}
any_cast<TestType2 &>(static_cast<any const&&>(a)); // expected-note {{requested here}}
- // expected-error at any:* {{cannot cast from lvalue of type 'const TestType2' to rvalue reference type 'TestType2 &&'; types are not compatible}}
// expected-error-re at any:* {{static_assert failed{{.*}} "ValueType is required to be a const lvalue reference or a CopyConstructible type"}}
any_cast<TestType2 &&>(static_cast<any const&&>(a)); // expected-note {{requested here}}
diff --git a/libcxx/test/std/utilities/any/any.nonmembers/any.cast/not_copy_constructible.fail.cpp b/libcxx/test/std/utilities/any/any.nonmembers/any.cast/not_copy_constructible.verify.cpp
similarity index 81%
rename from libcxx/test/std/utilities/any/any.nonmembers/any.cast/not_copy_constructible.fail.cpp
rename to libcxx/test/std/utilities/any/any.nonmembers/any.cast/not_copy_constructible.verify.cpp
index 44a67f7aa03dc..ec40eeeec11b4 100644
--- a/libcxx/test/std/utilities/any/any.nonmembers/any.cast/not_copy_constructible.fail.cpp
+++ b/libcxx/test/std/utilities/any/any.nonmembers/any.cast/not_copy_constructible.verify.cpp
@@ -24,6 +24,13 @@
// Test instantiating the any_cast with a non-copyable type.
+// This test only checks that we static_assert in any_cast when the
+// constraints are not respected, however Clang will sometimes emit
+// additional errors while trying to instantiate the rest of any_cast
+// following the static_assert. We ignore unexpected errors in
+// clang-verify to make the test more robust to changes in Clang.
+// ADDITIONAL_COMPILE_FLAGS: -Xclang -verify-ignore-unexpected=error
+
#include <any>
using std::any;
@@ -45,17 +52,14 @@ struct no_move {
int main(int, char**) {
any a;
// expected-error-re at any:* {{static_assert failed{{.*}} "ValueType is required to be an lvalue reference or a CopyConstructible type"}}
- // expected-error at any:* {{static_cast from 'no_copy' to 'no_copy' uses deleted function}}
any_cast<no_copy>(static_cast<any&>(a)); // expected-note {{requested here}}
// expected-error-re at any:* {{static_assert failed{{.*}} "ValueType is required to be a const lvalue reference or a CopyConstructible type"}}
- // expected-error at any:* {{static_cast from 'const no_copy' to 'no_copy' uses deleted function}}
any_cast<no_copy>(static_cast<any const&>(a)); // expected-note {{requested here}}
any_cast<no_copy>(static_cast<any &&>(a)); // OK
// expected-error-re at any:* {{static_assert failed{{.*}} "ValueType is required to be an rvalue reference or a CopyConstructible type"}}
- // expected-error at any:* {{static_cast from 'typename remove_reference<no_move &>::type' (aka 'no_move') to 'no_move' uses deleted function}}
any_cast<no_move>(static_cast<any &&>(a));
return 0;
diff --git a/lldb/test/Shell/SymbolFile/NativePDB/function-types-builtins.cpp b/lldb/test/Shell/SymbolFile/NativePDB/function-types-builtins.cpp
index 75f9a029d448c..69d8d17179fe9 100644
--- a/lldb/test/Shell/SymbolFile/NativePDB/function-types-builtins.cpp
+++ b/lldb/test/Shell/SymbolFile/NativePDB/function-types-builtins.cpp
@@ -118,7 +118,7 @@ auto aab = &unary<int(*)[5]>;
auto aac = &unary<int(&&)[5]>;
// CHECK: (void (*)(int (&&)[5])) aac = {{.*}}
auto aad = &unary<int(*const)[5]>;
-// CHECK: (void (*)(int (*)[5])) aad = {{.*}}
+// CHECK: (void (*)(int (*const)[5])) aad = {{.*}}
// same test cases with return values, note we can't overload on return type
More information about the libcxx-commits
mailing list