forked from OSchip/llvm-project
Implement the C++0x deduced 'auto' feature.
This fixes PR 8738, 9060 and 9132. llvm-svn: 126069
This commit is contained in:
parent
ba1186c23e
commit
30482bc786
|
@ -412,7 +412,7 @@ public:
|
|||
CanQualType FloatTy, DoubleTy, LongDoubleTy;
|
||||
CanQualType FloatComplexTy, DoubleComplexTy, LongDoubleComplexTy;
|
||||
CanQualType VoidPtrTy, NullPtrTy;
|
||||
CanQualType OverloadTy, UndeducedAutoTy;
|
||||
CanQualType OverloadTy;
|
||||
CanQualType DependentTy;
|
||||
CanQualType ObjCBuiltinIdTy, ObjCBuiltinClassTy, ObjCBuiltinSelTy;
|
||||
|
||||
|
@ -740,6 +740,9 @@ public:
|
|||
/// getDecltypeType - C++0x decltype.
|
||||
QualType getDecltypeType(Expr *e) const;
|
||||
|
||||
/// getAutoType - C++0x deduced auto type.
|
||||
QualType getAutoType(QualType DeducedType) const;
|
||||
|
||||
/// getTagDeclType - Return the unique reference to the type for the
|
||||
/// specified TagDecl (struct/union/class/enum) decl.
|
||||
QualType getTagDeclType(const TagDecl *Decl) const;
|
||||
|
|
|
@ -651,6 +651,10 @@ private:
|
|||
/// \brief Whether this local variable could be allocated in the return
|
||||
/// slot of its function, enabling the named return value optimization (NRVO).
|
||||
bool NRVOVariable : 1;
|
||||
|
||||
/// \brief Whether this variable has a deduced C++0x auto type for which we're
|
||||
/// currently parsing the initializer.
|
||||
bool ParsingAutoInit : 1;
|
||||
|
||||
friend class StmtIteratorBase;
|
||||
friend class ASTDeclReader;
|
||||
|
@ -661,7 +665,7 @@ protected:
|
|||
StorageClass SCAsWritten)
|
||||
: DeclaratorDecl(DK, DC, L, Id, T, TInfo), Init(),
|
||||
ThreadSpecified(false), HasCXXDirectInit(false),
|
||||
ExceptionVar(false), NRVOVariable(false) {
|
||||
ExceptionVar(false), NRVOVariable(false), ParsingAutoInit(false) {
|
||||
SClass = SC;
|
||||
SClassAsWritten = SCAsWritten;
|
||||
}
|
||||
|
@ -885,6 +889,18 @@ public:
|
|||
|
||||
void setInit(Expr *I);
|
||||
|
||||
/// \brief Check whether we are in the process of parsing an initializer
|
||||
/// needed to deduce the type of this variable.
|
||||
bool isParsingAutoInit() const {
|
||||
return ParsingAutoInit;
|
||||
}
|
||||
|
||||
/// \brief Note whether we are currently parsing an initializer needed to
|
||||
/// deduce the type of this variable.
|
||||
void setParsingAutoInit(bool P) {
|
||||
ParsingAutoInit = P;
|
||||
}
|
||||
|
||||
EvaluatedStmt *EnsureEvaluatedStmt() const {
|
||||
EvaluatedStmt *Eval = Init.dyn_cast<EvaluatedStmt *>();
|
||||
if (!Eval) {
|
||||
|
|
|
@ -715,6 +715,10 @@ DEF_TRAVERSE_TYPE(DecltypeType, {
|
|||
TRY_TO(TraverseStmt(T->getUnderlyingExpr()));
|
||||
})
|
||||
|
||||
DEF_TRAVERSE_TYPE(AutoType, {
|
||||
TRY_TO(TraverseType(T->getDeducedType()));
|
||||
})
|
||||
|
||||
DEF_TRAVERSE_TYPE(RecordType, { })
|
||||
DEF_TRAVERSE_TYPE(EnumType, { })
|
||||
DEF_TRAVERSE_TYPE(TemplateTypeParmType, { })
|
||||
|
@ -923,6 +927,10 @@ DEF_TRAVERSE_TYPELOC(DecltypeType, {
|
|||
TRY_TO(TraverseStmt(TL.getTypePtr()->getUnderlyingExpr()));
|
||||
})
|
||||
|
||||
DEF_TRAVERSE_TYPELOC(AutoType, {
|
||||
TRY_TO(TraverseType(TL.getTypePtr()->getDeducedType()));
|
||||
})
|
||||
|
||||
DEF_TRAVERSE_TYPELOC(RecordType, { })
|
||||
DEF_TRAVERSE_TYPELOC(EnumType, { })
|
||||
DEF_TRAVERSE_TYPELOC(TemplateTypeParmType, { })
|
||||
|
|
|
@ -1328,6 +1328,11 @@ public:
|
|||
/// because the type is a RecordType or because it is the injected-class-name
|
||||
/// type of a class template or class template partial specialization.
|
||||
CXXRecordDecl *getAsCXXRecordDecl() const;
|
||||
|
||||
/// \brief Get the AutoType whose type will be deduced for a variable with
|
||||
/// an initializer of this type. This looks through declarators like pointer
|
||||
/// types, but not through decltype or typedefs.
|
||||
AutoType *getContainedAutoType() const;
|
||||
|
||||
/// Member-template getAs<specific type>'. Look through sugar for
|
||||
/// an instance of <specific type>. This scheme will eventually
|
||||
|
@ -1478,9 +1483,6 @@ public:
|
|||
|
||||
Overload, // This represents the type of an overloaded function declaration.
|
||||
|
||||
UndeducedAuto, // In C++0x, this represents the type of an auto variable
|
||||
// that has not been deduced yet.
|
||||
|
||||
/// The primitive Objective C 'id' type. The type pointed to by the
|
||||
/// user-visible 'id' type. Only ever shows up in an AST as the base
|
||||
/// type of an ObjCObjectType.
|
||||
|
@ -1528,8 +1530,7 @@ public:
|
|||
/// i.e. a type which cannot appear in arbitrary positions in a
|
||||
/// fully-formed expression.
|
||||
bool isPlaceholderType() const {
|
||||
return getKind() == Overload ||
|
||||
getKind() == UndeducedAuto;
|
||||
return getKind() == Overload;
|
||||
}
|
||||
|
||||
static bool classof(const Type *T) { return T->getTypeClass() == Builtin; }
|
||||
|
@ -3014,6 +3015,48 @@ public:
|
|||
static bool classof(const SubstTemplateTypeParmPackType *T) { return true; }
|
||||
};
|
||||
|
||||
/// \brief Represents a C++0x auto type.
|
||||
///
|
||||
/// These types are usually a placeholder for a deduced type. However, within
|
||||
/// templates and before the initializer is attached, there is no deduced type
|
||||
/// and an auto type is type-dependent and canonical.
|
||||
class AutoType : public Type, public llvm::FoldingSetNode {
|
||||
AutoType(QualType DeducedType)
|
||||
: Type(Auto, DeducedType.isNull() ? QualType(this, 0) : DeducedType,
|
||||
/*Dependent=*/DeducedType.isNull(),
|
||||
/*VariablyModified=*/false, /*ContainsParameterPack=*/false) {
|
||||
assert((DeducedType.isNull() || !DeducedType->isDependentType()) &&
|
||||
"deduced a dependent type for auto");
|
||||
}
|
||||
|
||||
friend class ASTContext; // ASTContext creates these
|
||||
|
||||
public:
|
||||
bool isSugared() const { return isDeduced(); }
|
||||
QualType desugar() const { return getCanonicalTypeInternal(); }
|
||||
|
||||
QualType getDeducedType() const {
|
||||
return isDeduced() ? getCanonicalTypeInternal() : QualType();
|
||||
}
|
||||
bool isDeduced() const {
|
||||
return !isDependentType();
|
||||
}
|
||||
|
||||
void Profile(llvm::FoldingSetNodeID &ID) {
|
||||
Profile(ID, getDeducedType());
|
||||
}
|
||||
|
||||
static void Profile(llvm::FoldingSetNodeID &ID,
|
||||
QualType Deduced) {
|
||||
ID.AddPointer(Deduced.getAsOpaquePtr());
|
||||
}
|
||||
|
||||
static bool classof(const Type *T) {
|
||||
return T->getTypeClass() == Auto;
|
||||
}
|
||||
static bool classof(const AutoType *T) { return true; }
|
||||
};
|
||||
|
||||
/// \brief Represents the type of a template specialization as written
|
||||
/// in the source code.
|
||||
///
|
||||
|
|
|
@ -1381,6 +1381,11 @@ class DecltypeTypeLoc : public InheritingConcreteTypeLoc<TypeSpecTypeLoc,
|
|||
DecltypeType> {
|
||||
};
|
||||
|
||||
class AutoTypeLoc : public InheritingConcreteTypeLoc<TypeSpecTypeLoc,
|
||||
AutoTypeLoc,
|
||||
AutoType> {
|
||||
};
|
||||
|
||||
struct ElaboratedLocInfo {
|
||||
SourceLocation KeywordLoc;
|
||||
SourceRange QualifierRange;
|
||||
|
|
|
@ -93,6 +93,7 @@ DEPENDENT_TYPE(TemplateTypeParm, Type)
|
|||
NON_CANONICAL_TYPE(SubstTemplateTypeParm, Type)
|
||||
DEPENDENT_TYPE(SubstTemplateTypeParmPack, Type)
|
||||
NON_CANONICAL_UNLESS_DEPENDENT_TYPE(TemplateSpecialization, Type)
|
||||
NON_CANONICAL_UNLESS_DEPENDENT_TYPE(Auto, Type)
|
||||
DEPENDENT_TYPE(InjectedClassName, Type)
|
||||
DEPENDENT_TYPE(DependentName, Type)
|
||||
DEPENDENT_TYPE(DependentTemplateSpecialization, Type)
|
||||
|
|
|
@ -892,16 +892,31 @@ def err_cannot_determine_declared_type_of_overloaded_function : Error<
|
|||
def err_auto_variable_cannot_appear_in_own_initializer : Error<
|
||||
"variable %0 declared with 'auto' type cannot appear in its own initializer">;
|
||||
def err_illegal_decl_array_of_auto : Error<
|
||||
"'%0' declared as array of 'auto'">;
|
||||
"'%0' declared as array of %1">;
|
||||
def err_new_array_of_auto : Error<
|
||||
"cannot allocate array of 'auto'">;
|
||||
def err_auto_not_allowed : Error<
|
||||
"'auto' not allowed in %select{function prototype|struct member|union member"
|
||||
"|class member|exception declaration|template parameter|block literal}0">;
|
||||
"'auto' not allowed %select{in function prototype|in struct member"
|
||||
"|in union member|in class member|in exception declaration"
|
||||
"|in template parameter|in block literal|in template argument|here}0">;
|
||||
def err_auto_var_requires_init : Error<
|
||||
"declaration of variable %0 with type %1 requires an initializer">;
|
||||
def err_auto_new_requires_ctor_arg : Error<
|
||||
"new expression for type %0 requires a constructor argument">;
|
||||
def err_auto_var_init_multiple_expressions : Error<
|
||||
"initializer for variable %0 with type %1 contains multiple expressions">;
|
||||
def err_auto_new_ctor_multiple_expressions : Error<
|
||||
"new expression for type %0 contains multiple constructor arguments">;
|
||||
def err_auto_missing_trailing_return : Error<
|
||||
"'auto' return without trailing return type">;
|
||||
def err_trailing_return_without_auto : Error<
|
||||
"trailing return type without 'auto' return">;
|
||||
"function with trailing return type must specify return type 'auto', not %0">;
|
||||
def err_auto_var_deduction_failure : Error<
|
||||
"variable %0 with type %1 has incompatible initializer of type %2">;
|
||||
def err_auto_new_deduction_failure : Error<
|
||||
"new expression for type %0 has incompatible constructor argument of type %1">;
|
||||
def err_auto_different_deductions : Error<
|
||||
"'auto' deduced as %0 in declaration of %1 and deduced as %2 in declaration of %3">;
|
||||
|
||||
// C++0x override control
|
||||
def override_keyword_only_allowed_on_virtual_member_functions : Error<
|
||||
|
|
|
@ -730,7 +730,8 @@ public:
|
|||
QualType BuildParenType(QualType T);
|
||||
|
||||
TypeSourceInfo *GetTypeForDeclarator(Declarator &D, Scope *S,
|
||||
TagDecl **OwnedDecl = 0);
|
||||
TagDecl **OwnedDecl = 0,
|
||||
bool AllowAutoInTypeName = false);
|
||||
TypeSourceInfo *GetTypeSourceInfoForDeclarator(Declarator &D, QualType T,
|
||||
TypeSourceInfo *ReturnTypeInfo);
|
||||
/// \brief Package the given type and TSI into a ParsedType.
|
||||
|
@ -850,9 +851,9 @@ public:
|
|||
bool SetParamDefaultArgument(ParmVarDecl *Param, Expr *DefaultArg,
|
||||
SourceLocation EqualLoc);
|
||||
|
||||
void AddInitializerToDecl(Decl *dcl, Expr *init);
|
||||
void AddInitializerToDecl(Decl *dcl, Expr *init, bool DirectInit);
|
||||
void ActOnUninitializedDecl(Decl *dcl, bool TypeContainsUndeducedAuto);
|
||||
void AddInitializerToDecl(Decl *dcl, Expr *init, bool DirectInit,
|
||||
bool TypeMayContainAuto);
|
||||
void ActOnUninitializedDecl(Decl *dcl, bool TypeMayContainAuto);
|
||||
void ActOnInitializerError(Decl *Dcl);
|
||||
void SetDeclDeleted(Decl *dcl, SourceLocation DelLoc);
|
||||
DeclGroupPtrTy FinalizeDeclaratorGroup(Scope *S, const DeclSpec &DS,
|
||||
|
@ -1058,6 +1059,7 @@ public:
|
|||
void MergeTypeDefDecl(TypedefDecl *New, LookupResult &OldDecls);
|
||||
bool MergeFunctionDecl(FunctionDecl *New, Decl *Old);
|
||||
bool MergeCompatibleFunctionDecls(FunctionDecl *New, FunctionDecl *Old);
|
||||
void MergeVarDeclTypes(VarDecl *New, VarDecl *Old);
|
||||
void MergeVarDecl(VarDecl *New, LookupResult &OldDecls);
|
||||
bool MergeCXXFunctionDecl(FunctionDecl *New, FunctionDecl *Old);
|
||||
|
||||
|
@ -2237,7 +2239,8 @@ public:
|
|||
void AddCXXDirectInitializerToDecl(Decl *Dcl,
|
||||
SourceLocation LParenLoc,
|
||||
MultiExprArg Exprs,
|
||||
SourceLocation RParenLoc);
|
||||
SourceLocation RParenLoc,
|
||||
bool TypeMayContainAuto);
|
||||
|
||||
/// InitializeVarWithConstructor - Creates an CXXConstructExpr
|
||||
/// and sets it as the initializer for the the passed in VarDecl.
|
||||
|
@ -2458,7 +2461,8 @@ public:
|
|||
Expr *ArraySize,
|
||||
SourceLocation ConstructorLParen,
|
||||
MultiExprArg ConstructorArgs,
|
||||
SourceLocation ConstructorRParen);
|
||||
SourceLocation ConstructorRParen,
|
||||
bool TypeMayContainAuto = true);
|
||||
|
||||
bool CheckAllocatedType(QualType AllocType, SourceLocation Loc,
|
||||
SourceRange R);
|
||||
|
@ -3706,6 +3710,8 @@ public:
|
|||
FunctionDecl *&Specialization,
|
||||
sema::TemplateDeductionInfo &Info);
|
||||
|
||||
bool DeduceAutoType(QualType AutoType, Expr *Initializer, QualType &Result);
|
||||
|
||||
FunctionTemplateDecl *getMoreSpecializedTemplate(FunctionTemplateDecl *FT1,
|
||||
FunctionTemplateDecl *FT2,
|
||||
SourceLocation Loc,
|
||||
|
|
|
@ -578,7 +578,9 @@ namespace clang {
|
|||
/// \brief An AttributedType record.
|
||||
TYPE_ATTRIBUTED = 36,
|
||||
/// \brief A SubstTemplateTypeParmPackType record.
|
||||
TYPE_SUBST_TEMPLATE_TYPE_PARM_PACK = 37
|
||||
TYPE_SUBST_TEMPLATE_TYPE_PARM_PACK = 37,
|
||||
/// \brief A AutoType record.
|
||||
TYPE_AUTO = 38
|
||||
};
|
||||
|
||||
/// \brief The type IDs for special types constructed by semantic
|
||||
|
|
|
@ -380,10 +380,6 @@ void ASTContext::InitBuiltinTypes() {
|
|||
// Placeholder type for functions.
|
||||
InitBuiltinType(OverloadTy, BuiltinType::Overload);
|
||||
|
||||
// Placeholder type for C++0x auto declarations whose real type has
|
||||
// not yet been deduced.
|
||||
InitBuiltinType(UndeducedAutoTy, BuiltinType::UndeducedAuto);
|
||||
|
||||
// C99 6.2.5p11.
|
||||
FloatComplexTy = getComplexType(FloatTy);
|
||||
DoubleComplexTy = getComplexType(DoubleTy);
|
||||
|
@ -875,6 +871,12 @@ ASTContext::getTypeInfo(const Type *T) const {
|
|||
return getTypeInfo(cast<SubstTemplateTypeParmType>(T)->
|
||||
getReplacementType().getTypePtr());
|
||||
|
||||
case Type::Auto: {
|
||||
const AutoType *A = cast<AutoType>(T);
|
||||
assert(A->isDeduced() && "Cannot request the size of a dependent type");
|
||||
return getTypeInfo(cast<AutoType>(T)->getDeducedType().getTypePtr());
|
||||
}
|
||||
|
||||
case Type::Paren:
|
||||
return getTypeInfo(cast<ParenType>(T)->getInnerType().getTypePtr());
|
||||
|
||||
|
@ -1532,6 +1534,7 @@ QualType ASTContext::getVariableArrayDecayedType(QualType type) const {
|
|||
case Type::DependentTemplateSpecialization:
|
||||
case Type::TemplateTypeParm:
|
||||
case Type::SubstTemplateTypeParmPack:
|
||||
case Type::Auto:
|
||||
case Type::PackExpansion:
|
||||
llvm_unreachable("type should never be variably-modified");
|
||||
|
||||
|
@ -2680,6 +2683,14 @@ QualType ASTContext::getDecltypeType(Expr *e) const {
|
|||
return QualType(dt, 0);
|
||||
}
|
||||
|
||||
/// getAutoType - Unlike many "get<Type>" functions, we don't unique
|
||||
/// AutoType AST's.
|
||||
QualType ASTContext::getAutoType(QualType DeducedType) const {
|
||||
AutoType *at = new (*this, TypeAlignment) AutoType(DeducedType);
|
||||
Types.push_back(at);
|
||||
return QualType(at, 0);
|
||||
}
|
||||
|
||||
/// getTagDeclType - Return the unique reference to the type for the
|
||||
/// specified TagDecl (struct/union/class/enum) decl.
|
||||
QualType ASTContext::getTagDeclType(const TagDecl *Decl) const {
|
||||
|
|
|
@ -28,18 +28,26 @@ static QualType Desugar(ASTContext &Context, QualType QT, bool &ShouldAKA) {
|
|||
const Type *Ty = QC.strip(QT);
|
||||
|
||||
// Don't aka just because we saw an elaborated type...
|
||||
if (isa<ElaboratedType>(Ty)) {
|
||||
QT = cast<ElaboratedType>(Ty)->desugar();
|
||||
if (const ElaboratedType *ET = dyn_cast<ElaboratedType>(Ty)) {
|
||||
QT = ET->desugar();
|
||||
continue;
|
||||
}
|
||||
// ... or a paren type ...
|
||||
if (isa<ParenType>(Ty)) {
|
||||
QT = cast<ParenType>(Ty)->desugar();
|
||||
if (const ParenType *PT = dyn_cast<ParenType>(Ty)) {
|
||||
QT = PT->desugar();
|
||||
continue;
|
||||
}
|
||||
// ...or a substituted template type parameter.
|
||||
if (isa<SubstTemplateTypeParmType>(Ty)) {
|
||||
QT = cast<SubstTemplateTypeParmType>(Ty)->desugar();
|
||||
// ...or a substituted template type parameter ...
|
||||
if (const SubstTemplateTypeParmType *ST =
|
||||
dyn_cast<SubstTemplateTypeParmType>(Ty)) {
|
||||
QT = ST->desugar();
|
||||
continue;
|
||||
}
|
||||
// ... or an auto type.
|
||||
if (const AutoType *AT = dyn_cast<AutoType>(Ty)) {
|
||||
if (!AT->isSugared())
|
||||
break;
|
||||
QT = AT->desugar();
|
||||
continue;
|
||||
}
|
||||
|
||||
|
|
|
@ -64,6 +64,7 @@ namespace {
|
|||
// FIXME: DependentTypeOfExprType
|
||||
QualType VisitTypeOfType(const TypeOfType *T);
|
||||
QualType VisitDecltypeType(const DecltypeType *T);
|
||||
QualType VisitAutoType(const AutoType *T);
|
||||
// FIXME: DependentDecltypeType
|
||||
QualType VisitRecordType(const RecordType *T);
|
||||
QualType VisitEnumType(const EnumType *T);
|
||||
|
@ -604,6 +605,13 @@ static bool IsStructurallyEquivalent(StructuralEquivalenceContext &Context,
|
|||
return false;
|
||||
break;
|
||||
|
||||
case Type::Auto:
|
||||
if (!IsStructurallyEquivalent(Context,
|
||||
cast<AutoType>(T1)->getDeducedType(),
|
||||
cast<AutoType>(T2)->getDeducedType()))
|
||||
return false;
|
||||
break;
|
||||
|
||||
case Type::Record:
|
||||
case Type::Enum:
|
||||
if (!IsStructurallyEquivalent(Context,
|
||||
|
@ -1347,9 +1355,6 @@ QualType ASTNodeImporter::VisitBuiltinType(const BuiltinType *T) {
|
|||
|
||||
case BuiltinType::Overload: return Importer.getToContext().OverloadTy;
|
||||
case BuiltinType::Dependent: return Importer.getToContext().DependentTy;
|
||||
case BuiltinType::UndeducedAuto:
|
||||
// FIXME: Make sure that the "to" context supports C++0x!
|
||||
return Importer.getToContext().UndeducedAutoTy;
|
||||
|
||||
case BuiltinType::ObjCId:
|
||||
// FIXME: Make sure that the "to" context supports Objective-C!
|
||||
|
@ -1550,6 +1555,7 @@ QualType ASTNodeImporter::VisitTypeOfType(const TypeOfType *T) {
|
|||
}
|
||||
|
||||
QualType ASTNodeImporter::VisitDecltypeType(const DecltypeType *T) {
|
||||
// FIXME: Make sure that the "to" context supports C++0x!
|
||||
Expr *ToExpr = Importer.Import(T->getUnderlyingExpr());
|
||||
if (!ToExpr)
|
||||
return QualType();
|
||||
|
@ -1557,6 +1563,19 @@ QualType ASTNodeImporter::VisitDecltypeType(const DecltypeType *T) {
|
|||
return Importer.getToContext().getDecltypeType(ToExpr);
|
||||
}
|
||||
|
||||
QualType ASTNodeImporter::VisitAutoType(const AutoType *T) {
|
||||
// FIXME: Make sure that the "to" context supports C++0x!
|
||||
QualType FromDeduced = T->getDeducedType();
|
||||
QualType ToDeduced;
|
||||
if (!FromDeduced.isNull()) {
|
||||
ToDeduced = Importer.Import(FromDeduced);
|
||||
if (ToDeduced.isNull())
|
||||
return QualType();
|
||||
}
|
||||
|
||||
return Importer.getToContext().getAutoType(ToDeduced);
|
||||
}
|
||||
|
||||
QualType ASTNodeImporter::VisitRecordType(const RecordType *T) {
|
||||
RecordDecl *ToDecl
|
||||
= dyn_cast_or_null<RecordDecl>(Importer.Import(T->getDecl()));
|
||||
|
|
|
@ -1313,9 +1313,6 @@ void CXXNameMangler::mangleType(const BuiltinType *T) {
|
|||
assert(false &&
|
||||
"Overloaded and dependent types shouldn't get to name mangling");
|
||||
break;
|
||||
case BuiltinType::UndeducedAuto:
|
||||
assert(0 && "Should not see undeduced auto here");
|
||||
break;
|
||||
case BuiltinType::ObjCId: Out << "11objc_object"; break;
|
||||
case BuiltinType::ObjCClass: Out << "10objc_class"; break;
|
||||
case BuiltinType::ObjCSel: Out << "13objc_selector"; break;
|
||||
|
@ -1648,6 +1645,12 @@ void CXXNameMangler::mangleType(const DecltypeType *T) {
|
|||
Out << 'E';
|
||||
}
|
||||
|
||||
void CXXNameMangler::mangleType(const AutoType *T) {
|
||||
QualType D = T->getDeducedType();
|
||||
assert(!D.isNull() && "can't mangle undeduced auto type");
|
||||
mangleType(D);
|
||||
}
|
||||
|
||||
void CXXNameMangler::mangleIntegerLiteral(QualType T,
|
||||
const llvm::APSInt &Value) {
|
||||
// <expr-primary> ::= L <type> <value number> E # integer literal
|
||||
|
|
|
@ -720,9 +720,6 @@ void MicrosoftCXXNameMangler::mangleType(const BuiltinType *T) {
|
|||
assert(false &&
|
||||
"Overloaded and dependent types shouldn't get to name mangling");
|
||||
break;
|
||||
case BuiltinType::UndeducedAuto:
|
||||
assert(0 && "Should not see undeduced auto here");
|
||||
break;
|
||||
case BuiltinType::ObjCId: Out << "PAUobjc_object@@"; break;
|
||||
case BuiltinType::ObjCClass: Out << "PAUobjc_class@@"; break;
|
||||
case BuiltinType::ObjCSel: Out << "PAUobjc_selector@@"; break;
|
||||
|
@ -1119,6 +1116,10 @@ void MicrosoftCXXNameMangler::mangleType(const DecltypeType *T) {
|
|||
assert(false && "Don't know how to mangle DecltypeTypes yet!");
|
||||
}
|
||||
|
||||
void MicrosoftCXXNameMangler::mangleType(const AutoType *T) {
|
||||
assert(false && "Don't know how to mangle AutoTypes yet!");
|
||||
}
|
||||
|
||||
void MicrosoftMangleContext::mangleName(const NamedDecl *D,
|
||||
llvm::raw_ostream &Out) {
|
||||
assert((isa<FunctionDecl>(D) || isa<VarDecl>(D)) &&
|
||||
|
|
|
@ -432,6 +432,61 @@ CXXRecordDecl *Type::getAsCXXRecordDecl() const {
|
|||
return 0;
|
||||
}
|
||||
|
||||
namespace {
|
||||
class GetContainedAutoVisitor :
|
||||
public TypeVisitor<GetContainedAutoVisitor, AutoType*> {
|
||||
public:
|
||||
using TypeVisitor<GetContainedAutoVisitor, AutoType*>::Visit;
|
||||
AutoType *Visit(QualType T) {
|
||||
if (T.isNull())
|
||||
return 0;
|
||||
return Visit(T.getTypePtr());
|
||||
}
|
||||
|
||||
// The 'auto' type itself.
|
||||
AutoType *VisitAutoType(const AutoType *AT) {
|
||||
return const_cast<AutoType*>(AT);
|
||||
}
|
||||
|
||||
// Only these types can contain the desired 'auto' type.
|
||||
AutoType *VisitPointerType(const PointerType *T) {
|
||||
return Visit(T->getPointeeType());
|
||||
}
|
||||
AutoType *VisitBlockPointerType(const BlockPointerType *T) {
|
||||
return Visit(T->getPointeeType());
|
||||
}
|
||||
AutoType *VisitReferenceType(const ReferenceType *T) {
|
||||
return Visit(T->getPointeeTypeAsWritten());
|
||||
}
|
||||
AutoType *VisitMemberPointerType(const MemberPointerType *T) {
|
||||
return Visit(T->getPointeeType());
|
||||
}
|
||||
AutoType *VisitArrayType(const ArrayType *T) {
|
||||
return Visit(T->getElementType());
|
||||
}
|
||||
AutoType *VisitDependentSizedExtVectorType(
|
||||
const DependentSizedExtVectorType *T) {
|
||||
return Visit(T->getElementType());
|
||||
}
|
||||
AutoType *VisitVectorType(const VectorType *T) {
|
||||
return Visit(T->getElementType());
|
||||
}
|
||||
AutoType *VisitFunctionType(const FunctionType *T) {
|
||||
return Visit(T->getResultType());
|
||||
}
|
||||
AutoType *VisitParenType(const ParenType *T) {
|
||||
return Visit(T->getInnerType());
|
||||
}
|
||||
AutoType *VisitAttributedType(const AttributedType *T) {
|
||||
return Visit(T->getModifiedType());
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
AutoType *Type::getContainedAutoType() const {
|
||||
return GetContainedAutoVisitor().Visit(this);
|
||||
}
|
||||
|
||||
bool Type::isIntegerType() const {
|
||||
if (const BuiltinType *BT = dyn_cast<BuiltinType>(CanonicalType))
|
||||
return BT->getKind() >= BuiltinType::Bool &&
|
||||
|
@ -1066,7 +1121,6 @@ const char *BuiltinType::getName(const LangOptions &LO) const {
|
|||
case NullPtr: return "nullptr_t";
|
||||
case Overload: return "<overloaded function type>";
|
||||
case Dependent: return "<dependent type>";
|
||||
case UndeducedAuto: return "auto";
|
||||
case ObjCId: return "id";
|
||||
case ObjCClass: return "Class";
|
||||
case ObjCSel: return "SEL";
|
||||
|
|
|
@ -191,9 +191,7 @@ TypeSpecifierType BuiltinTypeLoc::getWrittenTypeSpec() const {
|
|||
case BuiltinType::WChar_S:
|
||||
case BuiltinType::WChar_U:
|
||||
return TST_wchar;
|
||||
case BuiltinType::UndeducedAuto:
|
||||
return TST_auto;
|
||||
|
||||
|
||||
case BuiltinType::UChar:
|
||||
case BuiltinType::UShort:
|
||||
case BuiltinType::UInt:
|
||||
|
|
|
@ -80,6 +80,8 @@ void TypePrinter::print(const Type *T, Qualifiers Quals, std::string &buffer) {
|
|||
bool CanPrefixQualifiers = false;
|
||||
|
||||
Type::TypeClass TC = T->getTypeClass();
|
||||
if (const AutoType *AT = dyn_cast<AutoType>(T))
|
||||
TC = AT->desugar()->getTypeClass();
|
||||
if (const SubstTemplateTypeParmType *Subst
|
||||
= dyn_cast<SubstTemplateTypeParmType>(T))
|
||||
TC = Subst->getReplacementType()->getTypeClass();
|
||||
|
@ -129,6 +131,7 @@ void TypePrinter::print(const Type *T, Qualifiers Quals, std::string &buffer) {
|
|||
case Type::Attributed:
|
||||
case Type::PackExpansion:
|
||||
case Type::SubstTemplateTypeParm:
|
||||
case Type::Auto:
|
||||
CanPrefixQualifiers = false;
|
||||
break;
|
||||
}
|
||||
|
@ -493,6 +496,17 @@ void TypePrinter::printDecltype(const DecltypeType *T, std::string &S) {
|
|||
S = "decltype(" + s.str() + ")" + S;
|
||||
}
|
||||
|
||||
void TypePrinter::printAuto(const AutoType *T, std::string &S) {
|
||||
// If the type has been deduced, do not print 'auto'.
|
||||
if (T->isDeduced()) {
|
||||
print(T->getDeducedType(), S);
|
||||
} else {
|
||||
if (!S.empty()) // Prefix the basic type, e.g. 'auto X'.
|
||||
S = ' ' + S;
|
||||
S = "auto" + S;
|
||||
}
|
||||
}
|
||||
|
||||
/// Appends the given scope to the end of a string.
|
||||
void TypePrinter::AppendScope(DeclContext *DC, std::string &Buffer) {
|
||||
if (DC->isTranslationUnit()) return;
|
||||
|
|
|
@ -1465,6 +1465,7 @@ llvm::DIType CGDebugInfo::CreateTypeNode(QualType Ty,
|
|||
case Type::TypeOfExpr:
|
||||
case Type::TypeOf:
|
||||
case Type::Decltype:
|
||||
case Type::Auto:
|
||||
llvm_unreachable("type should have been unwrapped!");
|
||||
return llvm::DIType();
|
||||
}
|
||||
|
|
|
@ -195,7 +195,6 @@ static bool TypeInfoIsInStandardLibrary(const BuiltinType *Ty) {
|
|||
|
||||
case BuiltinType::Overload:
|
||||
case BuiltinType::Dependent:
|
||||
case BuiltinType::UndeducedAuto:
|
||||
assert(false && "Should not see this type here!");
|
||||
|
||||
case BuiltinType::ObjCId:
|
||||
|
|
|
@ -253,7 +253,6 @@ const llvm::Type *CodeGenTypes::ConvertNewType(QualType T) {
|
|||
|
||||
case BuiltinType::Overload:
|
||||
case BuiltinType::Dependent:
|
||||
case BuiltinType::UndeducedAuto:
|
||||
assert(0 && "Unexpected builtin type!");
|
||||
break;
|
||||
}
|
||||
|
|
|
@ -392,7 +392,7 @@ Parser::DeclGroupPtrTy Parser::ParseSimpleDeclaration(StmtVector &Stmts,
|
|||
ParsingDeclSpec DS(*this);
|
||||
DS.takeAttributesFrom(attrs);
|
||||
ParseDeclarationSpecifiers(DS, ParsedTemplateInfo(), AS_none,
|
||||
getDeclSpecContextFromDeclaratorContext(Context));
|
||||
getDeclSpecContextFromDeclaratorContext(Context));
|
||||
StmtResult R = Actions.ActOnVlaStmt(DS);
|
||||
if (R.isUsable())
|
||||
Stmts.push_back(R.release());
|
||||
|
@ -587,6 +587,9 @@ Decl *Parser::ParseDeclarationAfterDeclarator(Declarator &D,
|
|||
}
|
||||
}
|
||||
|
||||
bool TypeContainsAuto =
|
||||
D.getDeclSpec().getTypeSpecType() == DeclSpec::TST_auto;
|
||||
|
||||
// Parse declarator '=' initializer.
|
||||
if (isTokenEqualOrMistypedEqualEqual(
|
||||
diag::err_invalid_equalequal_after_declarator)) {
|
||||
|
@ -622,7 +625,8 @@ Decl *Parser::ParseDeclarationAfterDeclarator(Declarator &D,
|
|||
SkipUntil(tok::comma, true, true);
|
||||
Actions.ActOnInitializerError(ThisDecl);
|
||||
} else
|
||||
Actions.AddInitializerToDecl(ThisDecl, Init.take());
|
||||
Actions.AddInitializerToDecl(ThisDecl, Init.take(),
|
||||
/*DirectInit=*/false, TypeContainsAuto);
|
||||
}
|
||||
} else if (Tok.is(tok::l_paren)) {
|
||||
// Parse C++ direct initializer: '(' expression-list ')'
|
||||
|
@ -656,12 +660,11 @@ Decl *Parser::ParseDeclarationAfterDeclarator(Declarator &D,
|
|||
|
||||
Actions.AddCXXDirectInitializerToDecl(ThisDecl, LParenLoc,
|
||||
move_arg(Exprs),
|
||||
RParenLoc);
|
||||
RParenLoc,
|
||||
TypeContainsAuto);
|
||||
}
|
||||
} else {
|
||||
bool TypeContainsUndeducedAuto =
|
||||
D.getDeclSpec().getTypeSpecType() == DeclSpec::TST_auto;
|
||||
Actions.ActOnUninitializedDecl(ThisDecl, TypeContainsUndeducedAuto);
|
||||
Actions.ActOnUninitializedDecl(ThisDecl, TypeContainsAuto);
|
||||
}
|
||||
|
||||
return ThisDecl;
|
||||
|
|
|
@ -827,7 +827,8 @@ bool Parser::ParseCXXCondition(ExprResult &ExprOut,
|
|||
ConsumeToken();
|
||||
ExprResult AssignExpr(ParseAssignmentExpression());
|
||||
if (!AssignExpr.isInvalid())
|
||||
Actions.AddInitializerToDecl(DeclOut, AssignExpr.take());
|
||||
Actions.AddInitializerToDecl(DeclOut, AssignExpr.take(), false,
|
||||
DS.getTypeSpecType() == DeclSpec::TST_auto);
|
||||
} else {
|
||||
// FIXME: C++0x allows a braced-init-list
|
||||
Diag(Tok, diag::err_expected_equal_after_declarator);
|
||||
|
|
|
@ -586,7 +586,6 @@ SimplifiedTypeClass clang::getSimplifiedTypeClass(CanQualType T) {
|
|||
|
||||
case BuiltinType::Overload:
|
||||
case BuiltinType::Dependent:
|
||||
case BuiltinType::UndeducedAuto:
|
||||
return STC_Other;
|
||||
|
||||
case BuiltinType::ObjCId:
|
||||
|
|
|
@ -1471,6 +1471,64 @@ bool Sema::MergeCompatibleFunctionDecls(FunctionDecl *New, FunctionDecl *Old) {
|
|||
return false;
|
||||
}
|
||||
|
||||
/// MergeVarDecl - We parsed a variable 'New' which has the same name and scope
|
||||
/// as a previous declaration 'Old'. Figure out how to merge their types,
|
||||
/// emitting diagnostics as appropriate.
|
||||
///
|
||||
/// Declarations using the auto type specifier (C++ [decl.spec.auto]) call back
|
||||
/// to here in AddInitializerToDecl and AddCXXDirectInitializerToDecl. We can't
|
||||
/// check them before the initializer is attached.
|
||||
///
|
||||
void Sema::MergeVarDeclTypes(VarDecl *New, VarDecl *Old) {
|
||||
if (New->isInvalidDecl() || Old->isInvalidDecl())
|
||||
return;
|
||||
|
||||
QualType MergedT;
|
||||
if (getLangOptions().CPlusPlus) {
|
||||
AutoType *AT = New->getType()->getContainedAutoType();
|
||||
if (AT && !AT->isDeduced()) {
|
||||
// We don't know what the new type is until the initializer is attached.
|
||||
return;
|
||||
} else if (Context.hasSameType(New->getType(), Old->getType()))
|
||||
return;
|
||||
// C++ [basic.link]p10:
|
||||
// [...] the types specified by all declarations referring to a given
|
||||
// object or function shall be identical, except that declarations for an
|
||||
// array object can specify array types that differ by the presence or
|
||||
// absence of a major array bound (8.3.4).
|
||||
else if (Old->getType()->isIncompleteArrayType() &&
|
||||
New->getType()->isArrayType()) {
|
||||
CanQual<ArrayType> OldArray
|
||||
= Context.getCanonicalType(Old->getType())->getAs<ArrayType>();
|
||||
CanQual<ArrayType> NewArray
|
||||
= Context.getCanonicalType(New->getType())->getAs<ArrayType>();
|
||||
if (OldArray->getElementType() == NewArray->getElementType())
|
||||
MergedT = New->getType();
|
||||
} else if (Old->getType()->isArrayType() &&
|
||||
New->getType()->isIncompleteArrayType()) {
|
||||
CanQual<ArrayType> OldArray
|
||||
= Context.getCanonicalType(Old->getType())->getAs<ArrayType>();
|
||||
CanQual<ArrayType> NewArray
|
||||
= Context.getCanonicalType(New->getType())->getAs<ArrayType>();
|
||||
if (OldArray->getElementType() == NewArray->getElementType())
|
||||
MergedT = Old->getType();
|
||||
} else if (New->getType()->isObjCObjectPointerType()
|
||||
&& Old->getType()->isObjCObjectPointerType()) {
|
||||
MergedT = Context.mergeObjCGCQualifiers(New->getType(),
|
||||
Old->getType());
|
||||
}
|
||||
} else {
|
||||
MergedT = Context.mergeTypes(New->getType(), Old->getType());
|
||||
}
|
||||
if (MergedT.isNull()) {
|
||||
Diag(New->getLocation(), diag::err_redefinition_different_type)
|
||||
<< New->getDeclName();
|
||||
Diag(Old->getLocation(), diag::note_previous_definition);
|
||||
return New->setInvalidDecl();
|
||||
}
|
||||
New->setType(MergedT);
|
||||
}
|
||||
|
||||
/// MergeVarDecl - We just parsed a variable 'New' which has the same name
|
||||
/// and scope as a previous declaration 'Old'. Figure out how to resolve this
|
||||
/// situation, merging decls or emitting diagnostics as appropriate.
|
||||
|
@ -1508,46 +1566,10 @@ void Sema::MergeVarDecl(VarDecl *New, LookupResult &Previous) {
|
|||
|
||||
MergeDeclAttributes(New, Old, Context);
|
||||
|
||||
// Merge the types
|
||||
QualType MergedT;
|
||||
if (getLangOptions().CPlusPlus) {
|
||||
if (Context.hasSameType(New->getType(), Old->getType()))
|
||||
MergedT = New->getType();
|
||||
// C++ [basic.link]p10:
|
||||
// [...] the types specified by all declarations referring to a given
|
||||
// object or function shall be identical, except that declarations for an
|
||||
// array object can specify array types that differ by the presence or
|
||||
// absence of a major array bound (8.3.4).
|
||||
else if (Old->getType()->isIncompleteArrayType() &&
|
||||
New->getType()->isArrayType()) {
|
||||
CanQual<ArrayType> OldArray
|
||||
= Context.getCanonicalType(Old->getType())->getAs<ArrayType>();
|
||||
CanQual<ArrayType> NewArray
|
||||
= Context.getCanonicalType(New->getType())->getAs<ArrayType>();
|
||||
if (OldArray->getElementType() == NewArray->getElementType())
|
||||
MergedT = New->getType();
|
||||
} else if (Old->getType()->isArrayType() &&
|
||||
New->getType()->isIncompleteArrayType()) {
|
||||
CanQual<ArrayType> OldArray
|
||||
= Context.getCanonicalType(Old->getType())->getAs<ArrayType>();
|
||||
CanQual<ArrayType> NewArray
|
||||
= Context.getCanonicalType(New->getType())->getAs<ArrayType>();
|
||||
if (OldArray->getElementType() == NewArray->getElementType())
|
||||
MergedT = Old->getType();
|
||||
} else if (New->getType()->isObjCObjectPointerType()
|
||||
&& Old->getType()->isObjCObjectPointerType()) {
|
||||
MergedT = Context.mergeObjCGCQualifiers(New->getType(), Old->getType());
|
||||
}
|
||||
} else {
|
||||
MergedT = Context.mergeTypes(New->getType(), Old->getType());
|
||||
}
|
||||
if (MergedT.isNull()) {
|
||||
Diag(New->getLocation(), diag::err_redefinition_different_type)
|
||||
<< New->getDeclName();
|
||||
Diag(Old->getLocation(), diag::note_previous_definition);
|
||||
return New->setInvalidDecl();
|
||||
}
|
||||
New->setType(MergedT);
|
||||
// Merge the types.
|
||||
MergeVarDeclTypes(New, Old);
|
||||
if (New->isInvalidDecl())
|
||||
return;
|
||||
|
||||
// C99 6.2.2p4: Check if we have a static decl followed by a non-static.
|
||||
if (New->getStorageClass() == SC_Static &&
|
||||
|
@ -3004,6 +3026,12 @@ Sema::ActOnVariableDeclarator(Scope *S, Declarator &D, DeclContext *DC,
|
|||
NewVD = VarDecl::Create(Context, DC, D.getIdentifierLoc(),
|
||||
II, R, TInfo, SC, SCAsWritten);
|
||||
|
||||
// If this decl has an auto type in need of deduction, mark the VarDecl so
|
||||
// we can diagnose uses of it in its own initializer.
|
||||
if (D.getDeclSpec().getTypeSpecType() == DeclSpec::TST_auto) {
|
||||
NewVD->setParsingAutoInit(R->getContainedAutoType());
|
||||
}
|
||||
|
||||
if (D.isInvalidType() || Invalid)
|
||||
NewVD->setInvalidDecl();
|
||||
|
||||
|
@ -4466,17 +4494,14 @@ bool Sema::CheckForConstantInitializer(Expr *Init, QualType DclT) {
|
|||
return true;
|
||||
}
|
||||
|
||||
void Sema::AddInitializerToDecl(Decl *dcl, Expr *init) {
|
||||
AddInitializerToDecl(dcl, init, /*DirectInit=*/false);
|
||||
}
|
||||
|
||||
/// AddInitializerToDecl - Adds the initializer Init to the
|
||||
/// declaration dcl. If DirectInit is true, this is C++ direct
|
||||
/// initialization rather than copy initialization.
|
||||
void Sema::AddInitializerToDecl(Decl *RealDecl, Expr *Init, bool DirectInit) {
|
||||
void Sema::AddInitializerToDecl(Decl *RealDecl, Expr *Init,
|
||||
bool DirectInit, bool TypeMayContainAuto) {
|
||||
// If there is no declaration, there was an error parsing it. Just ignore
|
||||
// the initializer.
|
||||
if (RealDecl == 0)
|
||||
if (RealDecl == 0 || RealDecl->isInvalidDecl())
|
||||
return;
|
||||
|
||||
if (CXXMethodDecl *Method = dyn_cast<CXXMethodDecl>(RealDecl)) {
|
||||
|
@ -4507,6 +4532,25 @@ void Sema::AddInitializerToDecl(Decl *RealDecl, Expr *Init, bool DirectInit) {
|
|||
return;
|
||||
}
|
||||
|
||||
// C++0x [decl.spec.auto]p6. Deduce the type which 'auto' stands in for.
|
||||
if (TypeMayContainAuto && VDecl->getType()->getContainedAutoType()) {
|
||||
VDecl->setParsingAutoInit(false);
|
||||
|
||||
QualType DeducedType;
|
||||
if (!DeduceAutoType(VDecl->getType(), Init, DeducedType)) {
|
||||
Diag(VDecl->getLocation(), diag::err_auto_var_deduction_failure)
|
||||
<< VDecl->getDeclName() << VDecl->getType() << Init->getType()
|
||||
<< Init->getSourceRange();
|
||||
RealDecl->setInvalidDecl();
|
||||
return;
|
||||
}
|
||||
VDecl->setType(DeducedType);
|
||||
|
||||
// If this is a redeclaration, check that the type we just deduced matches
|
||||
// the previously declared type.
|
||||
if (VarDecl *Old = VDecl->getPreviousDeclaration())
|
||||
MergeVarDeclTypes(VDecl, Old);
|
||||
}
|
||||
|
||||
|
||||
// A definition must end up with a complete type, which means it must be
|
||||
|
@ -4755,6 +4799,13 @@ void Sema::ActOnInitializerError(Decl *D) {
|
|||
VarDecl *VD = dyn_cast<VarDecl>(D);
|
||||
if (!VD) return;
|
||||
|
||||
// Auto types are meaningless if we can't make sense of the initializer.
|
||||
if (VD->isParsingAutoInit()) {
|
||||
VD->setParsingAutoInit(false);
|
||||
VD->setInvalidDecl();
|
||||
return;
|
||||
}
|
||||
|
||||
QualType Ty = VD->getType();
|
||||
if (Ty->isDependentType()) return;
|
||||
|
||||
|
@ -4779,7 +4830,7 @@ void Sema::ActOnInitializerError(Decl *D) {
|
|||
}
|
||||
|
||||
void Sema::ActOnUninitializedDecl(Decl *RealDecl,
|
||||
bool TypeContainsUndeducedAuto) {
|
||||
bool TypeMayContainAuto) {
|
||||
// If there is no declaration, there was an error parsing it. Just ignore it.
|
||||
if (RealDecl == 0)
|
||||
return;
|
||||
|
@ -4788,7 +4839,9 @@ void Sema::ActOnUninitializedDecl(Decl *RealDecl,
|
|||
QualType Type = Var->getType();
|
||||
|
||||
// C++0x [dcl.spec.auto]p3
|
||||
if (TypeContainsUndeducedAuto) {
|
||||
if (TypeMayContainAuto && Type->getContainedAutoType()) {
|
||||
Var->setParsingAutoInit(false);
|
||||
|
||||
Diag(Var->getLocation(), diag::err_auto_var_requires_init)
|
||||
<< Var->getDeclName() << Type;
|
||||
Var->setInvalidDecl();
|
||||
|
@ -4999,6 +5052,41 @@ Sema::FinalizeDeclaratorGroup(Scope *S, const DeclSpec &DS,
|
|||
if (DS.isTypeSpecOwned())
|
||||
Decls.push_back(DS.getRepAsDecl());
|
||||
|
||||
// C++0x [dcl.spec.auto]p7:
|
||||
// If the type deduced for the template parameter U is not the same in each
|
||||
// deduction, the program is ill-formed.
|
||||
// FIXME: When initializer-list support is added, a distinction is needed
|
||||
// between the deduced type U and the deduced type which 'auto' stands for.
|
||||
// auto a = 0, b = { 1, 2, 3 };
|
||||
// is legal because the deduced type U is 'int' in both cases.
|
||||
bool TypeContainsAuto = DS.getTypeSpecType() == DeclSpec::TST_auto;
|
||||
if (TypeContainsAuto && NumDecls > 1) {
|
||||
QualType Deduced;
|
||||
CanQualType DeducedCanon;
|
||||
VarDecl *DeducedDecl = 0;
|
||||
for (unsigned i = 0; i != NumDecls; ++i) {
|
||||
if (VarDecl *D = dyn_cast<VarDecl>(Group[i])) {
|
||||
AutoType *AT = D->getType()->getContainedAutoType();
|
||||
if (AT && AT->isDeduced()) {
|
||||
QualType U = AT->getDeducedType();
|
||||
CanQualType UCanon = Context.getCanonicalType(U);
|
||||
if (Deduced.isNull()) {
|
||||
Deduced = U;
|
||||
DeducedCanon = UCanon;
|
||||
DeducedDecl = D;
|
||||
} else if (DeducedCanon != UCanon) {
|
||||
Diag(DS.getTypeSpecTypeLoc(), diag::err_auto_different_deductions)
|
||||
<< Deduced << DeducedDecl->getDeclName()
|
||||
<< U << D->getDeclName()
|
||||
<< DeducedDecl->getInit()->getSourceRange()
|
||||
<< D->getInit()->getSourceRange();
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
for (unsigned i = 0; i != NumDecls; ++i)
|
||||
if (Decl *D = Group[i])
|
||||
Decls.push_back(D);
|
||||
|
|
|
@ -1073,7 +1073,8 @@ Sema::ActOnCXXMemberDeclarator(Scope *S, AccessSpecifier AS, Declarator &D,
|
|||
assert((Name || isInstField) && "No identifier for non-field ?");
|
||||
|
||||
if (Init)
|
||||
AddInitializerToDecl(Member, Init, false);
|
||||
AddInitializerToDecl(Member, Init, false,
|
||||
DS.getTypeSpecType() == DeclSpec::TST_auto);
|
||||
if (Deleted) // FIXME: Source location is not very good.
|
||||
SetDeclDeleted(Member, D.getSourceRange().getBegin());
|
||||
|
||||
|
@ -5953,7 +5954,8 @@ void Sema::FinalizeVarWithDestructor(VarDecl *VD, const RecordType *Record) {
|
|||
void Sema::AddCXXDirectInitializerToDecl(Decl *RealDecl,
|
||||
SourceLocation LParenLoc,
|
||||
MultiExprArg Exprs,
|
||||
SourceLocation RParenLoc) {
|
||||
SourceLocation RParenLoc,
|
||||
bool TypeMayContainAuto) {
|
||||
assert(Exprs.size() != 0 && Exprs.get() && "missing expressions");
|
||||
|
||||
// If there is no declaration, there was an error parsing it. Just ignore
|
||||
|
@ -5968,6 +5970,37 @@ void Sema::AddCXXDirectInitializerToDecl(Decl *RealDecl,
|
|||
return;
|
||||
}
|
||||
|
||||
// C++0x [decl.spec.auto]p6. Deduce the type which 'auto' stands in for.
|
||||
if (TypeMayContainAuto && VDecl->getType()->getContainedAutoType()) {
|
||||
VDecl->setParsingAutoInit(false);
|
||||
|
||||
// FIXME: n3225 doesn't actually seem to indicate this is ill-formed
|
||||
if (Exprs.size() > 1) {
|
||||
Diag(Exprs.get()[1]->getSourceRange().getBegin(),
|
||||
diag::err_auto_var_init_multiple_expressions)
|
||||
<< VDecl->getDeclName() << VDecl->getType()
|
||||
<< VDecl->getSourceRange();
|
||||
RealDecl->setInvalidDecl();
|
||||
return;
|
||||
}
|
||||
|
||||
Expr *Init = Exprs.get()[0];
|
||||
QualType DeducedType;
|
||||
if (!DeduceAutoType(VDecl->getType(), Init, DeducedType)) {
|
||||
Diag(VDecl->getLocation(), diag::err_auto_var_deduction_failure)
|
||||
<< VDecl->getDeclName() << VDecl->getType() << Init->getType()
|
||||
<< Init->getSourceRange();
|
||||
RealDecl->setInvalidDecl();
|
||||
return;
|
||||
}
|
||||
VDecl->setType(DeducedType);
|
||||
|
||||
// If this is a redeclaration, check that the type we just deduced matches
|
||||
// the previously declared type.
|
||||
if (VarDecl *Old = VDecl->getPreviousDeclaration())
|
||||
MergeVarDeclTypes(VDecl, Old);
|
||||
}
|
||||
|
||||
// We will represent direct-initialization similarly to copy-initialization:
|
||||
// int x(1); -as-> int x = 1;
|
||||
// ClassType x(a,b,c); -as-> ClassType x = ClassType(a,b,c);
|
||||
|
|
|
@ -75,6 +75,15 @@ bool Sema::DiagnoseUseOfDecl(NamedDecl *D, SourceLocation Loc,
|
|||
}
|
||||
}
|
||||
|
||||
// See if this is an auto-typed variable whose initializer we are parsing.
|
||||
if (const VarDecl *VD = dyn_cast<VarDecl>(D)) {
|
||||
if (VD->isParsingAutoInit()) {
|
||||
Diag(Loc, diag::err_auto_variable_cannot_appear_in_own_initializer)
|
||||
<< D->getDeclName();
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
// See if the decl is deprecated.
|
||||
if (const DeprecatedAttr *DA = D->getAttr<DeprecatedAttr>())
|
||||
EmitDeprecationWarning(D, DA->getMessage(), Loc, UnknownObjCClass);
|
||||
|
@ -964,13 +973,6 @@ ExprResult
|
|||
Sema::BuildDeclRefExpr(ValueDecl *D, QualType Ty, ExprValueKind VK,
|
||||
const DeclarationNameInfo &NameInfo,
|
||||
const CXXScopeSpec *SS) {
|
||||
if (Ty == Context.UndeducedAutoTy) {
|
||||
Diag(NameInfo.getLoc(),
|
||||
diag::err_auto_variable_cannot_appear_in_own_initializer)
|
||||
<< D->getDeclName();
|
||||
return ExprError();
|
||||
}
|
||||
|
||||
MarkDeclarationReferenced(NameInfo.getLoc(), D);
|
||||
|
||||
Expr *E = DeclRefExpr::Create(Context,
|
||||
|
@ -9650,26 +9652,18 @@ ExprResult Sema::CheckPlaceholderExpr(Expr *E, SourceLocation Loc) {
|
|||
if (!BT || !BT->isPlaceholderType()) return Owned(E);
|
||||
|
||||
// If this is overload, check for a single overload.
|
||||
if (BT->getKind() == BuiltinType::Overload) {
|
||||
if (FunctionDecl *Specialization
|
||||
= ResolveSingleFunctionTemplateSpecialization(E)) {
|
||||
// The access doesn't really matter in this case.
|
||||
DeclAccessPair Found = DeclAccessPair::make(Specialization,
|
||||
Specialization->getAccess());
|
||||
E = FixOverloadedFunctionReference(E, Found, Specialization);
|
||||
if (!E) return ExprError();
|
||||
return Owned(E);
|
||||
}
|
||||
assert(BT->getKind() == BuiltinType::Overload);
|
||||
|
||||
Diag(Loc, diag::err_ovl_unresolvable) << E->getSourceRange();
|
||||
return ExprError();
|
||||
if (FunctionDecl *Specialization
|
||||
= ResolveSingleFunctionTemplateSpecialization(E)) {
|
||||
// The access doesn't really matter in this case.
|
||||
DeclAccessPair Found = DeclAccessPair::make(Specialization,
|
||||
Specialization->getAccess());
|
||||
E = FixOverloadedFunctionReference(E, Found, Specialization);
|
||||
if (!E) return ExprError();
|
||||
return Owned(E);
|
||||
}
|
||||
|
||||
// Otherwise it's a use of undeduced auto.
|
||||
assert(BT->getKind() == BuiltinType::UndeducedAuto);
|
||||
|
||||
DeclRefExpr *DRE = cast<DeclRefExpr>(E->IgnoreParens());
|
||||
Diag(Loc, diag::err_auto_variable_cannot_appear_in_own_initializer)
|
||||
<< DRE->getDecl() << E->getSourceRange();
|
||||
Diag(Loc, diag::err_ovl_unresolvable) << E->getSourceRange();
|
||||
return ExprError();
|
||||
}
|
||||
|
|
|
@ -759,11 +759,16 @@ Sema::ActOnCXXNew(SourceLocation StartLoc, bool UseGlobal,
|
|||
Declarator &D, SourceLocation ConstructorLParen,
|
||||
MultiExprArg ConstructorArgs,
|
||||
SourceLocation ConstructorRParen) {
|
||||
bool TypeContainsAuto = D.getDeclSpec().getTypeSpecType() == DeclSpec::TST_auto;
|
||||
|
||||
Expr *ArraySize = 0;
|
||||
// If the specified type is an array, unwrap it and save the expression.
|
||||
if (D.getNumTypeObjects() > 0 &&
|
||||
D.getTypeObject(0).Kind == DeclaratorChunk::Array) {
|
||||
DeclaratorChunk &Chunk = D.getTypeObject(0);
|
||||
if (TypeContainsAuto)
|
||||
return ExprError(Diag(Chunk.Loc, diag::err_new_array_of_auto)
|
||||
<< D.getSourceRange());
|
||||
if (Chunk.Arr.hasStatic)
|
||||
return ExprError(Diag(Chunk.Loc, diag::err_static_illegal_in_new)
|
||||
<< D.getSourceRange());
|
||||
|
@ -793,14 +798,12 @@ Sema::ActOnCXXNew(SourceLocation StartLoc, bool UseGlobal,
|
|||
}
|
||||
}
|
||||
|
||||
TypeSourceInfo *TInfo = GetTypeForDeclarator(D, /*Scope=*/0);
|
||||
TypeSourceInfo *TInfo = GetTypeForDeclarator(D, /*Scope=*/0, /*OwnedDecl=*/0,
|
||||
/*AllowAuto=*/true);
|
||||
QualType AllocType = TInfo->getType();
|
||||
if (D.isInvalidType())
|
||||
return ExprError();
|
||||
|
||||
if (!TInfo)
|
||||
TInfo = Context.getTrivialTypeSourceInfo(AllocType);
|
||||
|
||||
return BuildCXXNew(StartLoc, UseGlobal,
|
||||
PlacementLParen,
|
||||
move(PlacementArgs),
|
||||
|
@ -811,7 +814,8 @@ Sema::ActOnCXXNew(SourceLocation StartLoc, bool UseGlobal,
|
|||
ArraySize,
|
||||
ConstructorLParen,
|
||||
move(ConstructorArgs),
|
||||
ConstructorRParen);
|
||||
ConstructorRParen,
|
||||
TypeContainsAuto);
|
||||
}
|
||||
|
||||
ExprResult
|
||||
|
@ -825,9 +829,33 @@ Sema::BuildCXXNew(SourceLocation StartLoc, bool UseGlobal,
|
|||
Expr *ArraySize,
|
||||
SourceLocation ConstructorLParen,
|
||||
MultiExprArg ConstructorArgs,
|
||||
SourceLocation ConstructorRParen) {
|
||||
SourceLocation ConstructorRParen,
|
||||
bool TypeMayContainAuto) {
|
||||
SourceRange TypeRange = AllocTypeInfo->getTypeLoc().getSourceRange();
|
||||
|
||||
// C++0x [decl.spec.auto]p6. Deduce the type which 'auto' stands in for.
|
||||
if (TypeMayContainAuto && AllocType->getContainedAutoType()) {
|
||||
if (ConstructorArgs.size() == 0)
|
||||
return ExprError(Diag(StartLoc, diag::err_auto_new_requires_ctor_arg)
|
||||
<< AllocType << TypeRange);
|
||||
if (ConstructorArgs.size() != 1) {
|
||||
Expr *FirstBad = ConstructorArgs.get()[1];
|
||||
return ExprError(Diag(FirstBad->getSourceRange().getBegin(),
|
||||
diag::err_auto_new_ctor_multiple_expressions)
|
||||
<< AllocType << TypeRange);
|
||||
}
|
||||
QualType DeducedType;
|
||||
if (!DeduceAutoType(AllocType, ConstructorArgs.get()[0], DeducedType))
|
||||
return ExprError(Diag(StartLoc, diag::err_auto_new_deduction_failure)
|
||||
<< AllocType
|
||||
<< ConstructorArgs.get()[0]->getType()
|
||||
<< TypeRange
|
||||
<< ConstructorArgs.get()[0]->getSourceRange());
|
||||
|
||||
AllocType = DeducedType;
|
||||
AllocTypeInfo = Context.getTrivialTypeSourceInfo(AllocType, StartLoc);
|
||||
}
|
||||
|
||||
// Per C++0x [expr.new]p5, the type being constructed may be a
|
||||
// typedef of an array type.
|
||||
if (!ArraySize) {
|
||||
|
|
|
@ -2783,6 +2783,10 @@ bool UnnamedLocalNoLinkageFinder::VisitDecltypeType(const DecltypeType*) {
|
|||
return false;
|
||||
}
|
||||
|
||||
bool UnnamedLocalNoLinkageFinder::VisitAutoType(const AutoType *T) {
|
||||
return Visit(T->getDeducedType());
|
||||
}
|
||||
|
||||
bool UnnamedLocalNoLinkageFinder::VisitRecordType(const RecordType* T) {
|
||||
return VisitTagDecl(T->getDecl());
|
||||
}
|
||||
|
|
|
@ -22,6 +22,7 @@
|
|||
#include "clang/AST/Expr.h"
|
||||
#include "clang/AST/ExprCXX.h"
|
||||
#include "llvm/ADT/BitVector.h"
|
||||
#include "TreeTransform.h"
|
||||
#include <algorithm>
|
||||
|
||||
namespace clang {
|
||||
|
@ -2445,21 +2446,22 @@ static bool AdjustFunctionParmAndArgTypesForDeduction(Sema &S,
|
|||
ParamType = ParamType.getLocalUnqualifiedType();
|
||||
const ReferenceType *ParamRefType = ParamType->getAs<ReferenceType>();
|
||||
if (ParamRefType) {
|
||||
QualType PointeeType = ParamRefType->getPointeeType();
|
||||
|
||||
// [C++0x] If P is an rvalue reference to a cv-unqualified
|
||||
// template parameter and the argument is an lvalue, the type
|
||||
// "lvalue reference to A" is used in place of A for type
|
||||
// deduction.
|
||||
if (const RValueReferenceType *RValueRef
|
||||
= dyn_cast<RValueReferenceType>(ParamType)) {
|
||||
if (!RValueRef->getPointeeType().getQualifiers() &&
|
||||
isa<TemplateTypeParmType>(RValueRef->getPointeeType()) &&
|
||||
if (isa<RValueReferenceType>(ParamType)) {
|
||||
if (!PointeeType.getQualifiers() &&
|
||||
isa<TemplateTypeParmType>(PointeeType) &&
|
||||
Arg->Classify(S.Context).isLValue())
|
||||
ArgType = S.Context.getLValueReferenceType(ArgType);
|
||||
}
|
||||
|
||||
// [...] If P is a reference type, the type referred to by P is used
|
||||
// for type deduction.
|
||||
ParamType = ParamRefType->getPointeeType();
|
||||
ParamType = PointeeType;
|
||||
}
|
||||
|
||||
// Overload sets usually make this parameter an undeduced
|
||||
|
@ -2946,6 +2948,95 @@ Sema::DeduceTemplateArguments(FunctionTemplateDecl *FunctionTemplate,
|
|||
QualType(), Specialization, Info);
|
||||
}
|
||||
|
||||
namespace {
|
||||
/// Substitute the 'auto' type specifier within a type for a given replacement
|
||||
/// type.
|
||||
class SubstituteAutoTransform :
|
||||
public TreeTransform<SubstituteAutoTransform> {
|
||||
QualType Replacement;
|
||||
public:
|
||||
SubstituteAutoTransform(Sema &SemaRef, QualType Replacement) :
|
||||
TreeTransform<SubstituteAutoTransform>(SemaRef), Replacement(Replacement) {
|
||||
}
|
||||
QualType TransformAutoType(TypeLocBuilder &TLB, AutoTypeLoc TL) {
|
||||
// If we're building the type pattern to deduce against, don't wrap the
|
||||
// substituted type in an AutoType. Certain template deduction rules
|
||||
// apply only when a template type parameter appears directly (and not if
|
||||
// the parameter is found through desugaring). For instance:
|
||||
// auto &&lref = lvalue;
|
||||
// must transform into "rvalue reference to T" not "rvalue reference to
|
||||
// auto type deduced as T" in order for [temp.deduct.call]p3 to apply.
|
||||
if (isa<TemplateTypeParmType>(Replacement)) {
|
||||
QualType Result = Replacement;
|
||||
TemplateTypeParmTypeLoc NewTL = TLB.push<TemplateTypeParmTypeLoc>(Result);
|
||||
NewTL.setNameLoc(TL.getNameLoc());
|
||||
return Result;
|
||||
} else {
|
||||
QualType Result = RebuildAutoType(Replacement);
|
||||
AutoTypeLoc NewTL = TLB.push<AutoTypeLoc>(Result);
|
||||
NewTL.setNameLoc(TL.getNameLoc());
|
||||
return Result;
|
||||
}
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
/// \brief Deduce the type for an auto type-specifier (C++0x [dcl.spec.auto]p6)
|
||||
///
|
||||
/// \param Type the type pattern using the auto type-specifier.
|
||||
///
|
||||
/// \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. This may still contain undeduced autos if the type is
|
||||
/// dependent.
|
||||
///
|
||||
/// \returns true if deduction succeeded, false if it failed.
|
||||
bool
|
||||
Sema::DeduceAutoType(QualType Type, Expr *Init, QualType &Result) {
|
||||
if (Init->isTypeDependent()) {
|
||||
Result = Type;
|
||||
return true;
|
||||
}
|
||||
|
||||
SourceLocation Loc = Init->getExprLoc();
|
||||
|
||||
LocalInstantiationScope InstScope(*this);
|
||||
|
||||
// Build template<class TemplParam> void Func(FuncParam);
|
||||
NamedDecl *TemplParam
|
||||
= TemplateTypeParmDecl::Create(Context, 0, Loc, 0, 0, 0, false, false);
|
||||
TemplateParameterList *TemplateParams
|
||||
= TemplateParameterList::Create(Context, Loc, Loc, &TemplParam, 1, Loc);
|
||||
|
||||
QualType TemplArg = Context.getTemplateTypeParmType(0, 0, false);
|
||||
QualType FuncParam =
|
||||
SubstituteAutoTransform(*this, TemplArg).TransformType(Type);
|
||||
|
||||
// Deduce type of TemplParam in Func(Init)
|
||||
llvm::SmallVector<DeducedTemplateArgument, 1> Deduced;
|
||||
Deduced.resize(1);
|
||||
QualType InitType = Init->getType();
|
||||
unsigned TDF = 0;
|
||||
if (AdjustFunctionParmAndArgTypesForDeduction(*this, TemplateParams,
|
||||
FuncParam, InitType, Init,
|
||||
TDF))
|
||||
return false;
|
||||
|
||||
TemplateDeductionInfo Info(Context, Loc);
|
||||
if (::DeduceTemplateArguments(*this, TemplateParams,
|
||||
FuncParam, InitType, Info, Deduced,
|
||||
TDF))
|
||||
return false;
|
||||
|
||||
QualType DeducedType = Deduced[0].getAsType();
|
||||
if (DeducedType.isNull())
|
||||
return false;
|
||||
|
||||
Result = SubstituteAutoTransform(*this, DeducedType).TransformType(Type);
|
||||
return true;
|
||||
}
|
||||
|
||||
static void
|
||||
MarkUsedTemplateParameters(Sema &SemaRef, QualType T,
|
||||
bool OnlyDeduced,
|
||||
|
@ -3740,6 +3831,11 @@ MarkUsedTemplateParameters(Sema &SemaRef, QualType T,
|
|||
OnlyDeduced, Depth, Used);
|
||||
break;
|
||||
|
||||
case Type::Auto:
|
||||
MarkUsedTemplateParameters(SemaRef,
|
||||
cast<AutoType>(T)->getDeducedType(),
|
||||
OnlyDeduced, Depth, Used);
|
||||
|
||||
// None of these types have any template parameters in them.
|
||||
case Type::Builtin:
|
||||
case Type::VariableArray:
|
||||
|
|
|
@ -324,19 +324,21 @@ Decl *TemplateDeclInstantiator::VisitVarDecl(VarDecl *D) {
|
|||
ASTOwningVector<Expr*> InitArgs(SemaRef);
|
||||
if (!InstantiateInitializer(SemaRef, D->getInit(), TemplateArgs, LParenLoc,
|
||||
InitArgs, RParenLoc)) {
|
||||
bool TypeMayContainAuto = true;
|
||||
// Attach the initializer to the declaration, if we have one.
|
||||
if (InitArgs.size() == 0)
|
||||
SemaRef.ActOnUninitializedDecl(Var, false);
|
||||
SemaRef.ActOnUninitializedDecl(Var, TypeMayContainAuto);
|
||||
else if (D->hasCXXDirectInitializer()) {
|
||||
// Add the direct initializer to the declaration.
|
||||
SemaRef.AddCXXDirectInitializerToDecl(Var,
|
||||
LParenLoc,
|
||||
move_arg(InitArgs),
|
||||
RParenLoc);
|
||||
RParenLoc,
|
||||
TypeMayContainAuto);
|
||||
} else {
|
||||
assert(InitArgs.size() == 1);
|
||||
Expr *Init = InitArgs.take()[0];
|
||||
SemaRef.AddInitializerToDecl(Var, Init, false);
|
||||
SemaRef.AddInitializerToDecl(Var, Init, false, TypeMayContainAuto);
|
||||
}
|
||||
} else {
|
||||
// FIXME: Not too happy about invalidating the declaration
|
||||
|
|
|
@ -791,7 +791,7 @@ static QualType ConvertDeclSpecToType(Sema &S, TypeProcessingState &state) {
|
|||
}
|
||||
case DeclSpec::TST_auto: {
|
||||
// TypeQuals handled by caller.
|
||||
Result = Context.UndeducedAutoTy;
|
||||
Result = Context.getAutoType(QualType());
|
||||
break;
|
||||
}
|
||||
|
||||
|
@ -1091,9 +1091,9 @@ QualType Sema::BuildArrayType(QualType T, ArrayType::ArraySizeModifier ASM,
|
|||
return QualType();
|
||||
}
|
||||
|
||||
if (Context.getCanonicalType(T) == Context.UndeducedAutoTy) {
|
||||
Diag(Loc, diag::err_illegal_decl_array_of_auto)
|
||||
<< getPrintableNameForEntity(Entity);
|
||||
if (T->getContainedAutoType()) {
|
||||
Diag(Loc, diag::err_illegal_decl_array_of_auto)
|
||||
<< getPrintableNameForEntity(Entity) << T;
|
||||
return QualType();
|
||||
}
|
||||
|
||||
|
@ -1405,7 +1405,8 @@ QualType Sema::GetTypeFromParser(ParsedType Ty, TypeSourceInfo **TInfo) {
|
|||
/// The result of this call will never be null, but the associated
|
||||
/// type may be a null type if there's an unrecoverable error.
|
||||
TypeSourceInfo *Sema::GetTypeForDeclarator(Declarator &D, Scope *S,
|
||||
TagDecl **OwnedDecl) {
|
||||
TagDecl **OwnedDecl,
|
||||
bool AutoAllowedInTypeName) {
|
||||
// Determine the type of the declarator. Not all forms of declarator
|
||||
// have a type.
|
||||
QualType T;
|
||||
|
@ -1449,33 +1450,8 @@ TypeSourceInfo *Sema::GetTypeForDeclarator(Declarator &D, Scope *S,
|
|||
if (D.getAttributes())
|
||||
distributeTypeAttrsFromDeclarator(state, T);
|
||||
|
||||
// Check for auto functions and trailing return type and adjust the
|
||||
// return type accordingly.
|
||||
if (getLangOptions().CPlusPlus0x && D.isFunctionDeclarator()) {
|
||||
const DeclaratorChunk::FunctionTypeInfo &FTI = D.getFunctionTypeInfo();
|
||||
if (T == Context.UndeducedAutoTy) {
|
||||
if (FTI.TrailingReturnType) {
|
||||
T = GetTypeFromParser(ParsedType::getFromOpaquePtr(FTI.TrailingReturnType),
|
||||
&ReturnTypeInfo);
|
||||
}
|
||||
else {
|
||||
Diag(D.getDeclSpec().getTypeSpecTypeLoc(),
|
||||
diag::err_auto_missing_trailing_return);
|
||||
T = Context.IntTy;
|
||||
D.setInvalidType(true);
|
||||
}
|
||||
}
|
||||
else if (FTI.TrailingReturnType) {
|
||||
Diag(D.getDeclSpec().getTypeSpecTypeLoc(),
|
||||
diag::err_trailing_return_without_auto);
|
||||
D.setInvalidType(true);
|
||||
}
|
||||
}
|
||||
|
||||
if (T.isNull())
|
||||
return Context.getNullTypeSourceInfo();
|
||||
|
||||
if (T == Context.UndeducedAutoTy) {
|
||||
if (D.getDeclSpec().getTypeSpecType() == DeclSpec::TST_auto &&
|
||||
!D.isFunctionDeclarator()) {
|
||||
int Error = -1;
|
||||
|
||||
switch (D.getContext()) {
|
||||
|
@ -1500,14 +1476,19 @@ TypeSourceInfo *Sema::GetTypeForDeclarator(Declarator &D, Scope *S,
|
|||
Error = 5; // Template parameter
|
||||
break;
|
||||
case Declarator::BlockLiteralContext:
|
||||
Error = 6; // Block literal
|
||||
Error = 6; // Block literal
|
||||
break;
|
||||
case Declarator::TemplateTypeArgContext:
|
||||
Error = 7; // Template type argument
|
||||
break;
|
||||
case Declarator::TypeNameContext:
|
||||
if (!AutoAllowedInTypeName)
|
||||
Error = 8; // Generic
|
||||
break;
|
||||
case Declarator::FileContext:
|
||||
case Declarator::BlockContext:
|
||||
case Declarator::ForContext:
|
||||
case Declarator::ConditionContext:
|
||||
case Declarator::TypeNameContext:
|
||||
case Declarator::TemplateTypeArgContext:
|
||||
break;
|
||||
}
|
||||
|
||||
|
@ -1519,6 +1500,9 @@ TypeSourceInfo *Sema::GetTypeForDeclarator(Declarator &D, Scope *S,
|
|||
}
|
||||
}
|
||||
|
||||
if (T.isNull())
|
||||
return Context.getNullTypeSourceInfo();
|
||||
|
||||
// The name we're declaring, if any.
|
||||
DeclarationName Name;
|
||||
if (D.getIdentifier())
|
||||
|
@ -1631,6 +1615,32 @@ TypeSourceInfo *Sema::GetTypeForDeclarator(Declarator &D, Scope *S,
|
|||
D.setInvalidType(true);
|
||||
}
|
||||
|
||||
// Check for auto functions and trailing return type and adjust the
|
||||
// return type accordingly.
|
||||
if (!D.isInvalidType()) {
|
||||
// trailing-return-type is only required if we're declaring a function,
|
||||
// and not, for instance, a pointer to a function.
|
||||
if (D.getDeclSpec().getTypeSpecType() == DeclSpec::TST_auto &&
|
||||
!FTI.TrailingReturnType && chunkIndex == 0) {
|
||||
Diag(D.getDeclSpec().getTypeSpecTypeLoc(),
|
||||
diag::err_auto_missing_trailing_return);
|
||||
T = Context.IntTy;
|
||||
D.setInvalidType(true);
|
||||
} else if (FTI.TrailingReturnType) {
|
||||
if (T.hasQualifiers() || !isa<AutoType>(T)) {
|
||||
// T must be exactly 'auto' at this point. See CWG issue 681.
|
||||
Diag(D.getDeclSpec().getTypeSpecTypeLoc(),
|
||||
diag::err_trailing_return_without_auto)
|
||||
<< T << D.getDeclSpec().getSourceRange();
|
||||
D.setInvalidType(true);
|
||||
}
|
||||
|
||||
T = GetTypeFromParser(
|
||||
ParsedType::getFromOpaquePtr(FTI.TrailingReturnType),
|
||||
&ReturnTypeInfo);
|
||||
}
|
||||
}
|
||||
|
||||
// cv-qualifiers on return types are pointless except when the type is a
|
||||
// class type in C++.
|
||||
if (T.getCVRQualifiers() && D.getDeclSpec().getTypeQualifiers() &&
|
||||
|
|
|
@ -676,6 +676,13 @@ public:
|
|||
/// Subclasses may override this routine to provide different behavior.
|
||||
QualType RebuildDecltypeType(Expr *Underlying, SourceLocation Loc);
|
||||
|
||||
/// \brief Build a new C++0x auto type.
|
||||
///
|
||||
/// By default, builds a new AutoType with the given deduced type.
|
||||
QualType RebuildAutoType(QualType Deduced) {
|
||||
return SemaRef.Context.getAutoType(Deduced);
|
||||
}
|
||||
|
||||
/// \brief Build a new template specialization type.
|
||||
///
|
||||
/// By default, performs semantic analysis when building the template
|
||||
|
@ -3950,6 +3957,31 @@ QualType TreeTransform<Derived>::TransformDecltypeType(TypeLocBuilder &TLB,
|
|||
return Result;
|
||||
}
|
||||
|
||||
template<typename Derived>
|
||||
QualType TreeTransform<Derived>::TransformAutoType(TypeLocBuilder &TLB,
|
||||
AutoTypeLoc TL) {
|
||||
const AutoType *T = TL.getTypePtr();
|
||||
QualType OldDeduced = T->getDeducedType();
|
||||
QualType NewDeduced;
|
||||
if (!OldDeduced.isNull()) {
|
||||
NewDeduced = getDerived().TransformType(OldDeduced);
|
||||
if (NewDeduced.isNull())
|
||||
return QualType();
|
||||
}
|
||||
|
||||
QualType Result = TL.getType();
|
||||
if (getDerived().AlwaysRebuild() || NewDeduced != OldDeduced) {
|
||||
Result = getDerived().RebuildAutoType(NewDeduced);
|
||||
if (Result.isNull())
|
||||
return QualType();
|
||||
}
|
||||
|
||||
AutoTypeLoc NewTL = TLB.push<AutoTypeLoc>(Result);
|
||||
NewTL.setNameLoc(TL.getNameLoc());
|
||||
|
||||
return Result;
|
||||
}
|
||||
|
||||
template<typename Derived>
|
||||
QualType TreeTransform<Derived>::TransformRecordType(TypeLocBuilder &TLB,
|
||||
RecordTypeLoc TL) {
|
||||
|
|
|
@ -54,9 +54,6 @@ serialization::TypeIdxFromBuiltin(const BuiltinType *BT) {
|
|||
case BuiltinType::ObjCId: ID = PREDEF_TYPE_OBJC_ID; break;
|
||||
case BuiltinType::ObjCClass: ID = PREDEF_TYPE_OBJC_CLASS; break;
|
||||
case BuiltinType::ObjCSel: ID = PREDEF_TYPE_OBJC_SEL; break;
|
||||
case BuiltinType::UndeducedAuto:
|
||||
assert(0 && "Should not see undeduced auto here");
|
||||
break;
|
||||
}
|
||||
|
||||
return TypeIdx(ID);
|
||||
|
|
|
@ -3146,6 +3146,9 @@ QualType ASTReader::ReadTypeRecord(unsigned Index) {
|
|||
case TYPE_DECLTYPE:
|
||||
return Context->getDecltypeType(ReadExpr(*Loc.F));
|
||||
|
||||
case TYPE_AUTO:
|
||||
return Context->getAutoType(GetType(Record[0]));
|
||||
|
||||
case TYPE_RECORD: {
|
||||
if (Record.size() != 2) {
|
||||
Error("incorrect encoding of record type");
|
||||
|
@ -3457,6 +3460,9 @@ void TypeLocReader::VisitTypeOfTypeLoc(TypeOfTypeLoc TL) {
|
|||
void TypeLocReader::VisitDecltypeTypeLoc(DecltypeTypeLoc TL) {
|
||||
TL.setNameLoc(ReadSourceLocation(Record, Idx));
|
||||
}
|
||||
void TypeLocReader::VisitAutoTypeLoc(AutoTypeLoc TL) {
|
||||
TL.setNameLoc(ReadSourceLocation(Record, Idx));
|
||||
}
|
||||
void TypeLocReader::VisitRecordTypeLoc(RecordTypeLoc TL) {
|
||||
TL.setNameLoc(ReadSourceLocation(Record, Idx));
|
||||
}
|
||||
|
|
|
@ -213,6 +213,11 @@ void ASTTypeWriter::VisitDecltypeType(const DecltypeType *T) {
|
|||
Code = TYPE_DECLTYPE;
|
||||
}
|
||||
|
||||
void ASTTypeWriter::VisitAutoType(const AutoType *T) {
|
||||
Writer.AddTypeRef(T->getDeducedType(), Record);
|
||||
Code = TYPE_AUTO;
|
||||
}
|
||||
|
||||
void ASTTypeWriter::VisitTagType(const TagType *T) {
|
||||
Record.push_back(T->isDependentType());
|
||||
Writer.AddDeclRef(T->getDecl(), Record);
|
||||
|
@ -477,6 +482,9 @@ void TypeLocWriter::VisitTypeOfTypeLoc(TypeOfTypeLoc TL) {
|
|||
void TypeLocWriter::VisitDecltypeTypeLoc(DecltypeTypeLoc TL) {
|
||||
Writer.AddSourceLocation(TL.getNameLoc(), Record);
|
||||
}
|
||||
void TypeLocWriter::VisitAutoTypeLoc(AutoTypeLoc TL) {
|
||||
Writer.AddSourceLocation(TL.getNameLoc(), Record);
|
||||
}
|
||||
void TypeLocWriter::VisitRecordTypeLoc(RecordTypeLoc TL) {
|
||||
Writer.AddSourceLocation(TL.getNameLoc(), Record);
|
||||
}
|
||||
|
|
|
@ -1,6 +1,8 @@
|
|||
// RUN: %clang_cc1 -fsyntax-only -verify %s -std=c++0x
|
||||
void f() {
|
||||
auto a = a; // expected-error{{variable 'a' declared with 'auto' type cannot appear in its own initializer}}
|
||||
auto *b = b; // expected-error{{variable 'b' declared with 'auto' type cannot appear in its own initializer}}
|
||||
const auto c = c; // expected-error{{variable 'c' declared with 'auto' type cannot appear in its own initializer}}
|
||||
}
|
||||
|
||||
void g() {
|
||||
|
@ -8,3 +10,32 @@ void g() {
|
|||
|
||||
auto *b; // expected-error{{declaration of variable 'b' with type 'auto *' requires an initializer}}
|
||||
}
|
||||
|
||||
auto n(1,2,3); // expected-error{{initializer for variable 'n' with type 'auto' contains multiple expressions}}
|
||||
|
||||
namespace N
|
||||
{
|
||||
auto a = "const char [16]", *p = &a;
|
||||
}
|
||||
|
||||
void h() {
|
||||
auto b = 42ULL;
|
||||
|
||||
for (auto c = 0; c < 100; ++c) {
|
||||
}
|
||||
}
|
||||
|
||||
template<typename T, typename U> struct same;
|
||||
template<typename T> struct same<T, T> {};
|
||||
|
||||
void p3example() {
|
||||
auto x = 5;
|
||||
const auto *v = &x, u = 6;
|
||||
static auto y = 0.0;
|
||||
auto int r; // expected-error{{cannot combine with previous}} expected-error{{requires an initializer}}
|
||||
|
||||
same<decltype(x), int> xHasTypeInt;
|
||||
same<decltype(v), const int*> vHasTypeConstIntPtr;
|
||||
same<decltype(u), const int> uHasTypeConstInt;
|
||||
same<decltype(y), double> yHasTypeDouble;
|
||||
}
|
||||
|
|
|
@ -0,0 +1,35 @@
|
|||
// RUN: %clang_cc1 -fsyntax-only -verify %s -std=c++0x
|
||||
|
||||
template<typename T>
|
||||
struct only {
|
||||
only(T);
|
||||
template<typename U> only(U) = delete;
|
||||
};
|
||||
|
||||
void f() {
|
||||
if (auto a = true) {
|
||||
}
|
||||
|
||||
switch (auto a = 0) {
|
||||
}
|
||||
|
||||
while (auto a = false) {
|
||||
}
|
||||
|
||||
for (; auto a = false; ) {
|
||||
}
|
||||
|
||||
new const auto (0);
|
||||
new (auto) (0.0);
|
||||
|
||||
#if 0
|
||||
// When clang supports for-range:
|
||||
for (auto i : {1,2,3}) {
|
||||
}
|
||||
|
||||
// When clang supports inline initialization of members.
|
||||
class X {
|
||||
static const auto &n = 'x';
|
||||
};
|
||||
#endif
|
||||
}
|
|
@ -1,13 +1,72 @@
|
|||
// RUN: %clang_cc1 -fexceptions -fsyntax-only -verify %s -std=c++0x
|
||||
void f() {
|
||||
auto a = a; // expected-error{{variable 'a' declared with 'auto' type cannot appear in its own initializer}}
|
||||
|
||||
struct S {
|
||||
virtual ~S();
|
||||
|
||||
auto a; // expected-error{{'auto' not allowed in struct member}}
|
||||
auto *b; // expected-error{{'auto' not allowed in struct member}}
|
||||
const auto c; // expected-error{{'auto' not allowed in struct member}}
|
||||
|
||||
void f() throw (auto); // expected-error{{'auto' not allowed here}}
|
||||
|
||||
friend auto; // expected-error{{'auto' not allowed in struct member}}
|
||||
|
||||
operator auto(); // expected-error{{'auto' not allowed here}}
|
||||
};
|
||||
|
||||
void g(auto a) { // expected-error{{'auto' not allowed in function prototype}}
|
||||
try { }
|
||||
catch (auto &a) { } // expected-error{{'auto' not allowed in exception declaration}}
|
||||
catch (const auto a) { } // expected-error{{'auto' not allowed in exception declaration}}
|
||||
try { } catch (auto a) { } // expected-error{{'auto' not allowed in exception declaration}}
|
||||
}
|
||||
|
||||
struct S { auto a; }; // expected-error{{'auto' not allowed in struct member}}
|
||||
void h(auto a[10]) { // expected-error{{'auto' not allowed in function prototype}}
|
||||
}
|
||||
|
||||
void f(auto a) // expected-error{{'auto' not allowed in function prototype}}
|
||||
{
|
||||
try { } catch (auto a) { } // expected-error{{'auto' not allowed in exception declaration}}
|
||||
void i(const auto a) { // expected-error{{'auto' not allowed in function prototype}}
|
||||
}
|
||||
|
||||
namespace std {
|
||||
class type_info;
|
||||
}
|
||||
|
||||
template<typename T> struct U {};
|
||||
|
||||
void j() {
|
||||
(void)typeid(auto); // expected-error{{'auto' not allowed here}}
|
||||
(void)sizeof(auto); // expected-error{{'auto' not allowed here}}
|
||||
(void)__alignof(auto); // expected-error{{'auto' not allowed here}}
|
||||
|
||||
// FIXME: don't issue the second diagnostic for this error.
|
||||
U<auto> v; // expected-error{{'auto' not allowed in template argument}} unexpected-error{{C++ requires a type specifier}}
|
||||
|
||||
int n;
|
||||
(void)dynamic_cast<auto&>(S()); // expected-error{{'auto' not allowed here}}
|
||||
(void)static_cast<auto*>(&n); // expected-error{{'auto' not allowed here}}
|
||||
(void)reinterpret_cast<auto*>(&n); // expected-error{{'auto' not allowed here}}
|
||||
(void)const_cast<auto>(n); // expected-error{{'auto' not allowed here}}
|
||||
(void)*(auto*)(&n); // expected-error{{'auto' not allowed here}}
|
||||
(void)auto(n); // expected-error{{expected expression}}
|
||||
(void)auto{n}; // expected-error{{expected expression}}
|
||||
}
|
||||
|
||||
template <auto a = 10> class C { }; // expected-error{{'auto' not allowed in template parameter}}
|
||||
int ints[] = {1, 2, 3};
|
||||
template <const auto (*a)[3] = &ints> class D { }; // expected-error{{'auto' not allowed in template parameter}}
|
||||
enum E : auto {}; // expected-error{{'auto' not allowed here}}
|
||||
struct F : auto {}; // expected-error{{expected class name}}
|
||||
template<typename T = auto> struct G { }; // expected-error{{'auto' not allowed here}}
|
||||
|
||||
using A = auto; // expected-error{{expected ';'}} expected-error{{requires a qualified name}}
|
||||
|
||||
// Whether this is illegal depends on the interpretation of [decl.spec.auto]p2 and p3,
|
||||
// and in particular the "Otherwise, ..." at the start of p3.
|
||||
namespace TrailingReturnType {
|
||||
// FIXME: don't issue the second diagnostic for this error.
|
||||
auto f() -> auto; // expected-error{{'auto' not allowed here}} unexpected-error{{without trailing return type}}
|
||||
int g();
|
||||
auto (*h)() -> auto = &g; // expected-error{{'auto' not allowed here}}
|
||||
auto (*i)() = &g; // ok; auto deduced as int.
|
||||
auto (*j)() -> int = i; // ok; no deduction.
|
||||
}
|
||||
|
|
|
@ -0,0 +1,86 @@
|
|||
// RUN: %clang_cc1 -fsyntax-only -verify %s -std=c++0x
|
||||
|
||||
template<typename T>
|
||||
struct only {
|
||||
only(T);
|
||||
template<typename U> only(U) = delete;
|
||||
};
|
||||
|
||||
namespace N
|
||||
{
|
||||
auto a = "const char [16]", *p = &a;
|
||||
|
||||
only<const char [16]> testA = a;
|
||||
only<const char **> testP = p;
|
||||
}
|
||||
|
||||
void h() {
|
||||
auto b = 42ULL;
|
||||
only<unsigned long long> testB = b;
|
||||
|
||||
for (auto c = 0; c < 100; ++c) {
|
||||
only<int> testC = c;
|
||||
}
|
||||
}
|
||||
|
||||
void p3example() {
|
||||
auto x = 5;
|
||||
const auto *v = &x, u = 6;
|
||||
static auto y = 0.0;
|
||||
|
||||
only<int> testX = x;
|
||||
only<const int*> testV = v;
|
||||
only<const int> testU = u;
|
||||
only<double> testY = y;
|
||||
}
|
||||
|
||||
void f() {
|
||||
if (auto a = true) {
|
||||
only<bool> testA = a;
|
||||
}
|
||||
|
||||
switch (auto a = 0) {
|
||||
case 0:
|
||||
only<int> testA = a;
|
||||
}
|
||||
|
||||
while (auto a = false) {
|
||||
only<bool> testA = a;
|
||||
}
|
||||
|
||||
for (; auto a = "test"; ) {
|
||||
only<const char[5]> testA = a;
|
||||
}
|
||||
|
||||
auto *fail1 = 0; // expected-error {{variable 'fail1' with type 'auto *' has incompatible initializer of type 'int'}}
|
||||
int **p;
|
||||
// FIXME: due to PR9233, we get the wrong diagnostic here.
|
||||
const auto **fail2(p); // desired-error {{variable 'fail2' with type 'auto const **' has incompatible initializer of type 'int **'}} expected-error {{cannot initialize}}
|
||||
}
|
||||
|
||||
struct S {
|
||||
void f();
|
||||
char g(int);
|
||||
float g(double);
|
||||
int m;
|
||||
|
||||
void test() {
|
||||
auto p1 = &S::f;
|
||||
auto S::*p2 = &S::f;
|
||||
auto (S::*p3)() = &S::f;
|
||||
auto p4 = &S::g; // expected-error {{incompatible initializer of type '<overloaded function type>'}}
|
||||
auto S::*p5 = &S::g; // expected-error {{incompatible initializer of type '<overloaded function type>'}}
|
||||
auto (S::*p6)(int) = &S::g;
|
||||
auto p7 = &S::m;
|
||||
auto S::*p8 = &S::m;
|
||||
|
||||
only<void (S::*)()> test1 = p1;
|
||||
only<void (S::*)()> test2 = p2;
|
||||
only<void (S::*)()> test3 = p3;
|
||||
only<char (S::*)(int)> test6 = p6;
|
||||
only<int (S::*)> test7 = p7;
|
||||
only<int (S::*)> test8 = p8;
|
||||
}
|
||||
};
|
||||
|
||||
// TODO: if the initializer is a braced-init-list, deduce auto as std::initializer_list<T>.
|
|
@ -0,0 +1,23 @@
|
|||
// RUN: %clang_cc1 -fsyntax-only -verify %s -std=c++0x
|
||||
void f() {
|
||||
auto a = 0, b = 0, c = 0;
|
||||
auto d = 0, e = 0.0; // expected-error {{'int' in declaration of 'd' and deduced as 'double' in declaration of 'e'}}
|
||||
|
||||
auto v1 = 0, *p1 = &v1;
|
||||
auto *p2 = 0, v2 = *p2; // expected-error {{incompatible initializer}}
|
||||
|
||||
const int k = 0;
|
||||
auto &f = k, &g = a; // expected-error {{'const int' in declaration of 'f' and deduced as 'int' in declaration of 'g'}}
|
||||
|
||||
typedef int I;
|
||||
I x;
|
||||
auto xa = x, xb = 0;
|
||||
|
||||
auto &&ra1 = a, rb1 = b; // expected-error {{'int &' in declaration of 'ra1' and deduced as 'int' in declaration of 'rb1'}}
|
||||
auto &&ra2 = +a, rb2 = b;
|
||||
}
|
||||
|
||||
void g() {
|
||||
auto a = 0, (*b)() -> void, c = 0;
|
||||
auto d = 0, (*e)() -> void, f = 0.0; // expected-error {{'auto' deduced as 'int' in declaration of 'd' and deduced as 'double' in declaration of 'f'}}
|
||||
}
|
|
@ -3,4 +3,5 @@
|
|||
void f() {
|
||||
int b[5];
|
||||
auto a[5] = b; // expected-error{{'a' declared as array of 'auto'}}
|
||||
auto *c[5] = b; // expected-error{{'c' declared as array of 'auto *'}}
|
||||
}
|
||||
|
|
|
@ -0,0 +1,5 @@
|
|||
// RUN: %clang_cc1 -fsyntax-only -verify -std=c++0x %s
|
||||
|
||||
auto a() -> int; // ok
|
||||
const auto b() -> int; // expected-error {{function with trailing return type must specify return type 'auto', not 'auto const'}}
|
||||
auto *c() -> int; // expected-error {{function with trailing return type must specify return type 'auto', not 'auto *'}}
|
|
@ -0,0 +1,23 @@
|
|||
// RUN: %clang_cc1 -fsyntax-only -verify %s -std=c++0x
|
||||
|
||||
template<typename T>
|
||||
struct only {
|
||||
only(T);
|
||||
template<typename U> only(U) = delete;
|
||||
};
|
||||
|
||||
void f() {
|
||||
only<const int*> p = new const auto (0);
|
||||
only<double*> q = new (auto) (0.0);
|
||||
|
||||
new auto; // expected-error{{new expression for type 'auto' requires a constructor argument}}
|
||||
new (const auto)(); // expected-error{{new expression for type 'auto const' requires a constructor argument}}
|
||||
new (auto) (1,2,3); // expected-error{{new expression for type 'auto' contains multiple constructor arguments}}
|
||||
}
|
||||
|
||||
void p2example() {
|
||||
only<int*> r = new auto(1);
|
||||
auto x = new auto('a');
|
||||
|
||||
only<char*> testX = x;
|
||||
}
|
|
@ -1,4 +1,4 @@
|
|||
// RUN: %clang_cc1 %s -fsyntax-only -verify
|
||||
// RUN: %clang_cc1 %s -fsyntax-only -verify -std=c++0x
|
||||
|
||||
struct X {};
|
||||
typedef X foo_t;
|
||||
|
@ -8,3 +8,7 @@ char c1 = ptr; // expected-error{{'foo_t *' (aka 'X *')}}
|
|||
|
||||
const foo_t &ref = foo_t();
|
||||
char c2 = ref; // expected-error{{'const foo_t' (aka 'const X')}}
|
||||
|
||||
// deduced auto should not produce an aka.
|
||||
auto aut = X();
|
||||
char c3 = aut; // expected-error{{from 'X' to 'char'}}
|
||||
|
|
|
@ -0,0 +1,34 @@
|
|||
// RUN: %clang_cc1 -fsyntax-only -verify %s -std=c++0x
|
||||
|
||||
template<typename T>
|
||||
struct only {
|
||||
only(T);
|
||||
template<typename U> only(U) = delete; // expected-note {{here}}
|
||||
};
|
||||
|
||||
template<typename ...T>
|
||||
void f(T ...t) {
|
||||
auto x(t...); // expected-error {{requires an initializer}} expected-error {{contains multiple expressions}}
|
||||
only<int> check = x;
|
||||
}
|
||||
|
||||
void g() {
|
||||
f(); // expected-note {{here}}
|
||||
f(0);
|
||||
f(0, 1); // expected-note {{here}}
|
||||
}
|
||||
|
||||
|
||||
template<typename T>
|
||||
bool h(T t) {
|
||||
auto a = t;
|
||||
decltype(a) b;
|
||||
a = a + b;
|
||||
|
||||
auto p = new auto(t);
|
||||
|
||||
only<double*> test = p; // expected-error {{conversion function from 'char *' to 'only<double *>'}}
|
||||
return p;
|
||||
}
|
||||
|
||||
bool b = h('x'); // expected-note {{here}}
|
|
@ -0,0 +1,26 @@
|
|||
// RUN: %clang_cc1 -fsyntax-only -verify %s -std=c++0x
|
||||
|
||||
extern int a;
|
||||
auto a = 0; // expected-note 2{{here}}
|
||||
auto a = 0; // expected-error {{redefinition}}
|
||||
int a = 0; // expected-error {{redefinition}}
|
||||
extern auto a; // expected-error {{requires an initializer}}
|
||||
|
||||
extern int b; // expected-note {{here}}
|
||||
auto b = 0.0; // expected-error {{different type}}
|
||||
|
||||
struct S {
|
||||
static int a;
|
||||
static int b; // expected-note {{here}}
|
||||
};
|
||||
|
||||
auto S::a = 0; // expected-note 2{{here}}
|
||||
auto S::a; // expected-error {{redefinition}} expected-error {{requires an initializer}}
|
||||
int S::a = 0; // expected-error {{redefinition}}
|
||||
|
||||
auto S::b = 0.0; // expected-error {{different type}}
|
||||
|
||||
void f() {
|
||||
extern int a;
|
||||
extern auto a; // expected-error {{requires an initializer}}
|
||||
}
|
|
@ -19,7 +19,7 @@ auto f() -> int
|
|||
|
||||
auto g(); // expected-error{{return without trailing return type}}
|
||||
|
||||
int h() -> int; // expected-error{{trailing return type without 'auto'}}
|
||||
int h() -> int; // expected-error{{trailing return type must specify return type 'auto', not 'int'}}
|
||||
|
||||
int x;
|
||||
|
||||
|
|
|
@ -1312,9 +1312,6 @@ bool CursorVisitor::VisitBuiltinTypeLoc(BuiltinTypeLoc TL) {
|
|||
case BuiltinType::Dependent:
|
||||
break;
|
||||
|
||||
case BuiltinType::UndeducedAuto: // FIXME: Deserves a cursor?
|
||||
break;
|
||||
|
||||
case BuiltinType::ObjCId:
|
||||
VisitType = Context.getObjCIdType();
|
||||
break;
|
||||
|
|
|
@ -571,7 +571,6 @@ void USRGenerator::VisitType(QualType T) {
|
|||
c = 'n'; break;
|
||||
case BuiltinType::Overload:
|
||||
case BuiltinType::Dependent:
|
||||
case BuiltinType::UndeducedAuto:
|
||||
IgnoreResults = true;
|
||||
return;
|
||||
case BuiltinType::ObjCId:
|
||||
|
|
Loading…
Reference in New Issue