forked from OSchip/llvm-project
parent
af7e8c367f
commit
74aeef50a0
|
@ -1100,7 +1100,7 @@ public:
|
|||
UnaryTransformType::UTTKind UKind) const;
|
||||
|
||||
/// \brief C++11 deduced auto type.
|
||||
QualType getAutoType(QualType DeducedType) const;
|
||||
QualType getAutoType(QualType DeducedType, bool IsDecltypeAuto) const;
|
||||
|
||||
/// \brief C++11 deduction pattern for 'auto' type.
|
||||
QualType getAutoDeductType() const;
|
||||
|
|
|
@ -1326,10 +1326,20 @@ protected:
|
|||
unsigned AttrKind : 32 - NumTypeBits;
|
||||
};
|
||||
|
||||
class AutoTypeBitfields {
|
||||
friend class AutoType;
|
||||
|
||||
unsigned : NumTypeBits;
|
||||
|
||||
/// Was this placeholder type spelled as 'decltype(auto)'?
|
||||
unsigned IsDecltypeAuto : 1;
|
||||
};
|
||||
|
||||
union {
|
||||
TypeBitfields TypeBits;
|
||||
ArrayTypeBitfields ArrayTypeBits;
|
||||
AttributedTypeBitfields AttributedTypeBits;
|
||||
AutoTypeBitfields AutoTypeBits;
|
||||
BuiltinTypeBitfields BuiltinTypeBits;
|
||||
FunctionTypeBitfields FunctionTypeBits;
|
||||
ObjCObjectTypeBitfields ObjCObjectTypeBits;
|
||||
|
@ -3542,24 +3552,27 @@ public:
|
|||
}
|
||||
};
|
||||
|
||||
/// \brief Represents a C++0x auto type.
|
||||
/// \brief Represents a C++11 auto or C++1y decltype(auto) type.
|
||||
///
|
||||
/// These types are usually a placeholder for a deduced type. However, within
|
||||
/// templates and before the initializer is attached, there is no deduced type
|
||||
/// and an auto type is type-dependent and canonical.
|
||||
class AutoType : public Type, public llvm::FoldingSetNode {
|
||||
AutoType(QualType DeducedType)
|
||||
AutoType(QualType DeducedType, bool IsDecltypeAuto)
|
||||
: Type(Auto, DeducedType.isNull() ? QualType(this, 0) : DeducedType,
|
||||
/*Dependent=*/DeducedType.isNull(),
|
||||
/*InstantiationDependent=*/DeducedType.isNull(),
|
||||
/*VariablyModified=*/false, /*ContainsParameterPack=*/false) {
|
||||
assert((DeducedType.isNull() || !DeducedType->isDependentType()) &&
|
||||
"deduced a dependent type for auto");
|
||||
AutoTypeBits.IsDecltypeAuto = IsDecltypeAuto;
|
||||
}
|
||||
|
||||
friend class ASTContext; // ASTContext creates these
|
||||
|
||||
public:
|
||||
bool isDecltypeAuto() const { return AutoTypeBits.IsDecltypeAuto; }
|
||||
|
||||
bool isSugared() const { return isDeduced(); }
|
||||
QualType desugar() const { return getCanonicalTypeInternal(); }
|
||||
|
||||
|
@ -3571,12 +3584,13 @@ public:
|
|||
}
|
||||
|
||||
void Profile(llvm::FoldingSetNodeID &ID) {
|
||||
Profile(ID, getDeducedType());
|
||||
Profile(ID, getDeducedType(), isDecltypeAuto());
|
||||
}
|
||||
|
||||
static void Profile(llvm::FoldingSetNodeID &ID,
|
||||
QualType Deduced) {
|
||||
QualType Deduced, bool IsDecltypeAuto) {
|
||||
ID.AddPointer(Deduced.getAsOpaquePtr());
|
||||
ID.AddBoolean(IsDecltypeAuto);
|
||||
}
|
||||
|
||||
static bool classof(const Type *T) {
|
||||
|
|
|
@ -277,6 +277,11 @@ def warn_auto_storage_class : Warning<
|
|||
def ext_auto_storage_class : ExtWarn<
|
||||
"'auto' storage class specifier is not permitted in C++11, and will not "
|
||||
"be supported in future releases">, InGroup<DiagGroup<"auto-storage-class">>;
|
||||
def ext_decltype_auto_type_specifier : ExtWarn<
|
||||
"'decltype(auto)' type specifier is a C++1y extension">, InGroup<CXX1y>;
|
||||
def warn_cxx11_compat_decltype_auto_type_specifier : Warning<
|
||||
"'decltype(auto)' type specifier is incompatible with C++ standards before "
|
||||
"C++1y">, InGroup<CXXPre1yCompat>, DefaultIgnore;
|
||||
def ext_for_range : ExtWarn<
|
||||
"range-based for loop is a C++11 extension">, InGroup<CXX11>;
|
||||
def warn_cxx98_compat_for_range : Warning<
|
||||
|
|
|
@ -1465,6 +1465,17 @@ def warn_dangling_std_initializer_list : Warning<
|
|||
"%select{the full-expression|the constructor}0">,
|
||||
InGroup<DiagGroup<"dangling-initializer-list">>;
|
||||
|
||||
// C++1y decltype(auto) type
|
||||
def err_decltype_auto_cannot_be_combined : Error<
|
||||
"'decltype(auto)' cannot be combined with other type specifiers">;
|
||||
def err_decltype_auto_function_declarator_not_declaration : Error<
|
||||
"'decltype(auto)' can only be used as a return type "
|
||||
"in a function declaration">;
|
||||
def err_decltype_auto_compound_type : Error<
|
||||
"cannot form %select{pointer to|reference to|array of}0 'decltype(auto)'">;
|
||||
def err_decltype_auto_initializer_list : Error<
|
||||
"cannot deduce 'decltype(auto)' from initializer list">;
|
||||
|
||||
// C++11 override control
|
||||
def override_keyword_only_allowed_on_virtual_member_functions : Error<
|
||||
"only virtual member functions can be marked '%0'">;
|
||||
|
|
|
@ -38,8 +38,8 @@ namespace clang {
|
|||
TST_void,
|
||||
TST_char,
|
||||
TST_wchar, // C++ wchar_t
|
||||
TST_char16, // C++0x char16_t
|
||||
TST_char32, // C++0x char32_t
|
||||
TST_char16, // C++11 char16_t
|
||||
TST_char32, // C++11 char32_t
|
||||
TST_int,
|
||||
TST_int128,
|
||||
TST_half, // OpenCL half, ARM NEON __fp16
|
||||
|
@ -57,11 +57,12 @@ namespace clang {
|
|||
TST_typename, // Typedef, C++ class-name or enum name, etc.
|
||||
TST_typeofType,
|
||||
TST_typeofExpr,
|
||||
TST_decltype, // C++0x decltype
|
||||
TST_underlyingType, // __underlying_type for C++0x
|
||||
TST_auto, // C++0x auto
|
||||
TST_unknown_anytype, // __unknown_anytype extension
|
||||
TST_atomic, // C11 _Atomic
|
||||
TST_decltype, // C++11 decltype
|
||||
TST_underlyingType, // __underlying_type for C++11
|
||||
TST_auto, // C++11 auto
|
||||
TST_decltype_auto, // C++1y decltype(auto)
|
||||
TST_unknown_anytype, // __unknown_anytype extension
|
||||
TST_atomic, // C11 _Atomic
|
||||
TST_image1d_t, // OpenCL image1d_t
|
||||
TST_image1d_array_t, // OpenCL image1d_array_t
|
||||
TST_image1d_buffer_t, // OpenCL image1d_buffer_t
|
||||
|
@ -145,7 +146,7 @@ namespace clang {
|
|||
TSK_ExplicitSpecialization,
|
||||
/// This template specialization was instantiated from a template
|
||||
/// due to an explicit instantiation declaration request
|
||||
/// (C++0x [temp.explicit]).
|
||||
/// (C++11 [temp.explicit]).
|
||||
TSK_ExplicitInstantiationDeclaration,
|
||||
/// This template specialization was instantiated from a template
|
||||
/// due to an explicit instantiation definition request
|
||||
|
|
|
@ -458,19 +458,13 @@ private:
|
|||
/// \brief Read an already-translated primary expression out of an annotation
|
||||
/// token.
|
||||
static ExprResult getExprAnnotation(Token &Tok) {
|
||||
if (Tok.getAnnotationValue())
|
||||
return ExprResult((Expr *)Tok.getAnnotationValue());
|
||||
|
||||
return ExprResult(true);
|
||||
return ExprResult::getFromOpaquePointer(Tok.getAnnotationValue());
|
||||
}
|
||||
|
||||
/// \brief Set the primary expression corresponding to the given annotation
|
||||
/// token.
|
||||
static void setExprAnnotation(Token &Tok, ExprResult ER) {
|
||||
if (ER.isInvalid())
|
||||
Tok.setAnnotationValue(0);
|
||||
else
|
||||
Tok.setAnnotationValue(ER.get());
|
||||
Tok.setAnnotationValue(ER.getAsOpaquePointer());
|
||||
}
|
||||
|
||||
public:
|
||||
|
|
|
@ -285,6 +285,7 @@ public:
|
|||
static const TST TST_typeofType = clang::TST_typeofType;
|
||||
static const TST TST_typeofExpr = clang::TST_typeofExpr;
|
||||
static const TST TST_decltype = clang::TST_decltype;
|
||||
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_unknown_anytype = clang::TST_unknown_anytype;
|
||||
|
@ -504,6 +505,10 @@ public:
|
|||
SourceRange getTypeofParensRange() const { return TypeofParensRange; }
|
||||
void setTypeofParensRange(SourceRange range) { TypeofParensRange = range; }
|
||||
|
||||
bool containsPlaceholderType() const {
|
||||
return TypeSpecType == TST_auto || TypeSpecType == TST_decltype_auto;
|
||||
}
|
||||
|
||||
/// \brief Turn a type-specifier-type into a string like "_Bool" or "union".
|
||||
static const char *getSpecifierName(DeclSpec::TST T);
|
||||
static const char *getSpecifierName(DeclSpec::TQ Q);
|
||||
|
|
|
@ -207,6 +207,15 @@ namespace clang {
|
|||
assert((PtrWithInvalid & 0x01) == 0 && "Badly aligned pointer");
|
||||
return *this;
|
||||
}
|
||||
|
||||
// For types where we can fit a flag in with the pointer, provide
|
||||
// conversions to/from pointer type.
|
||||
static ActionResult getFromOpaquePointer(void *P) {
|
||||
ActionResult Result;
|
||||
Result.PtrWithInvalid = (uintptr_t)P;
|
||||
return Result;
|
||||
}
|
||||
void *getAsOpaquePointer() const { return (void*)PtrWithInvalid; }
|
||||
};
|
||||
|
||||
/// An opaque type for threading parsed type information through the
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
|
|
@ -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) {
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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 '='.
|
||||
|
|
|
@ -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
|
||||
// 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++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));
|
||||
// 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) {
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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).
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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 &&
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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.
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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:
|
||||
|
|
|
@ -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();
|
||||
|
|
|
@ -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();
|
||||
}
|
||||
|
|
|
@ -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) {
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
||||
|
|
|
@ -0,0 +1,43 @@
|
|||
// RUN: %clang_cc1 -fsyntax-only -verify %s -std=c++1y
|
||||
// RUN: %clang_cc1 -fsyntax-only -verify %s -std=c++11 -Wno-c++1y-extensions
|
||||
|
||||
// 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}}
|
||||
}
|
||||
|
||||
void g() {
|
||||
decltype(auto) a; // expected-error{{declaration of variable 'a' with type 'decltype(auto)' requires an initializer}}
|
||||
|
||||
decltype(auto) *b; // expected-error{{cannot form pointer to 'decltype(auto)'}} expected-error{{declaration of variable 'b' with type 'decltype(auto) *' requires an initializer}}
|
||||
|
||||
if (decltype(auto) b) {} // expected-error {{must have an initializer}}
|
||||
for (;decltype(auto) b;) {} // expected-error {{must have an initializer}}
|
||||
while (decltype(auto) b) {} // expected-error {{must have an initializer}}
|
||||
if (decltype(auto) b = true) { (void)b; }
|
||||
}
|
||||
|
||||
decltype(auto) n(1,2,3); // expected-error{{initializer for variable 'n' with type 'decltype(auto)' contains multiple expressions}}
|
||||
|
||||
namespace N
|
||||
{
|
||||
// All of these are references, because a string literal is an lvalue.
|
||||
decltype(auto) a = "const char (&)[19]", b = a, c = (a);
|
||||
}
|
||||
|
||||
void h() {
|
||||
decltype(auto) b = 42ULL;
|
||||
|
||||
for (decltype(auto) c = 0; c < b; ++c) {
|
||||
}
|
||||
}
|
||||
|
||||
template<typename T, typename U> struct same;
|
||||
template<typename T> struct same<T, T> {};
|
||||
|
||||
void i() {
|
||||
decltype(auto) x = 5;
|
||||
decltype(auto) int r; // expected-error {{cannot combine with previous 'decltype(auto)' declaration specifier}} expected-error {{requires an initializer}}
|
||||
}
|
|
@ -0,0 +1,62 @@
|
|||
// RUN: %clang_cc1 -verify -std=c++1y %s
|
||||
|
||||
namespace std {
|
||||
template<typename T> struct initializer_list {
|
||||
const T *p;
|
||||
unsigned long n;
|
||||
initializer_list(const T *p, unsigned long n);
|
||||
};
|
||||
}
|
||||
|
||||
// FIXME: This may not be p6 in C++1y; N3638 isn't very clear whether paragraphs
|
||||
// were added. It might be p8?
|
||||
|
||||
int i;
|
||||
int &&f();
|
||||
|
||||
using Int = int;
|
||||
using IntLRef = int&;
|
||||
using IntRRef = int&&;
|
||||
using InitListInt = std::initializer_list<int>;
|
||||
using IntPtr = int*;
|
||||
|
||||
auto x3a = i;
|
||||
decltype(auto) x3d = i;
|
||||
using Int = decltype(x3a);
|
||||
using Int = decltype(x3d);
|
||||
|
||||
auto x4a = (i);
|
||||
decltype(auto) x4d = (i);
|
||||
using Int = decltype(x4a);
|
||||
using IntLRef = decltype(x4d);
|
||||
|
||||
auto x5a = f();
|
||||
decltype(auto) x5d = f();
|
||||
using Int = decltype(x5a);
|
||||
using IntRRef = decltype(x5d);
|
||||
|
||||
auto x6a = { 1, 2 };
|
||||
decltype(auto) x6d = { 1, 2 }; // expected-error {{cannot deduce 'decltype(auto)' from initializer list}}
|
||||
using InitListInt = decltype(x6a);
|
||||
|
||||
auto *x7a = &i;
|
||||
decltype(auto) *x7d = &i; // expected-error {{cannot form pointer to 'decltype(auto)'}}
|
||||
using IntPtr = decltype(x7a);
|
||||
|
||||
struct S {};
|
||||
|
||||
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}}
|
||||
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}}
|
||||
decltype(auto) &f9(); // expected-error {{cannot form reference to 'decltype(auto)'}}
|
||||
decltype(auto) (&f10())[10]; // expected-error {{cannot form array of 'decltype(auto)'}}
|
||||
|
||||
decltype(auto) ((((((v1)))))) = 0; // ok
|
||||
decltype(auto) v2[1] = { 0 }; // expected-error {{cannot form array of 'decltype(auto)'}}
|
||||
decltype(auto) &v3 = { 0 }; // expected-error {{cannot form reference to 'decltype(auto)'}}
|
||||
decltype(auto) *v4 = { 0 }; // expected-error {{cannot form pointer to 'decltype(auto)'}}
|
|
@ -0,0 +1,24 @@
|
|||
// RUN: %clang_cc1 -pedantic -std=c++1y -emit-pch %s -o %t
|
||||
// RUN: %clang_cc1 -pedantic -std=c++1y -include-pch %t -verify %s
|
||||
|
||||
#ifndef HEADER_INCLUDED
|
||||
|
||||
#define HEADER_INCLUDED
|
||||
|
||||
template<typename T> void f(T t) {
|
||||
auto a = t.x;
|
||||
decltype(auto) b = t.x;
|
||||
auto c = (t.x);
|
||||
decltype(auto) d = (t.x);
|
||||
}
|
||||
|
||||
#else
|
||||
|
||||
struct Z {
|
||||
int x : 5; // expected-note {{bit-field}}
|
||||
};
|
||||
|
||||
// expected-error@12 {{non-const reference cannot bind to bit-field 'x'}}
|
||||
template void f(Z); // expected-note {{in instantiation of}}
|
||||
|
||||
#endif
|
|
@ -424,9 +424,13 @@ ISO/IEC JTC1/SC22/WG21 post-Bristol mailing ships.</p>
|
|||
<td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2012/n3472.pdf">N3472</a></td>
|
||||
<td class="full" align="center">Yes</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>decltype(auto)</td>
|
||||
<td rowspan=2><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2013/n3638.html">N3638</a></td>
|
||||
<td class="svn" align="center">SVN</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>Return type deduction for normal functions</td>
|
||||
<td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2013/n3638.html">N3638</a></td>
|
||||
<td class="none" align="center">No</td>
|
||||
</tr>
|
||||
<tr>
|
||||
|
|
Loading…
Reference in New Issue