forked from OSchip/llvm-project
Revert "[clang] template / auto deduction deduces common sugar"
This reverts commit d200db3863
, which causes a
clang crash. See https://reviews.llvm.org/D111283#3785755
Test case for convenience:
```
template <typename T>
using P = int T::*;
template <typename T, typename... A>
void j(P<T>, T, A...);
template <typename T>
void j(P<T>, T);
struct S {
int b;
};
void g(P<S> k, S s) { j(k, s); }
```
This commit is contained in:
parent
0b8a44388e
commit
637da9de4c
|
@ -84,7 +84,7 @@ TEST(GetDeducedType, KwAutoKwDecltypeExpansion) {
|
|||
|
||||
^auto i = {1,2};
|
||||
)cpp",
|
||||
"std::initializer_list<int>",
|
||||
"class std::initializer_list<int>",
|
||||
},
|
||||
{
|
||||
R"cpp( // auto in function return type with trailing return type
|
||||
|
|
|
@ -1940,7 +1940,7 @@ TEST(Hover, All) {
|
|||
[](HoverInfo &HI) {
|
||||
HI.Name = "auto";
|
||||
HI.Kind = index::SymbolKind::TypeAlias;
|
||||
HI.Definition = "std::initializer_list<int>";
|
||||
HI.Definition = "class std::initializer_list<int>";
|
||||
}},
|
||||
{
|
||||
R"cpp(// User defined conversion to auto
|
||||
|
|
|
@ -2807,23 +2807,6 @@ public:
|
|||
return AddrSpaceMapMangling || isTargetAddressSpace(AS);
|
||||
}
|
||||
|
||||
// Merges two exception specifications, such that the resulting
|
||||
// exception spec is the union of both. For example, if either
|
||||
// of them can throw something, the result can throw it as well.
|
||||
FunctionProtoType::ExceptionSpecInfo
|
||||
mergeExceptionSpecs(FunctionProtoType::ExceptionSpecInfo ESI1,
|
||||
FunctionProtoType::ExceptionSpecInfo ESI2,
|
||||
SmallVectorImpl<QualType> &ExceptionTypeStorage,
|
||||
bool AcceptDependent);
|
||||
|
||||
// For two "same" types, return a type which has
|
||||
// the common sugar between them. If Unqualified is true,
|
||||
// both types need only be the same unqualified type.
|
||||
// The result will drop the qualifiers which do not occur
|
||||
// in both types.
|
||||
QualType getCommonSugaredType(QualType X, QualType Y,
|
||||
bool Unqualified = false);
|
||||
|
||||
private:
|
||||
// Helper for integer ordering
|
||||
unsigned getIntegerRank(const Type *T) const;
|
||||
|
|
|
@ -4320,9 +4320,10 @@ public:
|
|||
}
|
||||
|
||||
using param_type_iterator = const QualType *;
|
||||
using param_type_range = llvm::iterator_range<param_type_iterator>;
|
||||
|
||||
ArrayRef<QualType> param_types() const {
|
||||
return llvm::makeArrayRef(param_type_begin(), param_type_end());
|
||||
param_type_range param_types() const {
|
||||
return param_type_range(param_type_begin(), param_type_end());
|
||||
}
|
||||
|
||||
param_type_iterator param_type_begin() const {
|
||||
|
|
|
@ -8771,9 +8771,7 @@ public:
|
|||
/// Deduction failed; that's all we know.
|
||||
TDK_MiscellaneousDeductionFailure,
|
||||
/// CUDA Target attributes do not match.
|
||||
TDK_CUDATargetMismatch,
|
||||
/// Some error which was already diagnosed.
|
||||
TDK_AlreadyDiagnosed
|
||||
TDK_CUDATargetMismatch
|
||||
};
|
||||
|
||||
TemplateDeductionResult
|
||||
|
@ -8864,11 +8862,21 @@ public:
|
|||
TypeSourceInfo *ReplaceAutoTypeSourceInfo(TypeSourceInfo *TypeWithAuto,
|
||||
QualType Replacement);
|
||||
|
||||
TemplateDeductionResult DeduceAutoType(TypeLoc AutoTypeLoc, Expr *Initializer,
|
||||
QualType &Result,
|
||||
sema::TemplateDeductionInfo &Info,
|
||||
bool DependentDeduction = false,
|
||||
bool IgnoreConstraints = false);
|
||||
/// Result type of DeduceAutoType.
|
||||
enum DeduceAutoResult {
|
||||
DAR_Succeeded,
|
||||
DAR_Failed,
|
||||
DAR_FailedAlreadyDiagnosed
|
||||
};
|
||||
|
||||
DeduceAutoResult
|
||||
DeduceAutoType(TypeSourceInfo *AutoType, Expr *&Initializer, QualType &Result,
|
||||
Optional<unsigned> DependentDeductionDepth = None,
|
||||
bool IgnoreConstraints = false);
|
||||
DeduceAutoResult
|
||||
DeduceAutoType(TypeLoc AutoTypeLoc, Expr *&Initializer, QualType &Result,
|
||||
Optional<unsigned> DependentDeductionDepth = None,
|
||||
bool IgnoreConstraints = false);
|
||||
void DiagnoseAutoDeductionFailure(VarDecl *VDecl, Expr *Init);
|
||||
bool DeduceReturnType(FunctionDecl *FD, SourceLocation Loc,
|
||||
bool Diagnose = true);
|
||||
|
@ -8890,8 +8898,8 @@ public:
|
|||
TypeLoc getReturnTypeLoc(FunctionDecl *FD) const;
|
||||
|
||||
bool DeduceFunctionTypeFromReturnExpr(FunctionDecl *FD,
|
||||
SourceLocation ReturnLoc, Expr *RetExpr,
|
||||
const AutoType *AT);
|
||||
SourceLocation ReturnLoc,
|
||||
Expr *&RetExpr, const AutoType *AT);
|
||||
|
||||
FunctionTemplateDecl *getMoreSpecializedTemplate(
|
||||
FunctionTemplateDecl *FT1, FunctionTemplateDecl *FT2, SourceLocation Loc,
|
||||
|
|
|
@ -3207,9 +3207,9 @@ bool ASTContext::hasSameFunctionTypeIgnoringExceptionSpec(QualType T,
|
|||
QualType ASTContext::getFunctionTypeWithoutPtrSizes(QualType T) {
|
||||
if (const auto *Proto = T->getAs<FunctionProtoType>()) {
|
||||
QualType RetTy = removePtrSizeAddrSpace(Proto->getReturnType());
|
||||
SmallVector<QualType, 16> Args(Proto->param_types().size());
|
||||
SmallVector<QualType, 16> Args(Proto->param_types());
|
||||
for (unsigned i = 0, n = Args.size(); i != n; ++i)
|
||||
Args[i] = removePtrSizeAddrSpace(Proto->param_types()[i]);
|
||||
Args[i] = removePtrSizeAddrSpace(Args[i]);
|
||||
return getFunctionType(RetTy, Args, Proto->getExtProtoInfo());
|
||||
}
|
||||
|
||||
|
@ -12137,557 +12137,6 @@ unsigned ASTContext::getTargetAddressSpace(LangAS AS) const {
|
|||
return (*AddrSpaceMap)[(unsigned)AS];
|
||||
}
|
||||
|
||||
// The getCommon* helpers return, for given 'same' X and Y entities given as
|
||||
// inputs, another entity which is also the 'same' as the inputs, but which
|
||||
// is closer to the canonical form of the inputs, each according to a given
|
||||
// criteria.
|
||||
// The getCommon*Checked variants are 'null inputs not-allowed' equivalents of
|
||||
// the regular ones.
|
||||
|
||||
static Decl *getCommonDecl(Decl *X, Decl *Y) {
|
||||
if (X == Y)
|
||||
return X;
|
||||
assert(declaresSameEntity(X, Y));
|
||||
for (const Decl *DX : X->redecls()) {
|
||||
// If we reach Y before reaching the first decl, that means X is older.
|
||||
if (DX == Y)
|
||||
return X;
|
||||
// If we reach the first decl, then Y is older.
|
||||
if (DX->isFirstDecl())
|
||||
return Y;
|
||||
}
|
||||
llvm_unreachable("Corrupt redecls chain");
|
||||
}
|
||||
|
||||
template <class T,
|
||||
std::enable_if_t<std::is_base_of<Decl, T>::value, bool> = true>
|
||||
T *getCommonDecl(T *X, T *Y) {
|
||||
return cast_or_null<T>(
|
||||
getCommonDecl(const_cast<Decl *>(cast_or_null<Decl>(X)),
|
||||
const_cast<Decl *>(cast_or_null<Decl>(Y))));
|
||||
}
|
||||
|
||||
template <class T,
|
||||
std::enable_if_t<std::is_base_of<Decl, T>::value, bool> = true>
|
||||
T *getCommonDeclChecked(T *X, T *Y) {
|
||||
return cast<T>(getCommonDecl(const_cast<Decl *>(cast<Decl>(X)),
|
||||
const_cast<Decl *>(cast<Decl>(Y))));
|
||||
}
|
||||
|
||||
static TemplateName getCommonTemplateName(ASTContext &Ctx, TemplateName X,
|
||||
TemplateName Y) {
|
||||
if (X.getAsVoidPointer() == Y.getAsVoidPointer())
|
||||
return X;
|
||||
// FIXME: There are cases here where we could find a common template name
|
||||
// with more sugar. For example one could be a SubstTemplateTemplate*
|
||||
// replacing the other.
|
||||
TemplateName CX = Ctx.getCanonicalTemplateName(X);
|
||||
assert(CX.getAsVoidPointer() ==
|
||||
Ctx.getCanonicalTemplateName(Y).getAsVoidPointer());
|
||||
return CX;
|
||||
}
|
||||
|
||||
static auto getCommonTypes(ASTContext &Ctx, ArrayRef<QualType> Xs,
|
||||
ArrayRef<QualType> Ys, bool Unqualified = false) {
|
||||
assert(Xs.size() == Ys.size());
|
||||
SmallVector<QualType, 8> Rs(Xs.size());
|
||||
for (size_t I = 0; I < Rs.size(); ++I)
|
||||
Rs[I] = Ctx.getCommonSugaredType(Xs[I], Ys[I], Unqualified);
|
||||
return Rs;
|
||||
}
|
||||
|
||||
template <class T>
|
||||
static SourceLocation getCommonAttrLoc(const T *X, const T *Y) {
|
||||
return X->getAttributeLoc() == Y->getAttributeLoc() ? X->getAttributeLoc()
|
||||
: SourceLocation();
|
||||
}
|
||||
|
||||
static TemplateArgument getCommonTemplateArgument(ASTContext &Ctx,
|
||||
const TemplateArgument &X,
|
||||
const TemplateArgument &Y) {
|
||||
assert(X.getKind() == Y.getKind());
|
||||
switch (X.getKind()) {
|
||||
case TemplateArgument::ArgKind::Type:
|
||||
return TemplateArgument(
|
||||
Ctx.getCommonSugaredType(X.getAsType(), Y.getAsType()));
|
||||
case TemplateArgument::ArgKind::NullPtr:
|
||||
return TemplateArgument(
|
||||
Ctx.getCommonSugaredType(X.getNullPtrType(), Y.getNullPtrType()),
|
||||
/*Unqualified=*/true);
|
||||
default:
|
||||
// FIXME: Handle the other argument kinds.
|
||||
return X;
|
||||
}
|
||||
}
|
||||
|
||||
static auto getCommonTemplateArguments(ASTContext &Ctx,
|
||||
ArrayRef<TemplateArgument> X,
|
||||
ArrayRef<TemplateArgument> Y) {
|
||||
SmallVector<TemplateArgument, 8> R(X.size());
|
||||
for (size_t I = 0; I < R.size(); ++I)
|
||||
R[I] = getCommonTemplateArgument(Ctx, X[I], Y[I]);
|
||||
return R;
|
||||
}
|
||||
|
||||
template <class T>
|
||||
static ElaboratedTypeKeyword getCommonTypeKeyword(const T *X, const T *Y) {
|
||||
return X->getKeyword() == Y->getKeyword() ? X->getKeyword()
|
||||
: ElaboratedTypeKeyword::ETK_None;
|
||||
}
|
||||
|
||||
template <class T>
|
||||
static NestedNameSpecifier *getCommonNNS(ASTContext &Ctx, const T *X,
|
||||
const T *Y) {
|
||||
// FIXME: Try to keep the common NNS sugar.
|
||||
return X->getQualifier() == Y->getQualifier()
|
||||
? X->getQualifier()
|
||||
: Ctx.getCanonicalNestedNameSpecifier(X->getQualifier());
|
||||
}
|
||||
|
||||
template <class T>
|
||||
static QualType getCommonElementType(ASTContext &Ctx, const T *X, const T *Y) {
|
||||
return Ctx.getCommonSugaredType(X->getElementType(), Y->getElementType());
|
||||
}
|
||||
|
||||
template <class T>
|
||||
static QualType getCommonPointeeType(ASTContext &Ctx, const T *X, const T *Y) {
|
||||
return Ctx.getCommonSugaredType(X->getPointeeType(), Y->getPointeeType());
|
||||
}
|
||||
|
||||
template <class T> static auto *getCommonSizeExpr(T *X, T *Y) {
|
||||
assert(X->getSizeExpr() == Y->getSizeExpr());
|
||||
return X->getSizeExpr();
|
||||
}
|
||||
|
||||
static auto getCommonSizeModifier(const ArrayType *X, const ArrayType *Y) {
|
||||
assert(X->getSizeModifier() == Y->getSizeModifier());
|
||||
return X->getSizeModifier();
|
||||
}
|
||||
|
||||
static auto getCommonIndexTypeCVRQualifiers(const ArrayType *X,
|
||||
const ArrayType *Y) {
|
||||
assert(X->getIndexTypeCVRQualifiers() == Y->getIndexTypeCVRQualifiers());
|
||||
return X->getIndexTypeCVRQualifiers();
|
||||
}
|
||||
|
||||
// Merges two type lists such that the resulting vector will contain
|
||||
// each type (in a canonical sense) only once, in the order they appear
|
||||
// from X to Y. If they occur in both X and Y, the result will contain
|
||||
// the common sugared type between them.
|
||||
static void mergeTypeLists(ASTContext &Ctx, SmallVectorImpl<QualType> &Out,
|
||||
ArrayRef<QualType> X, ArrayRef<QualType> Y) {
|
||||
llvm::DenseMap<QualType, unsigned> Found;
|
||||
for (auto Ts : {X, Y}) {
|
||||
for (QualType T : Ts) {
|
||||
auto Res = Found.try_emplace(Ctx.getCanonicalType(T), Out.size());
|
||||
if (!Res.second) {
|
||||
QualType &U = Out[Res.first->second];
|
||||
U = Ctx.getCommonSugaredType(U, T);
|
||||
} else {
|
||||
Out.emplace_back(T);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
FunctionProtoType::ExceptionSpecInfo
|
||||
ASTContext::mergeExceptionSpecs(FunctionProtoType::ExceptionSpecInfo ESI1,
|
||||
FunctionProtoType::ExceptionSpecInfo ESI2,
|
||||
SmallVectorImpl<QualType> &ExceptionTypeStorage,
|
||||
bool AcceptDependent) {
|
||||
ExceptionSpecificationType EST1 = ESI1.Type, EST2 = ESI2.Type;
|
||||
|
||||
// If either of them can throw anything, that is the result.
|
||||
for (auto I : {EST_None, EST_MSAny, EST_NoexceptFalse}) {
|
||||
if (EST1 == I)
|
||||
return ESI1;
|
||||
if (EST2 == I)
|
||||
return ESI2;
|
||||
}
|
||||
|
||||
// If either of them is non-throwing, the result is the other.
|
||||
for (auto I :
|
||||
{EST_NoThrow, EST_DynamicNone, EST_BasicNoexcept, EST_NoexceptTrue}) {
|
||||
if (EST1 == I)
|
||||
return ESI2;
|
||||
if (EST2 == I)
|
||||
return ESI1;
|
||||
}
|
||||
|
||||
// If we're left with value-dependent computed noexcept expressions, we're
|
||||
// stuck. Before C++17, we can just drop the exception specification entirely,
|
||||
// since it's not actually part of the canonical type. And this should never
|
||||
// happen in C++17, because it would mean we were computing the composite
|
||||
// pointer type of dependent types, which should never happen.
|
||||
if (EST1 == EST_DependentNoexcept || EST2 == EST_DependentNoexcept) {
|
||||
assert(AcceptDependent &&
|
||||
"computing composite pointer type of dependent types");
|
||||
return FunctionProtoType::ExceptionSpecInfo();
|
||||
}
|
||||
|
||||
// Switch over the possibilities so that people adding new values know to
|
||||
// update this function.
|
||||
switch (EST1) {
|
||||
case EST_None:
|
||||
case EST_DynamicNone:
|
||||
case EST_MSAny:
|
||||
case EST_BasicNoexcept:
|
||||
case EST_DependentNoexcept:
|
||||
case EST_NoexceptFalse:
|
||||
case EST_NoexceptTrue:
|
||||
case EST_NoThrow:
|
||||
llvm_unreachable("These ESTs should be handled above");
|
||||
|
||||
case EST_Dynamic: {
|
||||
// This is the fun case: both exception specifications are dynamic. Form
|
||||
// the union of the two lists.
|
||||
assert(EST2 == EST_Dynamic && "other cases should already be handled");
|
||||
mergeTypeLists(*this, ExceptionTypeStorage, ESI1.Exceptions,
|
||||
ESI2.Exceptions);
|
||||
FunctionProtoType::ExceptionSpecInfo Result(EST_Dynamic);
|
||||
Result.Exceptions = ExceptionTypeStorage;
|
||||
return Result;
|
||||
}
|
||||
|
||||
case EST_Unevaluated:
|
||||
case EST_Uninstantiated:
|
||||
case EST_Unparsed:
|
||||
llvm_unreachable("shouldn't see unresolved exception specifications here");
|
||||
}
|
||||
|
||||
llvm_unreachable("invalid ExceptionSpecificationType");
|
||||
}
|
||||
|
||||
static QualType getCommonType(ASTContext &Ctx, const Type *X, const Type *Y) {
|
||||
Type::TypeClass TC = X->getTypeClass();
|
||||
assert(TC == Y->getTypeClass());
|
||||
switch (TC) {
|
||||
#define UNEXPECTED_TYPE(Class, Kind) \
|
||||
case Type::Class: \
|
||||
llvm_unreachable("Unexpected " Kind ": " #Class);
|
||||
|
||||
#define NON_CANONICAL_TYPE(Class, Base) UNEXPECTED_TYPE(Class, "non-canonical")
|
||||
#define TYPE(Class, Base)
|
||||
#include "clang/AST/TypeNodes.inc"
|
||||
|
||||
#define SUGAR_FREE_TYPE(Class) UNEXPECTED_TYPE(Class, "sugar-free")
|
||||
SUGAR_FREE_TYPE(Builtin)
|
||||
SUGAR_FREE_TYPE(Decltype)
|
||||
SUGAR_FREE_TYPE(DeducedTemplateSpecialization)
|
||||
SUGAR_FREE_TYPE(DependentBitInt)
|
||||
SUGAR_FREE_TYPE(Enum)
|
||||
SUGAR_FREE_TYPE(BitInt)
|
||||
SUGAR_FREE_TYPE(ObjCInterface)
|
||||
SUGAR_FREE_TYPE(Record)
|
||||
SUGAR_FREE_TYPE(SubstTemplateTypeParmPack)
|
||||
SUGAR_FREE_TYPE(TemplateTypeParm)
|
||||
SUGAR_FREE_TYPE(UnresolvedUsing)
|
||||
#undef SUGAR_FREE_TYPE
|
||||
#define NON_UNIQUE_TYPE(Class) UNEXPECTED_TYPE(Class, "non-unique")
|
||||
NON_UNIQUE_TYPE(TypeOfExpr)
|
||||
NON_UNIQUE_TYPE(VariableArray)
|
||||
#undef NON_UNIQUE_TYPE
|
||||
|
||||
UNEXPECTED_TYPE(TypeOf, "sugar")
|
||||
|
||||
#undef UNEXPECTED_TYPE
|
||||
|
||||
case Type::Auto: {
|
||||
const auto *AX = cast<AutoType>(X), *AY = cast<AutoType>(Y);
|
||||
assert(AX->getDeducedType().isNull());
|
||||
assert(AY->getDeducedType().isNull());
|
||||
assert(AX->getKeyword() == AY->getKeyword());
|
||||
assert(AX->isInstantiationDependentType() ==
|
||||
AY->isInstantiationDependentType());
|
||||
auto As = getCommonTemplateArguments(Ctx, AX->getTypeConstraintArguments(),
|
||||
AY->getTypeConstraintArguments());
|
||||
return Ctx.getAutoType(QualType(), AX->getKeyword(),
|
||||
AX->isInstantiationDependentType(),
|
||||
AX->containsUnexpandedParameterPack(),
|
||||
getCommonDecl(AX->getTypeConstraintConcept(),
|
||||
AY->getTypeConstraintConcept()),
|
||||
As);
|
||||
}
|
||||
case Type::IncompleteArray: {
|
||||
const auto *AX = cast<IncompleteArrayType>(X),
|
||||
*AY = cast<IncompleteArrayType>(Y);
|
||||
return Ctx.getIncompleteArrayType(getCommonElementType(Ctx, AX, AY),
|
||||
getCommonSizeModifier(AX, AY),
|
||||
getCommonIndexTypeCVRQualifiers(AX, AY));
|
||||
}
|
||||
case Type::DependentSizedArray: {
|
||||
const auto *AX = cast<DependentSizedArrayType>(X),
|
||||
*AY = cast<DependentSizedArrayType>(Y);
|
||||
return Ctx.getDependentSizedArrayType(
|
||||
getCommonElementType(Ctx, AX, AY), getCommonSizeExpr(AX, AY),
|
||||
getCommonSizeModifier(AX, AY), getCommonIndexTypeCVRQualifiers(AX, AY),
|
||||
AX->getBracketsRange() == AY->getBracketsRange()
|
||||
? AX->getBracketsRange()
|
||||
: SourceRange());
|
||||
}
|
||||
case Type::ConstantArray: {
|
||||
const auto *AX = cast<ConstantArrayType>(X),
|
||||
*AY = cast<ConstantArrayType>(Y);
|
||||
assert(AX->getSize() == AY->getSize());
|
||||
return Ctx.getConstantArrayType(getCommonElementType(Ctx, AX, AY),
|
||||
AX->getSize(), getCommonSizeExpr(AX, AY),
|
||||
getCommonSizeModifier(AX, AY),
|
||||
getCommonIndexTypeCVRQualifiers(AX, AY));
|
||||
}
|
||||
case Type::Atomic: {
|
||||
const auto *AX = cast<AtomicType>(X), *AY = cast<AtomicType>(Y);
|
||||
return Ctx.getAtomicType(
|
||||
Ctx.getCommonSugaredType(AX->getValueType(), AY->getValueType()));
|
||||
}
|
||||
case Type::Complex: {
|
||||
const auto *CX = cast<ComplexType>(X), *CY = cast<ComplexType>(Y);
|
||||
return Ctx.getComplexType(getCommonElementType(Ctx, CX, CY));
|
||||
}
|
||||
case Type::Pointer: {
|
||||
const auto *PX = cast<PointerType>(X), *PY = cast<PointerType>(Y);
|
||||
return Ctx.getPointerType(getCommonPointeeType(Ctx, PX, PY));
|
||||
}
|
||||
case Type::BlockPointer: {
|
||||
const auto *PX = cast<BlockPointerType>(X), *PY = cast<BlockPointerType>(Y);
|
||||
return Ctx.getBlockPointerType(getCommonPointeeType(Ctx, PX, PY));
|
||||
}
|
||||
case Type::ObjCObjectPointer: {
|
||||
const auto *PX = cast<ObjCObjectPointerType>(X),
|
||||
*PY = cast<ObjCObjectPointerType>(Y);
|
||||
return Ctx.getObjCObjectPointerType(getCommonPointeeType(Ctx, PX, PY));
|
||||
}
|
||||
case Type::MemberPointer: {
|
||||
const auto *PX = cast<MemberPointerType>(X),
|
||||
*PY = cast<MemberPointerType>(Y);
|
||||
return Ctx.getMemberPointerType(
|
||||
getCommonPointeeType(Ctx, PX, PY),
|
||||
Ctx.getCommonSugaredType(QualType(PX->getClass(), 0),
|
||||
QualType(PY->getClass(), 0))
|
||||
.getTypePtr());
|
||||
}
|
||||
case Type::LValueReference: {
|
||||
const auto *PX = cast<LValueReferenceType>(X),
|
||||
*PY = cast<LValueReferenceType>(Y);
|
||||
return Ctx.getLValueReferenceType(getCommonPointeeType(Ctx, PX, PY),
|
||||
PX->isSpelledAsLValue() ||
|
||||
PY->isSpelledAsLValue());
|
||||
}
|
||||
case Type::RValueReference: {
|
||||
const auto *PX = cast<RValueReferenceType>(X),
|
||||
*PY = cast<RValueReferenceType>(Y);
|
||||
return Ctx.getRValueReferenceType(getCommonPointeeType(Ctx, PX, PY));
|
||||
}
|
||||
case Type::DependentAddressSpace: {
|
||||
const auto *PX = cast<DependentAddressSpaceType>(X),
|
||||
*PY = cast<DependentAddressSpaceType>(Y);
|
||||
return Ctx.getDependentAddressSpaceType(getCommonPointeeType(Ctx, PX, PY),
|
||||
PX->getAddrSpaceExpr(),
|
||||
getCommonAttrLoc(PX, PY));
|
||||
}
|
||||
case Type::FunctionNoProto: {
|
||||
const auto *FX = cast<FunctionNoProtoType>(X),
|
||||
*FY = cast<FunctionNoProtoType>(Y);
|
||||
assert(FX->getExtInfo() == FY->getExtInfo());
|
||||
return Ctx.getFunctionNoProtoType(
|
||||
Ctx.getCommonSugaredType(FX->getReturnType(), FY->getReturnType()),
|
||||
FX->getExtInfo());
|
||||
}
|
||||
case Type::FunctionProto: {
|
||||
const auto *FX = cast<FunctionProtoType>(X),
|
||||
*FY = cast<FunctionProtoType>(Y);
|
||||
FunctionProtoType::ExtProtoInfo EPIX = FX->getExtProtoInfo(),
|
||||
EPIY = FY->getExtProtoInfo();
|
||||
assert(EPIX.ExtInfo == EPIY.ExtInfo);
|
||||
assert(EPIX.ExtParameterInfos == EPIY.ExtParameterInfos);
|
||||
assert(EPIX.RefQualifier == EPIY.RefQualifier);
|
||||
assert(EPIX.TypeQuals == EPIY.TypeQuals);
|
||||
assert(EPIX.Variadic == EPIY.Variadic);
|
||||
|
||||
// FIXME: Can we handle an empty EllipsisLoc?
|
||||
// Use emtpy EllipsisLoc if X and Y differ.
|
||||
|
||||
EPIX.HasTrailingReturn = EPIX.HasTrailingReturn && EPIY.HasTrailingReturn;
|
||||
|
||||
QualType R =
|
||||
Ctx.getCommonSugaredType(FX->getReturnType(), FY->getReturnType());
|
||||
auto P = getCommonTypes(Ctx, FX->param_types(), FY->param_types(),
|
||||
/*Unqualified=*/true);
|
||||
|
||||
SmallVector<QualType, 8> Exceptions;
|
||||
EPIX.ExceptionSpec = Ctx.mergeExceptionSpecs(
|
||||
EPIX.ExceptionSpec, EPIY.ExceptionSpec, Exceptions, true);
|
||||
return Ctx.getFunctionType(R, P, EPIX);
|
||||
}
|
||||
case Type::ObjCObject: {
|
||||
const auto *OX = cast<ObjCObjectType>(X), *OY = cast<ObjCObjectType>(Y);
|
||||
assert(llvm::equal(OX->getProtocols(), OY->getProtocols()));
|
||||
auto TAs = getCommonTypes(Ctx, OX->getTypeArgsAsWritten(),
|
||||
OY->getTypeArgsAsWritten());
|
||||
return Ctx.getObjCObjectType(
|
||||
Ctx.getCommonSugaredType(OX->getBaseType(), OY->getBaseType()), TAs,
|
||||
OX->getProtocols(),
|
||||
OX->isKindOfTypeAsWritten() && OY->isKindOfTypeAsWritten());
|
||||
}
|
||||
case Type::ConstantMatrix: {
|
||||
const auto *MX = cast<ConstantMatrixType>(X),
|
||||
*MY = cast<ConstantMatrixType>(Y);
|
||||
assert(MX->getNumRows() == MY->getNumRows());
|
||||
assert(MX->getNumColumns() == MY->getNumColumns());
|
||||
return Ctx.getConstantMatrixType(getCommonElementType(Ctx, MX, MY),
|
||||
MX->getNumRows(), MX->getNumColumns());
|
||||
}
|
||||
case Type::DependentSizedMatrix: {
|
||||
const auto *MX = cast<DependentSizedMatrixType>(X),
|
||||
*MY = cast<DependentSizedMatrixType>(Y);
|
||||
assert(MX->getRowExpr() == MY->getRowExpr());
|
||||
assert(MX->getColumnExpr() == MY->getColumnExpr());
|
||||
return Ctx.getDependentSizedMatrixType(
|
||||
getCommonElementType(Ctx, MX, MY), MX->getRowExpr(),
|
||||
MX->getColumnExpr(), getCommonAttrLoc(MX, MY));
|
||||
}
|
||||
case Type::Vector: {
|
||||
const auto *VX = cast<VectorType>(X), *VY = cast<VectorType>(Y);
|
||||
assert(VX->getNumElements() == VY->getNumElements());
|
||||
assert(VX->getVectorKind() == VY->getVectorKind());
|
||||
return Ctx.getVectorType(getCommonElementType(Ctx, VX, VY),
|
||||
VX->getNumElements(), VX->getVectorKind());
|
||||
}
|
||||
case Type::ExtVector: {
|
||||
const auto *VX = cast<ExtVectorType>(X), *VY = cast<ExtVectorType>(Y);
|
||||
assert(VX->getNumElements() == VY->getNumElements());
|
||||
return Ctx.getExtVectorType(getCommonElementType(Ctx, VX, VY),
|
||||
VX->getNumElements());
|
||||
}
|
||||
case Type::DependentSizedExtVector: {
|
||||
const auto *VX = cast<DependentSizedExtVectorType>(X),
|
||||
*VY = cast<DependentSizedExtVectorType>(Y);
|
||||
return Ctx.getDependentSizedExtVectorType(getCommonElementType(Ctx, VX, VY),
|
||||
getCommonSizeExpr(VX, VY),
|
||||
getCommonAttrLoc(VX, VY));
|
||||
}
|
||||
case Type::DependentVector: {
|
||||
const auto *VX = cast<DependentVectorType>(X),
|
||||
*VY = cast<DependentVectorType>(Y);
|
||||
assert(VX->getVectorKind() == VY->getVectorKind());
|
||||
return Ctx.getDependentVectorType(
|
||||
getCommonElementType(Ctx, VX, VY), getCommonSizeExpr(VX, VY),
|
||||
getCommonAttrLoc(VX, VY), VX->getVectorKind());
|
||||
}
|
||||
case Type::InjectedClassName: {
|
||||
const auto *IX = cast<InjectedClassNameType>(X),
|
||||
*IY = cast<InjectedClassNameType>(Y);
|
||||
return Ctx.getInjectedClassNameType(
|
||||
getCommonDeclChecked(IX->getDecl(), IY->getDecl()),
|
||||
Ctx.getCommonSugaredType(IX->getInjectedSpecializationType(),
|
||||
IY->getInjectedSpecializationType()));
|
||||
}
|
||||
case Type::TemplateSpecialization: {
|
||||
const auto *TX = cast<TemplateSpecializationType>(X),
|
||||
*TY = cast<TemplateSpecializationType>(Y);
|
||||
auto As = getCommonTemplateArguments(Ctx, TX->template_arguments(),
|
||||
TY->template_arguments());
|
||||
return Ctx.getTemplateSpecializationType(
|
||||
::getCommonTemplateName(Ctx, TX->getTemplateName(),
|
||||
TY->getTemplateName()),
|
||||
As, TX->getCanonicalTypeInternal());
|
||||
}
|
||||
case Type::DependentName: {
|
||||
const auto *NX = cast<DependentNameType>(X),
|
||||
*NY = cast<DependentNameType>(Y);
|
||||
assert(NX->getIdentifier() == NY->getIdentifier());
|
||||
return Ctx.getDependentNameType(
|
||||
getCommonTypeKeyword(NX, NY), getCommonNNS(Ctx, NX, NY),
|
||||
NX->getIdentifier(), NX->getCanonicalTypeInternal());
|
||||
}
|
||||
case Type::DependentTemplateSpecialization: {
|
||||
const auto *TX = cast<DependentTemplateSpecializationType>(X),
|
||||
*TY = cast<DependentTemplateSpecializationType>(Y);
|
||||
assert(TX->getIdentifier() == TY->getIdentifier());
|
||||
auto As = getCommonTemplateArguments(Ctx, TX->template_arguments(),
|
||||
TY->template_arguments());
|
||||
return Ctx.getDependentTemplateSpecializationType(
|
||||
getCommonTypeKeyword(TX, TY), getCommonNNS(Ctx, TX, TY),
|
||||
TX->getIdentifier(), As);
|
||||
}
|
||||
case Type::UnaryTransform: {
|
||||
const auto *TX = cast<UnaryTransformType>(X),
|
||||
*TY = cast<UnaryTransformType>(Y);
|
||||
assert(TX->getUTTKind() == TY->getUTTKind());
|
||||
return Ctx.getUnaryTransformType(
|
||||
Ctx.getCommonSugaredType(TX->getBaseType(), TY->getBaseType()),
|
||||
Ctx.getCommonSugaredType(TX->getUnderlyingType(),
|
||||
TY->getUnderlyingType()),
|
||||
TX->getUTTKind());
|
||||
}
|
||||
case Type::PackExpansion: {
|
||||
const auto *PX = cast<PackExpansionType>(X),
|
||||
*PY = cast<PackExpansionType>(Y);
|
||||
return Ctx.getPackExpansionType(
|
||||
Ctx.getCommonSugaredType(PX->getPattern(), PY->getPattern()),
|
||||
PX->getNumExpansions(), false);
|
||||
}
|
||||
case Type::Pipe: {
|
||||
const auto *PX = cast<PipeType>(X), *PY = cast<PipeType>(Y);
|
||||
assert(PX->isReadOnly() == PY->isReadOnly());
|
||||
auto MP = PX->isReadOnly() ? &ASTContext::getReadPipeType
|
||||
: &ASTContext::getWritePipeType;
|
||||
return (Ctx.*MP)(getCommonElementType(Ctx, PX, PY));
|
||||
}
|
||||
}
|
||||
llvm_unreachable("Unknown Type Class");
|
||||
}
|
||||
|
||||
static auto unwrapSugar(SplitQualType &T) {
|
||||
SmallVector<SplitQualType, 8> R;
|
||||
while (true) {
|
||||
QualType NT = T.Ty->getLocallyUnqualifiedSingleStepDesugaredType();
|
||||
if (NT == QualType(T.Ty, 0))
|
||||
break;
|
||||
SplitQualType SplitNT = NT.split();
|
||||
SplitNT.Quals += T.Quals;
|
||||
R.push_back(T);
|
||||
T = SplitNT;
|
||||
}
|
||||
return R;
|
||||
}
|
||||
|
||||
static bool removeDifferentTopLevelSugar(SplitQualType &SX, SplitQualType &SY) {
|
||||
auto Xs = ::unwrapSugar(SX), Ys = ::unwrapSugar(SY);
|
||||
if (SX.Ty != SY.Ty)
|
||||
return true;
|
||||
while (!Xs.empty() && !Ys.empty() && Xs.back().Ty == Ys.back().Ty) {
|
||||
SX = Xs.pop_back_val();
|
||||
SY = Ys.pop_back_val();
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
QualType ASTContext::getCommonSugaredType(QualType X, QualType Y,
|
||||
bool Unqualified) {
|
||||
assert(Unqualified ? hasSameUnqualifiedType(X, Y) : hasSameType(X, Y));
|
||||
if (X == Y)
|
||||
return X;
|
||||
if (!Unqualified) {
|
||||
if (X.isCanonical())
|
||||
return X;
|
||||
if (Y.isCanonical())
|
||||
return Y;
|
||||
}
|
||||
|
||||
SplitQualType SX = X.split(), SY = Y.split();
|
||||
if (::removeDifferentTopLevelSugar(SX, SY))
|
||||
SX.Ty = ::getCommonType(*this, SX.Ty, SY.Ty).getTypePtr();
|
||||
|
||||
if (Unqualified)
|
||||
SX.Quals = Qualifiers::removeCommonQualifiers(SX.Quals, SY.Quals);
|
||||
else
|
||||
assert(SX.Quals == SY.Quals);
|
||||
|
||||
QualType R = getQualifiedType(SX);
|
||||
assert(Unqualified ? hasSameUnqualifiedType(R, X) : hasSameType(R, X));
|
||||
return R;
|
||||
}
|
||||
|
||||
QualType ASTContext::getCorrespondingSaturatedType(QualType Ty) const {
|
||||
assert(Ty->isFixedPointType());
|
||||
|
||||
|
|
|
@ -4109,9 +4109,10 @@ bool Sema::MergeFunctionDecl(FunctionDecl *New, NamedDecl *&OldD, Scope *S,
|
|||
// The old declaration provided a function prototype, but the
|
||||
// new declaration does not. Merge in the prototype.
|
||||
assert(!OldProto->hasExceptionSpec() && "Exception spec in C");
|
||||
NewQType = Context.getFunctionType(NewFuncType->getReturnType(),
|
||||
OldProto->getParamTypes(),
|
||||
OldProto->getExtProtoInfo());
|
||||
SmallVector<QualType, 16> ParamTypes(OldProto->param_types());
|
||||
NewQType =
|
||||
Context.getFunctionType(NewFuncType->getReturnType(), ParamTypes,
|
||||
OldProto->getExtProtoInfo());
|
||||
New->setType(NewQType);
|
||||
New->setHasInheritedPrototype();
|
||||
|
||||
|
@ -12373,10 +12374,7 @@ QualType Sema::deduceVarTypeFromInitializer(VarDecl *VDecl,
|
|||
Type.getQualifiers());
|
||||
|
||||
QualType DeducedType;
|
||||
TemplateDeductionInfo Info(DeduceInit->getExprLoc());
|
||||
TemplateDeductionResult Result =
|
||||
DeduceAutoType(TSI->getTypeLoc(), DeduceInit, DeducedType, Info);
|
||||
if (Result != TDK_Success && Result != TDK_AlreadyDiagnosed) {
|
||||
if (DeduceAutoType(TSI, DeduceInit, DeducedType) == DAR_Failed) {
|
||||
if (!IsInitCapture)
|
||||
DiagnoseAutoDeductionFailure(VDecl, DeduceInit);
|
||||
else if (isa<InitListExpr>(Init))
|
||||
|
|
|
@ -11582,9 +11582,7 @@ QualType Sema::BuildStdInitializerList(QualType Element, SourceLocation Loc) {
|
|||
Args.addArgument(TemplateArgumentLoc(TemplateArgument(Element),
|
||||
Context.getTrivialTypeSourceInfo(Element,
|
||||
Loc)));
|
||||
return Context.getElaboratedType(
|
||||
ElaboratedTypeKeyword::ETK_None,
|
||||
NestedNameSpecifier::Create(Context, nullptr, getStdNamespace()),
|
||||
return Context.getCanonicalType(
|
||||
CheckTemplateIdType(TemplateName(StdInitializerList), Loc, Args));
|
||||
}
|
||||
|
||||
|
|
|
@ -1506,17 +1506,12 @@ Sema::BuildCXXTypeConstructExpr(TypeSourceInfo *TInfo,
|
|||
Diag(Deduce->getBeginLoc(), diag::err_auto_expr_init_paren_braces)
|
||||
<< ListInitialization << Ty << FullRange);
|
||||
QualType DeducedType;
|
||||
TemplateDeductionInfo Info(Deduce->getExprLoc());
|
||||
TemplateDeductionResult Result =
|
||||
DeduceAutoType(TInfo->getTypeLoc(), Deduce, DeducedType, Info);
|
||||
if (Result != TDK_Success && Result != TDK_AlreadyDiagnosed)
|
||||
if (DeduceAutoType(TInfo, Deduce, DeducedType) == DAR_Failed)
|
||||
return ExprError(Diag(TyBeginLoc, diag::err_auto_expr_deduction_failure)
|
||||
<< Ty << Deduce->getType() << FullRange
|
||||
<< Deduce->getSourceRange());
|
||||
if (DeducedType.isNull()) {
|
||||
assert(Result == TDK_AlreadyDiagnosed);
|
||||
if (DeducedType.isNull())
|
||||
return ExprError();
|
||||
}
|
||||
|
||||
Ty = DeducedType;
|
||||
Entity = InitializedEntity::InitializeTemporary(TInfo, Ty);
|
||||
|
@ -2050,17 +2045,12 @@ Sema::BuildCXXNew(SourceRange Range, bool UseGlobal,
|
|||
Diag(Deduce->getBeginLoc(), diag::err_auto_expr_init_paren_braces)
|
||||
<< Braced << AllocType << TypeRange);
|
||||
QualType DeducedType;
|
||||
TemplateDeductionInfo Info(Deduce->getExprLoc());
|
||||
TemplateDeductionResult Result =
|
||||
DeduceAutoType(AllocTypeInfo->getTypeLoc(), Deduce, DeducedType, Info);
|
||||
if (Result != TDK_Success && Result != TDK_AlreadyDiagnosed)
|
||||
if (DeduceAutoType(AllocTypeInfo, Deduce, DeducedType) == DAR_Failed)
|
||||
return ExprError(Diag(StartLoc, diag::err_auto_new_deduction_failure)
|
||||
<< AllocType << Deduce->getType() << TypeRange
|
||||
<< Deduce->getSourceRange());
|
||||
if (DeducedType.isNull()) {
|
||||
assert(Result == TDK_AlreadyDiagnosed);
|
||||
<< AllocType << Deduce->getType()
|
||||
<< TypeRange << Deduce->getSourceRange());
|
||||
if (DeducedType.isNull())
|
||||
return ExprError();
|
||||
}
|
||||
AllocType = DeducedType;
|
||||
}
|
||||
|
||||
|
@ -6698,6 +6688,79 @@ QualType Sema::CXXCheckConditionalOperands(ExprResult &Cond, ExprResult &LHS,
|
|||
return QualType();
|
||||
}
|
||||
|
||||
static FunctionProtoType::ExceptionSpecInfo
|
||||
mergeExceptionSpecs(Sema &S, FunctionProtoType::ExceptionSpecInfo ESI1,
|
||||
FunctionProtoType::ExceptionSpecInfo ESI2,
|
||||
SmallVectorImpl<QualType> &ExceptionTypeStorage) {
|
||||
ExceptionSpecificationType EST1 = ESI1.Type;
|
||||
ExceptionSpecificationType EST2 = ESI2.Type;
|
||||
|
||||
// If either of them can throw anything, that is the result.
|
||||
if (EST1 == EST_None) return ESI1;
|
||||
if (EST2 == EST_None) return ESI2;
|
||||
if (EST1 == EST_MSAny) return ESI1;
|
||||
if (EST2 == EST_MSAny) return ESI2;
|
||||
if (EST1 == EST_NoexceptFalse) return ESI1;
|
||||
if (EST2 == EST_NoexceptFalse) return ESI2;
|
||||
|
||||
// If either of them is non-throwing, the result is the other.
|
||||
if (EST1 == EST_NoThrow) return ESI2;
|
||||
if (EST2 == EST_NoThrow) return ESI1;
|
||||
if (EST1 == EST_DynamicNone) return ESI2;
|
||||
if (EST2 == EST_DynamicNone) return ESI1;
|
||||
if (EST1 == EST_BasicNoexcept) return ESI2;
|
||||
if (EST2 == EST_BasicNoexcept) return ESI1;
|
||||
if (EST1 == EST_NoexceptTrue) return ESI2;
|
||||
if (EST2 == EST_NoexceptTrue) return ESI1;
|
||||
|
||||
// If we're left with value-dependent computed noexcept expressions, we're
|
||||
// stuck. Before C++17, we can just drop the exception specification entirely,
|
||||
// since it's not actually part of the canonical type. And this should never
|
||||
// happen in C++17, because it would mean we were computing the composite
|
||||
// pointer type of dependent types, which should never happen.
|
||||
if (EST1 == EST_DependentNoexcept || EST2 == EST_DependentNoexcept) {
|
||||
assert(!S.getLangOpts().CPlusPlus17 &&
|
||||
"computing composite pointer type of dependent types");
|
||||
return FunctionProtoType::ExceptionSpecInfo();
|
||||
}
|
||||
|
||||
// Switch over the possibilities so that people adding new values know to
|
||||
// update this function.
|
||||
switch (EST1) {
|
||||
case EST_None:
|
||||
case EST_DynamicNone:
|
||||
case EST_MSAny:
|
||||
case EST_BasicNoexcept:
|
||||
case EST_DependentNoexcept:
|
||||
case EST_NoexceptFalse:
|
||||
case EST_NoexceptTrue:
|
||||
case EST_NoThrow:
|
||||
llvm_unreachable("handled above");
|
||||
|
||||
case EST_Dynamic: {
|
||||
// This is the fun case: both exception specifications are dynamic. Form
|
||||
// the union of the two lists.
|
||||
assert(EST2 == EST_Dynamic && "other cases should already be handled");
|
||||
llvm::SmallPtrSet<QualType, 8> Found;
|
||||
for (auto &Exceptions : {ESI1.Exceptions, ESI2.Exceptions})
|
||||
for (QualType E : Exceptions)
|
||||
if (Found.insert(S.Context.getCanonicalType(E)).second)
|
||||
ExceptionTypeStorage.push_back(E);
|
||||
|
||||
FunctionProtoType::ExceptionSpecInfo Result(EST_Dynamic);
|
||||
Result.Exceptions = ExceptionTypeStorage;
|
||||
return Result;
|
||||
}
|
||||
|
||||
case EST_Unevaluated:
|
||||
case EST_Uninstantiated:
|
||||
case EST_Unparsed:
|
||||
llvm_unreachable("shouldn't see unresolved exception specifications here");
|
||||
}
|
||||
|
||||
llvm_unreachable("invalid ExceptionSpecificationType");
|
||||
}
|
||||
|
||||
/// Find a merged pointer type and convert the two expressions to it.
|
||||
///
|
||||
/// This finds the composite pointer type for \p E1 and \p E2 according to
|
||||
|
@ -7001,9 +7064,9 @@ QualType Sema::FindCompositePointerType(SourceLocation Loc,
|
|||
|
||||
// The result is nothrow if both operands are.
|
||||
SmallVector<QualType, 8> ExceptionTypeStorage;
|
||||
EPI1.ExceptionSpec = EPI2.ExceptionSpec = Context.mergeExceptionSpecs(
|
||||
EPI1.ExceptionSpec, EPI2.ExceptionSpec, ExceptionTypeStorage,
|
||||
getLangOpts().CPlusPlus17);
|
||||
EPI1.ExceptionSpec = EPI2.ExceptionSpec =
|
||||
mergeExceptionSpecs(*this, EPI1.ExceptionSpec, EPI2.ExceptionSpec,
|
||||
ExceptionTypeStorage);
|
||||
|
||||
Composite1 = Context.getFunctionType(FPT1->getReturnType(),
|
||||
FPT1->getParamTypes(), EPI1);
|
||||
|
|
|
@ -684,7 +684,6 @@ clang::MakeDeductionFailureInfo(ASTContext &Context,
|
|||
|
||||
case Sema::TDK_Success:
|
||||
case Sema::TDK_NonDependentConversionFailure:
|
||||
case Sema::TDK_AlreadyDiagnosed:
|
||||
llvm_unreachable("not a deduction failure");
|
||||
}
|
||||
|
||||
|
@ -734,7 +733,6 @@ void DeductionFailureInfo::Destroy() {
|
|||
|
||||
// Unhandled
|
||||
case Sema::TDK_MiscellaneousDeductionFailure:
|
||||
case Sema::TDK_AlreadyDiagnosed:
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
@ -772,7 +770,6 @@ TemplateParameter DeductionFailureInfo::getTemplateParameter() {
|
|||
|
||||
// Unhandled
|
||||
case Sema::TDK_MiscellaneousDeductionFailure:
|
||||
case Sema::TDK_AlreadyDiagnosed:
|
||||
break;
|
||||
}
|
||||
|
||||
|
@ -808,7 +805,6 @@ TemplateArgumentList *DeductionFailureInfo::getTemplateArgumentList() {
|
|||
|
||||
// Unhandled
|
||||
case Sema::TDK_MiscellaneousDeductionFailure:
|
||||
case Sema::TDK_AlreadyDiagnosed:
|
||||
break;
|
||||
}
|
||||
|
||||
|
@ -840,7 +836,6 @@ const TemplateArgument *DeductionFailureInfo::getFirstArg() {
|
|||
|
||||
// Unhandled
|
||||
case Sema::TDK_MiscellaneousDeductionFailure:
|
||||
case Sema::TDK_AlreadyDiagnosed:
|
||||
break;
|
||||
}
|
||||
|
||||
|
@ -872,7 +867,6 @@ const TemplateArgument *DeductionFailureInfo::getSecondArg() {
|
|||
|
||||
// Unhandled
|
||||
case Sema::TDK_MiscellaneousDeductionFailure:
|
||||
case Sema::TDK_AlreadyDiagnosed:
|
||||
break;
|
||||
}
|
||||
|
||||
|
@ -11488,7 +11482,6 @@ static unsigned RankDeductionFailure(const DeductionFailureInfo &DFI) {
|
|||
switch ((Sema::TemplateDeductionResult)DFI.Result) {
|
||||
case Sema::TDK_Success:
|
||||
case Sema::TDK_NonDependentConversionFailure:
|
||||
case Sema::TDK_AlreadyDiagnosed:
|
||||
llvm_unreachable("non-deduction failure while diagnosing bad deduction");
|
||||
|
||||
case Sema::TDK_Invalid:
|
||||
|
|
|
@ -2308,14 +2308,11 @@ Sema::ActOnObjCForCollectionStmt(SourceLocation ForLoc,
|
|||
|
||||
// If the type contained 'auto', deduce the 'auto' to 'id'.
|
||||
if (FirstType->getContainedAutoType()) {
|
||||
SourceLocation Loc = D->getLocation();
|
||||
OpaqueValueExpr OpaqueId(Loc, Context.getObjCIdType(), VK_PRValue);
|
||||
OpaqueValueExpr OpaqueId(D->getLocation(), Context.getObjCIdType(),
|
||||
VK_PRValue);
|
||||
Expr *DeducedInit = &OpaqueId;
|
||||
TemplateDeductionInfo Info(Loc);
|
||||
FirstType = QualType();
|
||||
TemplateDeductionResult Result = DeduceAutoType(
|
||||
D->getTypeSourceInfo()->getTypeLoc(), DeducedInit, FirstType, Info);
|
||||
if (Result != TDK_Success && Result != TDK_AlreadyDiagnosed)
|
||||
if (DeduceAutoType(D->getTypeSourceInfo(), DeducedInit, FirstType) ==
|
||||
DAR_Failed)
|
||||
DiagnoseAutoDeductionFailure(D, DeducedInit);
|
||||
if (FirstType.isNull()) {
|
||||
D->setInvalidDecl();
|
||||
|
@ -2379,16 +2376,10 @@ static bool FinishForRangeVarDecl(Sema &SemaRef, VarDecl *Decl, Expr *Init,
|
|||
// Deduce the type for the iterator variable now rather than leaving it to
|
||||
// AddInitializerToDecl, so we can produce a more suitable diagnostic.
|
||||
QualType InitType;
|
||||
if (!isa<InitListExpr>(Init) && Init->getType()->isVoidType()) {
|
||||
if ((!isa<InitListExpr>(Init) && Init->getType()->isVoidType()) ||
|
||||
SemaRef.DeduceAutoType(Decl->getTypeSourceInfo(), Init, InitType) ==
|
||||
Sema::DAR_Failed)
|
||||
SemaRef.Diag(Loc, DiagID) << Init->getType();
|
||||
} else {
|
||||
TemplateDeductionInfo Info(Init->getExprLoc());
|
||||
Sema::TemplateDeductionResult Result = SemaRef.DeduceAutoType(
|
||||
Decl->getTypeSourceInfo()->getTypeLoc(), Init, InitType, Info);
|
||||
if (Result != Sema::TDK_Success && Result != Sema::TDK_AlreadyDiagnosed)
|
||||
SemaRef.Diag(Loc, DiagID) << Init->getType();
|
||||
}
|
||||
|
||||
if (InitType.isNull()) {
|
||||
Decl->setInvalidDecl();
|
||||
return true;
|
||||
|
@ -3778,13 +3769,17 @@ TypeLoc Sema::getReturnTypeLoc(FunctionDecl *FD) const {
|
|||
/// C++1y [dcl.spec.auto]p6.
|
||||
bool Sema::DeduceFunctionTypeFromReturnExpr(FunctionDecl *FD,
|
||||
SourceLocation ReturnLoc,
|
||||
Expr *RetExpr, const AutoType *AT) {
|
||||
Expr *&RetExpr,
|
||||
const AutoType *AT) {
|
||||
// If this is the conversion function for a lambda, we choose to deduce its
|
||||
// type from the corresponding call operator, not from the synthesized return
|
||||
// statement within it. See Sema::DeduceReturnType.
|
||||
if (isLambdaConversionOperator(FD))
|
||||
return false;
|
||||
|
||||
TypeLoc OrigResultType = getReturnTypeLoc(FD);
|
||||
QualType Deduced;
|
||||
|
||||
if (RetExpr && isa<InitListExpr>(RetExpr)) {
|
||||
// If the deduction is for a return statement and the initializer is
|
||||
// a braced-init-list, the program is ill-formed.
|
||||
|
@ -3804,74 +3799,87 @@ bool Sema::DeduceFunctionTypeFromReturnExpr(FunctionDecl *FD,
|
|||
return false;
|
||||
}
|
||||
|
||||
TypeLoc OrigResultType = getReturnTypeLoc(FD);
|
||||
// In the case of a return with no operand, the initializer is considered
|
||||
// to be void().
|
||||
CXXScalarValueInitExpr VoidVal(Context.VoidTy, nullptr, SourceLocation());
|
||||
if (!RetExpr) {
|
||||
// For a function with a deduced result type to return with omitted
|
||||
// expression, the result type as written must be 'auto' or
|
||||
// 'decltype(auto)', possibly cv-qualified or constrained, but not
|
||||
// ref-qualified.
|
||||
if (!OrigResultType.getType()->getAs<AutoType>()) {
|
||||
Diag(ReturnLoc, diag::err_auto_fn_return_void_but_not_auto)
|
||||
<< OrigResultType.getType();
|
||||
return true;
|
||||
}
|
||||
RetExpr = &VoidVal;
|
||||
}
|
||||
|
||||
QualType Deduced = AT->getDeducedType();
|
||||
{
|
||||
if (RetExpr) {
|
||||
// Otherwise, [...] deduce a value for U using the rules of template
|
||||
// argument deduction.
|
||||
TemplateDeductionInfo Info(RetExpr->getExprLoc());
|
||||
TemplateDeductionResult Res =
|
||||
DeduceAutoType(OrigResultType, RetExpr, Deduced, Info);
|
||||
if (Res != TDK_Success && FD->isInvalidDecl())
|
||||
return true;
|
||||
switch (Res) {
|
||||
case TDK_Success:
|
||||
break;
|
||||
case TDK_AlreadyDiagnosed:
|
||||
return true;
|
||||
case TDK_Inconsistent: {
|
||||
// If a function with a declared return type that contains a placeholder
|
||||
// type has multiple return statements, the return type is deduced for
|
||||
// each return statement. [...] if the type deduced is not the same in
|
||||
// each deduction, the program is ill-formed.
|
||||
const LambdaScopeInfo *LambdaSI = getCurLambda();
|
||||
if (LambdaSI && LambdaSI->HasImplicitReturnType)
|
||||
Diag(ReturnLoc, diag::err_typecheck_missing_return_type_incompatible)
|
||||
<< Info.SecondArg << Info.FirstArg << true /*IsLambda*/;
|
||||
else
|
||||
Diag(ReturnLoc, diag::err_auto_fn_different_deductions)
|
||||
<< (AT->isDecltypeAuto() ? 1 : 0) << Info.SecondArg
|
||||
<< Info.FirstArg;
|
||||
return true;
|
||||
}
|
||||
default:
|
||||
Diag(RetExpr->getExprLoc(), diag::err_auto_fn_deduction_failure)
|
||||
<< OrigResultType.getType() << RetExpr->getType();
|
||||
return true;
|
||||
}
|
||||
}
|
||||
DeduceAutoResult DAR = DeduceAutoType(OrigResultType, RetExpr, Deduced);
|
||||
|
||||
// If a local type is part of the returned type, mark its fields as
|
||||
// referenced.
|
||||
LocalTypedefNameReferencer(*this).TraverseType(RetExpr->getType());
|
||||
if (DAR == DAR_Failed && !FD->isInvalidDecl())
|
||||
Diag(RetExpr->getExprLoc(), diag::err_auto_fn_deduction_failure)
|
||||
<< OrigResultType.getType() << RetExpr->getType();
|
||||
|
||||
if (DAR != DAR_Succeeded)
|
||||
return true;
|
||||
|
||||
// If a local type is part of the returned type, mark its fields as
|
||||
// referenced.
|
||||
LocalTypedefNameReferencer Referencer(*this);
|
||||
Referencer.TraverseType(RetExpr->getType());
|
||||
} else {
|
||||
// For a function with a deduced result type to return void,
|
||||
// the result type as written must be 'auto' or 'decltype(auto)',
|
||||
// possibly cv-qualified or constrained, but not ref-qualified.
|
||||
if (!OrigResultType.getType()->getAs<AutoType>()) {
|
||||
Diag(ReturnLoc, diag::err_auto_fn_return_void_but_not_auto)
|
||||
<< OrigResultType.getType();
|
||||
return true;
|
||||
}
|
||||
// In the case of a return with no operand, the initializer is considered
|
||||
// to be 'void()'.
|
||||
Expr *Dummy = new (Context) CXXScalarValueInitExpr(
|
||||
Context.VoidTy,
|
||||
Context.getTrivialTypeSourceInfo(Context.VoidTy, ReturnLoc), ReturnLoc);
|
||||
DeduceAutoResult DAR = DeduceAutoType(OrigResultType, Dummy, Deduced);
|
||||
|
||||
if (DAR == DAR_Failed && !FD->isInvalidDecl())
|
||||
Diag(ReturnLoc, diag::err_auto_fn_deduction_failure)
|
||||
<< OrigResultType.getType() << Dummy->getType();
|
||||
|
||||
if (DAR != DAR_Succeeded)
|
||||
return true;
|
||||
}
|
||||
|
||||
// CUDA: Kernel function must have 'void' return type.
|
||||
if (getLangOpts().CUDA && FD->hasAttr<CUDAGlobalAttr>() &&
|
||||
!Deduced->isVoidType()) {
|
||||
Diag(FD->getLocation(), diag::err_kern_type_not_void_return)
|
||||
<< FD->getType() << FD->getSourceRange();
|
||||
return true;
|
||||
}
|
||||
if (getLangOpts().CUDA)
|
||||
if (FD->hasAttr<CUDAGlobalAttr>() && !Deduced->isVoidType()) {
|
||||
Diag(FD->getLocation(), diag::err_kern_type_not_void_return)
|
||||
<< FD->getType() << FD->getSourceRange();
|
||||
return true;
|
||||
}
|
||||
|
||||
if (!FD->isInvalidDecl() && AT->getDeducedType() != Deduced)
|
||||
// If a function with a declared return type that contains a placeholder type
|
||||
// has multiple return statements, the return type is deduced for each return
|
||||
// statement. [...] if the type deduced is not the same in each deduction,
|
||||
// the program is ill-formed.
|
||||
QualType DeducedT = AT->getDeducedType();
|
||||
if (!DeducedT.isNull() && !FD->isInvalidDecl()) {
|
||||
AutoType *NewAT = Deduced->getContainedAutoType();
|
||||
// It is possible that NewAT->getDeducedType() is null. When that happens,
|
||||
// we should not crash, instead we ignore this deduction.
|
||||
if (NewAT->getDeducedType().isNull())
|
||||
return false;
|
||||
|
||||
CanQualType OldDeducedType = Context.getCanonicalFunctionResultType(
|
||||
DeducedT);
|
||||
CanQualType NewDeducedType = Context.getCanonicalFunctionResultType(
|
||||
NewAT->getDeducedType());
|
||||
if (!FD->isDependentContext() && OldDeducedType != NewDeducedType) {
|
||||
const LambdaScopeInfo *LambdaSI = getCurLambda();
|
||||
if (LambdaSI && LambdaSI->HasImplicitReturnType) {
|
||||
Diag(ReturnLoc, diag::err_typecheck_missing_return_type_incompatible)
|
||||
<< NewAT->getDeducedType() << DeducedT
|
||||
<< true /*IsLambda*/;
|
||||
} else {
|
||||
Diag(ReturnLoc, diag::err_auto_fn_different_deductions)
|
||||
<< (AT->isDecltypeAuto() ? 1 : 0)
|
||||
<< NewAT->getDeducedType() << DeducedT;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
} else if (!FD->isInvalidDecl()) {
|
||||
// Update all declarations of the function to have the deduced return type.
|
||||
Context.adjustDeducedFunctionResultType(FD, Deduced);
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
|
|
@ -6884,6 +6884,7 @@ ExprResult Sema::CheckTemplateArgument(NonTypeTemplateParmDecl *Param,
|
|||
// When checking a deduced template argument, deduce from its type even if
|
||||
// the type is dependent, in order to check the types of non-type template
|
||||
// arguments line up properly in partial ordering.
|
||||
Optional<unsigned> Depth = Param->getDepth() + 1;
|
||||
Expr *DeductionArg = Arg;
|
||||
if (auto *PE = dyn_cast<PackExpansionExpr>(DeductionArg))
|
||||
DeductionArg = PE->getPattern();
|
||||
|
@ -6899,27 +6900,20 @@ ExprResult Sema::CheckTemplateArgument(NonTypeTemplateParmDecl *Param,
|
|||
DeduceTemplateSpecializationFromInitializer(TSI, Entity, Kind, Inits);
|
||||
if (ParamType.isNull())
|
||||
return ExprError();
|
||||
} else {
|
||||
TemplateDeductionInfo Info(DeductionArg->getExprLoc(),
|
||||
Param->getDepth() + 1);
|
||||
ParamType = QualType();
|
||||
TemplateDeductionResult Result =
|
||||
DeduceAutoType(TSI->getTypeLoc(), DeductionArg, ParamType, Info,
|
||||
/*DependentDeduction=*/true,
|
||||
// We do not check constraints right now because the
|
||||
// immediately-declared constraint of the auto type is
|
||||
// also an associated constraint, and will be checked
|
||||
// along with the other associated constraints after
|
||||
// checking the template argument list.
|
||||
/*IgnoreConstraints=*/true);
|
||||
if (Result != TDK_Success && Result != TDK_AlreadyDiagnosed) {
|
||||
Diag(Arg->getExprLoc(),
|
||||
diag::err_non_type_template_parm_type_deduction_failure)
|
||||
<< Param->getDeclName() << Param->getType() << Arg->getType()
|
||||
<< Arg->getSourceRange();
|
||||
Diag(Param->getLocation(), diag::note_template_param_here);
|
||||
return ExprError();
|
||||
}
|
||||
} else if (DeduceAutoType(
|
||||
TSI, DeductionArg, ParamType, Depth,
|
||||
// We do not check constraints right now because the
|
||||
// immediately-declared constraint of the auto type is also
|
||||
// an associated constraint, and will be checked along with
|
||||
// the other associated constraints after checking the
|
||||
// template argument list.
|
||||
/*IgnoreConstraints=*/true) == DAR_Failed) {
|
||||
Diag(Arg->getExprLoc(),
|
||||
diag::err_non_type_template_parm_type_deduction_failure)
|
||||
<< Param->getDeclName() << Param->getType() << Arg->getType()
|
||||
<< Arg->getSourceRange();
|
||||
Diag(Param->getLocation(), diag::note_template_param_here);
|
||||
return ExprError();
|
||||
}
|
||||
// CheckNonTypeTemplateParameterType will produce a diagnostic if there's
|
||||
// an error. The error message normally references the parameter
|
||||
|
|
|
@ -236,13 +236,11 @@ checkDeducedTemplateArguments(ASTContext &Context,
|
|||
case TemplateArgument::Null:
|
||||
llvm_unreachable("Non-deduced template arguments handled above");
|
||||
|
||||
case TemplateArgument::Type: {
|
||||
case TemplateArgument::Type:
|
||||
// If two template type arguments have the same type, they're compatible.
|
||||
QualType TX = X.getAsType(), TY = Y.getAsType();
|
||||
if (Y.getKind() == TemplateArgument::Type && Context.hasSameType(TX, TY))
|
||||
return DeducedTemplateArgument(Context.getCommonSugaredType(TX, TY),
|
||||
X.wasDeducedFromArrayBound() ||
|
||||
Y.wasDeducedFromArrayBound());
|
||||
if (Y.getKind() == TemplateArgument::Type &&
|
||||
Context.hasSameType(X.getAsType(), Y.getAsType()))
|
||||
return X;
|
||||
|
||||
// If one of the two arguments was deduced from an array bound, the other
|
||||
// supersedes it.
|
||||
|
@ -251,7 +249,6 @@ checkDeducedTemplateArguments(ASTContext &Context,
|
|||
|
||||
// The arguments are not compatible.
|
||||
return DeducedTemplateArgument();
|
||||
}
|
||||
|
||||
case TemplateArgument::Integral:
|
||||
// If we deduced a constant in one case and either a dependent expression or
|
||||
|
@ -329,9 +326,7 @@ checkDeducedTemplateArguments(ASTContext &Context,
|
|||
// If we deduced a null pointer and a dependent expression, keep the
|
||||
// null pointer.
|
||||
if (Y.getKind() == TemplateArgument::Expression)
|
||||
return TemplateArgument(Context.getCommonSugaredType(
|
||||
X.getNullPtrType(), Y.getAsExpr()->getType()),
|
||||
true);
|
||||
return X;
|
||||
|
||||
// If we deduced a null pointer and an integral constant, keep the
|
||||
// integral constant.
|
||||
|
@ -340,9 +335,7 @@ checkDeducedTemplateArguments(ASTContext &Context,
|
|||
|
||||
// If we deduced two null pointers, they are the same.
|
||||
if (Y.getKind() == TemplateArgument::NullPtr)
|
||||
return TemplateArgument(
|
||||
Context.getCommonSugaredType(X.getNullPtrType(), Y.getNullPtrType()),
|
||||
true);
|
||||
return X;
|
||||
|
||||
// All other combinations are incompatible.
|
||||
return DeducedTemplateArgument();
|
||||
|
@ -4581,9 +4574,42 @@ namespace {
|
|||
|
||||
} // namespace
|
||||
|
||||
static bool CheckDeducedPlaceholderConstraints(Sema &S, const AutoType &Type,
|
||||
AutoTypeLoc TypeLoc,
|
||||
QualType Deduced) {
|
||||
Sema::DeduceAutoResult
|
||||
Sema::DeduceAutoType(TypeSourceInfo *Type, Expr *&Init, QualType &Result,
|
||||
Optional<unsigned> DependentDeductionDepth,
|
||||
bool IgnoreConstraints) {
|
||||
return DeduceAutoType(Type->getTypeLoc(), Init, Result,
|
||||
DependentDeductionDepth, IgnoreConstraints);
|
||||
}
|
||||
|
||||
/// Attempt to produce an informative diagostic explaining why auto deduction
|
||||
/// failed.
|
||||
/// \return \c true if diagnosed, \c false if not.
|
||||
static bool diagnoseAutoDeductionFailure(Sema &S,
|
||||
Sema::TemplateDeductionResult TDK,
|
||||
TemplateDeductionInfo &Info,
|
||||
ArrayRef<SourceRange> Ranges) {
|
||||
switch (TDK) {
|
||||
case Sema::TDK_Inconsistent: {
|
||||
// Inconsistent deduction means we were deducing from an initializer list.
|
||||
auto D = S.Diag(Info.getLocation(), diag::err_auto_inconsistent_deduction);
|
||||
D << Info.FirstArg << Info.SecondArg;
|
||||
for (auto R : Ranges)
|
||||
D << R;
|
||||
return true;
|
||||
}
|
||||
|
||||
// FIXME: Are there other cases for which a custom diagnostic is more useful
|
||||
// than the basic "types don't match" diagnostic?
|
||||
|
||||
default:
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
static Sema::DeduceAutoResult
|
||||
CheckDeducedPlaceholderConstraints(Sema &S, const AutoType &Type,
|
||||
AutoTypeLoc TypeLoc, QualType Deduced) {
|
||||
ConstraintSatisfaction Satisfaction;
|
||||
ConceptDecl *Concept = Type.getTypeConstraintConcept();
|
||||
TemplateArgumentListInfo TemplateArgs(TypeLoc.getLAngleLoc(),
|
||||
|
@ -4598,13 +4624,13 @@ static bool CheckDeducedPlaceholderConstraints(Sema &S, const AutoType &Type,
|
|||
llvm::SmallVector<TemplateArgument, 4> Converted;
|
||||
if (S.CheckTemplateArgumentList(Concept, SourceLocation(), TemplateArgs,
|
||||
/*PartialTemplateArgs=*/false, Converted))
|
||||
return true;
|
||||
return Sema::DAR_FailedAlreadyDiagnosed;
|
||||
MultiLevelTemplateArgumentList MLTAL;
|
||||
MLTAL.addOuterTemplateArguments(Converted);
|
||||
if (S.CheckConstraintSatisfaction(Concept, {Concept->getConstraintExpr()},
|
||||
MLTAL, TypeLoc.getLocalSourceRange(),
|
||||
Satisfaction))
|
||||
return true;
|
||||
return Sema::DAR_FailedAlreadyDiagnosed;
|
||||
if (!Satisfaction.IsSatisfied) {
|
||||
std::string Buf;
|
||||
llvm::raw_string_ostream OS(Buf);
|
||||
|
@ -4618,11 +4644,11 @@ static bool CheckDeducedPlaceholderConstraints(Sema &S, const AutoType &Type,
|
|||
OS.flush();
|
||||
S.Diag(TypeLoc.getConceptNameLoc(),
|
||||
diag::err_placeholder_constraints_not_satisfied)
|
||||
<< Deduced << Buf << TypeLoc.getLocalSourceRange();
|
||||
<< Deduced << Buf << TypeLoc.getLocalSourceRange();
|
||||
S.DiagnoseUnsatisfiedConstraint(Satisfaction);
|
||||
return true;
|
||||
return Sema::DAR_FailedAlreadyDiagnosed;
|
||||
}
|
||||
return false;
|
||||
return Sema::DAR_Succeeded;
|
||||
}
|
||||
|
||||
/// Deduce the type for an auto type-specifier (C++11 [dcl.spec.auto]p6)
|
||||
|
@ -4635,165 +4661,184 @@ static bool CheckDeducedPlaceholderConstraints(Sema &S, const AutoType &Type,
|
|||
/// \param Init the initializer for the variable whose type is to be deduced.
|
||||
/// \param Result if type deduction was successful, this will be set to the
|
||||
/// deduced type.
|
||||
/// \param Info the argument will be updated to provide additional information
|
||||
/// about template argument deduction.
|
||||
/// \param DependentDeduction Set if we should permit deduction in
|
||||
/// \param DependentDeductionDepth Set if we should permit deduction in
|
||||
/// dependent cases. This is necessary for template partial ordering with
|
||||
/// 'auto' template parameters. The template parameter depth to be used
|
||||
/// should be specified in the 'Info' parameter.
|
||||
/// 'auto' template parameters. The value specified is the template
|
||||
/// parameter depth at which we should perform 'auto' deduction.
|
||||
/// \param IgnoreConstraints Set if we should not fail if the deduced type does
|
||||
/// not satisfy the type-constraint in the auto type.
|
||||
Sema::TemplateDeductionResult Sema::DeduceAutoType(TypeLoc Type, Expr *Init,
|
||||
QualType &Result,
|
||||
TemplateDeductionInfo &Info,
|
||||
bool DependentDeduction,
|
||||
bool IgnoreConstraints) {
|
||||
assert(DependentDeduction || Info.getDeducedDepth() == 0);
|
||||
Sema::DeduceAutoResult
|
||||
Sema::DeduceAutoType(TypeLoc Type, Expr *&Init, QualType &Result,
|
||||
Optional<unsigned> DependentDeductionDepth,
|
||||
bool IgnoreConstraints) {
|
||||
if (Init->containsErrors())
|
||||
return TDK_AlreadyDiagnosed;
|
||||
|
||||
const AutoType *AT = Type.getType()->getContainedAutoType();
|
||||
assert(AT);
|
||||
|
||||
if (Init->getType()->isNonOverloadPlaceholderType() || AT->isDecltypeAuto()) {
|
||||
return DAR_FailedAlreadyDiagnosed;
|
||||
if (Init->getType()->isNonOverloadPlaceholderType()) {
|
||||
ExprResult NonPlaceholder = CheckPlaceholderExpr(Init);
|
||||
if (NonPlaceholder.isInvalid())
|
||||
return TDK_AlreadyDiagnosed;
|
||||
return DAR_FailedAlreadyDiagnosed;
|
||||
Init = NonPlaceholder.get();
|
||||
}
|
||||
|
||||
DependentAuto DependentResult = {
|
||||
/*.IsPack = */ (bool)Type.getAs<PackExpansionTypeLoc>()};
|
||||
|
||||
if (!DependentDeduction &&
|
||||
if (!DependentDeductionDepth &&
|
||||
(Type.getType()->isDependentType() || Init->isTypeDependent() ||
|
||||
Init->containsUnexpandedParameterPack())) {
|
||||
Result = SubstituteDeducedTypeTransform(*this, DependentResult).Apply(Type);
|
||||
assert(!Result.isNull() && "substituting DependentTy can't fail");
|
||||
return TDK_Success;
|
||||
return DAR_Succeeded;
|
||||
}
|
||||
|
||||
auto *InitList = dyn_cast<InitListExpr>(Init);
|
||||
if (!getLangOpts().CPlusPlus && InitList) {
|
||||
Diag(Init->getBeginLoc(), diag::err_auto_init_list_from_c);
|
||||
return TDK_AlreadyDiagnosed;
|
||||
// Find the depth of template parameter to synthesize.
|
||||
unsigned Depth = DependentDeductionDepth.value_or(0);
|
||||
|
||||
// If this is a 'decltype(auto)' specifier, do the decltype dance.
|
||||
// Since 'decltype(auto)' can only occur at the top of the type, we
|
||||
// don't need to go digging for it.
|
||||
if (const AutoType *AT = Type.getType()->getAs<AutoType>()) {
|
||||
if (AT->isDecltypeAuto()) {
|
||||
if (isa<InitListExpr>(Init)) {
|
||||
Diag(Init->getBeginLoc(), diag::err_decltype_auto_initializer_list);
|
||||
return DAR_FailedAlreadyDiagnosed;
|
||||
}
|
||||
|
||||
ExprResult ER = CheckPlaceholderExpr(Init);
|
||||
if (ER.isInvalid())
|
||||
return DAR_FailedAlreadyDiagnosed;
|
||||
QualType Deduced = getDecltypeForExpr(ER.get());
|
||||
assert(!Deduced.isNull());
|
||||
if (AT->isConstrained() && !IgnoreConstraints) {
|
||||
auto ConstraintsResult =
|
||||
CheckDeducedPlaceholderConstraints(*this, *AT,
|
||||
Type.getContainedAutoTypeLoc(),
|
||||
Deduced);
|
||||
if (ConstraintsResult != DAR_Succeeded)
|
||||
return ConstraintsResult;
|
||||
}
|
||||
Result = SubstituteDeducedTypeTransform(*this, Deduced).Apply(Type);
|
||||
if (Result.isNull())
|
||||
return DAR_FailedAlreadyDiagnosed;
|
||||
return DAR_Succeeded;
|
||||
} else if (!getLangOpts().CPlusPlus) {
|
||||
if (isa<InitListExpr>(Init)) {
|
||||
Diag(Init->getBeginLoc(), diag::err_auto_init_list_from_c);
|
||||
return DAR_FailedAlreadyDiagnosed;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
SourceLocation Loc = Init->getExprLoc();
|
||||
|
||||
LocalInstantiationScope InstScope(*this);
|
||||
|
||||
// Build template<class TemplParam> void Func(FuncParam);
|
||||
TemplateTypeParmDecl *TemplParam = TemplateTypeParmDecl::Create(
|
||||
Context, nullptr, SourceLocation(), Loc, Depth, 0, nullptr, false, false,
|
||||
false);
|
||||
QualType TemplArg = QualType(TemplParam->getTypeForDecl(), 0);
|
||||
NamedDecl *TemplParamPtr = TemplParam;
|
||||
FixedSizeTemplateParameterListStorage<1, false> TemplateParamsSt(
|
||||
Context, Loc, Loc, TemplParamPtr, Loc, nullptr);
|
||||
|
||||
QualType FuncParam =
|
||||
SubstituteDeducedTypeTransform(*this, TemplArg, /*UseTypeSugar*/ true)
|
||||
.Apply(Type);
|
||||
assert(!FuncParam.isNull() &&
|
||||
"substituting template parameter for 'auto' failed");
|
||||
|
||||
// Deduce type of TemplParam in Func(Init)
|
||||
SmallVector<DeducedTemplateArgument, 1> Deduced;
|
||||
Deduced.resize(1);
|
||||
|
||||
TemplateDeductionInfo Info(Loc, Depth);
|
||||
|
||||
// If deduction failed, don't diagnose if the initializer is dependent; it
|
||||
// might acquire a matching type in the instantiation.
|
||||
auto DeductionFailed = [&](TemplateDeductionResult TDK) {
|
||||
auto DeductionFailed = [&](TemplateDeductionResult TDK,
|
||||
ArrayRef<SourceRange> Ranges) -> DeduceAutoResult {
|
||||
if (Init->isTypeDependent()) {
|
||||
Result =
|
||||
SubstituteDeducedTypeTransform(*this, DependentResult).Apply(Type);
|
||||
assert(!Result.isNull() && "substituting DependentTy can't fail");
|
||||
return TDK_Success;
|
||||
return DAR_Succeeded;
|
||||
}
|
||||
return TDK;
|
||||
if (diagnoseAutoDeductionFailure(*this, TDK, Info, Ranges))
|
||||
return DAR_FailedAlreadyDiagnosed;
|
||||
return DAR_Failed;
|
||||
};
|
||||
|
||||
SmallVector<OriginalCallArg, 4> OriginalCallArgs;
|
||||
|
||||
QualType DeducedType;
|
||||
// If this is a 'decltype(auto)' specifier, do the decltype dance.
|
||||
if (AT->isDecltypeAuto()) {
|
||||
if (InitList) {
|
||||
Diag(Init->getBeginLoc(), diag::err_decltype_auto_initializer_list);
|
||||
return TDK_AlreadyDiagnosed;
|
||||
}
|
||||
InitListExpr *InitList = dyn_cast<InitListExpr>(Init);
|
||||
if (InitList) {
|
||||
// Notionally, we substitute std::initializer_list<T> for 'auto' and deduce
|
||||
// against that. Such deduction only succeeds if removing cv-qualifiers and
|
||||
// references results in std::initializer_list<T>.
|
||||
if (!Type.getType().getNonReferenceType()->getAs<AutoType>())
|
||||
return DAR_Failed;
|
||||
|
||||
DeducedType = getDecltypeForExpr(Init);
|
||||
assert(!DeducedType.isNull());
|
||||
} else {
|
||||
LocalInstantiationScope InstScope(*this);
|
||||
// Resolving a core issue: a braced-init-list containing any designators is
|
||||
// a non-deduced context.
|
||||
for (Expr *E : InitList->inits())
|
||||
if (isa<DesignatedInitExpr>(E))
|
||||
return DAR_Failed;
|
||||
|
||||
// Build template<class TemplParam> void Func(FuncParam);
|
||||
SourceLocation Loc = Init->getExprLoc();
|
||||
TemplateTypeParmDecl *TemplParam = TemplateTypeParmDecl::Create(
|
||||
Context, nullptr, SourceLocation(), Loc, Info.getDeducedDepth(), 0,
|
||||
nullptr, false, false, false);
|
||||
QualType TemplArg = QualType(TemplParam->getTypeForDecl(), 0);
|
||||
NamedDecl *TemplParamPtr = TemplParam;
|
||||
FixedSizeTemplateParameterListStorage<1, false> TemplateParamsSt(
|
||||
Context, Loc, Loc, TemplParamPtr, Loc, nullptr);
|
||||
SourceRange DeducedFromInitRange;
|
||||
for (unsigned i = 0, e = InitList->getNumInits(); i < e; ++i) {
|
||||
Expr *Init = InitList->getInit(i);
|
||||
|
||||
if (InitList) {
|
||||
// Notionally, we substitute std::initializer_list<T> for 'auto' and
|
||||
// deduce against that. Such deduction only succeeds if removing
|
||||
// cv-qualifiers and references results in std::initializer_list<T>.
|
||||
if (!Type.getType().getNonReferenceType()->getAs<AutoType>())
|
||||
return TDK_Invalid;
|
||||
|
||||
SourceRange DeducedFromInitRange;
|
||||
for (Expr *Init : InitList->inits()) {
|
||||
// Resolving a core issue: a braced-init-list containing any designators
|
||||
// is a non-deduced context.
|
||||
if (isa<DesignatedInitExpr>(Init))
|
||||
return TDK_Invalid;
|
||||
if (auto TDK = DeduceTemplateArgumentsFromCallArgument(
|
||||
*this, TemplateParamsSt.get(), 0, TemplArg, Init, Info, Deduced,
|
||||
OriginalCallArgs, /*Decomposed=*/true,
|
||||
/*ArgIdx=*/0, /*TDF=*/0)) {
|
||||
if (TDK == TDK_Inconsistent) {
|
||||
Diag(Info.getLocation(), diag::err_auto_inconsistent_deduction)
|
||||
<< Info.FirstArg << Info.SecondArg << DeducedFromInitRange
|
||||
<< Init->getSourceRange();
|
||||
return DeductionFailed(TDK_AlreadyDiagnosed);
|
||||
}
|
||||
return DeductionFailed(TDK);
|
||||
}
|
||||
|
||||
if (DeducedFromInitRange.isInvalid() &&
|
||||
Deduced[0].getKind() != TemplateArgument::Null)
|
||||
DeducedFromInitRange = Init->getSourceRange();
|
||||
}
|
||||
} else {
|
||||
if (!getLangOpts().CPlusPlus && Init->refersToBitField()) {
|
||||
Diag(Loc, diag::err_auto_bitfield);
|
||||
return TDK_AlreadyDiagnosed;
|
||||
}
|
||||
QualType FuncParam =
|
||||
SubstituteDeducedTypeTransform(*this, TemplArg).Apply(Type);
|
||||
assert(!FuncParam.isNull() &&
|
||||
"substituting template parameter for 'auto' failed");
|
||||
if (auto TDK = DeduceTemplateArgumentsFromCallArgument(
|
||||
*this, TemplateParamsSt.get(), 0, FuncParam, Init, Info, Deduced,
|
||||
OriginalCallArgs, /*Decomposed=*/false, /*ArgIdx=*/0, /*TDF=*/0))
|
||||
return DeductionFailed(TDK);
|
||||
*this, TemplateParamsSt.get(), 0, TemplArg, Init,
|
||||
Info, Deduced, OriginalCallArgs, /*Decomposed*/ true,
|
||||
/*ArgIdx*/ 0, /*TDF*/ 0))
|
||||
return DeductionFailed(TDK, {DeducedFromInitRange,
|
||||
Init->getSourceRange()});
|
||||
|
||||
if (DeducedFromInitRange.isInvalid() &&
|
||||
Deduced[0].getKind() != TemplateArgument::Null)
|
||||
DeducedFromInitRange = Init->getSourceRange();
|
||||
}
|
||||
} else {
|
||||
if (!getLangOpts().CPlusPlus && Init->refersToBitField()) {
|
||||
Diag(Loc, diag::err_auto_bitfield);
|
||||
return DAR_FailedAlreadyDiagnosed;
|
||||
}
|
||||
|
||||
// Could be null if somehow 'auto' appears in a non-deduced context.
|
||||
if (Deduced[0].getKind() != TemplateArgument::Type)
|
||||
return DeductionFailed(TDK_Incomplete);
|
||||
DeducedType = Deduced[0].getAsType();
|
||||
|
||||
if (InitList) {
|
||||
DeducedType = BuildStdInitializerList(DeducedType, Loc);
|
||||
if (DeducedType.isNull())
|
||||
return TDK_AlreadyDiagnosed;
|
||||
}
|
||||
if (auto TDK = DeduceTemplateArgumentsFromCallArgument(
|
||||
*this, TemplateParamsSt.get(), 0, FuncParam, Init, Info, Deduced,
|
||||
OriginalCallArgs, /*Decomposed*/ false, /*ArgIdx*/ 0, /*TDF*/ 0))
|
||||
return DeductionFailed(TDK, {});
|
||||
}
|
||||
|
||||
if (!Result.isNull()) {
|
||||
if (!Context.hasSameType(DeducedType, Result)) {
|
||||
Info.FirstArg = Result;
|
||||
Info.SecondArg = DeducedType;
|
||||
return DeductionFailed(TDK_Inconsistent);
|
||||
}
|
||||
DeducedType = Context.getCommonSugaredType(Result, DeducedType);
|
||||
// Could be null if somehow 'auto' appears in a non-deduced context.
|
||||
if (Deduced[0].getKind() != TemplateArgument::Type)
|
||||
return DeductionFailed(TDK_Incomplete, {});
|
||||
|
||||
QualType DeducedType = Deduced[0].getAsType();
|
||||
|
||||
if (InitList) {
|
||||
DeducedType = BuildStdInitializerList(DeducedType, Loc);
|
||||
if (DeducedType.isNull())
|
||||
return DAR_FailedAlreadyDiagnosed;
|
||||
}
|
||||
|
||||
if (AT->isConstrained() && !IgnoreConstraints &&
|
||||
CheckDeducedPlaceholderConstraints(
|
||||
*this, *AT, Type.getContainedAutoTypeLoc(), DeducedType))
|
||||
return TDK_AlreadyDiagnosed;
|
||||
QualType MaybeAuto = Type.getType().getNonReferenceType();
|
||||
while (MaybeAuto->isPointerType())
|
||||
MaybeAuto = MaybeAuto->getPointeeType();
|
||||
if (const auto *AT = MaybeAuto->getAs<AutoType>()) {
|
||||
if (AT->isConstrained() && !IgnoreConstraints) {
|
||||
auto ConstraintsResult = CheckDeducedPlaceholderConstraints(
|
||||
*this, *AT, Type.getContainedAutoTypeLoc(), DeducedType);
|
||||
if (ConstraintsResult != DAR_Succeeded)
|
||||
return ConstraintsResult;
|
||||
}
|
||||
}
|
||||
|
||||
Result = SubstituteDeducedTypeTransform(*this, DeducedType).Apply(Type);
|
||||
if (Result.isNull())
|
||||
return TDK_AlreadyDiagnosed;
|
||||
return DAR_FailedAlreadyDiagnosed;
|
||||
|
||||
// Check that the deduced argument type is compatible with the original
|
||||
// argument type per C++ [temp.deduct.call]p4.
|
||||
|
@ -4804,11 +4849,11 @@ Sema::TemplateDeductionResult Sema::DeduceAutoType(TypeLoc Type, Expr *Init,
|
|||
if (auto TDK =
|
||||
CheckOriginalCallArgDeduction(*this, Info, OriginalArg, DeducedA)) {
|
||||
Result = QualType();
|
||||
return DeductionFailed(TDK);
|
||||
return DeductionFailed(TDK, {});
|
||||
}
|
||||
}
|
||||
|
||||
return TDK_Success;
|
||||
return DAR_Succeeded;
|
||||
}
|
||||
|
||||
QualType Sema::SubstAutoType(QualType TypeWithAuto,
|
||||
|
|
|
@ -374,7 +374,7 @@ namespace weird_initlist {
|
|||
// We don't check the struct layout in Sema.
|
||||
auto x = {weird{}, weird{}, weird{}, weird{}, weird{}};
|
||||
// ... but we do in constant evaluation.
|
||||
constexpr auto y = {weird{}, weird{}, weird{}, weird{}, weird{}}; // expected-error {{constant}} expected-note {{type 'const std::initializer_list<weird>' has unexpected layout}}
|
||||
constexpr auto y = {weird{}, weird{}, weird{}, weird{}, weird{}}; // expected-error {{constant}} expected-note {{type 'const std::initializer_list<weird_initlist::weird>' has unexpected layout}}
|
||||
}
|
||||
|
||||
auto v = std::initializer_list<int>{1,2,3}; // expected-warning {{array backing local initializer list 'v' will be destroyed at the end of the full-expression}}
|
||||
|
|
|
@ -115,7 +115,7 @@ auto& f4() {
|
|||
}
|
||||
auto& f5() {
|
||||
return i;
|
||||
return void(); // expected-error {{deduced as 'int' in earlier return statement}}
|
||||
return void(); // expected-error@-2 {{cannot form a reference to 'void'}}
|
||||
}
|
||||
auto& f6() { return 42; } // expected-error {{non-const lvalue reference to type 'int' cannot bind to a temporary of type 'int'}}
|
||||
|
||||
|
@ -130,9 +130,9 @@ auto l4 = []() -> auto& {
|
|||
return i;
|
||||
return; // expected-error {{cannot deduce return type 'auto &' from omitted return expression}}
|
||||
};
|
||||
auto l5 = []() -> auto & {
|
||||
auto l5 = []() -> auto& { // expected-error {{cannot form a reference to 'void'}}
|
||||
return i;
|
||||
return void(); // expected-error {{deduced as 'int' in earlier return statement}}
|
||||
return void();
|
||||
};
|
||||
auto l6 = []() -> auto& {
|
||||
return 42; // expected-error {{non-const lvalue reference to type 'int' cannot bind to a temporary of type 'int'}}
|
||||
|
|
|
@ -1,12 +1,4 @@
|
|||
// RUN: %clang_cc1 -fsyntax-only -verify -xobjective-c++ %s -std=c++20 -fms-extensions -fblocks -fobjc-arc -fobjc-runtime-has-weak -fenable-matrix -Wno-dynamic-exception-spec -Wno-c++17-compat-mangling
|
||||
// RUN: %clang_cc1 -fsyntax-only -verify -xobjective-c++ %s -std=c++14 -fms-extensions -fblocks -fobjc-arc -fobjc-runtime-has-weak -fenable-matrix -Wno-dynamic-exception-spec -Wno-c++17-compat-mangling
|
||||
|
||||
namespace std {
|
||||
template<typename T> struct initializer_list {
|
||||
const T *begin, *end;
|
||||
initializer_list();
|
||||
};
|
||||
} // namespace std
|
||||
// RUN: %clang_cc1 -fsyntax-only -verify %s -std=c++20
|
||||
|
||||
enum class N {};
|
||||
|
||||
|
@ -17,26 +9,6 @@ using AnimalPtr = Animal *;
|
|||
using Man = Animal;
|
||||
using Dog = Animal;
|
||||
|
||||
using ManPtr = Man *;
|
||||
using DogPtr = Dog *;
|
||||
|
||||
using SocratesPtr = ManPtr;
|
||||
|
||||
using ConstMan = const Man;
|
||||
using ConstDog = const Dog;
|
||||
|
||||
using Virus = void;
|
||||
using SARS = Virus;
|
||||
using Ebola = Virus;
|
||||
|
||||
using Bacteria = float;
|
||||
using Bacilli = Bacteria;
|
||||
using Vibrio = Bacteria;
|
||||
|
||||
struct Plant;
|
||||
using Gymnosperm = Plant;
|
||||
using Angiosperm = Plant;
|
||||
|
||||
namespace variable {
|
||||
|
||||
auto x1 = Animal();
|
||||
|
@ -53,9 +25,6 @@ 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')}}
|
||||
|
||||
auto x6 = { Man(), Dog() };
|
||||
N t6 = x6; // expected-error {{from 'std::initializer_list<Animal>' (aka 'initializer_list<int>')}}
|
||||
|
||||
} // namespace variable
|
||||
|
||||
namespace function_basic {
|
||||
|
@ -72,160 +41,3 @@ auto x3 = [a = Animal()] { return a; }();
|
|||
N t3 = x3; // expected-error {{lvalue of type 'Animal' (aka 'int')}}
|
||||
|
||||
} // namespace function_basic
|
||||
|
||||
namespace function_multiple_basic {
|
||||
|
||||
N t1 = [] { // expected-error {{rvalue of type 'Animal' (aka 'int')}}
|
||||
if (true)
|
||||
return Man();
|
||||
return Dog();
|
||||
}();
|
||||
|
||||
N t2 = []() -> decltype(auto) { // expected-error {{rvalue of type 'Animal' (aka 'int')}}
|
||||
if (true)
|
||||
return Man();
|
||||
return Dog();
|
||||
}();
|
||||
|
||||
N t3 = [] { // expected-error {{rvalue of type 'Animal' (aka 'int')}}
|
||||
if (true)
|
||||
return Dog();
|
||||
auto x = Man();
|
||||
return x;
|
||||
}();
|
||||
|
||||
N t4 = [] { // expected-error {{rvalue of type 'int'}}
|
||||
if (true)
|
||||
return Dog();
|
||||
return 1;
|
||||
}();
|
||||
|
||||
N t5 = [] { // expected-error {{rvalue of type 'Virus' (aka 'void')}}
|
||||
if (true)
|
||||
return Ebola();
|
||||
return SARS();
|
||||
}();
|
||||
|
||||
N t6 = [] { // expected-error {{rvalue of type 'void'}}
|
||||
if (true)
|
||||
return SARS();
|
||||
return;
|
||||
}();
|
||||
|
||||
} // namespace function_multiple_basic
|
||||
|
||||
#define TEST_AUTO(X, A, B) \
|
||||
static_assert(__is_same(A, B), ""); \
|
||||
auto X(A a, B b) { \
|
||||
if (0) \
|
||||
return a; \
|
||||
if (0) \
|
||||
return b; \
|
||||
return N(); \
|
||||
}
|
||||
#define TEST_DAUTO(X, A, B) \
|
||||
static_assert(__is_same(A, B), ""); \
|
||||
decltype(auto) X(A a, B b) { \
|
||||
if (0) \
|
||||
return static_cast<A>(a); \
|
||||
if (0) \
|
||||
return static_cast<B>(b); \
|
||||
return N(); \
|
||||
}
|
||||
|
||||
namespace misc {
|
||||
|
||||
TEST_AUTO(t1, ManPtr, DogPtr) // expected-error {{but deduced as 'Animal *' (aka 'int *')}}
|
||||
TEST_AUTO(t2, ManPtr, int *) // expected-error {{but deduced as 'int *'}}
|
||||
TEST_AUTO(t3, SocratesPtr, ManPtr) // expected-error {{but deduced as 'ManPtr' (aka 'int *')}}
|
||||
|
||||
TEST_AUTO(t4, _Atomic(Man), _Atomic(Dog)) // expected-error {{but deduced as '_Atomic(Animal)'}}
|
||||
|
||||
using block_man = void (^)(Man);
|
||||
using block_dog = void (^)(Dog);
|
||||
TEST_AUTO(t5, block_man, block_dog) // expected-error {{but deduced as 'void (^__strong)(Animal)'}}
|
||||
|
||||
#if __cplusplus >= 201500
|
||||
using fp1 = SARS (*)(Man, DogPtr) throw(Vibrio);
|
||||
using fp2 = Ebola (*)(Dog, ManPtr) throw(Bacilli);
|
||||
TEST_AUTO(t6, fp1, fp2); // expected-error {{but deduced as 'Virus (*)(Animal, Animal *) throw(Bacteria)' (aka 'void (*)(int, int *) throw(Bacteria)')}}
|
||||
|
||||
using fp3 = SARS (*)() throw(Man);
|
||||
using fp4 = Ebola (*)() throw(Vibrio);
|
||||
auto t7(fp3 a, fp4 b) {
|
||||
if (false)
|
||||
return true ? a : b;
|
||||
if (false)
|
||||
return a;
|
||||
return N(); // expected-error {{but deduced as 'SARS (*)() throw(Man, Vibrio)' (aka 'void (*)() throw(Man, Vibrio)')}}
|
||||
}
|
||||
#endif
|
||||
|
||||
using fp5 = void (*)(const Man);
|
||||
using fp6 = void (*)(Dog);
|
||||
TEST_AUTO(t8, fp5, fp6); // expected-error {{but deduced as 'void (*)(Animal)' (aka 'void (*)(int)')}}
|
||||
|
||||
using fp7 = void (*)(ConstMan);
|
||||
using fp8 = void (*)(ConstDog);
|
||||
TEST_AUTO(t9, fp7, fp8); // expected-error {{but deduced as 'void (*)(const Animal)' (aka 'void (*)(const int)')}}
|
||||
|
||||
using fp9 = void (*)(ConstMan);
|
||||
using fp10 = void (*)(const Dog);
|
||||
TEST_AUTO(t10, fp9, fp10); // expected-error {{but deduced as 'void (*)(const Animal)' (aka 'void (*)(const int)')}}
|
||||
|
||||
using fp11 = void (*)(__strong block_man);
|
||||
using fp12 = void (*)(__weak block_dog);
|
||||
TEST_AUTO(t11, fp11, fp12); // expected-error {{but deduced as 'void (*)(void (^)(Animal))'}}
|
||||
|
||||
TEST_AUTO(t12, Man Angiosperm::*, Dog Gymnosperm::*) // expected-error {{but deduced as 'Animal Plant::*'}}
|
||||
|
||||
TEST_DAUTO(t13, const Man &, const Dog &) // expected-error {{but deduced as 'const Animal &' (aka 'const int &')}}
|
||||
|
||||
TEST_DAUTO(t14, Man &&, Dog &&) // expected-error {{but deduced as 'Animal &&' (aka 'int &&')}}
|
||||
|
||||
using matrix_man = Man __attribute__((matrix_type(4, 4)));
|
||||
using matrix_dog = Dog __attribute__((matrix_type(4, 4)));
|
||||
TEST_AUTO(t15, matrix_man, matrix_dog) // expected-error {{but deduced as 'Animal __attribute__((matrix_type(4, 4)))'}}
|
||||
|
||||
using vector_man = Man __attribute__((vector_size(4)));
|
||||
using vector_dog = Dog __attribute__((vector_size(4)));
|
||||
TEST_AUTO(t16, vector_man, vector_dog) // expected-error {{but deduced as '__attribute__((__vector_size__(1 * sizeof(Animal)))) Animal' (vector of 1 'Animal' value)}}
|
||||
|
||||
using ext_vector_man = Man __attribute__((ext_vector_type(4)));
|
||||
using ext_vector_dog = Dog __attribute__((ext_vector_type(4)));
|
||||
TEST_AUTO(t17, ext_vector_man, ext_vector_dog) // expected-error {{but deduced as 'Animal __attribute__((ext_vector_type(4)))' (vector of 4 'Animal' values)}}
|
||||
|
||||
} // namespace misc
|
||||
|
||||
namespace exception_spec {
|
||||
|
||||
void none();
|
||||
void dyn_none() throw();
|
||||
void dyn() throw(int);
|
||||
void ms_any() throw(...);
|
||||
void __declspec(nothrow) nothrow();
|
||||
void noexcept_basic() noexcept;
|
||||
void noexcept_true() noexcept(true);
|
||||
void noexcept_false() noexcept(false);
|
||||
|
||||
#if __cplusplus < 201500
|
||||
TEST_AUTO(t1, decltype(&noexcept_false), decltype(&noexcept_true)) // expected-error {{but deduced as 'void (*)() noexcept(false)'}}
|
||||
TEST_AUTO(t2, decltype(&noexcept_basic), decltype(&noexcept_true)) // expected-error {{but deduced as 'void (*)() noexcept(true)'}}
|
||||
TEST_AUTO(t3, decltype(&none), decltype(&ms_any)) // expected-error {{but deduced as 'void (*)()'}}
|
||||
TEST_AUTO(t4, decltype(&noexcept_false), decltype(&ms_any)) // expected-error {{but deduced as 'void (*)() throw(...)'}}
|
||||
TEST_AUTO(t5, decltype(¬hrow), decltype(&noexcept_false)) // expected-error {{but deduced as 'void (*)() noexcept(false)'}}
|
||||
TEST_AUTO(t6, decltype(&dyn_none), decltype(¬hrow)) // expected-error {{but deduced as 'void (*)() throw()'}}
|
||||
TEST_AUTO(t7, decltype(&noexcept_true), decltype(&dyn)) // expected-error {{but deduced as 'void (*)() throw(int)'}}
|
||||
#endif
|
||||
} // namespace exception_spec
|
||||
|
||||
namespace non_deduced {
|
||||
void f();
|
||||
void g();
|
||||
void g(int);
|
||||
auto h() {
|
||||
if (false) return f;
|
||||
return g;
|
||||
// expected-error@-1 {{returned value of type '<overloaded function type>'}}
|
||||
}
|
||||
} // namespace non_deduced
|
||||
|
|
|
@ -162,15 +162,6 @@ template void e(const float *, int);
|
|||
|
||||
} // namespace test4
|
||||
|
||||
namespace test5 {
|
||||
|
||||
template <bool, int = 0> class a {};
|
||||
template <class b> void c(b, b);
|
||||
template <bool b> void c(a<b>, a<b>);
|
||||
void d() { c(a<true>(), a<true>()); }
|
||||
|
||||
} // namespace test5
|
||||
|
||||
// Verify that we can deduce enum-typed arguments correctly.
|
||||
namespace test14 {
|
||||
enum E { E0, E1 };
|
||||
|
|
Loading…
Reference in New Issue