forked from OSchip/llvm-project
Don't treat a non-deduced 'auto' type as being type-dependent. Instead, there
are now two distinct canonical 'AutoType's: one is the undeduced 'auto' placeholder type, and the other is a deduced-but-dependent type. All deduced-to-a-non-dependent-type cases are still non-canonical. llvm-svn: 180789
This commit is contained in:
parent
93b2cba03b
commit
27d807cc9c
|
@ -1100,7 +1100,8 @@ public:
|
||||||
UnaryTransformType::UTTKind UKind) const;
|
UnaryTransformType::UTTKind UKind) const;
|
||||||
|
|
||||||
/// \brief C++11 deduced auto type.
|
/// \brief C++11 deduced auto type.
|
||||||
QualType getAutoType(QualType DeducedType, bool IsDecltypeAuto) const;
|
QualType getAutoType(QualType DeducedType, bool IsDecltypeAuto,
|
||||||
|
bool IsDependent = false) const;
|
||||||
|
|
||||||
/// \brief C++11 deduction pattern for 'auto' type.
|
/// \brief C++11 deduction pattern for 'auto' type.
|
||||||
QualType getAutoDeductType() const;
|
QualType getAutoDeductType() const;
|
||||||
|
|
|
@ -1619,6 +1619,10 @@ public:
|
||||||
return TypeBits.InstantiationDependent;
|
return TypeBits.InstantiationDependent;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// \brief Determine whether this type is an undeduced type, meaning that
|
||||||
|
/// it somehow involves a C++11 'auto' type which has not yet been deduced.
|
||||||
|
bool isUndeducedType() const;
|
||||||
|
|
||||||
/// \brief Whether this type is a variably-modified type (C99 6.7.5).
|
/// \brief Whether this type is a variably-modified type (C99 6.7.5).
|
||||||
bool isVariablyModifiedType() const { return TypeBits.VariablyModified; }
|
bool isVariablyModifiedType() const { return TypeBits.VariablyModified; }
|
||||||
|
|
||||||
|
@ -3554,17 +3558,17 @@ public:
|
||||||
|
|
||||||
/// \brief Represents a C++11 auto or C++1y decltype(auto) type.
|
/// \brief Represents a C++11 auto or C++1y decltype(auto) type.
|
||||||
///
|
///
|
||||||
/// These types are usually a placeholder for a deduced type. However, within
|
/// These types are usually a placeholder for a deduced type. However, before
|
||||||
/// templates and before the initializer is attached, there is no deduced type
|
/// the initializer is attached, or if the initializer is type-dependent, there
|
||||||
/// and an auto type is type-dependent and canonical.
|
/// is no deduced type and an auto type is canonical. In the latter case, it is
|
||||||
|
/// also a dependent type.
|
||||||
class AutoType : public Type, public llvm::FoldingSetNode {
|
class AutoType : public Type, public llvm::FoldingSetNode {
|
||||||
AutoType(QualType DeducedType, bool IsDecltypeAuto)
|
AutoType(QualType DeducedType, bool IsDecltypeAuto, bool IsDependent)
|
||||||
: Type(Auto, DeducedType.isNull() ? QualType(this, 0) : DeducedType,
|
: Type(Auto, DeducedType.isNull() ? QualType(this, 0) : DeducedType,
|
||||||
/*Dependent=*/DeducedType.isNull(),
|
/*Dependent=*/IsDependent, /*InstantiationDependent=*/IsDependent,
|
||||||
/*InstantiationDependent=*/DeducedType.isNull(),
|
|
||||||
/*VariablyModified=*/false, /*ContainsParameterPack=*/false) {
|
/*VariablyModified=*/false, /*ContainsParameterPack=*/false) {
|
||||||
assert((DeducedType.isNull() || !DeducedType->isDependentType()) &&
|
assert((DeducedType.isNull() || !IsDependent) &&
|
||||||
"deduced a dependent type for auto");
|
"auto deduced to dependent type");
|
||||||
AutoTypeBits.IsDecltypeAuto = IsDecltypeAuto;
|
AutoTypeBits.IsDecltypeAuto = IsDecltypeAuto;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -3573,24 +3577,27 @@ class AutoType : public Type, public llvm::FoldingSetNode {
|
||||||
public:
|
public:
|
||||||
bool isDecltypeAuto() const { return AutoTypeBits.IsDecltypeAuto; }
|
bool isDecltypeAuto() const { return AutoTypeBits.IsDecltypeAuto; }
|
||||||
|
|
||||||
bool isSugared() const { return isDeduced(); }
|
bool isSugared() const { return !isCanonicalUnqualified(); }
|
||||||
QualType desugar() const { return getCanonicalTypeInternal(); }
|
QualType desugar() const { return getCanonicalTypeInternal(); }
|
||||||
|
|
||||||
|
/// \brief Get the type deduced for this auto type, or null if it's either
|
||||||
|
/// not been deduced or was deduced to a dependent type.
|
||||||
QualType getDeducedType() const {
|
QualType getDeducedType() const {
|
||||||
return isDeduced() ? getCanonicalTypeInternal() : QualType();
|
return !isCanonicalUnqualified() ? getCanonicalTypeInternal() : QualType();
|
||||||
}
|
}
|
||||||
bool isDeduced() const {
|
bool isDeduced() const {
|
||||||
return !isDependentType();
|
return !isCanonicalUnqualified() || isDependentType();
|
||||||
}
|
}
|
||||||
|
|
||||||
void Profile(llvm::FoldingSetNodeID &ID) {
|
void Profile(llvm::FoldingSetNodeID &ID) {
|
||||||
Profile(ID, getDeducedType(), isDecltypeAuto());
|
Profile(ID, getDeducedType(), isDecltypeAuto(), isDependentType());
|
||||||
}
|
}
|
||||||
|
|
||||||
static void Profile(llvm::FoldingSetNodeID &ID,
|
static void Profile(llvm::FoldingSetNodeID &ID, QualType Deduced,
|
||||||
QualType Deduced, bool IsDecltypeAuto) {
|
bool IsDecltypeAuto, bool IsDependent) {
|
||||||
ID.AddPointer(Deduced.getAsOpaquePtr());
|
ID.AddPointer(Deduced.getAsOpaquePtr());
|
||||||
ID.AddBoolean(IsDecltypeAuto);
|
ID.AddBoolean(IsDecltypeAuto);
|
||||||
|
ID.AddBoolean(IsDependent);
|
||||||
}
|
}
|
||||||
|
|
||||||
static bool classof(const Type *T) {
|
static bool classof(const Type *T) {
|
||||||
|
@ -5033,6 +5040,11 @@ inline bool Type::isBooleanType() const {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
inline bool Type::isUndeducedType() const {
|
||||||
|
const AutoType *AT = getContainedAutoType();
|
||||||
|
return AT && !AT->isDeduced();
|
||||||
|
}
|
||||||
|
|
||||||
/// \brief Determines whether this is a type for which one can define
|
/// \brief Determines whether this is a type for which one can define
|
||||||
/// an overloaded operator.
|
/// an overloaded operator.
|
||||||
inline bool Type::isOverloadableType() const {
|
inline bool Type::isOverloadableType() const {
|
||||||
|
|
|
@ -94,7 +94,7 @@ DEPENDENT_TYPE(TemplateTypeParm, Type)
|
||||||
NON_CANONICAL_TYPE(SubstTemplateTypeParm, Type)
|
NON_CANONICAL_TYPE(SubstTemplateTypeParm, Type)
|
||||||
DEPENDENT_TYPE(SubstTemplateTypeParmPack, Type)
|
DEPENDENT_TYPE(SubstTemplateTypeParmPack, Type)
|
||||||
NON_CANONICAL_UNLESS_DEPENDENT_TYPE(TemplateSpecialization, Type)
|
NON_CANONICAL_UNLESS_DEPENDENT_TYPE(TemplateSpecialization, Type)
|
||||||
NON_CANONICAL_UNLESS_DEPENDENT_TYPE(Auto, Type)
|
TYPE(Auto, Type)
|
||||||
DEPENDENT_TYPE(InjectedClassName, Type)
|
DEPENDENT_TYPE(InjectedClassName, Type)
|
||||||
DEPENDENT_TYPE(DependentName, Type)
|
DEPENDENT_TYPE(DependentName, Type)
|
||||||
DEPENDENT_TYPE(DependentTemplateSpecialization, Type)
|
DEPENDENT_TYPE(DependentTemplateSpecialization, Type)
|
||||||
|
|
|
@ -1400,6 +1400,7 @@ public:
|
||||||
MultiTemplateParamsArg TemplateParamLists);
|
MultiTemplateParamsArg TemplateParamLists);
|
||||||
// Returns true if the variable declaration is a redeclaration
|
// Returns true if the variable declaration is a redeclaration
|
||||||
bool CheckVariableDeclaration(VarDecl *NewVD, LookupResult &Previous);
|
bool CheckVariableDeclaration(VarDecl *NewVD, LookupResult &Previous);
|
||||||
|
void CheckVariableDeclarationType(VarDecl *NewVD);
|
||||||
void CheckCompleteVariableDeclaration(VarDecl *var);
|
void CheckCompleteVariableDeclaration(VarDecl *var);
|
||||||
void MaybeSuggestAddingStaticToDecl(const FunctionDecl *D);
|
void MaybeSuggestAddingStaticToDecl(const FunctionDecl *D);
|
||||||
void ActOnStartFunctionDeclarator();
|
void ActOnStartFunctionDeclarator();
|
||||||
|
@ -5643,6 +5644,7 @@ public:
|
||||||
|
|
||||||
DeduceAutoResult DeduceAutoType(TypeSourceInfo *AutoType, Expr *&Initializer,
|
DeduceAutoResult DeduceAutoType(TypeSourceInfo *AutoType, Expr *&Initializer,
|
||||||
TypeSourceInfo *&Result);
|
TypeSourceInfo *&Result);
|
||||||
|
QualType SubstAutoType(QualType TypeWithAuto, QualType Replacement);
|
||||||
void DiagnoseAutoDeductionFailure(VarDecl *VDecl, Expr *Init);
|
void DiagnoseAutoDeductionFailure(VarDecl *VDecl, Expr *Init);
|
||||||
|
|
||||||
FunctionTemplateDecl *getMoreSpecializedTemplate(FunctionTemplateDecl *FT1,
|
FunctionTemplateDecl *getMoreSpecializedTemplate(FunctionTemplateDecl *FT1,
|
||||||
|
|
|
@ -1597,7 +1597,8 @@ ASTContext::getTypeInfoImpl(const Type *T) const {
|
||||||
|
|
||||||
case Type::Auto: {
|
case Type::Auto: {
|
||||||
const AutoType *A = cast<AutoType>(T);
|
const AutoType *A = cast<AutoType>(T);
|
||||||
assert(A->isDeduced() && "Cannot request the size of a dependent type");
|
assert(!A->getDeducedType().isNull() &&
|
||||||
|
"cannot request the size of an undeduced or dependent auto type");
|
||||||
return getTypeInfo(A->getDeducedType().getTypePtr());
|
return getTypeInfo(A->getDeducedType().getTypePtr());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -3564,18 +3565,20 @@ QualType ASTContext::getUnaryTransformType(QualType BaseType,
|
||||||
|
|
||||||
/// getAutoType - We only unique auto types after they've been deduced.
|
/// getAutoType - We only unique auto types after they've been deduced.
|
||||||
QualType ASTContext::getAutoType(QualType DeducedType,
|
QualType ASTContext::getAutoType(QualType DeducedType,
|
||||||
bool IsDecltypeAuto) const {
|
bool IsDecltypeAuto,
|
||||||
|
bool IsDependent) const {
|
||||||
void *InsertPos = 0;
|
void *InsertPos = 0;
|
||||||
if (!DeducedType.isNull()) {
|
if (!DeducedType.isNull()) {
|
||||||
// Look in the folding set for an existing type.
|
// Look in the folding set for an existing type.
|
||||||
llvm::FoldingSetNodeID ID;
|
llvm::FoldingSetNodeID ID;
|
||||||
AutoType::Profile(ID, DeducedType, IsDecltypeAuto);
|
AutoType::Profile(ID, DeducedType, IsDecltypeAuto, IsDependent);
|
||||||
if (AutoType *AT = AutoTypes.FindNodeOrInsertPos(ID, InsertPos))
|
if (AutoType *AT = AutoTypes.FindNodeOrInsertPos(ID, InsertPos))
|
||||||
return QualType(AT, 0);
|
return QualType(AT, 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
AutoType *AT = new (*this, TypeAlignment) AutoType(DeducedType,
|
AutoType *AT = new (*this, TypeAlignment) AutoType(DeducedType,
|
||||||
IsDecltypeAuto);
|
IsDecltypeAuto,
|
||||||
|
IsDependent);
|
||||||
Types.push_back(AT);
|
Types.push_back(AT);
|
||||||
if (InsertPos)
|
if (InsertPos)
|
||||||
AutoTypes.InsertNode(AT, InsertPos);
|
AutoTypes.InsertNode(AT, InsertPos);
|
||||||
|
@ -5387,6 +5390,11 @@ void ASTContext::getObjCEncodingForTypeImpl(QualType T, std::string& S,
|
||||||
// FIXME. We should do a better job than gcc.
|
// FIXME. We should do a better job than gcc.
|
||||||
return;
|
return;
|
||||||
|
|
||||||
|
case Type::Auto:
|
||||||
|
// We could see an undeduced auto type here during error recovery.
|
||||||
|
// Just ignore it.
|
||||||
|
return;
|
||||||
|
|
||||||
#define ABSTRACT_TYPE(KIND, BASE)
|
#define ABSTRACT_TYPE(KIND, BASE)
|
||||||
#define TYPE(KIND, BASE)
|
#define TYPE(KIND, BASE)
|
||||||
#define DEPENDENT_TYPE(KIND, BASE) \
|
#define DEPENDENT_TYPE(KIND, BASE) \
|
||||||
|
@ -7028,6 +7036,7 @@ QualType ASTContext::mergeTypes(QualType LHS, QualType RHS,
|
||||||
#include "clang/AST/TypeNodes.def"
|
#include "clang/AST/TypeNodes.def"
|
||||||
llvm_unreachable("Non-canonical and dependent types shouldn't get here");
|
llvm_unreachable("Non-canonical and dependent types shouldn't get here");
|
||||||
|
|
||||||
|
case Type::Auto:
|
||||||
case Type::LValueReference:
|
case Type::LValueReference:
|
||||||
case Type::RValueReference:
|
case Type::RValueReference:
|
||||||
case Type::MemberPointer:
|
case Type::MemberPointer:
|
||||||
|
|
|
@ -2105,6 +2105,11 @@ static CachedProperties computeCachedProperties(const Type *T) {
|
||||||
assert(T->isInstantiationDependentType());
|
assert(T->isInstantiationDependentType());
|
||||||
return CachedProperties(ExternalLinkage, false);
|
return CachedProperties(ExternalLinkage, false);
|
||||||
|
|
||||||
|
case Type::Auto:
|
||||||
|
// Give non-deduced 'auto' types external linkage. We should only see them
|
||||||
|
// here in error recovery.
|
||||||
|
return CachedProperties(ExternalLinkage, false);
|
||||||
|
|
||||||
case Type::Builtin:
|
case Type::Builtin:
|
||||||
// C++ [basic.link]p8:
|
// C++ [basic.link]p8:
|
||||||
// A type is said to have linkage if and only if:
|
// A type is said to have linkage if and only if:
|
||||||
|
@ -2206,6 +2211,9 @@ static LinkageInfo computeLinkageInfo(const Type *T) {
|
||||||
case Type::Builtin:
|
case Type::Builtin:
|
||||||
return LinkageInfo::external();
|
return LinkageInfo::external();
|
||||||
|
|
||||||
|
case Type::Auto:
|
||||||
|
return LinkageInfo::external();
|
||||||
|
|
||||||
case Type::Record:
|
case Type::Record:
|
||||||
case Type::Enum:
|
case Type::Enum:
|
||||||
return cast<TagType>(T)->getDecl()->getLinkageAndVisibility();
|
return cast<TagType>(T)->getDecl()->getLinkageAndVisibility();
|
||||||
|
|
|
@ -776,7 +776,7 @@ void TypePrinter::printUnaryTransformAfter(const UnaryTransformType *T,
|
||||||
|
|
||||||
void TypePrinter::printAutoBefore(const AutoType *T, raw_ostream &OS) {
|
void TypePrinter::printAutoBefore(const AutoType *T, raw_ostream &OS) {
|
||||||
// If the type has been deduced, do not print 'auto'.
|
// If the type has been deduced, do not print 'auto'.
|
||||||
if (T->isDeduced()) {
|
if (!T->getDeducedType().isNull()) {
|
||||||
printBefore(T->getDeducedType(), OS);
|
printBefore(T->getDeducedType(), OS);
|
||||||
} else {
|
} else {
|
||||||
OS << (T->isDecltypeAuto() ? "decltype(auto)" : "auto");
|
OS << (T->isDecltypeAuto() ? "decltype(auto)" : "auto");
|
||||||
|
@ -785,7 +785,7 @@ void TypePrinter::printAutoBefore(const AutoType *T, raw_ostream &OS) {
|
||||||
}
|
}
|
||||||
void TypePrinter::printAutoAfter(const AutoType *T, raw_ostream &OS) {
|
void TypePrinter::printAutoAfter(const AutoType *T, raw_ostream &OS) {
|
||||||
// If the type has been deduced, do not print 'auto'.
|
// If the type has been deduced, do not print 'auto'.
|
||||||
if (T->isDeduced())
|
if (!T->getDeducedType().isNull())
|
||||||
printAfter(T->getDeducedType(), OS);
|
printAfter(T->getDeducedType(), OS);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -412,6 +412,9 @@ void RTTIBuilder::BuildVTablePointer(const Type *Ty) {
|
||||||
case Type::RValueReference:
|
case Type::RValueReference:
|
||||||
llvm_unreachable("References shouldn't get here");
|
llvm_unreachable("References shouldn't get here");
|
||||||
|
|
||||||
|
case Type::Auto:
|
||||||
|
llvm_unreachable("Undeduced auto type shouldn't get here");
|
||||||
|
|
||||||
case Type::Builtin:
|
case Type::Builtin:
|
||||||
// GCC treats vector and complex types as fundamental types.
|
// GCC treats vector and complex types as fundamental types.
|
||||||
case Type::Vector:
|
case Type::Vector:
|
||||||
|
@ -619,6 +622,9 @@ llvm::Constant *RTTIBuilder::BuildTypeInfo(QualType Ty, bool Force) {
|
||||||
case Type::RValueReference:
|
case Type::RValueReference:
|
||||||
llvm_unreachable("References shouldn't get here");
|
llvm_unreachable("References shouldn't get here");
|
||||||
|
|
||||||
|
case Type::Auto:
|
||||||
|
llvm_unreachable("Undeduced auto type shouldn't get here");
|
||||||
|
|
||||||
case Type::ConstantArray:
|
case Type::ConstantArray:
|
||||||
case Type::IncompleteArray:
|
case Type::IncompleteArray:
|
||||||
case Type::VariableArray:
|
case Type::VariableArray:
|
||||||
|
|
|
@ -91,6 +91,9 @@ TypeEvaluationKind CodeGenFunction::getEvaluationKind(QualType type) {
|
||||||
#include "clang/AST/TypeNodes.def"
|
#include "clang/AST/TypeNodes.def"
|
||||||
llvm_unreachable("non-canonical or dependent type in IR-generation");
|
llvm_unreachable("non-canonical or dependent type in IR-generation");
|
||||||
|
|
||||||
|
case Type::Auto:
|
||||||
|
llvm_unreachable("undeduced auto type in IR-generation");
|
||||||
|
|
||||||
// Various scalar types.
|
// Various scalar types.
|
||||||
case Type::Builtin:
|
case Type::Builtin:
|
||||||
case Type::Pointer:
|
case Type::Pointer:
|
||||||
|
|
|
@ -392,6 +392,8 @@ llvm::Type *CodeGenTypes::ConvertType(QualType T) {
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
case Type::Auto:
|
||||||
|
llvm_unreachable("Unexpected undeduced auto type!");
|
||||||
case Type::Complex: {
|
case Type::Complex: {
|
||||||
llvm::Type *EltTy = ConvertType(cast<ComplexType>(Ty)->getElementType());
|
llvm::Type *EltTy = ConvertType(cast<ComplexType>(Ty)->getElementType());
|
||||||
ResultType = llvm::StructType::get(EltTy, EltTy, NULL);
|
ResultType = llvm::StructType::get(EltTy, EltTy, NULL);
|
||||||
|
|
|
@ -1456,6 +1456,8 @@ bool Parser::ParseCXXCondition(ExprResult &ExprOut,
|
||||||
if (!InitExpr.isInvalid())
|
if (!InitExpr.isInvalid())
|
||||||
Actions.AddInitializerToDecl(DeclOut, InitExpr.take(), !CopyInitialization,
|
Actions.AddInitializerToDecl(DeclOut, InitExpr.take(), !CopyInitialization,
|
||||||
DS.containsPlaceholderType());
|
DS.containsPlaceholderType());
|
||||||
|
else
|
||||||
|
Actions.ActOnInitializerError(DeclOut);
|
||||||
|
|
||||||
// FIXME: Build a reference to this declaration? Convert it to bool?
|
// FIXME: Build a reference to this declaration? Convert it to bool?
|
||||||
// (This is currently handled by Sema).
|
// (This is currently handled by Sema).
|
||||||
|
|
|
@ -2798,8 +2798,7 @@ void Sema::MergeVarDeclTypes(VarDecl *New, VarDecl *Old, bool OldWasHidden) {
|
||||||
|
|
||||||
QualType MergedT;
|
QualType MergedT;
|
||||||
if (getLangOpts().CPlusPlus) {
|
if (getLangOpts().CPlusPlus) {
|
||||||
AutoType *AT = New->getType()->getContainedAutoType();
|
if (New->getType()->isUndeducedType()) {
|
||||||
if (AT && !AT->isDeduced()) {
|
|
||||||
// We don't know what the new type is until the initializer is attached.
|
// We don't know what the new type is until the initializer is attached.
|
||||||
return;
|
return;
|
||||||
} else if (Context.hasSameType(New->getType(), Old->getType())) {
|
} else if (Context.hasSameType(New->getType(), Old->getType())) {
|
||||||
|
@ -5142,27 +5141,18 @@ static bool mayConflictWithNonVisibleExternC(const T *ND) {
|
||||||
return ND->isExternC();
|
return ND->isExternC();
|
||||||
}
|
}
|
||||||
|
|
||||||
/// \brief Perform semantic checking on a newly-created variable
|
void Sema::CheckVariableDeclarationType(VarDecl *NewVD) {
|
||||||
/// declaration.
|
|
||||||
///
|
|
||||||
/// This routine performs all of the type-checking required for a
|
|
||||||
/// variable declaration once it has been built. It is used both to
|
|
||||||
/// check variables after they have been parsed and their declarators
|
|
||||||
/// have been translated into a declaration, and to check variables
|
|
||||||
/// that have been instantiated from a template.
|
|
||||||
///
|
|
||||||
/// Sets NewVD->isInvalidDecl() if an error was encountered.
|
|
||||||
///
|
|
||||||
/// Returns true if the variable declaration is a redeclaration.
|
|
||||||
bool Sema::CheckVariableDeclaration(VarDecl *NewVD,
|
|
||||||
LookupResult &Previous) {
|
|
||||||
// If the decl is already known invalid, don't check it.
|
// If the decl is already known invalid, don't check it.
|
||||||
if (NewVD->isInvalidDecl())
|
if (NewVD->isInvalidDecl())
|
||||||
return false;
|
return;
|
||||||
|
|
||||||
TypeSourceInfo *TInfo = NewVD->getTypeSourceInfo();
|
TypeSourceInfo *TInfo = NewVD->getTypeSourceInfo();
|
||||||
QualType T = TInfo->getType();
|
QualType T = TInfo->getType();
|
||||||
|
|
||||||
|
// Defer checking an 'auto' type until its initializer is attached.
|
||||||
|
if (T->isUndeducedType())
|
||||||
|
return;
|
||||||
|
|
||||||
if (T->isObjCObjectType()) {
|
if (T->isObjCObjectType()) {
|
||||||
Diag(NewVD->getLocation(), diag::err_statically_allocated_object)
|
Diag(NewVD->getLocation(), diag::err_statically_allocated_object)
|
||||||
<< FixItHint::CreateInsertion(NewVD->getLocation(), "*");
|
<< FixItHint::CreateInsertion(NewVD->getLocation(), "*");
|
||||||
|
@ -5177,7 +5167,7 @@ bool Sema::CheckVariableDeclaration(VarDecl *NewVD,
|
||||||
if (NewVD->hasLocalStorage() && T.getAddressSpace() != 0) {
|
if (NewVD->hasLocalStorage() && T.getAddressSpace() != 0) {
|
||||||
Diag(NewVD->getLocation(), diag::err_as_qualified_auto_decl);
|
Diag(NewVD->getLocation(), diag::err_as_qualified_auto_decl);
|
||||||
NewVD->setInvalidDecl();
|
NewVD->setInvalidDecl();
|
||||||
return false;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
// OpenCL v1.2 s6.5 - All program scope variables must be declared in the
|
// OpenCL v1.2 s6.5 - All program scope variables must be declared in the
|
||||||
|
@ -5187,7 +5177,7 @@ bool Sema::CheckVariableDeclaration(VarDecl *NewVD,
|
||||||
&& !T->isSamplerT()){
|
&& !T->isSamplerT()){
|
||||||
Diag(NewVD->getLocation(), diag::err_opencl_global_invalid_addr_space);
|
Diag(NewVD->getLocation(), diag::err_opencl_global_invalid_addr_space);
|
||||||
NewVD->setInvalidDecl();
|
NewVD->setInvalidDecl();
|
||||||
return false;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
// OpenCL v1.2 s6.8 -- The static qualifier is valid only in program
|
// OpenCL v1.2 s6.8 -- The static qualifier is valid only in program
|
||||||
|
@ -5196,7 +5186,7 @@ bool Sema::CheckVariableDeclaration(VarDecl *NewVD,
|
||||||
&& NewVD->isStaticLocal()) {
|
&& NewVD->isStaticLocal()) {
|
||||||
Diag(NewVD->getLocation(), diag::err_static_function_scope);
|
Diag(NewVD->getLocation(), diag::err_static_function_scope);
|
||||||
NewVD->setInvalidDecl();
|
NewVD->setInvalidDecl();
|
||||||
return false;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (NewVD->hasLocalStorage() && T.isObjCGCWeak()
|
if (NewVD->hasLocalStorage() && T.isObjCGCWeak()
|
||||||
|
@ -5237,7 +5227,7 @@ bool Sema::CheckVariableDeclaration(VarDecl *NewVD,
|
||||||
Diag(NewVD->getLocation(), diag::err_vla_decl_has_extern_linkage)
|
Diag(NewVD->getLocation(), diag::err_vla_decl_has_extern_linkage)
|
||||||
<< SizeRange;
|
<< SizeRange;
|
||||||
NewVD->setInvalidDecl();
|
NewVD->setInvalidDecl();
|
||||||
return false;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (FixedTInfo == 0) {
|
if (FixedTInfo == 0) {
|
||||||
|
@ -5246,7 +5236,7 @@ bool Sema::CheckVariableDeclaration(VarDecl *NewVD,
|
||||||
else
|
else
|
||||||
Diag(NewVD->getLocation(), diag::err_vm_decl_has_extern_linkage);
|
Diag(NewVD->getLocation(), diag::err_vm_decl_has_extern_linkage);
|
||||||
NewVD->setInvalidDecl();
|
NewVD->setInvalidDecl();
|
||||||
return false;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
Diag(NewVD->getLocation(), diag::warn_illegal_constant_array_size);
|
Diag(NewVD->getLocation(), diag::warn_illegal_constant_array_size);
|
||||||
|
@ -5254,6 +5244,54 @@ bool Sema::CheckVariableDeclaration(VarDecl *NewVD,
|
||||||
NewVD->setTypeSourceInfo(FixedTInfo);
|
NewVD->setTypeSourceInfo(FixedTInfo);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (T->isVoidType() && NewVD->isThisDeclarationADefinition()) {
|
||||||
|
Diag(NewVD->getLocation(), diag::err_typecheck_decl_incomplete_type)
|
||||||
|
<< T;
|
||||||
|
NewVD->setInvalidDecl();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!NewVD->hasLocalStorage() && NewVD->hasAttr<BlocksAttr>()) {
|
||||||
|
Diag(NewVD->getLocation(), diag::err_block_on_nonlocal);
|
||||||
|
NewVD->setInvalidDecl();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (isVM && NewVD->hasAttr<BlocksAttr>()) {
|
||||||
|
Diag(NewVD->getLocation(), diag::err_block_on_vm);
|
||||||
|
NewVD->setInvalidDecl();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (NewVD->isConstexpr() && !T->isDependentType() &&
|
||||||
|
RequireLiteralType(NewVD->getLocation(), T,
|
||||||
|
diag::err_constexpr_var_non_literal)) {
|
||||||
|
// Can't perform this check until the type is deduced.
|
||||||
|
NewVD->setInvalidDecl();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// \brief Perform semantic checking on a newly-created variable
|
||||||
|
/// declaration.
|
||||||
|
///
|
||||||
|
/// This routine performs all of the type-checking required for a
|
||||||
|
/// variable declaration once it has been built. It is used both to
|
||||||
|
/// check variables after they have been parsed and their declarators
|
||||||
|
/// have been translated into a declaration, and to check variables
|
||||||
|
/// that have been instantiated from a template.
|
||||||
|
///
|
||||||
|
/// Sets NewVD->isInvalidDecl() if an error was encountered.
|
||||||
|
///
|
||||||
|
/// Returns true if the variable declaration is a redeclaration.
|
||||||
|
bool Sema::CheckVariableDeclaration(VarDecl *NewVD,
|
||||||
|
LookupResult &Previous) {
|
||||||
|
CheckVariableDeclarationType(NewVD);
|
||||||
|
|
||||||
|
// If the decl is already known invalid, don't check it.
|
||||||
|
if (NewVD->isInvalidDecl())
|
||||||
|
return false;
|
||||||
|
|
||||||
// If we did not find anything by this name, look for a non-visible
|
// If we did not find anything by this name, look for a non-visible
|
||||||
// extern "C" declaration with the same name.
|
// extern "C" declaration with the same name.
|
||||||
//
|
//
|
||||||
|
@ -5292,32 +5330,6 @@ bool Sema::CheckVariableDeclaration(VarDecl *NewVD,
|
||||||
// Filter out any non-conflicting previous declarations.
|
// Filter out any non-conflicting previous declarations.
|
||||||
filterNonConflictingPreviousDecls(Context, NewVD, Previous);
|
filterNonConflictingPreviousDecls(Context, NewVD, Previous);
|
||||||
|
|
||||||
if (T->isVoidType() && NewVD->isThisDeclarationADefinition()) {
|
|
||||||
Diag(NewVD->getLocation(), diag::err_typecheck_decl_incomplete_type)
|
|
||||||
<< T;
|
|
||||||
NewVD->setInvalidDecl();
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!NewVD->hasLocalStorage() && NewVD->hasAttr<BlocksAttr>()) {
|
|
||||||
Diag(NewVD->getLocation(), diag::err_block_on_nonlocal);
|
|
||||||
NewVD->setInvalidDecl();
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (isVM && NewVD->hasAttr<BlocksAttr>()) {
|
|
||||||
Diag(NewVD->getLocation(), diag::err_block_on_vm);
|
|
||||||
NewVD->setInvalidDecl();
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (NewVD->isConstexpr() && !T->isDependentType() &&
|
|
||||||
RequireLiteralType(NewVD->getLocation(), T,
|
|
||||||
diag::err_constexpr_var_non_literal)) {
|
|
||||||
NewVD->setInvalidDecl();
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!Previous.empty()) {
|
if (!Previous.empty()) {
|
||||||
MergeVarDecl(NewVD, Previous, PreviousWasHidden);
|
MergeVarDecl(NewVD, Previous, PreviousWasHidden);
|
||||||
return true;
|
return true;
|
||||||
|
@ -7284,10 +7296,7 @@ void Sema::AddInitializerToDecl(Decl *RealDecl, Expr *Init,
|
||||||
ParenListExpr *CXXDirectInit = dyn_cast<ParenListExpr>(Init);
|
ParenListExpr *CXXDirectInit = dyn_cast<ParenListExpr>(Init);
|
||||||
|
|
||||||
// C++11 [decl.spec.auto]p6. Deduce the type which 'auto' stands in for.
|
// C++11 [decl.spec.auto]p6. Deduce the type which 'auto' stands in for.
|
||||||
AutoType *Auto = 0;
|
if (TypeMayContainAuto && VDecl->getType()->isUndeducedType()) {
|
||||||
if (TypeMayContainAuto &&
|
|
||||||
(Auto = VDecl->getType()->getContainedAutoType()) &&
|
|
||||||
!Auto->isDeduced()) {
|
|
||||||
Expr *DeduceInit = Init;
|
Expr *DeduceInit = Init;
|
||||||
// Initializer could be a C++ direct-initializer. Deduction only works if it
|
// Initializer could be a C++ direct-initializer. Deduction only works if it
|
||||||
// contains exactly one expression.
|
// contains exactly one expression.
|
||||||
|
@ -7357,6 +7366,11 @@ void Sema::AddInitializerToDecl(Decl *RealDecl, Expr *Init,
|
||||||
// the previously declared type.
|
// the previously declared type.
|
||||||
if (VarDecl *Old = VDecl->getPreviousDecl())
|
if (VarDecl *Old = VDecl->getPreviousDecl())
|
||||||
MergeVarDeclTypes(VDecl, Old, /*OldWasHidden*/ false);
|
MergeVarDeclTypes(VDecl, Old, /*OldWasHidden*/ false);
|
||||||
|
|
||||||
|
// Check the deduced type is valid for a variable declaration.
|
||||||
|
CheckVariableDeclarationType(VDecl);
|
||||||
|
if (VDecl->isInvalidDecl())
|
||||||
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (VDecl->isLocalVarDecl() && VDecl->hasExternalStorage()) {
|
if (VDecl->isLocalVarDecl() && VDecl->hasExternalStorage()) {
|
||||||
|
@ -8190,8 +8204,8 @@ Sema::BuildDeclaratorGroup(Decl **Group, unsigned NumDecls,
|
||||||
// Don't reissue diagnostics when instantiating a template.
|
// Don't reissue diagnostics when instantiating a template.
|
||||||
if (AT && D->isInvalidDecl())
|
if (AT && D->isInvalidDecl())
|
||||||
break;
|
break;
|
||||||
if (AT && AT->isDeduced()) {
|
QualType U = AT ? AT->getDeducedType() : QualType();
|
||||||
QualType U = AT->getDeducedType();
|
if (!U.isNull()) {
|
||||||
CanQualType UCanon = Context.getCanonicalType(U);
|
CanQualType UCanon = Context.getCanonicalType(U);
|
||||||
if (Deduced.isNull()) {
|
if (Deduced.isNull()) {
|
||||||
Deduced = U;
|
Deduced = U;
|
||||||
|
|
|
@ -1118,9 +1118,7 @@ Sema::BuildCXXNew(SourceRange Range, bool UseGlobal,
|
||||||
HaveCompleteInit = true;
|
HaveCompleteInit = true;
|
||||||
|
|
||||||
// C++11 [decl.spec.auto]p6. Deduce the type which 'auto' stands in for.
|
// C++11 [decl.spec.auto]p6. Deduce the type which 'auto' stands in for.
|
||||||
AutoType *AT = 0;
|
if (TypeMayContainAuto && AllocType->isUndeducedType()) {
|
||||||
if (TypeMayContainAuto &&
|
|
||||||
(AT = AllocType->getContainedAutoType()) && !AT->isDeduced()) {
|
|
||||||
if (initStyle == CXXNewExpr::NoInit || NumInits == 0)
|
if (initStyle == CXXNewExpr::NoInit || NumInits == 0)
|
||||||
return ExprError(Diag(StartLoc, diag::err_auto_new_requires_ctor_arg)
|
return ExprError(Diag(StartLoc, diag::err_auto_new_requires_ctor_arg)
|
||||||
<< AllocType << TypeRange);
|
<< AllocType << TypeRange);
|
||||||
|
@ -2279,6 +2277,9 @@ Sema::ActOnCXXDelete(SourceLocation StartLoc, bool UseGlobal,
|
||||||
ExprResult Sema::CheckConditionVariable(VarDecl *ConditionVar,
|
ExprResult Sema::CheckConditionVariable(VarDecl *ConditionVar,
|
||||||
SourceLocation StmtLoc,
|
SourceLocation StmtLoc,
|
||||||
bool ConvertToBoolean) {
|
bool ConvertToBoolean) {
|
||||||
|
if (ConditionVar->isInvalidDecl())
|
||||||
|
return ExprError();
|
||||||
|
|
||||||
QualType T = ConditionVar->getType();
|
QualType T = ConditionVar->getType();
|
||||||
|
|
||||||
// C++ [stmt.select]p2:
|
// C++ [stmt.select]p2:
|
||||||
|
|
|
@ -2087,6 +2087,10 @@ addAssociatedClassesAndNamespaces(AssociatedLookup &Result, QualType Ty) {
|
||||||
case Type::Complex:
|
case Type::Complex:
|
||||||
break;
|
break;
|
||||||
|
|
||||||
|
// Non-deduced auto types only get here for error cases.
|
||||||
|
case Type::Auto:
|
||||||
|
break;
|
||||||
|
|
||||||
// If T is an Objective-C object or interface type, or a pointer to an
|
// If T is an Objective-C object or interface type, or a pointer to an
|
||||||
// object or interface type, the associated namespace is the global
|
// object or interface type, the associated namespace is the global
|
||||||
// namespace.
|
// namespace.
|
||||||
|
|
|
@ -1923,7 +1923,15 @@ Sema::BuildCXXForRangeStmt(SourceLocation ForLoc, SourceLocation ColonLoc,
|
||||||
StmtResult BeginEndDecl = BeginEnd;
|
StmtResult BeginEndDecl = BeginEnd;
|
||||||
ExprResult NotEqExpr = Cond, IncrExpr = Inc;
|
ExprResult NotEqExpr = Cond, IncrExpr = Inc;
|
||||||
|
|
||||||
if (!BeginEndDecl.get() && !RangeVarType->isDependentType()) {
|
if (RangeVarType->isDependentType()) {
|
||||||
|
// The range is implicitly used as a placeholder when it is dependent.
|
||||||
|
RangeVar->setUsed();
|
||||||
|
|
||||||
|
// Deduce any 'auto's in the loop variable as 'DependentTy'. We'll fill
|
||||||
|
// them in properly when we instantiate the loop.
|
||||||
|
if (!LoopVar->isInvalidDecl() && Kind != BFRK_Check)
|
||||||
|
LoopVar->setType(SubstAutoType(LoopVar->getType(), Context.DependentTy));
|
||||||
|
} else if (!BeginEndDecl.get()) {
|
||||||
SourceLocation RangeLoc = RangeVar->getLocation();
|
SourceLocation RangeLoc = RangeVar->getLocation();
|
||||||
|
|
||||||
const QualType RangeVarNonRefType = RangeVarType.getNonReferenceType();
|
const QualType RangeVarNonRefType = RangeVarType.getNonReferenceType();
|
||||||
|
@ -2110,9 +2118,6 @@ Sema::BuildCXXForRangeStmt(SourceLocation ForLoc, SourceLocation ColonLoc,
|
||||||
if (LoopVar->isInvalidDecl())
|
if (LoopVar->isInvalidDecl())
|
||||||
NoteForRangeBeginEndFunction(*this, BeginExpr.get(), BEF_begin);
|
NoteForRangeBeginEndFunction(*this, BeginExpr.get(), BEF_begin);
|
||||||
}
|
}
|
||||||
} else {
|
|
||||||
// The range is implicitly used as a placeholder when it is dependent.
|
|
||||||
RangeVar->setUsed();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Don't bother to actually allocate the result if we're just trying to
|
// Don't bother to actually allocate the result if we're just trying to
|
||||||
|
|
|
@ -3584,8 +3584,12 @@ namespace {
|
||||||
NewTL.setNameLoc(TL.getNameLoc());
|
NewTL.setNameLoc(TL.getNameLoc());
|
||||||
return Result;
|
return Result;
|
||||||
} else {
|
} else {
|
||||||
QualType Result = RebuildAutoType(Replacement,
|
bool Dependent =
|
||||||
TL.getTypePtr()->isDecltypeAuto());
|
!Replacement.isNull() && Replacement->isDependentType();
|
||||||
|
QualType Result =
|
||||||
|
SemaRef.Context.getAutoType(Dependent ? QualType() : Replacement,
|
||||||
|
TL.getTypePtr()->isDecltypeAuto(),
|
||||||
|
Dependent);
|
||||||
AutoTypeLoc NewTL = TLB.push<AutoTypeLoc>(Result);
|
AutoTypeLoc NewTL = TLB.push<AutoTypeLoc>(Result);
|
||||||
NewTL.setNameLoc(TL.getNameLoc());
|
NewTL.setNameLoc(TL.getNameLoc());
|
||||||
return Result;
|
return Result;
|
||||||
|
@ -3597,41 +3601,6 @@ namespace {
|
||||||
return E;
|
return E;
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
/// Determine whether the specified type (which contains an 'auto' type
|
|
||||||
/// specifier) is dependent. This is not trivial, because the 'auto' specifier
|
|
||||||
/// itself claims to be type-dependent.
|
|
||||||
bool isDependentAutoType(QualType Ty) {
|
|
||||||
while (1) {
|
|
||||||
QualType Pointee = Ty->getPointeeType();
|
|
||||||
if (!Pointee.isNull()) {
|
|
||||||
Ty = Pointee;
|
|
||||||
} else if (const MemberPointerType *MPT = Ty->getAs<MemberPointerType>()){
|
|
||||||
if (MPT->getClass()->isDependentType())
|
|
||||||
return true;
|
|
||||||
Ty = MPT->getPointeeType();
|
|
||||||
} else if (const FunctionProtoType *FPT = Ty->getAs<FunctionProtoType>()){
|
|
||||||
for (FunctionProtoType::arg_type_iterator I = FPT->arg_type_begin(),
|
|
||||||
E = FPT->arg_type_end();
|
|
||||||
I != E; ++I)
|
|
||||||
if ((*I)->isDependentType())
|
|
||||||
return true;
|
|
||||||
Ty = FPT->getResultType();
|
|
||||||
} else if (Ty->isDependentSizedArrayType()) {
|
|
||||||
return true;
|
|
||||||
} else if (const ArrayType *AT = Ty->getAsArrayTypeUnsafe()) {
|
|
||||||
Ty = AT->getElementType();
|
|
||||||
} else if (Ty->getAs<DependentSizedExtVectorType>()) {
|
|
||||||
return true;
|
|
||||||
} else if (const VectorType *VT = Ty->getAs<VectorType>()) {
|
|
||||||
Ty = VT->getElementType();
|
|
||||||
} else {
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
assert(Ty->getAs<AutoType>() && "didn't find 'auto' in auto type");
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/// \brief Deduce the type for an auto type-specifier (C++0x [dcl.spec.auto]p6)
|
/// \brief Deduce the type for an auto type-specifier (C++0x [dcl.spec.auto]p6)
|
||||||
|
@ -3654,8 +3623,9 @@ Sema::DeduceAutoType(TypeSourceInfo *Type, Expr *&Init,
|
||||||
Init = result.take();
|
Init = result.take();
|
||||||
}
|
}
|
||||||
|
|
||||||
if (Init->isTypeDependent() || isDependentAutoType(Type->getType())) {
|
if (Init->isTypeDependent() || Type->getType()->isDependentType()) {
|
||||||
Result = Type;
|
Result =
|
||||||
|
SubstituteAutoTransform(*this, Context.DependentTy).TransformType(Type);
|
||||||
return DAR_Succeeded;
|
return DAR_Succeeded;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -3749,6 +3719,10 @@ Sema::DeduceAutoType(TypeSourceInfo *Type, Expr *&Init,
|
||||||
return DAR_Succeeded;
|
return DAR_Succeeded;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
QualType Sema::SubstAutoType(QualType Type, QualType Deduced) {
|
||||||
|
return SubstituteAutoTransform(*this, Deduced).TransformType(Type);
|
||||||
|
}
|
||||||
|
|
||||||
void Sema::DiagnoseAutoDeductionFailure(VarDecl *VDecl, Expr *Init) {
|
void Sema::DiagnoseAutoDeductionFailure(VarDecl *VDecl, Expr *Init) {
|
||||||
if (isa<InitListExpr>(Init))
|
if (isa<InitListExpr>(Init))
|
||||||
Diag(VDecl->getLocation(),
|
Diag(VDecl->getLocation(),
|
||||||
|
|
|
@ -2569,11 +2569,11 @@ static TypeSourceInfo *GetFullTypeForDeclarator(TypeProcessingState &state,
|
||||||
|
|
||||||
if (const AutoType *AT = T->getContainedAutoType()) {
|
if (const AutoType *AT = T->getContainedAutoType()) {
|
||||||
// We've already diagnosed this for decltype(auto).
|
// We've already diagnosed this for decltype(auto).
|
||||||
if (!AT->isDecltypeAuto()) {
|
if (!AT->isDecltypeAuto())
|
||||||
S.Diag(DeclType.Loc, diag::err_illegal_decl_array_of_auto)
|
S.Diag(DeclType.Loc, diag::err_illegal_decl_array_of_auto)
|
||||||
<< getPrintableNameForEntity(Name) << T;
|
<< getPrintableNameForEntity(Name) << T;
|
||||||
D.setInvalidType(true);
|
T = QualType();
|
||||||
}
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
T = S.BuildArrayType(T, ASM, ArraySize, ATI.TypeQuals,
|
T = S.BuildArrayType(T, ASM, ArraySize, ATI.TypeQuals,
|
||||||
|
@ -3831,7 +3831,7 @@ static bool handleObjCOwnershipTypeAttr(TypeProcessingState &state,
|
||||||
QualType &type) {
|
QualType &type) {
|
||||||
bool NonObjCPointer = false;
|
bool NonObjCPointer = false;
|
||||||
|
|
||||||
if (!type->isDependentType()) {
|
if (!type->isDependentType() && !type->isUndeducedType()) {
|
||||||
if (const PointerType *ptr = type->getAs<PointerType>()) {
|
if (const PointerType *ptr = type->getAs<PointerType>()) {
|
||||||
QualType pointee = ptr->getPointeeType();
|
QualType pointee = ptr->getPointeeType();
|
||||||
if (pointee->isObjCRetainableType() || pointee->isPointerType())
|
if (pointee->isObjCRetainableType() || pointee->isPointerType())
|
||||||
|
|
|
@ -764,6 +764,9 @@ public:
|
||||||
///
|
///
|
||||||
/// By default, builds a new AutoType with the given deduced type.
|
/// By default, builds a new AutoType with the given deduced type.
|
||||||
QualType RebuildAutoType(QualType Deduced, bool IsDecltypeAuto) {
|
QualType RebuildAutoType(QualType Deduced, bool IsDecltypeAuto) {
|
||||||
|
// Note, IsDependent is always false here: we implicitly convert an 'auto'
|
||||||
|
// which has been deduced to a dependent type into an undeduced 'auto', so
|
||||||
|
// that we'll retry deduction after the transformation.
|
||||||
return SemaRef.Context.getAutoType(Deduced, IsDecltypeAuto);
|
return SemaRef.Context.getAutoType(Deduced, IsDecltypeAuto);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -4500,7 +4503,8 @@ QualType TreeTransform<Derived>::TransformAutoType(TypeLocBuilder &TLB,
|
||||||
}
|
}
|
||||||
|
|
||||||
QualType Result = TL.getType();
|
QualType Result = TL.getType();
|
||||||
if (getDerived().AlwaysRebuild() || NewDeduced != OldDeduced) {
|
if (getDerived().AlwaysRebuild() || NewDeduced != OldDeduced ||
|
||||||
|
T->isDependentType()) {
|
||||||
Result = getDerived().RebuildAutoType(NewDeduced, T->isDecltypeAuto());
|
Result = getDerived().RebuildAutoType(NewDeduced, T->isDecltypeAuto());
|
||||||
if (Result.isNull())
|
if (Result.isNull())
|
||||||
return QualType();
|
return QualType();
|
||||||
|
|
|
@ -4641,7 +4641,8 @@ QualType ASTReader::readTypeRecord(unsigned Index) {
|
||||||
case TYPE_AUTO: {
|
case TYPE_AUTO: {
|
||||||
QualType Deduced = readType(*Loc.F, Record, Idx);
|
QualType Deduced = readType(*Loc.F, Record, Idx);
|
||||||
bool IsDecltypeAuto = Record[Idx++];
|
bool IsDecltypeAuto = Record[Idx++];
|
||||||
return Context.getAutoType(Deduced, IsDecltypeAuto);
|
bool IsDependent = Deduced.isNull() ? Record[Idx++] : false;
|
||||||
|
return Context.getAutoType(Deduced, IsDecltypeAuto, IsDependent);
|
||||||
}
|
}
|
||||||
|
|
||||||
case TYPE_RECORD: {
|
case TYPE_RECORD: {
|
||||||
|
|
|
@ -246,6 +246,8 @@ void ASTTypeWriter::VisitUnaryTransformType(const UnaryTransformType *T) {
|
||||||
void ASTTypeWriter::VisitAutoType(const AutoType *T) {
|
void ASTTypeWriter::VisitAutoType(const AutoType *T) {
|
||||||
Writer.AddTypeRef(T->getDeducedType(), Record);
|
Writer.AddTypeRef(T->getDeducedType(), Record);
|
||||||
Record.push_back(T->isDecltypeAuto());
|
Record.push_back(T->isDecltypeAuto());
|
||||||
|
if (T->getDeducedType().isNull())
|
||||||
|
Record.push_back(T->isDependentType());
|
||||||
Code = TYPE_AUTO;
|
Code = TYPE_AUTO;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -1,4 +1,4 @@
|
||||||
// RUN: %clang_cc1 -fsyntax-only -verify %s
|
// RUN: %clang_cc1 -fsyntax-only -verify -std=c++11 %s
|
||||||
|
|
||||||
void test() {
|
void test() {
|
||||||
int x;
|
int x;
|
||||||
|
@ -6,7 +6,7 @@ void test() {
|
||||||
if (int x=0) ++x;
|
if (int x=0) ++x;
|
||||||
|
|
||||||
typedef int arr[10];
|
typedef int arr[10];
|
||||||
while (arr x=0) ; // expected-error {{an array type is not allowed here}} expected-error {{array initializer must be an initializer list}}
|
while (arr x={0}) ; // expected-error {{an array type is not allowed here}}
|
||||||
while (int f()=0) ; // expected-error {{a function type is not allowed here}}
|
while (int f()=0) ; // expected-error {{a function type is not allowed here}}
|
||||||
|
|
||||||
struct S {} s;
|
struct S {} s;
|
||||||
|
@ -19,9 +19,7 @@ void test() {
|
||||||
while (struct NewS *x=0) ;
|
while (struct NewS *x=0) ;
|
||||||
while (struct S {} *x=0) ; // expected-error {{types may not be defined in conditions}}
|
while (struct S {} *x=0) ; // expected-error {{types may not be defined in conditions}}
|
||||||
while (struct {} *x=0) ; // expected-error {{types may not be defined in conditions}}
|
while (struct {} *x=0) ; // expected-error {{types may not be defined in conditions}}
|
||||||
switch (enum {E} x=0) ; // expected-error {{types may not be defined in conditions}} \
|
switch (enum {E} x=0) ; // expected-error {{types may not be defined in conditions}}
|
||||||
// expected-warning{{enumeration value 'E' not handled in switch}} expected-warning {{switch statement has empty body}} \
|
|
||||||
// expected-note{{put the semicolon on a separate line}}
|
|
||||||
|
|
||||||
if (int x=0) { // expected-note 2 {{previous definition is here}}
|
if (int x=0) { // expected-note 2 {{previous definition is here}}
|
||||||
int x; // expected-error {{redefinition of 'x'}}
|
int x; // expected-error {{redefinition of 'x'}}
|
||||||
|
|
|
@ -70,7 +70,9 @@ namespace b6981007 {
|
||||||
for (auto x : s) {
|
for (auto x : s) {
|
||||||
// We used to attempt to evaluate the initializer of this variable,
|
// We used to attempt to evaluate the initializer of this variable,
|
||||||
// and crash because it has an undeduced type.
|
// and crash because it has an undeduced type.
|
||||||
const int &n(x);
|
// FIXME: We should set the loop variable to be invalid if we can't build
|
||||||
|
// the loop, to suppress this follow-on error.
|
||||||
|
const int &n(x); // expected-error {{could not bind to an lvalue of type 'auto'}}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -7,7 +7,7 @@ template <typename T>
|
||||||
void doIt() {
|
void doIt() {
|
||||||
int a; // expected-warning {{unused variable 'a'}}
|
int a; // expected-warning {{unused variable 'a'}}
|
||||||
|
|
||||||
for (auto& e : elements)
|
for (auto& e : elements) // expected-warning {{unused variable 'e'}}
|
||||||
;
|
;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -17,5 +17,5 @@ template <typename T>
|
||||||
|
|
||||||
int main(int, char**) {
|
int main(int, char**) {
|
||||||
Vector<int> vector;
|
Vector<int> vector;
|
||||||
vector.doIt();
|
vector.doIt(); // expected-note {{here}}
|
||||||
}
|
}
|
||||||
|
|
|
@ -264,7 +264,7 @@ namespace PR10053 {
|
||||||
}
|
}
|
||||||
|
|
||||||
namespace PR10187 {
|
namespace PR10187 {
|
||||||
namespace A {
|
namespace A1 {
|
||||||
template<typename T>
|
template<typename T>
|
||||||
struct S {
|
struct S {
|
||||||
void f() {
|
void f() {
|
||||||
|
@ -278,6 +278,25 @@ namespace PR10187 {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
namespace A2 {
|
||||||
|
template<typename T>
|
||||||
|
struct S {
|
||||||
|
void f() {
|
||||||
|
for (auto &a : e)
|
||||||
|
__range(a); // expected-error {{undeclared identifier '__range'}}
|
||||||
|
}
|
||||||
|
T e[10];
|
||||||
|
};
|
||||||
|
void g() {
|
||||||
|
S<int>().f(); // expected-note {{here}}
|
||||||
|
}
|
||||||
|
struct X {};
|
||||||
|
void __range(X);
|
||||||
|
void h() {
|
||||||
|
S<X>().f();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
namespace B {
|
namespace B {
|
||||||
template<typename T> void g(); // expected-note {{not viable}}
|
template<typename T> void g(); // expected-note {{not viable}}
|
||||||
template<typename T> void f() {
|
template<typename T> void f() {
|
||||||
|
|
Loading…
Reference in New Issue