Revert "[clang] retain type sugar in auto / template argument deduction"

This reverts commit 4d8fff477e.
This commit is contained in:
Matheus Izvekov 2021-11-15 00:29:05 +01:00
parent d259594be9
commit 6438a52df1
No known key found for this signature in database
GPG Key ID: 5C771D2BB8AB9907
47 changed files with 852 additions and 833 deletions

View File

@ -134,9 +134,14 @@ 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(allOf(hasInitializer(CreatesOwner),
unless(IsOwnerType)))
.bind("bad_owner_creation_variable"))),
traverse(
TK_AsIs,
namedDecl(
varDecl(eachOf(allOf(hasInitializer(CreatesOwner),
unless(IsOwnerType)),
allOf(hasInitializer(ConsideredOwner),
hasType(autoType().bind("deduced_type")))))
.bind("bad_owner_creation_variable"))),
this);
// Match on all function calls that expect owners as arguments, but didn't
@ -319,6 +324,13 @@ 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;
}

View File

@ -20,11 +20,9 @@ void ProBoundsPointerArithmeticCheck::registerMatchers(MatchFinder *Finder) {
if (!getLangOpts().CPlusPlus)
return;
const auto AllPointerTypes =
anyOf(hasType(pointerType()),
hasType(autoType(
hasDeducedType(hasUnqualifiedDesugaredType(pointerType())))),
hasType(decltypeType(hasUnderlyingType(pointerType()))));
const auto AllPointerTypes = anyOf(
hasType(pointerType()), hasType(autoType(hasDeducedType(pointerType()))),
hasType(decltypeType(hasUnderlyingType(pointerType()))));
// Flag all operators +, -, +=, -=, ++, -- that result in a pointer
Finder->addMatcher(

View File

@ -125,22 +125,18 @@ 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(IsAutoDeducedToPointer(UnlessFunctionType)),
ExplicitSingleVarDecl(hasType(autoType(hasDeducedType(
pointerType(pointee(unless(functionType())))))),
"auto"),
this);
Finder->addMatcher(
ExplicitSingleVarDeclInTemplate(
allOf(hasType(IsAutoDeducedToPointer(
hasUnqualifiedType(qualType().bind("type")),
UnlessFunctionType)),
allOf(hasType(autoType(hasDeducedType(pointerType(
pointee(hasUnqualifiedType(qualType().bind("type")),
unless(functionType())))))),
anyOf(hasAncestor(
functionDecl(hasAnyTemplateArgument(IsBoundToType))),
hasAncestor(classTemplateSpecializationDecl(

View File

@ -374,7 +374,7 @@ public:
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);
Outer.add(DT->getDeducedType(), Flags | Rel::Underlying);
}
void VisitDeducedTemplateSpecializationType(
const DeducedTemplateSpecializationType *DTST) {

View File

@ -38,9 +38,10 @@ public:
// 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.
// Not setting PrintCanonicalTypes for "auto" allows
// SuppressDefaultTemplateArgs (set by default) to have an effect.
// 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.
StructuredBindingPolicy = TypeHintPolicy;
StructuredBindingPolicy.PrintCanonicalTypes = true;
}

View File

@ -43,7 +43,7 @@ TEST(GetDeducedType, KwAutoKwDecltypeExpansion) {
namespace ns1 { struct S {}; }
^auto v = ns1::S{};
)cpp",
"ns1::S",
"struct ns1::S",
},
{
R"cpp( // decltype on struct
@ -63,7 +63,7 @@ TEST(GetDeducedType, KwAutoKwDecltypeExpansion) {
ns1::S& j = i;
^decltype(auto) k = j;
)cpp",
"ns1::S &",
"struct 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",
"Foo<class X>",
"class Foo<class X>",
},
{
R"cpp( // auto on initializer list.
@ -177,7 +177,8 @@ TEST(GetDeducedType, KwAutoKwDecltypeExpansion) {
using Bar = Foo;
^auto x = Bar();
)cpp",
"Bar",
// FIXME: it'd be nice if this resolved to the alias instead
"struct Foo",
},
};
for (Test T : Tests) {

View File

@ -461,7 +461,7 @@ class Foo {})cpp";
[](HoverInfo &HI) {
HI.Name = "auto";
HI.Kind = index::SymbolKind::TypeAlias;
HI.Definition = "Foo<int>";
HI.Definition = "class 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 = "Foo<int>";
HI.Definition = "class Foo<int>";
}},
// macro
@ -648,7 +648,7 @@ class Foo {})cpp";
[](HoverInfo &HI) {
HI.Name = "auto";
HI.Kind = index::SymbolKind::TypeAlias;
HI.Definition = "Foo<X>";
HI.Definition = "class 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_type";
HI.Definition = "int";
}},
{
R"cpp(// auto on alias
@ -2035,7 +2035,7 @@ TEST(Hover, All) {
[](HoverInfo &HI) {
HI.Name = "auto";
HI.Kind = index::SymbolKind::TypeAlias;
HI.Definition = "cls_type";
HI.Definition = "struct cls";
HI.Documentation = "auto on alias";
}},
{
@ -2047,7 +2047,7 @@ TEST(Hover, All) {
[](HoverInfo &HI) {
HI.Name = "auto";
HI.Kind = index::SymbolKind::TypeAlias;
HI.Definition = "templ<int>";
HI.Definition = "struct templ<int>";
HI.Documentation = "auto on alias";
}},
{

View File

@ -466,14 +466,7 @@ TEST(TypeHints, NoQualifiers) {
}
}
)cpp",
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"});
ExpectedHint{": S1", "x"}, ExpectedHint{": Inner<int>", "y"});
}
TEST(TypeHints, Lambda) {

View File

@ -57,7 +57,7 @@ TEST_F(ExpandAutoTypeTest, Test) {
EXPECT_UNAVAILABLE("au^to x = []{};");
// inline namespaces
EXPECT_EQ(apply("au^to x = inl_ns::Visible();"),
"inl_ns::Visible x = inl_ns::Visible();");
"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,9 +67,8 @@ 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() { ns::Class::Nested * x = new ns::Class::Nested{}; }");
EXPECT_EQ(apply("void ns::Func() { au^to x = new ns::Class::Nested{}; }"),
"void ns::Func() { Class::Nested * x = new ns::Class::Nested{}; }");
EXPECT_UNAVAILABLE("dec^ltype(au^to) x = 10;");
// expanding types in structured bindings is syntactically invalid.

View File

@ -91,9 +91,13 @@ 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(); // Ok, since type deduction does not eliminate the owner wrapper
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
const auto owned_int8 = returns_owner2(); // 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
gsl::owner<int *> owned_int9 = returns_owner1(); // Ok
int *unowned_int3 = returns_owner1(); // Bad
@ -281,12 +285,15 @@ 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(); // Ok, deduces Owner1 to owner<ArbitraryClass *> const
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
auto Owner2 = C2.buggy_but_returns_owner(); //Ok, deduces Owner2 to owner<ArbitraryClass *>
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
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 *'
Owner2 = &A; // Ok, since type deduction did NOT result in owner<int*>
gsl::owner<ArbitraryClass *> Owner3 = C1.buggy_but_returns_owner(); // Ok, still an owner
Owner3 = &A; // Bad, since assignment of non-owner to owner

View File

@ -1531,12 +1531,6 @@ private:
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

View File

@ -4944,29 +4944,29 @@ public:
/// 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, QualType Canon)
: Type(TC, Canon,
TypeDependence ExtraDependence)
: Type(TC,
// FIXME: Retain the sugared deduced type?
DeducedAsType.isNull() ? QualType(this, 0)
: DeducedAsType.getCanonicalType(),
ExtraDependence | (DeducedAsType.isNull()
? TypeDependence::None
: DeducedAsType->getDependence() &
~TypeDependence::VariablyModified)),
DeducedAsType(DeducedAsType) {}
~TypeDependence::VariablyModified)) {}
public:
bool isSugared() const { return !DeducedAsType.isNull(); }
QualType desugar() const {
return isSugared() ? DeducedAsType : QualType(this, 0);
}
bool isSugared() const { return !isCanonicalUnqualified(); }
QualType desugar() const { return getCanonicalTypeInternal(); }
/// Get the type deduced for this placeholder type, or null if it
/// has not been deduced.
QualType getDeducedType() const { return DeducedAsType; }
/// 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 isDeduced() const {
return !DeducedAsType.isNull() || isDependentType();
return !isCanonicalUnqualified() || 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, QualType Canon, ConceptDecl *CD,
TypeDependence ExtraDependence, ConceptDecl *CD,
ArrayRef<TemplateArgument> TypeConstraintArgs);
const TemplateArgument *getArgBuffer() const {
@ -5057,9 +5057,7 @@ class DeducedTemplateSpecializationType : public DeducedType,
toTypeDependence(Template.getDependence()) |
(IsDeducedAsDependent
? TypeDependence::DependentInstantiation
: TypeDependence::None),
DeducedAsType.isNull() ? QualType(this, 0)
: DeducedAsType.getCanonicalType()),
: TypeDependence::None)),
Template(Template) {}
public:

View File

@ -1027,29 +1027,31 @@ private:
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)) {
QualType DT = S->getDeducedType();
return !DT.isNull() ? matchesSpecialized(*DT, Finder, Builder) : false;
EffectiveType = S->getDeducedType().getTypePtrOrNull();
if (!EffectiveType)
return false;
}
// First, for any types that have a declaration, extract the declaration and
// match on it.
if (const auto *S = dyn_cast<TagType>(&Node)) {
if (const auto *S = dyn_cast<TagType>(EffectiveType)) {
return matchesDecl(S->getDecl(), Finder, Builder);
}
if (const auto *S = dyn_cast<InjectedClassNameType>(&Node)) {
if (const auto *S = dyn_cast<InjectedClassNameType>(EffectiveType)) {
return matchesDecl(S->getDecl(), Finder, Builder);
}
if (const auto *S = dyn_cast<TemplateTypeParmType>(&Node)) {
if (const auto *S = dyn_cast<TemplateTypeParmType>(EffectiveType)) {
return matchesDecl(S->getDecl(), Finder, Builder);
}
if (const auto *S = dyn_cast<TypedefType>(&Node)) {
if (const auto *S = dyn_cast<TypedefType>(EffectiveType)) {
return matchesDecl(S->getDecl(), Finder, Builder);
}
if (const auto *S = dyn_cast<UnresolvedUsingType>(&Node)) {
if (const auto *S = dyn_cast<UnresolvedUsingType>(EffectiveType)) {
return matchesDecl(S->getDecl(), Finder, Builder);
}
if (const auto *S = dyn_cast<ObjCObjectType>(&Node)) {
if (const auto *S = dyn_cast<ObjCObjectType>(EffectiveType)) {
return matchesDecl(S->getInterface(), Finder, Builder);
}
@ -1061,14 +1063,14 @@ private:
// 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>(&Node)) {
if (const auto *S = dyn_cast<SubstTemplateTypeParmType>(EffectiveType)) {
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>(&Node)) {
if (const auto *S = dyn_cast<TemplateSpecializationType>(EffectiveType)) {
if (!S->isTypeAlias() && S->isSugared()) {
// If the template is non-dependent, we want to match the instantiated
// tag type.
@ -1087,7 +1089,7 @@ private:
// 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>(&Node)) {
if (const auto *S = dyn_cast<ElaboratedType>(EffectiveType)) {
return matchesSpecialized(S->desugar(), Finder, Builder);
}
return false;

View File

@ -2359,13 +2359,11 @@ public:
const CXXScopeSpec &SS, QualType T,
TagDecl *OwnedTagDecl = nullptr);
// Returns the underlying type of a decltype with the given expression.
QualType getDecltypeForExpr(Expr *E);
QualType BuildTypeofExprType(Expr *E);
QualType BuildTypeofExprType(Expr *E, SourceLocation Loc);
/// 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, bool AsUnevaluated = true);
QualType BuildDecltypeType(Expr *E, SourceLocation Loc,
bool AsUnevaluated = true);
QualType BuildUnaryTransformType(QualType BaseType,
UnaryTransformType::UTTKind UKind,
SourceLocation Loc);
@ -3504,7 +3502,7 @@ public:
bool IsFunctionConversion(QualType FromType, QualType ToType,
QualType &ResultTy);
bool DiagnoseMultipleUserDefinedConversion(Expr *From, QualType ToType);
bool isSameOrCompatibleFunctionType(QualType Param, QualType Arg);
bool isSameOrCompatibleFunctionType(CanQualType Param, CanQualType Arg);
bool CanPerformAggregateInitializationForOverloadResolution(
const InitializedEntity &Entity, InitListExpr *From);
@ -8567,14 +8565,6 @@ public:
/// 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);

View File

@ -4815,23 +4815,6 @@ 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() &&
@ -4844,7 +4827,10 @@ QualType ASTContext::getCanonicalTemplateSpecializationType(
// Build the canonical template specialization type.
TemplateName CanonTemplate = getCanonicalTemplateName(Template);
SmallVector<TemplateArgument, 4> CanonArgs;
::getCanonicalTemplateArguments(*this, Args, CanonArgs);
unsigned NumArgs = Args.size();
CanonArgs.reserve(NumArgs);
for (const TemplateArgument &Arg : Args)
CanonArgs.push_back(getCanonicalTemplateArgument(Arg));
// Determine whether this canonical template specialization type already
// exists.
@ -4859,7 +4845,7 @@ QualType ASTContext::getCanonicalTemplateSpecializationType(
if (!Spec) {
// Allocate a new canonical template specialization type.
void *Mem = Allocate((sizeof(TemplateSpecializationType) +
sizeof(TemplateArgument) * CanonArgs.size()),
sizeof(TemplateArgument) * NumArgs),
TypeAlignment);
Spec = new (Mem) TemplateSpecializationType(CanonTemplate,
CanonArgs,
@ -5001,9 +4987,14 @@ ASTContext::getDependentTemplateSpecializationType(
ElaboratedTypeKeyword CanonKeyword = Keyword;
if (Keyword == ETK_None) CanonKeyword = ETK_Typename;
SmallVector<TemplateArgument, 16> CanonArgs;
bool AnyNonCanonArgs =
::getCanonicalTemplateArguments(*this, Args, CanonArgs);
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;
}
QualType Canon;
if (AnyNonCanonArgs || CanonNNS != NNS || CanonKeyword != Keyword) {
@ -5016,7 +5007,7 @@ ASTContext::getDependentTemplateSpecializationType(
}
void *Mem = Allocate((sizeof(DependentTemplateSpecializationType) +
sizeof(TemplateArgument) * Args.size()),
sizeof(TemplateArgument) * NumArgs),
TypeAlignment);
T = new (Mem) DependentTemplateSpecializationType(Keyword, NNS,
Name, Args, Canon);
@ -5598,10 +5589,15 @@ QualType ASTContext::getUnaryTransformType(QualType BaseType,
return QualType(ut, 0);
}
QualType ASTContext::getAutoTypeInternal(
QualType DeducedType, AutoTypeKeyword Keyword, bool IsDependent,
bool IsPack, ConceptDecl *TypeConstraintConcept,
ArrayRef<TemplateArgument> TypeConstraintArgs, bool IsCanon) const {
/// 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");
if (DeducedType.isNull() && Keyword == AutoTypeKeyword::Auto &&
!TypeConstraintConcept && !IsDependent)
return getAutoDeductType();
@ -5614,52 +5610,21 @@ QualType ASTContext::getAutoTypeInternal(
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),
Canon, TypeConstraintConcept, TypeConstraintArgs);
TypeConstraintConcept, TypeConstraintArgs);
Types.push_back(AT);
AutoTypes.InsertNode(AT, InsertPos);
if (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.
@ -5677,7 +5642,8 @@ QualType ASTContext::getDeducedTemplateSpecializationType(
auto *DTST = new (*this, TypeAlignment)
DeducedTemplateSpecializationType(Template, DeducedType, IsDependent);
Types.push_back(DTST);
DeducedTemplateSpecializationTypes.InsertNode(DTST, InsertPos);
if (InsertPos)
DeducedTemplateSpecializationTypes.InsertNode(DTST, InsertPos);
return QualType(DTST, 0);
}
@ -5714,7 +5680,7 @@ QualType ASTContext::getAutoDeductType() const {
if (AutoDeductTy.isNull())
AutoDeductTy = QualType(new (*this, TypeAlignment)
AutoType(QualType(), AutoTypeKeyword::Auto,
TypeDependence::None, QualType(),
TypeDependence::None,
/*concept*/ nullptr, /*args*/ {}),
0);
return AutoDeductTy;

View File

@ -3172,14 +3172,13 @@ static bool isAncestorDeclContextOf(const DeclContext *DC, const Decl *D) {
bool ASTNodeImporter::hasAutoReturnTypeDeclaredInside(FunctionDecl *D) {
QualType FromTy = D->getType();
const auto *FromFPT = FromTy->getAs<FunctionProtoType>();
const FunctionProtoType *FromFPT = FromTy->getAs<FunctionProtoType>();
assert(FromFPT && "Must be called on FunctionProtoType");
if (const AutoType *AutoT =
FromFPT->getReturnType()->getContainedAutoType()) {
if (AutoType *AutoT = FromFPT->getReturnType()->getContainedAutoType()) {
QualType DeducedT = AutoT->getDeducedType();
if (const auto *RecordT =
!DeducedT.isNull() ? DeducedT->getAs<RecordType>() : nullptr) {
const RecordDecl *RD = RecordT->getDecl();
if (const RecordType *RecordT =
DeducedT.isNull() ? nullptr : dyn_cast<RecordType>(DeducedT)) {
RecordDecl *RD = RecordT->getDecl();
assert(RD);
if (isAncestorDeclContextOf(D, RD)) {
assert(RD->getLexicalDeclContext() == RD->getDeclContext());
@ -3187,8 +3186,9 @@ bool ASTNodeImporter::hasAutoReturnTypeDeclaredInside(FunctionDecl *D) {
}
}
}
if (const auto *TypedefT = FromFPT->getReturnType()->getAs<TypedefType>()) {
const TypedefNameDecl *TD = TypedefT->getDecl();
if (const TypedefType *TypedefT =
dyn_cast<TypedefType>(FromFPT->getReturnType())) {
TypedefNameDecl *TD = TypedefT->getDecl();
assert(TD);
if (isAncestorDeclContextOf(D, TD)) {
assert(TD->getLexicalDeclContext() == TD->getDeclContext());

View File

@ -4400,10 +4400,10 @@ void clang::FixedPointValueToString(SmallVectorImpl<char> &Str,
}
AutoType::AutoType(QualType DeducedAsType, AutoTypeKeyword Keyword,
TypeDependence ExtraDependence, QualType Canon,
TypeDependence ExtraDependence,
ConceptDecl *TypeConstraintConcept,
ArrayRef<TemplateArgument> TypeConstraintArgs)
: DeducedType(Auto, DeducedAsType, ExtraDependence, Canon) {
: DeducedType(Auto, DeducedAsType, ExtraDependence) {
AutoTypeBits.Keyword = (unsigned)Keyword;
AutoTypeBits.NumArgs = TypeConstraintArgs.size();
this->TypeConstraintConcept = TypeConstraintConcept;

View File

@ -865,7 +865,7 @@ bool Sema::ActOnCXXNestedNameSpecifierDecltype(CXXScopeSpec &SS,
assert(DS.getTypeSpecType() == DeclSpec::TST_decltype);
QualType T = BuildDecltypeType(DS.getRepAsExpr());
QualType T = BuildDecltypeType(DS.getRepAsExpr(), DS.getTypeSpecTypeLoc());
if (T.isNull())
return true;

View File

@ -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()) {
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));
}
New->setType(
SubstAutoType(New->getType(),
OldAT->isDependentType() ? Context.DependentTy
: OldAT->getDeducedType()));
NewQType = Context.getCanonicalType(
SubstAutoType(NewQType,
OldAT->isDependentType() ? Context.DependentTy
: OldAT->getDeducedType()));
}
}
@ -9258,7 +9258,8 @@ 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 = SubstAutoTypeDependent(FPT->getReturnType());
QualType Result =
SubstAutoType(FPT->getReturnType(), Context.DependentTy);
NewFD->setType(Context.getFunctionType(Result, FPT->getParamTypes(),
FPT->getExtProtoInfo()));
}
@ -12349,7 +12350,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 provided initializer fails to initialize the var decl,
// If the provied initializer fails to initialize the var decl,
// we attach a recovery expr for better recovery.
auto RecoveryExpr =
CreateRecoveryExpr(Init->getBeginLoc(), Init->getEndLoc(), Args);

View File

@ -4219,7 +4219,7 @@ Sema::BuildMemInitializer(Decl *ConstructorD,
if (BaseType.isNull())
return true;
} else if (DS.getTypeSpecType() == TST_decltype) {
BaseType = BuildDecltypeType(DS.getRepAsExpr());
BaseType = BuildDecltypeType(DS.getRepAsExpr(), DS.getTypeSpecTypeLoc());
} else if (DS.getTypeSpecType() == TST_decltype_auto) {
Diag(DS.getTypeSpecTypeLoc(), diag::err_decltype_auto_invalid);
return true;

View File

@ -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());
QualType T = BuildDecltypeType(DS.getRepAsExpr(), DS.getTypeSpecTypeLoc());
// 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,7 +7761,8 @@ ExprResult Sema::ActOnPseudoDestructorExpr(Scope *S, Expr *Base,
return true;
}
QualType T = BuildDecltypeType(DS.getRepAsExpr(), /*AsUnevaluated=*/false);
QualType T = BuildDecltypeType(DS.getRepAsExpr(), DS.getTypeSpecTypeLoc(),
false);
TypeLocBuilder TLB;
DecltypeTypeLoc DecltypeTL = TLB.push<DecltypeTypeLoc>(T);

View File

@ -9972,7 +9972,7 @@ QualType Sema::DeduceTemplateSpecializationFromInitializer(
auto TemplateName = DeducedTST->getTemplateName();
if (TemplateName.isDependent())
return SubstAutoTypeDependent(TSInfo->getType());
return SubstAutoType(TSInfo->getType(), Context.DependentTy);
// 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 SubstAutoTypeDependent(TSInfo->getType());
return SubstAutoType(TSInfo->getType(), Context.DependentTy);
}
// FIXME: Perform "exact type" matching first, per CWG discussion?

View File

@ -373,7 +373,7 @@ CXXMethodDecl *Sema::startLambdaDefinition(CXXRecordDecl *Class,
const FunctionProtoType *FPT = MethodType->castAs<FunctionProtoType>();
QualType Result = FPT->getReturnType();
if (Result->isUndeducedType()) {
Result = SubstAutoTypeDependent(Result);
Result = SubstAutoType(Result, Context.DependentTy);
MethodType = Context.getFunctionType(Result, FPT->getParamTypes(),
FPT->getExtProtoInfo());
}

View File

@ -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(SubstAutoTypeDependent(LoopVar->getType()));
LoopVar->setType(SubstAutoType(LoopVar->getType(), Context.DependentTy));
}
} else if (!BeginDeclStmt.get()) {
SourceLocation RangeLoc = RangeVar->getLocation();

View File

@ -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(),
[&](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()), 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 = SubstAutoTypeSourceInfoDependent(TSI);
TSI = SubstAutoTypeSourceInfo(TSI, Context.DependentTy);
}
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 = SubstAutoTypeSourceInfoDependent(NewTSI);
NewTSI = SubstAutoTypeSourceInfo(NewTSI, Context.DependentTy);
}
if (NewTSI != NTTP->getTypeSourceInfo()) {

File diff suppressed because it is too large Load Diff

View File

@ -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);
Result = S.BuildTypeofExprType(E, DS.getTypeSpecTypeLoc());
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);
Result = S.BuildDecltypeType(E, DS.getTypeSpecTypeLoc());
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) {
QualType Sema::BuildTypeofExprType(Expr *E, SourceLocation Loc) {
assert(!E->hasPlaceholderType() && "unexpected placeholder");
if (!getLangOpts().CPlusPlus && E->refersToBitField())
@ -8942,9 +8942,9 @@ QualType Sema::BuildTypeofExprType(Expr *E) {
/// 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.
QualType Sema::getDecltypeForExpr(Expr *E) {
static QualType getDecltypeForExpr(Sema &S, Expr *E) {
if (E->isTypeDependent())
return Context.DependentTy;
return S.Context.DependentTy;
Expr *IDExpr = E;
if (auto *ImplCastExpr = dyn_cast<ImplicitCastExpr>(E))
@ -8961,7 +8961,7 @@ QualType Sema::getDecltypeForExpr(Expr *E) {
// parameter object. This rule makes no difference before C++20 so we apply
// it unconditionally.
if (const auto *SNTTPE = dyn_cast<SubstNonTypeTemplateParmExpr>(IDExpr))
return SNTTPE->getParameterType(Context);
return SNTTPE->getParameterType(S.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,21 +8969,22 @@ QualType Sema::getDecltypeForExpr(Expr *E) {
// functions, the program is ill-formed;
//
// We apply the same rules for Objective-C ivar and property references.
if (const auto *DRE = dyn_cast<DeclRefExpr>(IDExpr)) {
if (const DeclRefExpr *DRE = dyn_cast<DeclRefExpr>(IDExpr)) {
const ValueDecl *VD = DRE->getDecl();
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 (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())
if (isa<FieldDecl>(VD) || isa<VarDecl>(VD))
return VD->getType();
} else if (const auto *IR = dyn_cast<ObjCIvarRefExpr>(IDExpr)) {
} else if (const ObjCIvarRefExpr *IR = dyn_cast<ObjCIvarRefExpr>(IDExpr)) {
return IR->getDecl()->getType();
} else if (const auto *PR = dyn_cast<ObjCPropertyRefExpr>(IDExpr)) {
} else if (const ObjCPropertyRefExpr *PR =
dyn_cast<ObjCPropertyRefExpr>(IDExpr)) {
if (PR->isExplicitProperty())
return PR->getExplicitProperty()->getType();
} else if (const auto *PE = dyn_cast<PredefinedExpr>(IDExpr)) {
} else if (auto *PE = dyn_cast<PredefinedExpr>(IDExpr)) {
return PE->getType();
}
@ -8994,20 +8995,24 @@ QualType Sema::getDecltypeForExpr(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.
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);
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);
}
}
}
}
return Context.getReferenceQualifiedType(E);
return S.Context.getReferenceQualifiedType(E);
}
QualType Sema::BuildDecltypeType(Expr *E, bool AsUnevaluated) {
QualType Sema::BuildDecltypeType(Expr *E, SourceLocation Loc,
bool AsUnevaluated) {
assert(!E->hasPlaceholderType() && "unexpected placeholder");
if (AsUnevaluated && CodeSynthesisContexts.empty() &&
@ -9018,7 +9023,8 @@ QualType Sema::BuildDecltypeType(Expr *E, bool AsUnevaluated) {
// used to build SFINAE gadgets.
Diag(E->getExprLoc(), diag::warn_side_effects_unevaluated_context);
}
return Context.getDecltypeType(E, getDecltypeForExpr(E));
return Context.getDecltypeType(E, getDecltypeForExpr(*this, E));
}
QualType Sema::BuildUnaryTransformType(QualType BaseType,

View File

@ -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(NewTemplateArgs.size());
NewArgList.reserve(NewArgList.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) {
return SemaRef.BuildTypeofExprType(E);
SourceLocation Loc) {
return SemaRef.BuildTypeofExprType(E, Loc);
}
template<typename Derived>
@ -14512,9 +14512,10 @@ QualType TreeTransform<Derived>::RebuildTypeOfType(QualType Underlying) {
return SemaRef.Context.getTypeOfType(Underlying);
}
template <typename Derived>
QualType TreeTransform<Derived>::RebuildDecltypeType(Expr *E, SourceLocation) {
return SemaRef.BuildDecltypeType(E);
template<typename Derived>
QualType TreeTransform<Derived>::RebuildDecltypeType(Expr *E,
SourceLocation Loc) {
return SemaRef.BuildDecltypeType(E, Loc);
}
template<typename Derived>

View File

@ -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 'std::initializer_list<T>' against 'p0702r1::Z'}}
X(std::initializer_list<T>); // expected-note {{candidate template ignored: could not match 'initializer_list<type-parameter-0-0>' against 'p0702r1::Z'}}
};
X xi = {0};

View File

@ -321,14 +321,14 @@ namespace p0962r1 {
namespace NE {
struct E {
void begin(); // expected-note {{member is not a candidate because range type 'NE::E' has no 'end' member}}
void begin(); // expected-note {{member is not a candidate because range type 'p0962r1::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 'NF::F' has no 'begin' member}}
void end(); // expected-note {{member is not a candidate because range type 'p0962r1::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 '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}}
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}}
}
}

View File

@ -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@-1 {{candidate template ignored: could not match 'tuple<T, U>' against 'int'}}
// expected-note@-1 {{candidate template ignored: could not match 'tuple<type-parameter-0-0, type-parameter-0-0>' against 'int'}}
// expected-note@-2 {{candidate template ignored: substitution failure: deduced incomplete pack <(no value)> for template parameter 'U'}}
template<typename...U>

View File

@ -53,8 +53,9 @@ 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<Args1, Args2>' against 'int'}}
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'}}
template<typename ...Args1, typename ...Args2>
typename get_nth_type<1, Args1...>::type second_arg_pair(pair<Args1, Args2>...);

View File

@ -18,12 +18,6 @@ namespace PR12132 {
void foo() {
fun(&A::x);
}
struct B { char* x; };
void bar() {
fun(&B::x);
// expected-error@-1 {{no matching function for call to 'fun'}}
// expected-note@-9 {{candidate template ignored: could not match 'const int' against 'char'}}
}
}
#if __cplusplus > 201402L
@ -58,4 +52,6 @@ namespace noexcept_conversion {
int i1 = i(g1);
int i2 = i(g2);
}
#else
// expected-no-diagnostics
#endif

View File

@ -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=Auto]
// 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: 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]

View File

@ -569,52 +569,6 @@ 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@-1 {{no matching function for call to 'foo3'}}
// expected-note@-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@-1 {{no matching function for call to 'foo4'}}
// expected-note@-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@-1 {{no matching function for call to 'foo5'}}
// expected-note@-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

View File

@ -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 'struct A0' decomposes into 0 elements, but 1 name was provided}}
auto [v1] = a0; // expected-error {{type '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 'struct (unnamed struct at {{.*}})' decomposes into 2 elements, but 3 names were provided}}
auto &[p, q, r] = a; // expected-error-re {{type '(unnamed struct at {{.*}})' decomposes into 2 elements, but 3 names were provided}}
}
void for_range() {

View File

@ -300,7 +300,7 @@ namespace Constexpr {
}
struct NonLiteral { ~NonLiteral(); } nl; // cxx14-note {{user-provided destructor}}
// cxx20_2b-note@-1 {{'NonLiteral' is not literal because its destructor is not constexpr}}
constexpr auto f2(int n) { return nl; } // expected-error {{return type 'struct NonLiteral' is not a literal type}}
constexpr auto f2(int n) { return nl; } // expected-error {{return type 'Constexpr::NonLiteral' is not a literal type}}
}
// It's not really clear whether these are valid, but this matches g++.

View File

@ -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 'T *' against 'double'}}
template<typename T> void f(T*); // expected-note {{could not match 'type-parameter-0-0 *' 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 'T *' against 'double'}}
template<typename T> void f(T*); // expected-note {{could not match 'type-parameter-0-0 *' 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'}}

View File

@ -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 'S<void *>'}}
bar(S(123)); // expected-error {{no matching conversion for functional-style cast from 'int' to 'test11::S<>'}}
}
} // namespace test11

View File

@ -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' (aka '__SVInt8_t')}}
auto [auto_int8_a] = local_int8; // expected-error {{cannot decompose non-class, non-array type '__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' (aka '__SVInt8_t')}}
auto fn3 = [a(return_int8())] {}; // expected-error {{field has sizeless type '__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'}}

View File

@ -1,43 +0,0 @@
// 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

View File

@ -124,8 +124,7 @@ namespace preferred_name {
struct [[clang::preferred_name(iterator),
clang::preferred_name(const_iterator)]] Iter {};
};
template<typename T> T desugar(T);
auto it = desugar(MemberTemplate<int>::Iter<const int>());
auto it = 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;

View File

@ -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 'T *' against 'double'}}
template<typename T> void f(T*); // expected-note 2{{could not match 'type-parameter-0-0 *' 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 'T *' against 'double'}}
template<typename T> void f(T*); // expected-note 2{{could not match 'type-parameter-0-0 *' against 'double'}}
template<typename T> void nondep();
};

View File

@ -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<X>' against 'B<int> *'}}
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> *'}}
int a(A<int> x) { return operator==(x,1); }

View File

@ -18,13 +18,6 @@
// 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 {};
@ -37,15 +30,19 @@ int main(int, char**)
any a;
// expected-error@any:* {{drops 'const' qualifier}}
// expected-error-re@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@any:* {{cannot cast from lvalue of type 'const TestType' to rvalue reference type 'TestType &&'; types are not compatible}}
// expected-error-re@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@any:* {{drops 'const' qualifier}}
// expected-error-re@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@any:* {{cannot cast from lvalue of type 'const TestType2' to rvalue reference type 'TestType2 &&'; types are not compatible}}
// expected-error-re@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}}

View File

@ -24,13 +24,6 @@
// 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;
@ -52,14 +45,17 @@ struct no_move {
int main(int, char**) {
any a;
// expected-error-re@any:* {{static_assert failed{{.*}} "ValueType is required to be an lvalue reference or a CopyConstructible type"}}
// expected-error@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@any:* {{static_assert failed{{.*}} "ValueType is required to be a const lvalue reference or a CopyConstructible type"}}
// expected-error@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@any:* {{static_assert failed{{.*}} "ValueType is required to be an rvalue reference or a CopyConstructible type"}}
// expected-error@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;

View File

@ -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 (*const)[5])) aad = {{.*}}
// CHECK: (void (*)(int (*)[5])) aad = {{.*}}
// same test cases with return values, note we can't overload on return type