Implement the C++0x deduced 'auto' feature.

This fixes PR 8738, 9060 and 9132.

llvm-svn: 126069
This commit is contained in:
Richard Smith 2011-02-20 03:19:35 +00:00
parent ba1186c23e
commit 30482bc786
49 changed files with 1021 additions and 191 deletions

View File

@ -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;

View File

@ -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) {

View File

@ -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, { })

View File

@ -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.
///

View File

@ -1381,6 +1381,11 @@ class DecltypeTypeLoc : public InheritingConcreteTypeLoc<TypeSpecTypeLoc,
DecltypeType> {
};
class AutoTypeLoc : public InheritingConcreteTypeLoc<TypeSpecTypeLoc,
AutoTypeLoc,
AutoType> {
};
struct ElaboratedLocInfo {
SourceLocation KeywordLoc;
SourceRange QualifierRange;

View File

@ -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)

View File

@ -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<

View File

@ -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,

View File

@ -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

View File

@ -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 {

View File

@ -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;
}

View File

@ -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()));

View File

@ -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

View File

@ -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)) &&

View File

@ -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";

View File

@ -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:

View File

@ -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;

View File

@ -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();
}

View File

@ -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:

View File

@ -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;
}

View File

@ -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;

View File

@ -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);

View File

@ -586,7 +586,6 @@ SimplifiedTypeClass clang::getSimplifiedTypeClass(CanQualType T) {
case BuiltinType::Overload:
case BuiltinType::Dependent:
case BuiltinType::UndeducedAuto:
return STC_Other;
case BuiltinType::ObjCId:

View File

@ -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);

View File

@ -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);

View File

@ -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();
}

View File

@ -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) {

View File

@ -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());
}

View File

@ -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:

View File

@ -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

View File

@ -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() &&

View File

@ -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) {

View File

@ -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);

View File

@ -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));
}

View File

@ -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);
}

View File

@ -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;
}

View File

@ -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
}

View File

@ -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.
}

View File

@ -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>.

View File

@ -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'}}
}

View File

@ -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 *'}}
}

View File

@ -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 *'}}

View File

@ -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;
}

View File

@ -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'}}

View File

@ -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}}

View File

@ -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}}
}

View File

@ -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;

View File

@ -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;

View File

@ -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: