Index: include/clang/AST/ASTContext.h =================================================================== --- include/clang/AST/ASTContext.h +++ include/clang/AST/ASTContext.h @@ -1232,7 +1232,7 @@ UnaryTransformType::UTTKind UKind) const; /// \brief C++11 deduced auto type. - QualType getAutoType(QualType DeducedType, bool IsDecltypeAuto, + QualType getAutoType(QualType DeducedType, AutoTypeKeyword Keyword, bool IsDependent) const; /// \brief C++11 deduction pattern for 'auto' type. Index: include/clang/AST/Type.h =================================================================== --- include/clang/AST/Type.h +++ include/clang/AST/Type.h @@ -1206,6 +1206,16 @@ RQ_RValue }; +/// Which keyword(s) were used to create an AutoType. +enum class AutoTypeKeyword : unsigned char { + /// \brief auto + Auto, + /// \brief decltype(auto) + DecltypeAuto, + /// \brief __auto_type (GNU extension) + GNUAutoType +}; + /// The base class of the type hierarchy. /// /// A central concept with types is that each type always has a canonical @@ -1424,8 +1434,8 @@ unsigned : NumTypeBits; - /// Was this placeholder type spelled as 'decltype(auto)'? - unsigned IsDecltypeAuto : 1; + /// Was this placeholder type spelled as 'auto', 'decltype(auto)', or '__auto_type'? + AutoTypeKeyword Keyword : 2; }; union { @@ -3871,8 +3881,7 @@ /// is no deduced type and an auto type is canonical. In the latter case, it is /// also a dependent type. class AutoType : public Type, public llvm::FoldingSetNode { - AutoType(QualType DeducedType, bool IsDecltypeAuto, - bool IsDependent) + AutoType(QualType DeducedType, AutoTypeKeyword Keyword, bool IsDependent) : Type(Auto, DeducedType.isNull() ? QualType(this, 0) : DeducedType, /*Dependent=*/IsDependent, /*InstantiationDependent=*/IsDependent, /*VariablyModified=*/false, @@ -3880,13 +3889,16 @@ ? false : DeducedType->containsUnexpandedParameterPack()) { assert((DeducedType.isNull() || !IsDependent) && "auto deduced to dependent type"); - AutoTypeBits.IsDecltypeAuto = IsDecltypeAuto; + AutoTypeBits.Keyword = Keyword; } friend class ASTContext; // ASTContext creates these public: - bool isDecltypeAuto() const { return AutoTypeBits.IsDecltypeAuto; } + bool isDecltypeAuto() const { + return AutoTypeBits.Keyword == AutoTypeKeyword::DecltypeAuto; + } + AutoTypeKeyword getKeyword() const { return AutoTypeBits.Keyword; } bool isSugared() const { return !isCanonicalUnqualified(); } QualType desugar() const { return getCanonicalTypeInternal(); } @@ -3901,14 +3913,13 @@ } void Profile(llvm::FoldingSetNodeID &ID) { - Profile(ID, getDeducedType(), isDecltypeAuto(), - isDependentType()); + Profile(ID, getDeducedType(), AutoTypeBits.Keyword, isDependentType()); } static void Profile(llvm::FoldingSetNodeID &ID, QualType Deduced, - bool IsDecltypeAuto, bool IsDependent) { + AutoTypeKeyword Keyword, bool IsDependent) { ID.AddPointer(Deduced.getAsOpaquePtr()); - ID.AddBoolean(IsDecltypeAuto); + ID.AddInteger((unsigned)Keyword); ID.AddBoolean(IsDependent); } Index: include/clang/Basic/DiagnosticGroups.td =================================================================== --- include/clang/Basic/DiagnosticGroups.td +++ include/clang/Basic/DiagnosticGroups.td @@ -24,6 +24,7 @@ def GNUAlignofExpression : DiagGroup<"gnu-alignof-expression">; def AmbigMemberTemplate : DiagGroup<"ambiguous-member-template">; def GNUAnonymousStruct : DiagGroup<"gnu-anonymous-struct">; +def GNUAutoType : DiagGroup<"gnu-auto-type">; def ArrayBounds : DiagGroup<"array-bounds">; def ArrayBoundsPointerArithmetic : DiagGroup<"array-bounds-pointer-arithmetic">; def Availability : DiagGroup<"availability">; @@ -700,6 +701,7 @@ // A warning group for warnings about GCC extensions. def GNU : DiagGroup<"gnu", [GNUAlignofExpression, GNUAnonymousStruct, + GNUAutoType, GNUBinaryLiteral, GNUCaseRange, GNUComplexInteger, GNUCompoundLiteralInitializer, GNUConditionalOmittedOperand, GNUDesignator, Index: include/clang/Basic/DiagnosticParseKinds.td =================================================================== --- include/clang/Basic/DiagnosticParseKinds.td +++ include/clang/Basic/DiagnosticParseKinds.td @@ -299,6 +299,9 @@ def warn_cxx11_compat_decltype_auto_type_specifier : Warning< "'decltype(auto)' type specifier is incompatible with C++ standards before " "C++14">, InGroup, DefaultIgnore; +def ext_auto_type : Extension< + "'__auto_type' is a GNU extension">, + InGroup; def ext_for_range : ExtWarn< "range-based for loop is a C++11 extension">, InGroup; def warn_cxx98_compat_for_range : Warning< Index: include/clang/Basic/DiagnosticSemaKinds.td =================================================================== --- include/clang/Basic/DiagnosticSemaKinds.td +++ include/clang/Basic/DiagnosticSemaKinds.td @@ -1657,15 +1657,18 @@ "'auto' type specifier is incompatible with C++98">, InGroup, DefaultIgnore; def err_auto_variable_cannot_appear_in_own_initializer : Error< - "variable %0 declared with 'auto' type cannot appear in its own initializer">; + "variable %0 declared with %select{'auto'|'decltype(auto)'|'__auto_type'}1 " + "type cannot appear in its own initializer">; def err_illegal_decl_array_of_auto : Error< "'%0' declared as array of %1">; def err_new_array_of_auto : Error< "cannot allocate array of 'auto'">; def err_auto_not_allowed : Error< - "%select{'auto'|'decltype(auto)'}0 not allowed %select{in function prototype" - "|in non-static struct member" - "|in non-static union member|in non-static class member|in interface member" + "%select{'auto'|'decltype(auto)'|'__auto_type'}0 not allowed " + "%select{in function prototype" + "|in non-static struct member|in struct member" + "|in non-static union member|in union member" + "|in non-static class member|in interface member" "|in exception declaration|in template parameter|in block literal" "|in template argument|in typedef|in type alias|in function return type" "|in conversion function type|here|in lambda parameter}1">; @@ -1706,8 +1709,8 @@ 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< - "'%select{auto|decltype(auto)}0' deduced as %1 in declaration of %2 and " - "deduced as %3 in declaration of %4">; + "'%select{auto|decltype(auto)|__auto_type}0' deduced as %1 in declaration " + "of %2 and deduced as %3 in declaration of %4">; def err_implied_std_initializer_list_not_found : Error< "cannot deduce type of initializer list because std::initializer_list was " "not found; include ">; @@ -1717,6 +1720,10 @@ "array backing the initializer list will be destroyed at the end of " "%select{the full-expression|the constructor}0">, InGroup>; +def err_auto_init_list_from_c : Error< + "cannot use __auto_type with initializer list in C">; +def err_auto_bitfield : Error< + "cannot pass bit-field as __auto_type initializer in C">; // C++1y decltype(auto) type def err_decltype_auto_cannot_be_combined : Error< @@ -4750,8 +4757,8 @@ "function type">; def err_openmp_default_simd_align_expr : Error< "invalid application of '__builtin_omp_required_simd_align' to an expression, only type is allowed">; -def err_sizeof_alignof_bitfield : Error< - "invalid application of '%select{sizeof|alignof}0' to bit-field">; +def err_sizeof_alignof_typeof_bitfield : Error< + "invalid application of '%select{sizeof|alignof|typeof}0' to bit-field">; def err_alignof_member_of_incomplete_type : Error< "invalid application of 'alignof' to a field of a class still being defined">; def err_vecstep_non_scalar_vector_type : Error< Index: include/clang/Basic/Specifiers.h =================================================================== --- include/clang/Basic/Specifiers.h +++ include/clang/Basic/Specifiers.h @@ -64,6 +64,7 @@ TST_underlyingType, // __underlying_type for C++11 TST_auto, // C++11 auto TST_decltype_auto, // C++1y decltype(auto) + TST_auto_type, // __auto_type extension TST_unknown_anytype, // __unknown_anytype extension TST_atomic, // C11 _Atomic TST_error // erroneous type Index: include/clang/Basic/TokenKinds.def =================================================================== --- include/clang/Basic/TokenKinds.def +++ include/clang/Basic/TokenKinds.def @@ -377,6 +377,7 @@ KEYWORD(__thread , KEYALL) KEYWORD(__FUNCTION__ , KEYALL) KEYWORD(__PRETTY_FUNCTION__ , KEYALL) +KEYWORD(__auto_type , KEYALL) // GNU Extensions (outside impl-reserved namespace) KEYWORD(typeof , KEYGNU) Index: include/clang/Sema/DeclSpec.h =================================================================== --- include/clang/Sema/DeclSpec.h +++ include/clang/Sema/DeclSpec.h @@ -301,6 +301,7 @@ static const TST TST_decltype_auto = clang::TST_decltype_auto; static const TST TST_underlyingType = clang::TST_underlyingType; static const TST TST_auto = clang::TST_auto; + static const TST TST_auto_type = clang::TST_auto_type; static const TST TST_unknown_anytype = clang::TST_unknown_anytype; static const TST TST_atomic = clang::TST_atomic; static const TST TST_error = clang::TST_error; @@ -512,7 +513,8 @@ void setTypeofParensRange(SourceRange range) { TypeofParensRange = range; } bool containsPlaceholderType() const { - return TypeSpecType == TST_auto || TypeSpecType == TST_decltype_auto; + return (TypeSpecType == TST_auto || TypeSpecType == TST_auto_type || + TypeSpecType == TST_decltype_auto); } bool hasTagDefinition() const; Index: lib/AST/ASTContext.cpp =================================================================== --- lib/AST/ASTContext.cpp +++ lib/AST/ASTContext.cpp @@ -3931,20 +3931,20 @@ /// getAutoType - Return the uniqued reference to the 'auto' type which has been /// deduced to the given type, or to the canonical undeduced 'auto' type, or the /// canonical deduced-but-dependent 'auto' type. -QualType ASTContext::getAutoType(QualType DeducedType, bool IsDecltypeAuto, +QualType ASTContext::getAutoType(QualType DeducedType, AutoTypeKeyword Keyword, bool IsDependent) const { - if (DeducedType.isNull() && !IsDecltypeAuto && !IsDependent) + if (DeducedType.isNull() && Keyword == AutoTypeKeyword::Auto && !IsDependent) return getAutoDeductType(); // Look in the folding set for an existing type. void *InsertPos = nullptr; llvm::FoldingSetNodeID ID; - AutoType::Profile(ID, DeducedType, IsDecltypeAuto, IsDependent); + AutoType::Profile(ID, DeducedType, Keyword, IsDependent); if (AutoType *AT = AutoTypes.FindNodeOrInsertPos(ID, InsertPos)) return QualType(AT, 0); AutoType *AT = new (*this, TypeAlignment) AutoType(DeducedType, - IsDecltypeAuto, + Keyword, IsDependent); Types.push_back(AT); if (InsertPos) @@ -3984,7 +3984,7 @@ QualType ASTContext::getAutoDeductType() const { if (AutoDeductTy.isNull()) AutoDeductTy = QualType( - new (*this, TypeAlignment) AutoType(QualType(), /*decltype(auto)*/false, + new (*this, TypeAlignment) AutoType(QualType(), AutoTypeKeyword::Auto, /*dependent*/false), 0); return AutoDeductTy; Index: lib/AST/ASTImporter.cpp =================================================================== --- lib/AST/ASTImporter.cpp +++ lib/AST/ASTImporter.cpp @@ -1746,7 +1746,7 @@ return QualType(); } - return Importer.getToContext().getAutoType(ToDeduced, T->isDecltypeAuto(), + return Importer.getToContext().getAutoType(ToDeduced, T->getKeyword(), /*IsDependent*/false); } Index: lib/AST/ItaniumMangle.cpp =================================================================== --- lib/AST/ItaniumMangle.cpp +++ lib/AST/ItaniumMangle.cpp @@ -2553,9 +2553,11 @@ void CXXNameMangler::mangleType(const AutoType *T) { QualType D = T->getDeducedType(); // ::= Da # dependent auto - if (D.isNull()) + if (D.isNull()) { + assert(T->getKeyword() != AutoTypeKeyword::GNUAutoType && + "shouldn't need to mangle __auto_type!"); Out << (T->isDecltypeAuto() ? "Dc" : "Da"); - else + } else mangleType(D); } Index: lib/AST/MicrosoftMangle.cpp =================================================================== --- lib/AST/MicrosoftMangle.cpp +++ lib/AST/MicrosoftMangle.cpp @@ -1713,6 +1713,8 @@ Out << '?'; mangleQualifiers(ResultType.getLocalQualifiers(), /*IsMember=*/false); Out << '?'; + assert(AT->getKeyword() != AutoTypeKeyword::GNUAutoType && + "shouldn't need to mangle __auto_type!"); mangleSourceName(AT->isDecltypeAuto() ? "" : ""); Out << '@'; } else { Index: lib/AST/Type.cpp =================================================================== --- lib/AST/Type.cpp +++ lib/AST/Type.cpp @@ -948,7 +948,7 @@ == T->getDeducedType().getAsOpaquePtr()) return QualType(T, 0); - return Ctx.getAutoType(deducedType, T->isDecltypeAuto(), + return Ctx.getAutoType(deducedType, T->getKeyword(), T->isDependentType()); } Index: lib/AST/TypePrinter.cpp =================================================================== --- lib/AST/TypePrinter.cpp +++ lib/AST/TypePrinter.cpp @@ -835,7 +835,11 @@ if (!T->getDeducedType().isNull()) { printBefore(T->getDeducedType(), OS); } else { - OS << (T->isDecltypeAuto() ? "decltype(auto)" : "auto"); + switch (T->getKeyword()) { + case AutoTypeKeyword::Auto: OS << "auto"; break; + case AutoTypeKeyword::DecltypeAuto: OS << "decltype(auto)"; break; + case AutoTypeKeyword::GNUAutoType: OS << "__auto_type"; break; + } spaceBeforePlaceHolder(OS); } } Index: lib/Format/TokenAnnotator.cpp =================================================================== --- lib/Format/TokenAnnotator.cpp +++ lib/Format/TokenAnnotator.cpp @@ -906,7 +906,7 @@ (!Line.MightBeFunctionDecl || Current.NestingLevel != 0)) { Contexts.back().FirstStartOfName = &Current; Current.Type = TT_StartOfName; - } else if (Current.is(tok::kw_auto)) { + } else if (Current.isOneOf(tok::kw_auto, tok::kw___auto_type)) { AutoFound = true; } else if (Current.is(tok::arrow) && Style.Language == FormatStyle::LK_Java) { Index: lib/Parse/ParseDecl.cpp =================================================================== --- lib/Parse/ParseDecl.cpp +++ lib/Parse/ParseDecl.cpp @@ -3145,6 +3145,11 @@ PrevSpec, DiagID, Policy); isStorageClass = true; break; + case tok::kw___auto_type: + Diag(Tok, diag::ext_auto_type); + isInvalid = DS.SetTypeSpecType(DeclSpec::TST_auto_type, Loc, PrevSpec, + DiagID, Policy); + break; case tok::kw_register: isInvalid = DS.SetStorageClassSpec(Actions, DeclSpec::SCS_register, Loc, PrevSpec, DiagID, Policy); @@ -4446,6 +4451,7 @@ case tok::kw___private_extern__: case tok::kw_static: case tok::kw_auto: + case tok::kw___auto_type: case tok::kw_register: case tok::kw___thread: case tok::kw_thread_local: Index: lib/Parse/ParseDeclCXX.cpp =================================================================== --- lib/Parse/ParseDeclCXX.cpp +++ lib/Parse/ParseDeclCXX.cpp @@ -1116,6 +1116,7 @@ case tok::kw_typedef: // struct foo {...} typedef x; case tok::kw_register: // struct foo {...} register x; case tok::kw_auto: // struct foo {...} auto x; + case tok::kw___auto_type: // struct foo {...} __auto_type x; case tok::kw_mutable: // struct foo {...} mutable x; case tok::kw_thread_local: // struct foo {...} thread_local x; case tok::kw_constexpr: // struct foo {...} constexpr x; Index: lib/Parse/ParseObjc.cpp =================================================================== --- lib/Parse/ParseObjc.cpp +++ lib/Parse/ParseObjc.cpp @@ -1114,6 +1114,7 @@ case tok::kw__Bool: case tok::kw__Complex: case tok::kw___alignof: + case tok::kw___auto_type: IdentifierInfo *II = Tok.getIdentifierInfo(); SelectorLoc = ConsumeToken(); return II; Index: lib/Parse/ParseTentative.cpp =================================================================== --- lib/Parse/ParseTentative.cpp +++ lib/Parse/ParseTentative.cpp @@ -1224,6 +1224,7 @@ case tok::kw_extern: case tok::kw_mutable: case tok::kw_auto: + case tok::kw___auto_type: case tok::kw___thread: case tok::kw_thread_local: case tok::kw__Thread_local: @@ -1515,6 +1516,7 @@ case tok::kw_double: case tok::kw_void: case tok::kw___unknown_anytype: + case tok::kw___auto_type: return true; case tok::kw_auto: Index: lib/Sema/DeclSpec.cpp =================================================================== --- lib/Sema/DeclSpec.cpp +++ lib/Sema/DeclSpec.cpp @@ -288,6 +288,7 @@ switch (DS.getTypeSpecType()) { case TST_atomic: case TST_auto: + case TST_auto_type: case TST_bool: case TST_char: case TST_char16: @@ -476,6 +477,7 @@ case DeclSpec::TST_typeofType: case DeclSpec::TST_typeofExpr: return "typeof"; case DeclSpec::TST_auto: return "auto"; + case DeclSpec::TST_auto_type: return "__auto_type"; case DeclSpec::TST_decltype: return "(decltype)"; case DeclSpec::TST_decltype_auto: return "decltype(auto)"; case DeclSpec::TST_underlyingType: return "__underlying_type"; Index: lib/Sema/SemaDecl.cpp =================================================================== --- lib/Sema/SemaDecl.cpp +++ lib/Sema/SemaDecl.cpp @@ -111,6 +111,7 @@ case tok::kw_wchar_t: case tok::kw_bool: case tok::kw___underlying_type: + case tok::kw___auto_type: return true; case tok::annot_typename: @@ -5723,7 +5724,10 @@ NewVD = VarDecl::Create(Context, DC, D.getLocStart(), D.getIdentifierLoc(), II, R, TInfo, SC); - + + if (D.getDeclSpec().containsPlaceholderType() && R->getContainedAutoType()) + ParsingInitForAutoVars.insert(NewVD); + if (D.isInvalidType()) NewVD->setInvalidDecl(); } else { @@ -10139,7 +10143,7 @@ } else if (DeducedCanon != UCanon) { Diag(D->getTypeSourceInfo()->getTypeLoc().getBeginLoc(), diag::err_auto_different_deductions) - << (AT->isDecltypeAuto() ? 1 : 0) + << (unsigned)AT->getKeyword() << Deduced << DeducedDecl->getDeclName() << U << D->getDeclName() << DeducedDecl->getInit()->getSourceRange() Index: lib/Sema/SemaExpr.cpp =================================================================== --- lib/Sema/SemaExpr.cpp +++ lib/Sema/SemaExpr.cpp @@ -349,8 +349,10 @@ // See if this is an auto-typed variable whose initializer we are parsing. if (ParsingInitForAutoVars.count(D)) { + const AutoType* AT = cast(D)->getType()->getContainedAutoType(); + Diag(Loc, diag::err_auto_variable_cannot_appear_in_own_initializer) - << D->getDeclName(); + << D->getDeclName() << (unsigned)AT->getKeyword(); return true; } @@ -3717,7 +3719,7 @@ return false; if (E->getObjectKind() == OK_BitField) { - S.Diag(E->getExprLoc(), diag::err_sizeof_alignof_bitfield) + S.Diag(E->getExprLoc(), diag::err_sizeof_alignof_typeof_bitfield) << 1 << E->getSourceRange(); return true; } @@ -3819,7 +3821,7 @@ Diag(E->getExprLoc(), diag::err_openmp_default_simd_align_expr); isInvalid = true; } else if (E->refersToBitField()) { // C99 6.5.3.4p1. - Diag(E->getExprLoc(), diag::err_sizeof_alignof_bitfield) << 0; + Diag(E->getExprLoc(), diag::err_sizeof_alignof_typeof_bitfield) << 0; isInvalid = true; } else { isInvalid = CheckUnaryExprOrTypeTraitOperand(E, UETT_SizeOf); Index: lib/Sema/SemaTemplateDeduction.cpp =================================================================== --- lib/Sema/SemaTemplateDeduction.cpp +++ lib/Sema/SemaTemplateDeduction.cpp @@ -3908,7 +3908,7 @@ !Replacement.isNull() && Replacement->isDependentType(); QualType Result = SemaRef.Context.getAutoType(Dependent ? QualType() : Replacement, - TL.getTypePtr()->isDecltypeAuto(), + TL.getTypePtr()->getKeyword(), Dependent); AutoTypeLoc NewTL = TLB.push(Result); NewTL.setNameLoc(TL.getNameLoc()); @@ -4006,6 +4006,10 @@ InitListExpr *InitList = dyn_cast(Init); if (InitList) { + if (!getLangOpts().CPlusPlus) { + Diag(Loc, diag::err_auto_init_list_from_c); + return DAR_Failed; + } for (unsigned i = 0, e = InitList->getNumInits(); i < e; ++i) { if (DeduceTemplateArgumentByListElement(*this, TemplateParamsSt.get(), TemplArg, InitList->getInit(i), @@ -4013,6 +4017,11 @@ return DAR_Failed; } } else { + if (!getLangOpts().CPlusPlus && Init->refersToBitField()) { + Diag(Loc, diag::err_auto_bitfield); + return DAR_FailedAlreadyDiagnosed; + } + if (AdjustFunctionParmAndArgTypesForDeduction( *this, TemplateParamsSt.get(), FuncParam, InitType, Init, TDF)) return DAR_Failed; Index: lib/Sema/SemaTemplateVariadic.cpp =================================================================== --- lib/Sema/SemaTemplateVariadic.cpp +++ lib/Sema/SemaTemplateVariadic.cpp @@ -737,6 +737,7 @@ case TST_interface: case TST_class: case TST_auto: + case TST_auto_type: case TST_decltype_auto: case TST_unknown_anytype: case TST_error: Index: lib/Sema/SemaType.cpp =================================================================== --- lib/Sema/SemaType.cpp +++ lib/Sema/SemaType.cpp @@ -1448,6 +1448,7 @@ break; case DeclSpec::TST_auto: + case DeclSpec::TST_auto_type: // TypeQuals handled by caller. // If auto is mentioned in a lambda parameter context, convert it to a // template parameter type immediately, with the appropriate depth and @@ -1480,14 +1481,17 @@ // template type parameter. Result = QualType(CorrespondingTemplateParam->getTypeForDecl(), 0); } else { - Result = Context.getAutoType(QualType(), /*decltype(auto)*/false, false); + Result = Context.getAutoType(QualType(), + DS.getTypeSpecType() == DeclSpec::TST_auto_type ? + AutoTypeKeyword::GNUAutoType : AutoTypeKeyword::Auto, + false); } break; case DeclSpec::TST_decltype_auto: - Result = Context.getAutoType(QualType(), - /*decltype(auto)*/true, - /*IsDependent*/ false); + Result = Context.getAutoType(QualType(), + /*Keyword*/ AutoTypeKeyword::DecltypeAuto, + /*IsDependent*/ false); break; case DeclSpec::TST_unknown_anytype: @@ -2558,7 +2562,6 @@ case UnqualifiedId::IK_LiteralOperatorId: case UnqualifiedId::IK_TemplateId: T = ConvertDeclSpecToType(state); - ContainsPlaceholderType = D.getDeclSpec().containsPlaceholderType(); if (!D.isInvalidType() && D.getDeclSpec().isTypeSpecOwned()) { OwnedTagDecl = cast(D.getDeclSpec().getRepAsDecl()); @@ -2582,7 +2585,6 @@ // converts to. T = SemaRef.GetTypeFromParser(D.getName().ConversionFunctionId, &ReturnTypeInfo); - ContainsPlaceholderType = T->getContainedAutoType(); break; } @@ -2594,7 +2596,7 @@ // type (this is checked later) and we can skip this. In other languages // using auto, we need to check regardless. // C++14 In generic lambdas allow 'auto' in their parameters. - if (ContainsPlaceholderType && + if (D.getDeclSpec().containsPlaceholderType() && (!SemaRef.getLangOpts().CPlusPlus11 || !D.isFunctionDeclarator())) { int Error = -1; @@ -2611,46 +2613,49 @@ case Declarator::LambdaExprParameterContext: if (!(SemaRef.getLangOpts().CPlusPlus14 && D.getDeclSpec().getTypeSpecType() == DeclSpec::TST_auto)) - Error = 14; + Error = 16; break; - case Declarator::MemberContext: + case Declarator::MemberContext: { if (D.getDeclSpec().getStorageClassSpec() == DeclSpec::SCS_static) break; + bool Cxx = SemaRef.getLangOpts().CPlusPlus; switch (cast(SemaRef.CurContext)->getTagKind()) { case TTK_Enum: llvm_unreachable("unhandled tag kind"); - case TTK_Struct: Error = 1; /* Struct member */ break; - case TTK_Union: Error = 2; /* Union member */ break; - case TTK_Class: Error = 3; /* Class member */ break; - case TTK_Interface: Error = 4; /* Interface member */ break; + case TTK_Struct: Error = Cxx ? 1 : 2; /* Struct member */ break; + case TTK_Union: Error = Cxx ? 3 : 4; /* Union member */ break; + case TTK_Class: Error = 5; /* Class member */ break; + case TTK_Interface: Error = 6; /* Interface member */ break; } break; + } case Declarator::CXXCatchContext: case Declarator::ObjCCatchContext: - Error = 5; // Exception declaration + Error = 7; // Exception declaration break; case Declarator::TemplateParamContext: - Error = 6; // Template parameter + Error = 8; // Template parameter break; case Declarator::BlockLiteralContext: - Error = 7; // Block literal + Error = 9; // Block literal break; case Declarator::TemplateTypeArgContext: - Error = 8; // Template type argument + Error = 10; // Template type argument break; case Declarator::AliasDeclContext: case Declarator::AliasTemplateContext: - Error = 10; // Type alias + Error = 12; // Type alias break; case Declarator::TrailingReturnContext: - if (!SemaRef.getLangOpts().CPlusPlus14) - Error = 11; // Function return type + if (!SemaRef.getLangOpts().CPlusPlus14 || + D.getDeclSpec().getTypeSpecType() == DeclSpec::TST_auto_type) + Error = 13; // Function return type break; case Declarator::ConversionIdContext: if (!SemaRef.getLangOpts().CPlusPlus14) - Error = 12; // conversion-type-id + Error = 14; // conversion-type-id break; case Declarator::TypeNameContext: - Error = 13; // Generic + Error = 15; // Generic break; case Declarator::FileContext: case Declarator::BlockContext: @@ -2661,11 +2666,11 @@ } if (D.getDeclSpec().getStorageClassSpec() == DeclSpec::SCS_typedef) - Error = 9; + Error = 11; // In Objective-C it is an error to use 'auto' on a function declarator. if (D.isFunctionDeclarator()) - Error = 11; + Error = 13; // C++11 [dcl.spec.auto]p2: 'auto' is always fine if the declarator // contains a trailing return type. That is only legal at the outermost @@ -2691,10 +2696,15 @@ AutoRange = D.getName().getSourceRange(); if (Error != -1) { - const bool IsDeclTypeAuto = - D.getDeclSpec().getTypeSpecType() == DeclSpec::TST_decltype_auto; + unsigned Keyword; + switch (D.getDeclSpec().getTypeSpecType()) { + case DeclSpec::TST_auto: Keyword = 0; break; + case DeclSpec::TST_decltype_auto: Keyword = 1; break; + case DeclSpec::TST_auto_type: Keyword = 2; break; + default: llvm_unreachable("unknown auto TypeSpecType"); + } SemaRef.Diag(AutoRange.getBegin(), diag::err_auto_not_allowed) - << IsDeclTypeAuto << Error << AutoRange; + << Keyword << Error << AutoRange; T = SemaRef.Context.IntTy; D.setInvalidType(true); } else @@ -3700,7 +3710,7 @@ D.setInvalidType(true); } else if (D.getContext() != Declarator::LambdaExprContext && (T.hasQualifiers() || !isa(T) || - cast(T)->isDecltypeAuto())) { + cast(T)->getKeyword() != AutoTypeKeyword::Auto)) { S.Diag(D.getDeclSpec().getTypeSpecTypeLoc(), diag::err_trailing_return_without_auto) << T << D.getDeclSpec().getSourceRange(); @@ -3712,6 +3722,11 @@ T = Context.IntTy; D.setInvalidType(true); } + } else if (D.getDeclSpec().getTypeSpecType() == DeclSpec::TST_auto_type) { + S.Diag(D.getDeclSpec().getTypeSpecTypeLoc(), + diag::err_auto_not_allowed) + << 2 << 13 << D.getDeclSpec().getSourceRange(); + D.setInvalidType(true); } } @@ -6748,6 +6763,9 @@ if (ER.isInvalid()) return QualType(); E = ER.get(); + if (!getLangOpts().CPlusPlus && E->refersToBitField()) + Diag(E->getExprLoc(), diag::err_sizeof_alignof_typeof_bitfield) << 2; + if (!E->isTypeDependent()) { QualType T = E->getType(); if (const TagType *TT = T->getAs()) Index: lib/Sema/TreeTransform.h =================================================================== --- lib/Sema/TreeTransform.h +++ lib/Sema/TreeTransform.h @@ -844,11 +844,11 @@ /// \brief Build a new C++11 auto type. /// /// By default, builds a new AutoType with the given deduced type. - QualType RebuildAutoType(QualType Deduced, bool IsDecltypeAuto) { + QualType RebuildAutoType(QualType Deduced, AutoTypeKeyword Keyword) { // Note, IsDependent is always false here: we implicitly convert an 'auto' // which has been deduced to a dependent type into an undeduced 'auto', so // that we'll retry deduction after the transformation. - return SemaRef.Context.getAutoType(Deduced, IsDecltypeAuto, + return SemaRef.Context.getAutoType(Deduced, Keyword, /*IsDependent*/ false); } @@ -3863,7 +3863,7 @@ Qs.removeObjCLifetime(); Deduced = SemaRef.Context.getQualifiedType(Deduced.getUnqualifiedType(), Qs); - Result = SemaRef.Context.getAutoType(Deduced, AutoTy->isDecltypeAuto(), + Result = SemaRef.Context.getAutoType(Deduced, AutoTy->getKeyword(), AutoTy->isDependentType()); TLB.TypeWasModifiedSafely(Result); } else { @@ -5066,7 +5066,7 @@ QualType Result = TL.getType(); if (getDerived().AlwaysRebuild() || NewDeduced != OldDeduced || T->isDependentType()) { - Result = getDerived().RebuildAutoType(NewDeduced, T->isDecltypeAuto()); + Result = getDerived().RebuildAutoType(NewDeduced, T->getKeyword()); if (Result.isNull()) return QualType(); } Index: lib/Serialization/ASTReader.cpp =================================================================== --- lib/Serialization/ASTReader.cpp +++ lib/Serialization/ASTReader.cpp @@ -5270,9 +5270,9 @@ case TYPE_AUTO: { QualType Deduced = readType(*Loc.F, Record, Idx); - bool IsDecltypeAuto = Record[Idx++]; + AutoTypeKeyword Keyword = (AutoTypeKeyword)Record[Idx++]; bool IsDependent = Deduced.isNull() ? Record[Idx++] : false; - return Context.getAutoType(Deduced, IsDecltypeAuto, IsDependent); + return Context.getAutoType(Deduced, Keyword, IsDependent); } case TYPE_RECORD: { Index: lib/Serialization/ASTWriter.cpp =================================================================== --- lib/Serialization/ASTWriter.cpp +++ lib/Serialization/ASTWriter.cpp @@ -280,7 +280,7 @@ void ASTTypeWriter::VisitAutoType(const AutoType *T) { Writer.AddTypeRef(T->getDeducedType(), Record); - Record.push_back(T->isDecltypeAuto()); + Record.push_back((unsigned)T->getKeyword()); if (T->getDeducedType().isNull()) Record.push_back(T->isDependentType()); Code = TYPE_AUTO; Index: test/CXX/dcl.dcl/dcl.spec/dcl.type/dcl.spec.auto/p3-1y.cpp =================================================================== --- test/CXX/dcl.dcl/dcl.spec/dcl.type/dcl.spec.auto/p3-1y.cpp +++ test/CXX/dcl.dcl/dcl.spec/dcl.type/dcl.spec.auto/p3-1y.cpp @@ -3,9 +3,9 @@ // FIXME: This is in p11 (?) in C++1y. void f() { - decltype(auto) a = a; // expected-error{{variable 'a' declared with 'auto' type cannot appear in its own initializer}} - if (decltype(auto) b = b) {} // expected-error {{variable 'b' declared with 'auto' type cannot appear in its own initializer}} - decltype(auto) c = ({ decltype(auto) d = c; 0; }); // expected-error {{variable 'c' declared with 'auto' type cannot appear in its own initializer}} + decltype(auto) a = a; // expected-error{{variable 'a' declared with 'decltype(auto)' type cannot appear in its own initializer}} + if (decltype(auto) b = b) {} // expected-error {{variable 'b' declared with 'decltype(auto)' type cannot appear in its own initializer}} + decltype(auto) c = ({ decltype(auto) d = c; 0; }); // expected-error {{variable 'c' declared with 'decltype(auto)' type cannot appear in its own initializer}} } void g() { Index: test/Sema/auto-type.c =================================================================== --- /dev/null +++ test/Sema/auto-type.c @@ -0,0 +1,22 @@ +// RUN: %clang_cc1 %s -fsyntax-only -verify -pedantic -std=c11 + +__auto_type a = 5; // expected-warning {{'__auto_type' is a GNU extension}} +__extension__ __auto_type a1 = 5; +#pragma clang diagnostic ignored "-Wgnu-auto-type" +__auto_type b = 5.0; +__auto_type c = &b; +__auto_type d = (struct {int a;}) {5}; +_Static_assert(__builtin_types_compatible_p(__typeof(a), int), ""); +__auto_type e = e; // expected-error {{variable 'e' declared with '__auto_type' type cannot appear in its own initializer}} + +struct s { __auto_type a; }; // expected-error {{'__auto_type' not allowed in struct member}} + +__auto_type f = 1, g = 1.0; // expected-error {{'__auto_type' deduced as 'int' in declaration of 'f' and deduced as 'double' in declaration of 'g'}} + +__auto_type h() {} // expected-error {{'__auto_type' not allowed in function return type}} + +int i() { + struct bitfield { int field:2; }; + __auto_type j = (struct bitfield){1}.field; // expected-error {{cannot pass bit-field as __auto_type initializer in C}} + +} Index: test/Sema/bitfield.c =================================================================== --- test/Sema/bitfield.c +++ test/Sema/bitfield.c @@ -63,7 +63,8 @@ typedef signed Signed; struct Test5 { unsigned n : 2; } t5; -typedef __typeof__(t5.n) Unsigned; // Bitfield is unsigned +// Bitfield is unsigned +struct Test5 sometest5 = {-1}; // expected-warning {{implicit truncation from 'int' to bitfield changes value from -1 to 3}} typedef __typeof__(+t5.n) Signed; // ... but promotes to signed. typedef __typeof__(t5.n + 0) Signed; // Arithmetic promotes. Index: test/Sema/exprs.c =================================================================== --- test/Sema/exprs.c +++ test/Sema/exprs.c @@ -97,6 +97,7 @@ R = __alignof(P->x); // expected-error {{invalid application of 'alignof' to bit-field}} R = __alignof(P->y); // ok. R = sizeof(P->x); // expected-error {{invalid application of 'sizeof' to bit-field}} + __extension__ ({ R = (__typeof__(P->x)) 2; }); // expected-error {{invalid application of 'typeof' to bit-field}} return R; } Index: test/SemaCXX/auto-type-from-cxx.cpp =================================================================== --- /dev/null +++ test/SemaCXX/auto-type-from-cxx.cpp @@ -0,0 +1,14 @@ +// RUN: %clang_cc1 -std=c++14 -fsyntax-only -verify %s + +__auto_type a() -> int; // expected-error {{function with trailing return type must specify return type 'auto', not '__auto_type'}} +template +__auto_type b() { return T::x; } // expected-error {{'__auto_type' not allowed in function return type}} +auto c() -> __auto_type { __builtin_unreachable(); } // expected-error {{'__auto_type' not allowed in function return type}} +int d() { + decltype(__auto_type) e = 1; // expected-error {{expected expression}} + auto _ = [](__auto_type f) {}; // expected-error {{'__auto_type' not allowed in lambda parameter}} + __auto_type g = 2; + struct BitField { int field:2; }; + __auto_type h = BitField{1}.field; // (should work from C++) +} +