summaryrefslogtreecommitdiffstats
path: root/clang/lib
diff options
context:
space:
mode:
authorRichard Smith <richard-llvm@metafoo.co.uk>2013-04-26 16:15:35 +0000
committerRichard Smith <richard-llvm@metafoo.co.uk>2013-04-26 16:15:35 +0000
commit74aeef50a0cc0547f387a38d32b77a2592ccc823 (patch)
treefe9ab0af5b819e3903258ff5c2ab860573a7f66c /clang/lib
parentaf7e8c367f25d6e6cbc6ab50f56ad41d42617f7d (diff)
downloadbcm5719-llvm-74aeef50a0cc0547f387a38d32b77a2592ccc823.tar.gz
bcm5719-llvm-74aeef50a0cc0547f387a38d32b77a2592ccc823.zip
Implement C++1y decltype(auto).
llvm-svn: 180610
Diffstat (limited to 'clang/lib')
-rw-r--r--clang/lib/AST/ASTContext.cpp10
-rw-r--r--clang/lib/AST/ASTImporter.cpp4
-rw-r--r--clang/lib/AST/ItaniumMangle.cpp2
-rw-r--r--clang/lib/AST/TypePrinter.cpp2
-rw-r--r--clang/lib/Parse/ParseCXXInlineMethods.cpp3
-rw-r--r--clang/lib/Parse/ParseDecl.cpp3
-rw-r--r--clang/lib/Parse/ParseDeclCXX.cpp79
-rw-r--r--clang/lib/Parse/ParseExpr.cpp8
-rw-r--r--clang/lib/Parse/ParseExprCXX.cpp2
-rw-r--r--clang/lib/Parse/ParseTentative.cpp1
-rw-r--r--clang/lib/Sema/DeclSpec.cpp43
-rw-r--r--clang/lib/Sema/SemaDecl.cpp5
-rw-r--r--clang/lib/Sema/SemaExprCXX.cpp2
-rw-r--r--clang/lib/Sema/SemaTemplateDeduction.cpp24
-rw-r--r--clang/lib/Sema/SemaTemplateVariadic.cpp1
-rw-r--r--clang/lib/Sema/SemaType.cpp69
-rw-r--r--clang/lib/Sema/TreeTransform.h12
-rw-r--r--clang/lib/Serialization/ASTReader.cpp7
-rw-r--r--clang/lib/Serialization/ASTWriter.cpp1
19 files changed, 207 insertions, 71 deletions
diff --git a/clang/lib/AST/ASTContext.cpp b/clang/lib/AST/ASTContext.cpp
index f9622455c0f..22ee0cfcb69 100644
--- a/clang/lib/AST/ASTContext.cpp
+++ b/clang/lib/AST/ASTContext.cpp
@@ -3516,17 +3516,19 @@ QualType ASTContext::getUnaryTransformType(QualType BaseType,
}
/// getAutoType - We only unique auto types after they've been deduced.
-QualType ASTContext::getAutoType(QualType DeducedType) const {
+QualType ASTContext::getAutoType(QualType DeducedType,
+ bool IsDecltypeAuto) const {
void *InsertPos = 0;
if (!DeducedType.isNull()) {
// Look in the folding set for an existing type.
llvm::FoldingSetNodeID ID;
- AutoType::Profile(ID, DeducedType);
+ AutoType::Profile(ID, DeducedType, IsDecltypeAuto);
if (AutoType *AT = AutoTypes.FindNodeOrInsertPos(ID, InsertPos))
return QualType(AT, 0);
}
- AutoType *AT = new (*this, TypeAlignment) AutoType(DeducedType);
+ AutoType *AT = new (*this, TypeAlignment) AutoType(DeducedType,
+ IsDecltypeAuto);
Types.push_back(AT);
if (InsertPos)
AutoTypes.InsertNode(AT, InsertPos);
@@ -3564,7 +3566,7 @@ QualType ASTContext::getAtomicType(QualType T) const {
/// getAutoDeductType - Get type pattern for deducing against 'auto'.
QualType ASTContext::getAutoDeductType() const {
if (AutoDeductTy.isNull())
- AutoDeductTy = getAutoType(QualType());
+ AutoDeductTy = getAutoType(QualType(), false);
assert(!AutoDeductTy.isNull() && "can't build 'auto' pattern");
return AutoDeductTy;
}
diff --git a/clang/lib/AST/ASTImporter.cpp b/clang/lib/AST/ASTImporter.cpp
index d2e6d297053..8b5f21ddda0 100644
--- a/clang/lib/AST/ASTImporter.cpp
+++ b/clang/lib/AST/ASTImporter.cpp
@@ -1680,7 +1680,7 @@ QualType ASTNodeImporter::VisitUnaryTransformType(const UnaryTransformType *T) {
}
QualType ASTNodeImporter::VisitAutoType(const AutoType *T) {
- // FIXME: Make sure that the "to" context supports C++0x!
+ // FIXME: Make sure that the "to" context supports C++11!
QualType FromDeduced = T->getDeducedType();
QualType ToDeduced;
if (!FromDeduced.isNull()) {
@@ -1689,7 +1689,7 @@ QualType ASTNodeImporter::VisitAutoType(const AutoType *T) {
return QualType();
}
- return Importer.getToContext().getAutoType(ToDeduced);
+ return Importer.getToContext().getAutoType(ToDeduced, T->isDecltypeAuto());
}
QualType ASTNodeImporter::VisitRecordType(const RecordType *T) {
diff --git a/clang/lib/AST/ItaniumMangle.cpp b/clang/lib/AST/ItaniumMangle.cpp
index 0b77933f0b4..5ad8021fac9 100644
--- a/clang/lib/AST/ItaniumMangle.cpp
+++ b/clang/lib/AST/ItaniumMangle.cpp
@@ -2275,7 +2275,7 @@ void CXXNameMangler::mangleType(const AutoType *T) {
QualType D = T->getDeducedType();
// <builtin-type> ::= Da # dependent auto
if (D.isNull())
- Out << "Da";
+ Out << (T->isDecltypeAuto() ? "Dc" : "Da");
else
mangleType(D);
}
diff --git a/clang/lib/AST/TypePrinter.cpp b/clang/lib/AST/TypePrinter.cpp
index 9d1717a220c..07bcb74d79b 100644
--- a/clang/lib/AST/TypePrinter.cpp
+++ b/clang/lib/AST/TypePrinter.cpp
@@ -779,7 +779,7 @@ void TypePrinter::printAutoBefore(const AutoType *T, raw_ostream &OS) {
if (T->isDeduced()) {
printBefore(T->getDeducedType(), OS);
} else {
- OS << "auto";
+ OS << (T->isDecltypeAuto() ? "decltype(auto)" : "auto");
spaceBeforePlaceHolder(OS);
}
}
diff --git a/clang/lib/Parse/ParseCXXInlineMethods.cpp b/clang/lib/Parse/ParseCXXInlineMethods.cpp
index bc634b57d9c..5d77f81ee4b 100644
--- a/clang/lib/Parse/ParseCXXInlineMethods.cpp
+++ b/clang/lib/Parse/ParseCXXInlineMethods.cpp
@@ -57,8 +57,7 @@ NamedDecl *Parser::ParseCXXInlineMethodDef(AccessSpecifier AS,
if (FnD) {
Actions.ProcessDeclAttributeList(getCurScope(), FnD, AccessAttrs,
false, true);
- bool TypeSpecContainsAuto
- = D.getDeclSpec().getTypeSpecType() == DeclSpec::TST_auto;
+ bool TypeSpecContainsAuto = D.getDeclSpec().containsPlaceholderType();
if (Init.isUsable())
Actions.AddInitializerToDecl(FnD, Init.get(), false,
TypeSpecContainsAuto);
diff --git a/clang/lib/Parse/ParseDecl.cpp b/clang/lib/Parse/ParseDecl.cpp
index 697e95a73ef..957e2eb1649 100644
--- a/clang/lib/Parse/ParseDecl.cpp
+++ b/clang/lib/Parse/ParseDecl.cpp
@@ -1809,8 +1809,7 @@ Decl *Parser::ParseDeclarationAfterDeclaratorAndAttributes(Declarator &D,
}
}
- bool TypeContainsAuto =
- D.getDeclSpec().getTypeSpecType() == DeclSpec::TST_auto;
+ bool TypeContainsAuto = D.getDeclSpec().containsPlaceholderType();
// Parse declarator '=' initializer.
// If a '==' or '+=' is found, suggest a fixit to '='.
diff --git a/clang/lib/Parse/ParseDeclCXX.cpp b/clang/lib/Parse/ParseDeclCXX.cpp
index d7f8e982aa5..f1fbbb15fed 100644
--- a/clang/lib/Parse/ParseDeclCXX.cpp
+++ b/clang/lib/Parse/ParseDeclCXX.cpp
@@ -674,15 +674,15 @@ Decl *Parser::ParseStaticAssertDeclaration(SourceLocation &DeclEnd){
T.getCloseLocation());
}
-/// ParseDecltypeSpecifier - Parse a C++0x decltype specifier.
+/// ParseDecltypeSpecifier - Parse a C++11 decltype specifier.
///
/// 'decltype' ( expression )
+/// 'decltype' ( 'auto' ) [C++1y]
///
SourceLocation Parser::ParseDecltypeSpecifier(DeclSpec &DS) {
assert((Tok.is(tok::kw_decltype) || Tok.is(tok::annot_decltype))
&& "Not a decltype specifier");
-
ExprResult Result;
SourceLocation StartLoc = Tok.getLocation();
SourceLocation EndLoc;
@@ -709,29 +709,44 @@ SourceLocation Parser::ParseDecltypeSpecifier(DeclSpec &DS) {
StartLoc : T.getOpenLocation();
}
- // Parse the expression
-
- // C++0x [dcl.type.simple]p4:
- // The operand of the decltype specifier is an unevaluated operand.
- EnterExpressionEvaluationContext Unevaluated(Actions, Sema::Unevaluated,
- 0, /*IsDecltype=*/true);
- Result = ParseExpression();
- if (Result.isInvalid()) {
- DS.SetTypeSpecError();
- if (SkipUntil(tok::r_paren, /*StopAtSemi=*/true, /*DontConsume=*/true)) {
- EndLoc = ConsumeParen();
- } else {
- if (PP.isBacktrackEnabled() && Tok.is(tok::semi)) {
- // Backtrack to get the location of the last token before the semi.
- PP.RevertCachedTokens(2);
- ConsumeToken(); // the semi.
- EndLoc = ConsumeAnyToken();
- assert(Tok.is(tok::semi));
+ // Check for C++1y 'decltype(auto)'.
+ if (Tok.is(tok::kw_auto)) {
+ // No need to disambiguate here: an expression can't start with 'auto',
+ // because the typename-specifier in a function-style cast operation can't
+ // be 'auto'.
+ Diag(Tok.getLocation(),
+ getLangOpts().CPlusPlus1y
+ ? diag::warn_cxx11_compat_decltype_auto_type_specifier
+ : diag::ext_decltype_auto_type_specifier);
+ ConsumeToken();
+ } else {
+ // Parse the expression
+
+ // C++11 [dcl.type.simple]p4:
+ // The operand of the decltype specifier is an unevaluated operand.
+ EnterExpressionEvaluationContext Unevaluated(Actions, Sema::Unevaluated,
+ 0, /*IsDecltype=*/true);
+ Result = ParseExpression();
+ if (Result.isInvalid()) {
+ DS.SetTypeSpecError();
+ if (SkipUntil(tok::r_paren, /*StopAtSemi=*/true,
+ /*DontConsume=*/true)) {
+ EndLoc = ConsumeParen();
} else {
- EndLoc = Tok.getLocation();
+ if (PP.isBacktrackEnabled() && Tok.is(tok::semi)) {
+ // Backtrack to get the location of the last token before the semi.
+ PP.RevertCachedTokens(2);
+ ConsumeToken(); // the semi.
+ EndLoc = ConsumeAnyToken();
+ assert(Tok.is(tok::semi));
+ } else {
+ EndLoc = Tok.getLocation();
+ }
}
+ return EndLoc;
}
- return EndLoc;
+
+ Result = Actions.ActOnDecltypeExpression(Result.take());
}
// Match the ')'
@@ -743,7 +758,6 @@ SourceLocation Parser::ParseDecltypeSpecifier(DeclSpec &DS) {
return T.getCloseLocation();
}
- Result = Actions.ActOnDecltypeExpression(Result.take());
if (Result.isInvalid()) {
DS.SetTypeSpecError();
return T.getCloseLocation();
@@ -751,12 +765,16 @@ SourceLocation Parser::ParseDecltypeSpecifier(DeclSpec &DS) {
EndLoc = T.getCloseLocation();
}
+ assert(!Result.isInvalid());
const char *PrevSpec = 0;
unsigned DiagID;
// Check for duplicate type specifiers (e.g. "int decltype(a)").
- if (DS.SetTypeSpecType(DeclSpec::TST_decltype, StartLoc, PrevSpec,
- DiagID, Result.release())) {
+ if (Result.get()
+ ? DS.SetTypeSpecType(DeclSpec::TST_decltype, StartLoc, PrevSpec,
+ DiagID, Result.release())
+ : DS.SetTypeSpecType(DeclSpec::TST_decltype_auto, StartLoc, PrevSpec,
+ DiagID)) {
Diag(StartLoc, DiagID) << PrevSpec;
DS.SetTypeSpecError();
}
@@ -773,8 +791,10 @@ void Parser::AnnotateExistingDecltypeSpecifier(const DeclSpec& DS,
PP.EnterToken(Tok);
Tok.setKind(tok::annot_decltype);
- setExprAnnotation(Tok, DS.getTypeSpecType() == TST_decltype ?
- DS.getRepAsExpr() : ExprResult());
+ setExprAnnotation(Tok,
+ DS.getTypeSpecType() == TST_decltype ? DS.getRepAsExpr() :
+ DS.getTypeSpecType() == TST_decltype_auto ? ExprResult() :
+ ExprError());
Tok.setAnnotationEndLoc(EndLoc);
Tok.setLocation(StartLoc);
PP.AnnotateCachedTokens(Tok);
@@ -2267,11 +2287,10 @@ void Parser::ParseCXXClassMemberDeclaration(AccessSpecifier AS,
SkipUntil(tok::comma, true, true);
else if (ThisDecl)
Actions.AddInitializerToDecl(ThisDecl, Init.get(), EqualLoc.isInvalid(),
- DS.getTypeSpecType() == DeclSpec::TST_auto);
+ DS.containsPlaceholderType());
} else if (ThisDecl && DS.getStorageClassSpec() == DeclSpec::SCS_static) {
// No initializer.
- Actions.ActOnUninitializedDecl(ThisDecl,
- DS.getTypeSpecType() == DeclSpec::TST_auto);
+ Actions.ActOnUninitializedDecl(ThisDecl, DS.containsPlaceholderType());
}
if (ThisDecl) {
diff --git a/clang/lib/Parse/ParseExpr.cpp b/clang/lib/Parse/ParseExpr.cpp
index 956ba36d3c8..326056daf44 100644
--- a/clang/lib/Parse/ParseExpr.cpp
+++ b/clang/lib/Parse/ParseExpr.cpp
@@ -691,8 +691,14 @@ ExprResult Parser::ParseCastExpression(bool isUnaryExpression,
Res = getExprAnnotation(Tok);
ConsumeToken();
break;
-
+
case tok::kw_decltype:
+ // Annotate the token and tail recurse.
+ if (TryAnnotateTypeOrScopeToken())
+ return ExprError();
+ assert(Tok.isNot(tok::kw_decltype));
+ return ParseCastExpression(isUnaryExpression, isAddressOfOperand);
+
case tok::identifier: { // primary-expression: identifier
// unqualified-id: identifier
// constant: enumeration-constant
diff --git a/clang/lib/Parse/ParseExprCXX.cpp b/clang/lib/Parse/ParseExprCXX.cpp
index 17c4adf7d7e..ab8be570c1a 100644
--- a/clang/lib/Parse/ParseExprCXX.cpp
+++ b/clang/lib/Parse/ParseExprCXX.cpp
@@ -1455,7 +1455,7 @@ bool Parser::ParseCXXCondition(ExprResult &ExprOut,
if (!InitExpr.isInvalid())
Actions.AddInitializerToDecl(DeclOut, InitExpr.take(), !CopyInitialization,
- DS.getTypeSpecType() == DeclSpec::TST_auto);
+ DS.containsPlaceholderType());
// FIXME: Build a reference to this declaration? Convert it to bool?
// (This is currently handled by Sema).
diff --git a/clang/lib/Parse/ParseTentative.cpp b/clang/lib/Parse/ParseTentative.cpp
index 00ca3d84654..dff3b64c5b3 100644
--- a/clang/lib/Parse/ParseTentative.cpp
+++ b/clang/lib/Parse/ParseTentative.cpp
@@ -942,6 +942,7 @@ bool Parser::isTentativelyDeclared(IdentifierInfo *II) {
/// [GNU] '_Complex'
/// [C++11] 'auto'
/// [C++11] 'decltype' ( expression )
+/// [C++1y] 'decltype' ( 'auto' )
///
/// type-name:
/// class-name
diff --git a/clang/lib/Sema/DeclSpec.cpp b/clang/lib/Sema/DeclSpec.cpp
index 7a69eef2bb1..998e2c0c367 100644
--- a/clang/lib/Sema/DeclSpec.cpp
+++ b/clang/lib/Sema/DeclSpec.cpp
@@ -294,6 +294,11 @@ bool Declarator::isDeclarationOfFunction() const {
case TST_event_t:
return false;
+ case TST_decltype_auto:
+ // This must have an initializer, so can't be a function declaration,
+ // even if the initializer has function type.
+ return false;
+
case TST_decltype:
case TST_typeofExpr:
if (Expr *E = DS.getRepAsExpr())
@@ -434,6 +439,7 @@ const char *DeclSpec::getSpecifierName(DeclSpec::TST T) {
case DeclSpec::TST_typeofExpr: return "typeof";
case DeclSpec::TST_auto: return "auto";
case DeclSpec::TST_decltype: return "(decltype)";
+ case DeclSpec::TST_decltype_auto: return "decltype(auto)";
case DeclSpec::TST_underlyingType: return "__underlying_type";
case DeclSpec::TST_unknown_anytype: return "__unknown_anytype";
case DeclSpec::TST_atomic: return "_Atomic";
@@ -494,7 +500,7 @@ bool DeclSpec::SetStorageClassSpec(Sema &S, SCS SC, SourceLocation Loc,
}
if (StorageClassSpec != SCS_unspecified) {
- // Maybe this is an attempt to use C++0x 'auto' outside of C++0x mode.
+ // Maybe this is an attempt to use C++11 'auto' outside of C++11 mode.
bool isInvalid = true;
if (TypeSpecType == TST_unspecified && S.getLangOpts().CPlusPlus) {
if (SC == SCS_auto)
@@ -834,6 +840,39 @@ void DeclSpec::Finish(DiagnosticsEngine &D, Preprocessor &PP) {
// Check the type specifier components first.
+ // If decltype(auto) is used, no other type specifiers are permitted.
+ if (TypeSpecType == TST_decltype_auto &&
+ (TypeSpecWidth != TSW_unspecified ||
+ TypeSpecComplex != TSC_unspecified ||
+ TypeSpecSign != TSS_unspecified ||
+ TypeAltiVecVector || TypeAltiVecPixel || TypeAltiVecBool ||
+ TypeQualifiers)) {
+ const int NumLocs = 8;
+ SourceLocation ExtraLocs[NumLocs] = {
+ TSWLoc, TSCLoc, TSSLoc, AltiVecLoc,
+ TQ_constLoc, TQ_restrictLoc, TQ_volatileLoc, TQ_atomicLoc
+ };
+ FixItHint Hints[NumLocs];
+ SourceLocation FirstLoc;
+ for (unsigned I = 0; I != NumLocs; ++I) {
+ if (!ExtraLocs[I].isInvalid()) {
+ if (FirstLoc.isInvalid() ||
+ PP.getSourceManager().isBeforeInTranslationUnit(ExtraLocs[I],
+ FirstLoc))
+ FirstLoc = ExtraLocs[I];
+ Hints[I] = FixItHint::CreateRemoval(ExtraLocs[I]);
+ }
+ }
+ TypeSpecWidth = TSW_unspecified;
+ TypeSpecComplex = TSC_unspecified;
+ TypeSpecSign = TSS_unspecified;
+ TypeAltiVecVector = TypeAltiVecPixel = TypeAltiVecBool = false;
+ TypeQualifiers = 0;
+ Diag(D, TSTLoc, diag::err_decltype_auto_cannot_be_combined)
+ << Hints[0] << Hints[1] << Hints[2] << Hints[3]
+ << Hints[4] << Hints[5] << Hints[6] << Hints[7];
+ }
+
// Validate and finalize AltiVec vector declspec.
if (TypeAltiVecVector) {
if (TypeAltiVecBool) {
@@ -973,7 +1012,7 @@ void DeclSpec::Finish(DiagnosticsEngine &D, Preprocessor &PP) {
StorageClassSpecLoc = SourceLocation();
}
// Diagnose if we've recovered from an ill-formed 'auto' storage class
- // specifier in a pre-C++0x dialect of C++.
+ // specifier in a pre-C++11 dialect of C++.
if (!PP.getLangOpts().CPlusPlus11 && TypeSpecType == TST_auto)
Diag(D, TSTLoc, diag::ext_auto_type_specifier);
if (PP.getLangOpts().CPlusPlus && !PP.getLangOpts().CPlusPlus11 &&
diff --git a/clang/lib/Sema/SemaDecl.cpp b/clang/lib/Sema/SemaDecl.cpp
index 53f726bc051..3d4f97fbd25 100644
--- a/clang/lib/Sema/SemaDecl.cpp
+++ b/clang/lib/Sema/SemaDecl.cpp
@@ -4844,8 +4844,7 @@ Sema::ActOnVariableDeclarator(Scope *S, Declarator &D, DeclContext *DC,
// If this decl has an auto type in need of deduction, make a note of the
// Decl so we can diagnose uses of it in its own initializer.
- if (D.getDeclSpec().getTypeSpecType() == DeclSpec::TST_auto &&
- R->getContainedAutoType())
+ if (D.getDeclSpec().containsPlaceholderType() && R->getContainedAutoType())
ParsingInitForAutoVars.insert(NewVD);
if (D.isInvalidType() || Invalid)
@@ -8166,7 +8165,7 @@ Sema::FinalizeDeclaratorGroup(Scope *S, const DeclSpec &DS,
getASTContext().addUnnamedTag(Tag);
return BuildDeclaratorGroup(Decls.data(), Decls.size(),
- DS.getTypeSpecType() == DeclSpec::TST_auto);
+ DS.containsPlaceholderType());
}
/// BuildDeclaratorGroup - convert a list of declarations into a declaration
diff --git a/clang/lib/Sema/SemaExprCXX.cpp b/clang/lib/Sema/SemaExprCXX.cpp
index ba2291e09cf..65ad83d5fcb 100644
--- a/clang/lib/Sema/SemaExprCXX.cpp
+++ b/clang/lib/Sema/SemaExprCXX.cpp
@@ -996,7 +996,7 @@ Sema::ActOnCXXNew(SourceLocation StartLoc, bool UseGlobal,
SourceLocation PlacementLParen, MultiExprArg PlacementArgs,
SourceLocation PlacementRParen, SourceRange TypeIdParens,
Declarator &D, Expr *Initializer) {
- bool TypeContainsAuto = D.getDeclSpec().getTypeSpecType() == DeclSpec::TST_auto;
+ bool TypeContainsAuto = D.getDeclSpec().containsPlaceholderType();
Expr *ArraySize = 0;
// If the specified type is an array, unwrap it and save the expression.
diff --git a/clang/lib/Sema/SemaTemplateDeduction.cpp b/clang/lib/Sema/SemaTemplateDeduction.cpp
index d559833c481..a681371c9b2 100644
--- a/clang/lib/Sema/SemaTemplateDeduction.cpp
+++ b/clang/lib/Sema/SemaTemplateDeduction.cpp
@@ -3579,11 +3579,13 @@ namespace {
// auto type deduced as T" in order for [temp.deduct.call]p3 to apply.
if (isa<TemplateTypeParmType>(Replacement)) {
QualType Result = Replacement;
- TemplateTypeParmTypeLoc NewTL = TLB.push<TemplateTypeParmTypeLoc>(Result);
+ TemplateTypeParmTypeLoc NewTL =
+ TLB.push<TemplateTypeParmTypeLoc>(Result);
NewTL.setNameLoc(TL.getNameLoc());
return Result;
} else {
- QualType Result = RebuildAutoType(Replacement);
+ QualType Result = RebuildAutoType(Replacement,
+ TL.getTypePtr()->isDecltypeAuto());
AutoTypeLoc NewTL = TLB.push<AutoTypeLoc>(Result);
NewTL.setNameLoc(TL.getNameLoc());
return Result;
@@ -3657,6 +3659,24 @@ Sema::DeduceAutoType(TypeSourceInfo *Type, Expr *&Init,
return DAR_Succeeded;
}
+ // If this is a 'decltype(auto)' specifier, do the decltype dance.
+ // Since 'decltype(auto)' can only occur at the top of the type, we
+ // don't need to go digging for it.
+ if (const AutoType *AT = Type->getType()->getAs<AutoType>()) {
+ if (AT->isDecltypeAuto()) {
+ if (isa<InitListExpr>(Init)) {
+ Diag(Init->getLocStart(), diag::err_decltype_auto_initializer_list);
+ return DAR_FailedAlreadyDiagnosed;
+ }
+
+ QualType Deduced = BuildDecltypeType(Init, Init->getLocStart());
+ // FIXME: Support a non-canonical deduced type for 'auto'.
+ Deduced = Context.getCanonicalType(Deduced);
+ Result = SubstituteAutoTransform(*this, Deduced).TransformType(Type);
+ return DAR_Succeeded;
+ }
+ }
+
SourceLocation Loc = Init->getExprLoc();
LocalInstantiationScope InstScope(*this);
diff --git a/clang/lib/Sema/SemaTemplateVariadic.cpp b/clang/lib/Sema/SemaTemplateVariadic.cpp
index c0ad2be6d40..db885aeec7b 100644
--- a/clang/lib/Sema/SemaTemplateVariadic.cpp
+++ b/clang/lib/Sema/SemaTemplateVariadic.cpp
@@ -727,6 +727,7 @@ bool Sema::containsUnexpandedParameterPacks(Declarator &D) {
case TST_interface:
case TST_class:
case TST_auto:
+ case TST_decltype_auto:
case TST_unknown_anytype:
case TST_image1d_t:
case TST_image1d_array_t:
diff --git a/clang/lib/Sema/SemaType.cpp b/clang/lib/Sema/SemaType.cpp
index 5289d15c34a..8bf5143beda 100644
--- a/clang/lib/Sema/SemaType.cpp
+++ b/clang/lib/Sema/SemaType.cpp
@@ -994,11 +994,14 @@ static QualType ConvertDeclSpecToType(TypeProcessingState &state) {
}
break;
- case DeclSpec::TST_auto: {
+ case DeclSpec::TST_auto:
// TypeQuals handled by caller.
- Result = Context.getAutoType(QualType());
+ Result = Context.getAutoType(QualType(), /*decltype(auto)*/false);
+ break;
+
+ case DeclSpec::TST_decltype_auto:
+ Result = Context.getAutoType(QualType(), /*decltype(auto)*/true);
break;
- }
case DeclSpec::TST_unknown_anytype:
Result = Context.UnknownAnyTy;
@@ -1457,12 +1460,6 @@ QualType Sema::BuildArrayType(QualType T, ArrayType::ArraySizeModifier ASM,
return QualType();
}
- if (T->getContainedAutoType()) {
- Diag(Loc, diag::err_illegal_decl_array_of_auto)
- << getPrintableNameForEntity(Entity) << T;
- return QualType();
- }
-
if (const RecordType *EltTy = T->getAs<RecordType>()) {
// If the element type is a struct or union that contains a variadic
// array, accept it as a GNU extension: C99 6.7.2.1p2.
@@ -2063,7 +2060,7 @@ static QualType GetDeclSpecTypeForDeclarator(TypeProcessingState &state,
// 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.
- if (D.getDeclSpec().getTypeSpecType() == DeclSpec::TST_auto &&
+ if (D.getDeclSpec().containsPlaceholderType() &&
(!SemaRef.getLangOpts().CPlusPlus11 || !D.isFunctionDeclarator())) {
int Error = -1;
@@ -2402,6 +2399,46 @@ static TypeSourceInfo *GetFullTypeForDeclarator(TypeProcessingState &state,
(T->castAs<FunctionProtoType>()->getTypeQuals() != 0 ||
T->castAs<FunctionProtoType>()->getRefQualifier() != RQ_None);
+ // If T is 'decltype(auto)', the only declarators we can have are parens
+ // and at most one function declarator if this is a function declaration.
+ if (const AutoType *AT = T->getAs<AutoType>()) {
+ if (AT->isDecltypeAuto()) {
+ for (unsigned I = 0, E = D.getNumTypeObjects(); I != E; ++I) {
+ unsigned Index = E - I - 1;
+ DeclaratorChunk &DeclChunk = D.getTypeObject(Index);
+ unsigned DiagId = diag::err_decltype_auto_compound_type;
+ unsigned DiagKind = 0;
+ switch (DeclChunk.Kind) {
+ case DeclaratorChunk::Paren:
+ continue;
+ case DeclaratorChunk::Function: {
+ unsigned FnIndex;
+ if (D.isFunctionDeclarationContext() &&
+ D.isFunctionDeclarator(FnIndex) && FnIndex == Index)
+ continue;
+ DiagId = diag::err_decltype_auto_function_declarator_not_declaration;
+ break;
+ }
+ case DeclaratorChunk::Pointer:
+ case DeclaratorChunk::BlockPointer:
+ case DeclaratorChunk::MemberPointer:
+ DiagKind = 0;
+ break;
+ case DeclaratorChunk::Reference:
+ DiagKind = 1;
+ break;
+ case DeclaratorChunk::Array:
+ DiagKind = 2;
+ break;
+ }
+
+ S.Diag(DeclChunk.Loc, DiagId) << DiagKind;
+ D.setInvalidType(true);
+ break;
+ }
+ }
+ }
+
// Walk the DeclTypeInfo, building the recursive type as we go.
// DeclTypeInfos are ordered from the identifier out, which is
// opposite of what we want :).
@@ -2530,6 +2567,15 @@ static TypeSourceInfo *GetFullTypeForDeclarator(TypeProcessingState &state,
}
}
+ if (const AutoType *AT = T->getContainedAutoType()) {
+ // We've already diagnosed this for decltype(auto).
+ if (!AT->isDecltypeAuto()) {
+ S.Diag(DeclType.Loc, diag::err_illegal_decl_array_of_auto)
+ << getPrintableNameForEntity(Name) << T;
+ D.setInvalidType(true);
+ }
+ }
+
T = S.BuildArrayType(T, ASM, ArraySize, ATI.TypeQuals,
SourceRange(DeclType.Loc, DeclType.EndLoc), Name);
break;
@@ -2560,7 +2606,8 @@ static TypeSourceInfo *GetFullTypeForDeclarator(TypeProcessingState &state,
<< T << D.getDeclSpec().getSourceRange();
D.setInvalidType(true);
} else if (D.getContext() != Declarator::LambdaExprContext &&
- (T.hasQualifiers() || !isa<AutoType>(T))) {
+ (T.hasQualifiers() || !isa<AutoType>(T) ||
+ cast<AutoType>(T)->isDecltypeAuto())) {
S.Diag(D.getDeclSpec().getTypeSpecTypeLoc(),
diag::err_trailing_return_without_auto)
<< T << D.getDeclSpec().getSourceRange();
diff --git a/clang/lib/Sema/TreeTransform.h b/clang/lib/Sema/TreeTransform.h
index 97316f89b32..c0bc34fa975 100644
--- a/clang/lib/Sema/TreeTransform.h
+++ b/clang/lib/Sema/TreeTransform.h
@@ -754,17 +754,17 @@ public:
UnaryTransformType::UTTKind UKind,
SourceLocation Loc);
- /// \brief Build a new C++0x decltype type.
+ /// \brief Build a new C++11 decltype type.
///
/// By default, performs semantic analysis when building the decltype type.
/// Subclasses may override this routine to provide different behavior.
QualType RebuildDecltypeType(Expr *Underlying, SourceLocation Loc);
- /// \brief Build a new C++0x auto type.
+ /// \brief Build a new C++11 auto type.
///
/// By default, builds a new AutoType with the given deduced type.
- QualType RebuildAutoType(QualType Deduced) {
- return SemaRef.Context.getAutoType(Deduced);
+ QualType RebuildAutoType(QualType Deduced, bool IsDecltypeAuto) {
+ return SemaRef.Context.getAutoType(Deduced, IsDecltypeAuto);
}
/// \brief Build a new template specialization type.
@@ -3407,7 +3407,7 @@ TreeTransform<Derived>::TransformQualifiedType(TypeLocBuilder &TLB,
Qs.removeObjCLifetime();
Deduced = SemaRef.Context.getQualifiedType(Deduced.getUnqualifiedType(),
Qs);
- Result = SemaRef.Context.getAutoType(Deduced);
+ Result = SemaRef.Context.getAutoType(Deduced, AutoTy->isDecltypeAuto());
TLB.TypeWasModifiedSafely(Result);
} else {
// Otherwise, complain about the addition of a qualifier to an
@@ -4501,7 +4501,7 @@ QualType TreeTransform<Derived>::TransformAutoType(TypeLocBuilder &TLB,
QualType Result = TL.getType();
if (getDerived().AlwaysRebuild() || NewDeduced != OldDeduced) {
- Result = getDerived().RebuildAutoType(NewDeduced);
+ Result = getDerived().RebuildAutoType(NewDeduced, T->isDecltypeAuto());
if (Result.isNull())
return QualType();
}
diff --git a/clang/lib/Serialization/ASTReader.cpp b/clang/lib/Serialization/ASTReader.cpp
index 5123b79d2e9..c06153a61a9 100644
--- a/clang/lib/Serialization/ASTReader.cpp
+++ b/clang/lib/Serialization/ASTReader.cpp
@@ -4626,8 +4626,11 @@ QualType ASTReader::readTypeRecord(unsigned Index) {
return Context.getUnaryTransformType(BaseType, UnderlyingType, UKind);
}
- case TYPE_AUTO:
- return Context.getAutoType(readType(*Loc.F, Record, Idx));
+ case TYPE_AUTO: {
+ QualType Deduced = readType(*Loc.F, Record, Idx);
+ bool IsDecltypeAuto = Record[Idx++];
+ return Context.getAutoType(Deduced, IsDecltypeAuto);
+ }
case TYPE_RECORD: {
if (Record.size() != 2) {
diff --git a/clang/lib/Serialization/ASTWriter.cpp b/clang/lib/Serialization/ASTWriter.cpp
index b6d25d22d59..c5a055072d9 100644
--- a/clang/lib/Serialization/ASTWriter.cpp
+++ b/clang/lib/Serialization/ASTWriter.cpp
@@ -245,6 +245,7 @@ void ASTTypeWriter::VisitUnaryTransformType(const UnaryTransformType *T) {
void ASTTypeWriter::VisitAutoType(const AutoType *T) {
Writer.AddTypeRef(T->getDeducedType(), Record);
+ Record.push_back(T->isDecltypeAuto());
Code = TYPE_AUTO;
}
OpenPOWER on IntegriCloud