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.
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
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 {
/// 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,
? 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(); }
}
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);
}
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">;
// A warning group for warnings about GCC extensions.
def GNU : DiagGroup<"gnu", [GNUAlignofExpression, GNUAnonymousStruct,
+ GNUAutoType,
GNUBinaryLiteral, GNUCaseRange,
GNUComplexInteger, GNUCompoundLiteralInitializer,
GNUConditionalOmittedOperand, GNUDesignator,
def warn_cxx11_compat_decltype_auto_type_specifier : Warning<
"'decltype(auto)' type specifier is incompatible with C++ standards before "
"C++14">, InGroup<CXXPre14Compat>, DefaultIgnore;
+def ext_auto_type : Extension<
+ "'__auto_type' is a GNU extension">,
+ InGroup<GNUAutoType>;
def ext_for_range : ExtWarn<
"range-based for loop is a C++11 extension">, InGroup<CXX11>;
def warn_cxx98_compat_for_range : Warning<
"'auto' type specifier is incompatible with C++98">,
InGroup<CXX98Compat>, 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<
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 <initializer_list>">;
"array backing the initializer list will be destroyed at the end of "
"%select{the full-expression|the constructor}0">,
InGroup<DiagGroup<"dangling-initializer-list">>;
+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<
"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<
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
KEYWORD(__thread , KEYALL)
KEYWORD(__FUNCTION__ , KEYALL)
KEYWORD(__PRETTY_FUNCTION__ , KEYALL)
+KEYWORD(__auto_type , KEYALL)
// GNU Extensions (outside impl-reserved namespace)
KEYWORD(typeof , KEYGNU)
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;
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;
/// 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)
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;
return QualType();
}
- return Importer.getToContext().getAutoType(ToDeduced, T->isDecltypeAuto(),
+ return Importer.getToContext().getAutoType(ToDeduced, T->getKeyword(),
/*IsDependent*/false);
}
void CXXNameMangler::mangleType(const AutoType *T) {
QualType D = T->getDeducedType();
// <builtin-type> ::= 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);
}
Out << '?';
mangleQualifiers(ResultType.getLocalQualifiers(), /*IsMember=*/false);
Out << '?';
+ assert(AT->getKeyword() != AutoTypeKeyword::GNUAutoType &&
+ "shouldn't need to mangle __auto_type!");
mangleSourceName(AT->isDecltypeAuto() ? "<decltype-auto>" : "<auto>");
Out << '@';
} else {
== T->getDeducedType().getAsOpaquePtr())
return QualType(T, 0);
- return Ctx.getAutoType(deducedType, T->isDecltypeAuto(),
+ return Ctx.getAutoType(deducedType, T->getKeyword(),
T->isDependentType());
}
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);
}
}
(!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) {
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);
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:
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;
/// [GNU] typeof-specifier
/// [GNU] '_Complex'
/// [C++11] 'auto'
+/// [GNU] '__auto_type'
/// [C++11] 'decltype' ( expression )
/// [C++1y] 'decltype' ( 'auto' )
///
case tok::kw_restrict:
case tok::kw__Complex:
case tok::kw___attribute:
+ case tok::kw___auto_type:
return TPResult::True;
// Microsoft
case tok::kw_double:
case tok::kw_void:
case tok::kw___unknown_anytype:
+ case tok::kw___auto_type:
return true;
case tok::kw_auto:
switch (DS.getTypeSpecType()) {
case TST_atomic:
case TST_auto:
+ case TST_auto_type:
case TST_bool:
case TST_char:
case TST_char16:
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";
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:
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 {
} 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()
// See if this is an auto-typed variable whose initializer we are parsing.
if (ParsingInitForAutoVars.count(D)) {
+ const AutoType *AT = cast<VarDecl>(D)->getType()->getContainedAutoType();
+
Diag(Loc, diag::err_auto_variable_cannot_appear_in_own_initializer)
- << D->getDeclName();
+ << D->getDeclName() << (unsigned)AT->getKeyword();
return true;
}
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;
}
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);
!Replacement.isNull() && Replacement->isDependentType();
QualType Result =
SemaRef.Context.getAutoType(Dependent ? QualType() : Replacement,
- TL.getTypePtr()->isDecltypeAuto(),
+ TL.getTypePtr()->getKeyword(),
Dependent);
AutoTypeLoc NewTL = TLB.push<AutoTypeLoc>(Result);
NewTL.setNameLoc(TL.getNameLoc());
if (Result.isNull())
return DAR_FailedAlreadyDiagnosed;
return DAR_Succeeded;
+ } else if (!getLangOpts().CPlusPlus) {
+ if (isa<InitListExpr>(Init)) {
+ Diag(Init->getLocStart(), diag::err_auto_init_list_from_c);
+ return DAR_FailedAlreadyDiagnosed;
+ }
}
}
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;
case TST_interface:
case TST_class:
case TST_auto:
+ case TST_auto_type:
case TST_decltype_auto:
case TST_unknown_anytype:
case TST_error:
// 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:
// The TagDecl owned by the DeclSpec.
TagDecl *OwnedTagDecl = nullptr;
- bool ContainsPlaceholderType = false;
-
switch (D.getName().getKind()) {
case UnqualifiedId::IK_ImplicitSelfParam:
case UnqualifiedId::IK_OperatorFunctionId:
case UnqualifiedId::IK_LiteralOperatorId:
case UnqualifiedId::IK_TemplateId:
T = ConvertDeclSpecToType(state);
- ContainsPlaceholderType = D.getDeclSpec().containsPlaceholderType();
if (!D.isInvalidType() && D.getDeclSpec().isTypeSpecOwned()) {
OwnedTagDecl = cast<TagDecl>(D.getDeclSpec().getRepAsDecl());
// converts to.
T = SemaRef.GetTypeFromParser(D.getName().ConversionFunctionId,
&ReturnTypeInfo);
- ContainsPlaceholderType = T->getContainedAutoType();
break;
}
distributeTypeAttrsFromDeclarator(state, T);
// C++11 [dcl.spec.auto]p5: reject 'auto' if it is not in an allowed context.
- // In C++11, a function declarator using 'auto' must have a trailing return
- // 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:
Error = 0;
break;
case Declarator::LambdaExprParameterContext:
+ // In C++14, generic lambdas allow 'auto' in their parameters.
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<TagDecl>(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);
if (DeclType.Kind == DeclaratorChunk::Function) {
const DeclaratorChunk::FunctionTypeInfo &FTI = DeclType.Fun;
if (FTI.hasTrailingReturnType()) {
+ HaveTrailing = true;
Error = -1;
break;
}
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 &&
D.setInvalidType(true);
} else if (D.getContext() != Declarator::LambdaExprContext &&
(T.hasQualifiers() || !isa<AutoType>(T) ||
- cast<AutoType>(T)->isDecltypeAuto())) {
+ cast<AutoType>(T)->getKeyword() != AutoTypeKeyword::Auto)) {
S.Diag(D.getDeclSpec().getTypeSpecTypeLoc(),
diag::err_trailing_return_without_auto)
<< T << D.getDeclSpec().getSourceRange();
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<TagType>())
/// \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);
}
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 {
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();
}
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: {
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;
// 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() {
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}}
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.
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;
}
// RUN: %clang_cc1 -fsyntax-only -verify %s -std=c++11
+// RUN: %clang_cc1 -fsyntax-only -verify %s -std=c++1y
void f() {
auto int a; // expected-warning {{'auto' storage class specifier is not permitted in C++11, and will not be supported in future releases}}
int auto b; // expected-error{{cannot combine with previous 'int' declaration specifier}}
}
+
+typedef auto PR25449(); // expected-error {{'auto' not allowed in typedef}}
};
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};