Index: include/clang/AST/ASTContext.h =================================================================== --- include/clang/AST/ASTContext.h +++ include/clang/AST/ASTContext.h @@ -1299,7 +1299,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 @@ -1210,6 +1210,16 @@ RQ_RValue }; +/// Which keyword(s) were used to create an AutoType. +enum class AutoTypeKeyword { + /// \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 @@ -1428,8 +1438,9 @@ 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 value. + unsigned Keyword : 2; }; union { @@ -3902,8 +3913,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, @@ -3911,13 +3921,18 @@ ? false : DeducedType->containsUnexpandedParameterPack()) { assert((DeducedType.isNull() || !IsDependent) && "auto deduced to dependent type"); - AutoTypeBits.IsDecltypeAuto = IsDecltypeAuto; + AutoTypeBits.Keyword = (unsigned)Keyword; } friend class ASTContext; // ASTContext creates these public: - bool isDecltypeAuto() const { return AutoTypeBits.IsDecltypeAuto; } + bool isDecltypeAuto() const { + return getKeyword() == AutoTypeKeyword::DecltypeAuto; + } + AutoTypeKeyword getKeyword() const { + return (AutoTypeKeyword)AutoTypeBits.Keyword; + } bool isSugared() const { return !isCanonicalUnqualified(); } QualType desugar() const { return getCanonicalTypeInternal(); } @@ -3932,14 +3947,13 @@ } void Profile(llvm::FoldingSetNodeID &ID) { - Profile(ID, getDeducedType(), isDecltypeAuto(), - isDependentType()); + Profile(ID, getDeducedType(), getKeyword(), 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">; @@ -707,6 +708,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 @@ -1664,18 +1664,22 @@ "'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">; + "|in conversion function type|here|in lambda parameter" + "|in type allocated by 'new'|in K&R-style function parameter}1">; def err_auto_not_allowed_var_inst : Error< "'auto' variable template instantiation is not allowed">; def err_auto_var_requires_init : Error< @@ -1713,8 +1717,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 ">; @@ -1724,6 +1728,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< @@ -4810,8 +4818,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 @@ -384,6 +384,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 @@ -3983,20 +3983,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) @@ -4036,7 +4036,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 @@ -2653,9 +2653,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 @@ -1818,6 +1818,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 @@ -905,7 +905,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 @@ -3138,6 +3138,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); @@ -4440,6 +4445,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/ParseObjc.cpp =================================================================== --- lib/Parse/ParseObjc.cpp +++ lib/Parse/ParseObjc.cpp @@ -1127,6 +1127,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 @@ -1089,6 +1089,7 @@ /// [GNU] typeof-specifier /// [GNU] '_Complex' /// [C++11] 'auto' +/// [GNU] '__auto_type' /// [C++11] 'decltype' ( expression ) /// [C++1y] 'decltype' ( 'auto' ) /// @@ -1262,6 +1263,7 @@ case tok::kw_restrict: case tok::kw__Complex: case tok::kw___attribute: + case tok::kw___auto_type: return TPResult::True; // Microsoft @@ -1515,6 +1517,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: @@ -5741,7 +5742,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 { @@ -10200,7 +10204,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; } @@ -3685,7 +3687,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; } @@ -3787,7 +3789,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()); @@ -3976,6 +3976,11 @@ if (Result.isNull()) return DAR_FailedAlreadyDiagnosed; return DAR_Succeeded; + } else if (!getLangOpts().CPlusPlus) { + if (isa(Init)) { + Diag(Init->getLocStart(), diag::err_auto_init_list_from_c); + return DAR_FailedAlreadyDiagnosed; + } } } @@ -4013,6 +4018,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 @@ -1504,14 +1504,17 @@ // template type parameter. Result = QualType(CorrespondingTemplateParam->getTypeForDecl(), 0); } else { - Result = Context.getAutoType(QualType(), /*decltype(auto)*/false, false); + Result = Context.getAutoType(QualType(), AutoTypeKeyword::Auto, false); } break; + case DeclSpec::TST_auto_type: + Result = Context.getAutoType(QualType(), AutoTypeKeyword::GNUAutoType, false); + break; + case DeclSpec::TST_decltype_auto: - Result = Context.getAutoType(QualType(), - /*decltype(auto)*/true, - /*IsDependent*/ false); + Result = Context.getAutoType(QualType(), AutoTypeKeyword::DecltypeAuto, + /*IsDependent*/ false); break; case DeclSpec::TST_unknown_anytype: @@ -2573,8 +2576,6 @@ // The TagDecl owned by the DeclSpec. TagDecl *OwnedTagDecl = nullptr; - bool ContainsPlaceholderType = false; - switch (D.getName().getKind()) { case UnqualifiedId::IK_ImplicitSelfParam: case UnqualifiedId::IK_OperatorFunctionId: @@ -2582,7 +2583,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()); @@ -2606,7 +2606,6 @@ // converts to. T = SemaRef.GetTypeFromParser(D.getName().ConversionFunctionId, &ReturnTypeInfo); - ContainsPlaceholderType = T->getContainedAutoType(); break; } @@ -2618,13 +2617,10 @@ // 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 && - (!SemaRef.getLangOpts().CPlusPlus11 || !D.isFunctionDeclarator())) { + if (D.getDeclSpec().containsPlaceholderType()) { int Error = -1; switch (D.getContext()) { - case Declarator::KNRTypeListContext: - llvm_unreachable("K&R type lists aren't allowed in C++"); case Declarator::LambdaExprContext: llvm_unreachable("Can't specify a type specifier in lambda grammar"); case Declarator::ObjCParameterContext: @@ -2635,67 +2631,85 @@ case Declarator::LambdaExprParameterContext: if (!(SemaRef.getLangOpts().CPlusPlus14 && D.getDeclSpec().getTypeSpecType() == DeclSpec::TST_auto)) - Error = 14; + Error = 16; break; - case Declarator::MemberContext: - if (D.getDeclSpec().getStorageClassSpec() == DeclSpec::SCS_static) + case Declarator::MemberContext: { + if (D.getDeclSpec().getStorageClassSpec() == DeclSpec::SCS_static || + D.isFunctionDeclarator()) 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 + if (!SemaRef.getLangOpts().CPlusPlus14 || + D.getDeclSpec().getTypeSpecType() == DeclSpec::TST_auto_type) + Error = 14; // conversion-type-id break; case Declarator::TypeNameContext: - Error = 13; // Generic + Error = 15; // Generic break; case Declarator::FileContext: case Declarator::BlockContext: case Declarator::ForContext: case Declarator::ConditionContext: + break; case Declarator::CXXNewContext: + if (D.getDeclSpec().getTypeSpecType() == DeclSpec::TST_auto_type) + Error = 17; // 'new' type + break; + case Declarator::KNRTypeListContext: + Error = 18; // K&R function parameter break; } if (D.getDeclSpec().getStorageClassSpec() == DeclSpec::SCS_typedef) - Error = 9; - - // In Objective-C it is an error to use 'auto' on a function declarator. - if (D.isFunctionDeclarator()) Error = 11; + // In Objective-C it is an error to use 'auto' on a function declarator + // (and everywhere for '__auto_type'). + if (D.isFunctionDeclarator() && + (!SemaRef.getLangOpts().CPlusPlus11 || + D.getDeclSpec().getTypeSpecType() == DeclSpec::TST_auto_type)) + Error = 13; + + bool HaveTrailing = false; + // 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 // level. Check all declarator chunks (outermost first) anyway, to give // better diagnostics. - if (SemaRef.getLangOpts().CPlusPlus11 && Error != -1) { + // We don't support '__auto_type' with trailing return types. + if (SemaRef.getLangOpts().CPlusPlus11 && + D.getDeclSpec().getTypeSpecType() != DeclSpec::TST_auto_type) { for (unsigned i = 0, e = D.getNumTypeObjects(); i != e; ++i) { unsigned chunkIndex = e - i - 1; state.setCurrentChunkIndex(chunkIndex); @@ -2703,6 +2717,7 @@ if (DeclType.Kind == DeclaratorChunk::Function) { const DeclaratorChunk::FunctionTypeInfo &FTI = DeclType.Fun; if (FTI.hasTrailingReturnType()) { + HaveTrailing = true; Error = -1; break; } @@ -2715,16 +2730,24 @@ 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 + } else if (!HaveTrailing) { + // If there was a trailing return type, we already got + // warn_cxx98_compat_trailing_return_type in the parser. SemaRef.Diag(AutoRange.getBegin(), diag::warn_cxx98_compat_auto_type_specifier) << AutoRange; + } } if (SemaRef.getLangOpts().CPlusPlus && @@ -3729,7 +3752,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(); @@ -6792,6 +6815,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 @@ -848,11 +848,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); } @@ -3888,7 +3888,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 { @@ -5091,7 +5091,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 @@ -5413,9 +5413,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 @@ -281,7 +281,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/CXX/dcl.dcl/dcl.spec/dcl.type/dcl.spec.auto/p7-1y.cpp =================================================================== --- test/CXX/dcl.dcl/dcl.spec/dcl.type/dcl.spec.auto/p7-1y.cpp +++ test/CXX/dcl.dcl/dcl.spec/dcl.type/dcl.spec.auto/p7-1y.cpp @@ -49,7 +49,7 @@ decltype(auto) (*f2)(); // expected-error {{'decltype(auto)' can only be used as a return type in a function declaration}} expected-error {{requires an initializer}} decltype(auto) *f3(); // expected-error {{cannot form pointer to 'decltype(auto)'}} const decltype(auto) f4(); // expected-error {{'decltype(auto)' cannot be combined with other type specifiers}} -typedef decltype(auto) f5(); // expected-error {{'decltype(auto)' can only be used as a return type in a function declaration}} +typedef decltype(auto) f5(); // expected-error {{'decltype(auto)' not allowed in typedef}} decltype(auto) ((((((f6))))())); // ok decltype(auto) f7()(); // expected-error {{'decltype(auto)' can only be used as a return type in a function declaration}} expected-error {{function cannot return function type}} decltype(auto) (S::*f8)(); // expected-error {{'decltype(auto)' can only be used as a return type in a function declaration}} expected-error {{requires an initializer}} Index: test/Sema/auto-type.c =================================================================== --- /dev/null +++ test/Sema/auto-type.c @@ -0,0 +1,26 @@ +// 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}} + +} + +int k(l) +__auto_type l; // expected-error {{'__auto_type' not allowed in K&R-style function parameter}} +{} 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,19 @@ +// RUN: %clang_cc1 -std=c++14 -fsyntax-only -verify %s + +struct A { + operator __auto_type() {} // expected-error {{'__auto_type' not allowed in conversion function type}} +}; + +__auto_type a() -> int; // expected-error {{'__auto_type' not allowed in function return 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++) + new __auto_type; // expected-error {{'__auto_type' not allowed in type allocated by 'new'}} +} + Index: test/SemaCXX/cxx98-compat.cpp =================================================================== --- test/SemaCXX/cxx98-compat.cpp +++ test/SemaCXX/cxx98-compat.cpp @@ -100,6 +100,9 @@ }; auto f() -> int; // expected-warning {{trailing return types are incompatible with C++98}} +#ifdef CXX14COMPAT +auto ff() { return 5; } // expected-warning {{'auto' type specifier is incompatible with C++98}} +#endif void RangeFor() { int xs[] = {1, 2, 3};