8 changes: 6 additions & 2 deletions clang/lib/Sema/SemaDecl.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -111,6 +111,7 @@ bool Sema::isSimpleTypeSpecifier(tok::TokenKind Kind) const {
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:
Expand Down Expand Up @@ -5765,7 +5766,10 @@ Sema::ActOnVariableDeclarator(Scope *S, Declarator &D, DeclContext *DC,
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 {
Expand Down Expand Up @@ -10243,7 +10247,7 @@ Sema::BuildDeclaratorGroup(MutableArrayRef<Decl *> Group,
} 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()
Expand Down
8 changes: 5 additions & 3 deletions clang/lib/Sema/SemaExpr.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -349,8 +349,10 @@ bool Sema::DiagnoseUseOfDecl(NamedDecl *D, SourceLocation Loc,

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

Expand Down Expand Up @@ -3685,7 +3687,7 @@ static bool CheckAlignOfExpr(Sema &S, Expr *E) {
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;
}
Expand Down Expand Up @@ -3787,7 +3789,7 @@ Sema::CreateUnaryExprOrTypeTraitExpr(Expr *E, SourceLocation OpLoc,
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);
Expand Down
12 changes: 11 additions & 1 deletion clang/lib/Sema/SemaTemplateDeduction.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -3908,7 +3908,7 @@ namespace {
!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());
Expand Down Expand Up @@ -3976,6 +3976,11 @@ Sema::DeduceAutoType(TypeLoc Type, Expr *&Init, QualType &Result) {
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;
}
}
}

Expand Down Expand Up @@ -4013,6 +4018,11 @@ Sema::DeduceAutoType(TypeLoc Type, Expr *&Init, QualType &Result) {
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;
Expand Down
1 change: 1 addition & 0 deletions clang/lib/Sema/SemaTemplateVariadic.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -737,6 +737,7 @@ bool Sema::containsUnexpandedParameterPacks(Declarator &D) {
case TST_interface:
case TST_class:
case TST_auto:
case TST_auto_type:
case TST_decltype_auto:
case TST_unknown_anytype:
case TST_error:
Expand Down
109 changes: 66 additions & 43 deletions clang/lib/Sema/SemaType.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1504,14 +1504,17 @@ static QualType ConvertDeclSpecToType(TypeProcessingState &state) {
// 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:
Expand Down Expand Up @@ -2573,16 +2576,13 @@ static QualType GetDeclSpecTypeForDeclarator(TypeProcessingState &state,
// 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_Identifier:
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());
Expand All @@ -2606,25 +2606,17 @@ static QualType GetDeclSpecTypeForDeclarator(TypeProcessingState &state,
// converts to.
T = SemaRef.GetTypeFromParser(D.getName().ConversionFunctionId,
&ReturnTypeInfo);
ContainsPlaceholderType = T->getContainedAutoType();
break;
}

if (D.getAttributes())
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:
Expand All @@ -2633,76 +2625,96 @@ static QualType GetDeclSpecTypeForDeclarator(TypeProcessingState &state,
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);
DeclaratorChunk &DeclType = D.getTypeObject(chunkIndex);
if (DeclType.Kind == DeclaratorChunk::Function) {
const DeclaratorChunk::FunctionTypeInfo &FTI = DeclType.Fun;
if (FTI.hasTrailingReturnType()) {
HaveTrailing = true;
Error = -1;
break;
}
Expand All @@ -2715,16 +2727,24 @@ static QualType GetDeclSpecTypeForDeclarator(TypeProcessingState &state,
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 &&
Expand Down Expand Up @@ -3729,7 +3749,7 @@ static TypeSourceInfo *GetFullTypeForDeclarator(TypeProcessingState &state,
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();
Expand Down Expand Up @@ -6792,6 +6812,9 @@ QualType Sema::BuildTypeofExprType(Expr *E, SourceLocation Loc) {
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>())
Expand Down
8 changes: 4 additions & 4 deletions clang/lib/Sema/TreeTransform.h
Original file line number Diff line number Diff line change
Expand Up @@ -848,11 +848,11 @@ class TreeTransform {
/// \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);
}

Expand Down Expand Up @@ -3888,7 +3888,7 @@ TreeTransform<Derived>::TransformQualifiedType(TypeLocBuilder &TLB,
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 {
Expand Down Expand Up @@ -5091,7 +5091,7 @@ QualType TreeTransform<Derived>::TransformAutoType(TypeLocBuilder &TLB,
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();
}
Expand Down
4 changes: 2 additions & 2 deletions clang/lib/Serialization/ASTReader.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -5413,9 +5413,9 @@ QualType ASTReader::readTypeRecord(unsigned Index) {

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: {
Expand Down
2 changes: 1 addition & 1 deletion clang/lib/Serialization/ASTWriter.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -281,7 +281,7 @@ void ASTTypeWriter::VisitUnaryTransformType(const UnaryTransformType *T) {

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;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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() {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -49,7 +49,7 @@ decltype(auto) f1();
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}}
Expand Down
3 changes: 2 additions & 1 deletion clang/test/Sema/bitfield.c
Original file line number Diff line number Diff line change
Expand Up @@ -63,7 +63,8 @@ typedef unsigned Unsigned;
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.
Expand Down
1 change: 1 addition & 0 deletions clang/test/Sema/exprs.c
Original file line number Diff line number Diff line change
Expand Up @@ -97,6 +97,7 @@ int test9(struct f *P) {
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;
}

Expand Down
3 changes: 3 additions & 0 deletions clang/test/SemaCXX/auto-cxx0x.cpp
Original file line number Diff line number Diff line change
@@ -1,5 +1,8 @@
// 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}}
3 changes: 3 additions & 0 deletions clang/test/SemaCXX/cxx98-compat.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -100,6 +100,9 @@ struct RefQualifier {
};

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};
Expand Down