forked from OSchip/llvm-project
PR21437, final part of DR1330: delay-parsing of exception-specifications. This
is a re-commit of Doug's r154844 (modernized and updated to fit into current Clang). llvm-svn: 221918
This commit is contained in:
parent
cc8d3b8774
commit
0b3a46247e
|
@ -930,6 +930,12 @@ public:
|
|||
/// \brief Change the result type of a function type once it is deduced.
|
||||
void adjustDeducedFunctionResultType(FunctionDecl *FD, QualType ResultType);
|
||||
|
||||
/// \brief Change the exception specification on a function once it is
|
||||
/// delay-parsed, instantiated, or computed.
|
||||
void adjustExceptionSpec(FunctionDecl *FD,
|
||||
const FunctionProtoType::ExceptionSpecInfo &ESI,
|
||||
bool AsWritten = false);
|
||||
|
||||
/// \brief Return the uniqued reference to the type for a complex
|
||||
/// number with the specified element type.
|
||||
QualType getComplexType(QualType T) const;
|
||||
|
|
|
@ -68,6 +68,9 @@ public:
|
|||
|
||||
/// \brief Return the TypeLoc wrapper for the type source info.
|
||||
TypeLoc getTypeLoc() const; // implemented in TypeLoc.h
|
||||
|
||||
/// \brief Override the type stored in this TypeSourceInfo. Use with caution!
|
||||
void overrideType(QualType T) { Ty = T; }
|
||||
};
|
||||
|
||||
/// TranslationUnitDecl - The top declaration context.
|
||||
|
|
|
@ -1245,6 +1245,7 @@ protected:
|
|||
|
||||
class FunctionTypeBitfields {
|
||||
friend class FunctionType;
|
||||
friend class FunctionProtoType;
|
||||
|
||||
unsigned : NumTypeBits;
|
||||
|
||||
|
@ -1259,6 +1260,11 @@ protected:
|
|||
/// C++ 8.3.5p4: The return type, the parameter type list and the
|
||||
/// cv-qualifier-seq, [...], are part of the function type.
|
||||
unsigned TypeQuals : 3;
|
||||
|
||||
/// \brief The ref-qualifier associated with a \c FunctionProtoType.
|
||||
///
|
||||
/// This is a value of type \c RefQualifierKind.
|
||||
unsigned RefQualifier : 2;
|
||||
};
|
||||
|
||||
class ObjCObjectTypeBitfields {
|
||||
|
@ -2765,7 +2771,7 @@ class FunctionType : public Type {
|
|||
|
||||
protected:
|
||||
FunctionType(TypeClass tc, QualType res,
|
||||
unsigned typeQuals, QualType Canonical, bool Dependent,
|
||||
QualType Canonical, bool Dependent,
|
||||
bool InstantiationDependent,
|
||||
bool VariablyModified, bool ContainsUnexpandedParameterPack,
|
||||
ExtInfo Info)
|
||||
|
@ -2773,7 +2779,6 @@ protected:
|
|||
ContainsUnexpandedParameterPack),
|
||||
ResultType(res) {
|
||||
FunctionTypeBits.ExtInfo = Info.Bits;
|
||||
FunctionTypeBits.TypeQuals = typeQuals;
|
||||
}
|
||||
unsigned getTypeQuals() const { return FunctionTypeBits.TypeQuals; }
|
||||
|
||||
|
@ -2810,7 +2815,7 @@ public:
|
|||
/// no information available about its arguments.
|
||||
class FunctionNoProtoType : public FunctionType, public llvm::FoldingSetNode {
|
||||
FunctionNoProtoType(QualType Result, QualType Canonical, ExtInfo Info)
|
||||
: FunctionType(FunctionNoProto, Result, 0, Canonical,
|
||||
: FunctionType(FunctionNoProto, Result, Canonical,
|
||||
/*Dependent=*/false, /*InstantiationDependent=*/false,
|
||||
Result->isVariablyModifiedType(),
|
||||
/*ContainsUnexpandedParameterPack=*/false, Info) {}
|
||||
|
@ -2914,7 +2919,7 @@ private:
|
|||
unsigned NumExceptions : 9;
|
||||
|
||||
/// ExceptionSpecType - The type of exception specification this function has.
|
||||
unsigned ExceptionSpecType : 3;
|
||||
unsigned ExceptionSpecType : 4;
|
||||
|
||||
/// HasAnyConsumedParams - Whether this function has any consumed parameters.
|
||||
unsigned HasAnyConsumedParams : 1;
|
||||
|
@ -2925,11 +2930,6 @@ private:
|
|||
/// HasTrailingReturn - Whether this function has a trailing return type.
|
||||
unsigned HasTrailingReturn : 1;
|
||||
|
||||
/// \brief The ref-qualifier associated with a \c FunctionProtoType.
|
||||
///
|
||||
/// This is a value of type \c RefQualifierKind.
|
||||
unsigned RefQualifier : 2;
|
||||
|
||||
// ParamInfo - There is an variable size array after the class in memory that
|
||||
// holds the parameter types.
|
||||
|
||||
|
@ -3076,7 +3076,7 @@ public:
|
|||
|
||||
/// \brief Retrieve the ref-qualifier associated with this function type.
|
||||
RefQualifierKind getRefQualifier() const {
|
||||
return static_cast<RefQualifierKind>(RefQualifier);
|
||||
return static_cast<RefQualifierKind>(FunctionTypeBits.RefQualifier);
|
||||
}
|
||||
|
||||
typedef const QualType *param_type_iterator;
|
||||
|
|
|
@ -496,6 +496,8 @@ def ext_ellipsis_exception_spec : Extension<
|
|||
InGroup<Microsoft>;
|
||||
def err_dynamic_and_noexcept_specification : Error<
|
||||
"cannot have both throw() and noexcept() clause on the same function">;
|
||||
def err_except_spec_unparsed : Error<
|
||||
"unexpected end of exception specification">;
|
||||
def warn_cxx98_compat_noexcept_decl : Warning<
|
||||
"noexcept specifications are incompatible with C++98">,
|
||||
InGroup<CXX98Compat>, DefaultIgnore;
|
||||
|
|
|
@ -1117,6 +1117,8 @@ def warn_missing_exception_specification : Warning<
|
|||
"%0 is missing exception specification '%1'">;
|
||||
def err_noexcept_needs_constant_expression : Error<
|
||||
"argument to noexcept specifier must be a constant expression">;
|
||||
def err_exception_spec_not_parsed : Error<
|
||||
"exception specification is not available until end of class definition">;
|
||||
|
||||
// C++ access checking
|
||||
def err_class_redeclared_with_different_access : Error<
|
||||
|
|
|
@ -26,7 +26,8 @@ enum ExceptionSpecificationType {
|
|||
EST_BasicNoexcept, ///< noexcept
|
||||
EST_ComputedNoexcept, ///< noexcept(expression)
|
||||
EST_Unevaluated, ///< not evaluated yet, for special member function
|
||||
EST_Uninstantiated ///< not instantiated yet
|
||||
EST_Uninstantiated, ///< not instantiated yet
|
||||
EST_Unparsed ///< not parsed yet
|
||||
};
|
||||
|
||||
inline bool isDynamicExceptionSpec(ExceptionSpecificationType ESpecType) {
|
||||
|
|
|
@ -117,6 +117,7 @@ TOK(eod) // End of preprocessing directive (end of line inside a
|
|||
// directive).
|
||||
TOK(code_completion) // Code completion marker
|
||||
TOK(cxx_defaultarg_end) // C++ default argument end marker
|
||||
TOK(cxx_exceptspec_end) // C++ exception-specification end marker
|
||||
|
||||
// C99 6.4.9: Comments.
|
||||
TOK(comment) // Comment (only in -E -C[C] mode)
|
||||
|
|
|
@ -1453,10 +1453,12 @@ private:
|
|||
ExprResult ParseThrowExpression();
|
||||
|
||||
ExceptionSpecificationType tryParseExceptionSpecification(
|
||||
bool Delayed,
|
||||
SourceRange &SpecificationRange,
|
||||
SmallVectorImpl<ParsedType> &DynamicExceptions,
|
||||
SmallVectorImpl<SourceRange> &DynamicExceptionRanges,
|
||||
ExprResult &NoexceptExpr);
|
||||
ExprResult &NoexceptExpr,
|
||||
CachedTokens *&ExceptionSpecTokens);
|
||||
|
||||
// EndLoc is filled with the location of the last token of the specification.
|
||||
ExceptionSpecificationType ParseDynamicExceptionSpecification(
|
||||
|
|
|
@ -1176,7 +1176,7 @@ struct DeclaratorChunk {
|
|||
unsigned TypeQuals : 3;
|
||||
|
||||
/// ExceptionSpecType - An ExceptionSpecificationType value.
|
||||
unsigned ExceptionSpecType : 3;
|
||||
unsigned ExceptionSpecType : 4;
|
||||
|
||||
/// DeleteParams - If this is true, we need to delete[] Params.
|
||||
unsigned DeleteParams : 1;
|
||||
|
@ -1243,6 +1243,10 @@ struct DeclaratorChunk {
|
|||
/// \brief Pointer to the expression in the noexcept-specifier of this
|
||||
/// function, if it has one.
|
||||
Expr *NoexceptExpr;
|
||||
|
||||
/// \brief Pointer to the cached tokens for an exception-specification
|
||||
/// that has not yet been parsed.
|
||||
CachedTokens *ExceptionSpecTokens;
|
||||
};
|
||||
|
||||
/// \brief If HasTrailingReturnType is true, this is the trailing return
|
||||
|
@ -1269,6 +1273,8 @@ struct DeclaratorChunk {
|
|||
delete[] Params;
|
||||
if (getExceptionSpecType() == EST_Dynamic)
|
||||
delete[] Exceptions;
|
||||
else if (getExceptionSpecType() == EST_Unparsed)
|
||||
delete ExceptionSpecTokens;
|
||||
}
|
||||
|
||||
/// isKNRPrototype - Return true if this is a K&R style identifier list,
|
||||
|
@ -1464,6 +1470,7 @@ struct DeclaratorChunk {
|
|||
SourceRange *ExceptionRanges,
|
||||
unsigned NumExceptions,
|
||||
Expr *NoexceptExpr,
|
||||
CachedTokens *ExceptionSpecTokens,
|
||||
SourceLocation LocalRangeBegin,
|
||||
SourceLocation LocalRangeEnd,
|
||||
Declarator &TheDeclarator,
|
||||
|
|
|
@ -4106,6 +4106,16 @@ public:
|
|||
SmallVectorImpl<QualType> &Exceptions,
|
||||
FunctionProtoType::ExceptionSpecInfo &ESI);
|
||||
|
||||
/// \brief Add an exception-specification to the given member function
|
||||
/// (or member function template). The exception-specification was parsed
|
||||
/// after the method itself was declared.
|
||||
void actOnDelayedExceptionSpecification(Decl *Method,
|
||||
ExceptionSpecificationType EST,
|
||||
SourceRange SpecificationRange,
|
||||
ArrayRef<ParsedType> DynamicExceptions,
|
||||
ArrayRef<SourceRange> DynamicExceptionRanges,
|
||||
Expr *NoexceptExpr);
|
||||
|
||||
/// \brief Determine if a special member function should have a deleted
|
||||
/// definition when it is defaulted.
|
||||
bool ShouldDeleteSpecialMember(CXXMethodDecl *MD, CXXSpecialMember CSM,
|
||||
|
|
|
@ -2111,6 +2111,62 @@ void ASTContext::adjustDeducedFunctionResultType(FunctionDecl *FD,
|
|||
L->DeducedReturnType(FD, ResultType);
|
||||
}
|
||||
|
||||
/// Get a function type and produce the equivalent function type with the
|
||||
/// specified exception specification. Type sugar that can be present on a
|
||||
/// declaration of a function with an exception specification is permitted
|
||||
/// and preserved. Other type sugar (for instance, typedefs) is not.
|
||||
static QualType getFunctionTypeWithExceptionSpec(
|
||||
ASTContext &Context, QualType Orig,
|
||||
const FunctionProtoType::ExceptionSpecInfo &ESI) {
|
||||
// Might have some parens.
|
||||
if (auto *PT = dyn_cast<ParenType>(Orig))
|
||||
return Context.getParenType(
|
||||
getFunctionTypeWithExceptionSpec(Context, PT->getInnerType(), ESI));
|
||||
|
||||
// Might have a calling-convention attribute.
|
||||
if (auto *AT = dyn_cast<AttributedType>(Orig))
|
||||
return Context.getAttributedType(
|
||||
AT->getAttrKind(),
|
||||
getFunctionTypeWithExceptionSpec(Context, AT->getModifiedType(), ESI),
|
||||
getFunctionTypeWithExceptionSpec(Context, AT->getEquivalentType(),
|
||||
ESI));
|
||||
|
||||
// Anything else must be a function type. Rebuild it with the new exception
|
||||
// specification.
|
||||
const FunctionProtoType *Proto = cast<FunctionProtoType>(Orig);
|
||||
return Context.getFunctionType(
|
||||
Proto->getReturnType(), Proto->getParamTypes(),
|
||||
Proto->getExtProtoInfo().withExceptionSpec(ESI));
|
||||
}
|
||||
|
||||
void ASTContext::adjustExceptionSpec(
|
||||
FunctionDecl *FD, const FunctionProtoType::ExceptionSpecInfo &ESI,
|
||||
bool AsWritten) {
|
||||
// Update the type.
|
||||
QualType Updated =
|
||||
getFunctionTypeWithExceptionSpec(*this, FD->getType(), ESI);
|
||||
FD->setType(Updated);
|
||||
|
||||
if (!AsWritten)
|
||||
return;
|
||||
|
||||
// Update the type in the type source information too.
|
||||
if (TypeSourceInfo *TSInfo = FD->getTypeSourceInfo()) {
|
||||
// If the type and the type-as-written differ, we may need to update
|
||||
// the type-as-written too.
|
||||
if (TSInfo->getType() != FD->getType())
|
||||
Updated = getFunctionTypeWithExceptionSpec(*this, TSInfo->getType(), ESI);
|
||||
|
||||
// FIXME: When we get proper type location information for exceptions,
|
||||
// we'll also have to rebuild the TypeSourceInfo. For now, we just patch
|
||||
// up the TypeSourceInfo;
|
||||
assert(TypeLoc::getFullDataSizeForType(Updated) ==
|
||||
TypeLoc::getFullDataSizeForType(TSInfo->getType()) &&
|
||||
"TypeLoc size mismatch from updating exception specification");
|
||||
TSInfo->overrideType(Updated);
|
||||
}
|
||||
}
|
||||
|
||||
/// getComplexType - Return the uniqued reference to the type for a complex
|
||||
/// number with the specified element type.
|
||||
QualType ASTContext::getComplexType(QualType T) const {
|
||||
|
|
|
@ -1593,7 +1593,7 @@ StringRef FunctionType::getNameForCallConv(CallingConv CC) {
|
|||
FunctionProtoType::FunctionProtoType(QualType result, ArrayRef<QualType> params,
|
||||
QualType canonical,
|
||||
const ExtProtoInfo &epi)
|
||||
: FunctionType(FunctionProto, result, epi.TypeQuals, canonical,
|
||||
: FunctionType(FunctionProto, result, canonical,
|
||||
result->isDependentType(),
|
||||
result->isInstantiationDependentType(),
|
||||
result->isVariablyModifiedType(),
|
||||
|
@ -1602,10 +1602,12 @@ FunctionProtoType::FunctionProtoType(QualType result, ArrayRef<QualType> params,
|
|||
NumExceptions(epi.ExceptionSpec.Exceptions.size()),
|
||||
ExceptionSpecType(epi.ExceptionSpec.Type),
|
||||
HasAnyConsumedParams(epi.ConsumedParameters != nullptr),
|
||||
Variadic(epi.Variadic), HasTrailingReturn(epi.HasTrailingReturn),
|
||||
RefQualifier(epi.RefQualifier) {
|
||||
Variadic(epi.Variadic), HasTrailingReturn(epi.HasTrailingReturn) {
|
||||
assert(NumParams == params.size() && "function has too many parameters");
|
||||
|
||||
FunctionTypeBits.TypeQuals = epi.TypeQuals;
|
||||
FunctionTypeBits.RefQualifier = epi.RefQualifier;
|
||||
|
||||
// Fill in the trailing argument array.
|
||||
QualType *argSlot = reinterpret_cast<QualType*>(this+1);
|
||||
for (unsigned i = 0; i != NumParams; ++i) {
|
||||
|
@ -1772,7 +1774,7 @@ void FunctionProtoType::Profile(llvm::FoldingSetNodeID &ID, QualType Result,
|
|||
assert(!(unsigned(epi.Variadic) & ~1) &&
|
||||
!(unsigned(epi.TypeQuals) & ~255) &&
|
||||
!(unsigned(epi.RefQualifier) & ~3) &&
|
||||
!(unsigned(epi.ExceptionSpec.Type) & ~7) &&
|
||||
!(unsigned(epi.ExceptionSpec.Type) & ~15) &&
|
||||
"Values larger than expected.");
|
||||
ID.AddInteger(unsigned(epi.Variadic) +
|
||||
(epi.TypeQuals << 1) +
|
||||
|
|
|
@ -366,6 +366,76 @@ void Parser::ParseLexedMethodDeclaration(LateParsedMethodDeclaration &LM) {
|
|||
}
|
||||
}
|
||||
|
||||
// Parse a delayed exception-specification, if there is one.
|
||||
if (CachedTokens *Toks = LM.ExceptionSpecTokens) {
|
||||
// Save the current token position.
|
||||
SourceLocation origLoc = Tok.getLocation();
|
||||
|
||||
// Parse the default argument from its saved token stream.
|
||||
Toks->push_back(Tok); // So that the current token doesn't get lost
|
||||
PP.EnterTokenStream(&Toks->front(), Toks->size(), true, false);
|
||||
|
||||
// Consume the previously-pushed token.
|
||||
ConsumeAnyToken();
|
||||
|
||||
// C++11 [expr.prim.general]p3:
|
||||
// If a declaration declares a member function or member function
|
||||
// template of a class X, the expression this is a prvalue of type
|
||||
// "pointer to cv-qualifier-seq X" between the optional cv-qualifer-seq
|
||||
// and the end of the function-definition, member-declarator, or
|
||||
// declarator.
|
||||
CXXMethodDecl *Method;
|
||||
if (FunctionTemplateDecl *FunTmpl
|
||||
= dyn_cast<FunctionTemplateDecl>(LM.Method))
|
||||
Method = cast<CXXMethodDecl>(FunTmpl->getTemplatedDecl());
|
||||
else
|
||||
Method = cast<CXXMethodDecl>(LM.Method);
|
||||
|
||||
Sema::CXXThisScopeRAII ThisScope(Actions, Method->getParent(),
|
||||
Method->getTypeQualifiers(),
|
||||
getLangOpts().CPlusPlus11);
|
||||
|
||||
// Parse the exception-specification.
|
||||
SourceRange SpecificationRange;
|
||||
SmallVector<ParsedType, 4> DynamicExceptions;
|
||||
SmallVector<SourceRange, 4> DynamicExceptionRanges;
|
||||
ExprResult NoexceptExpr;
|
||||
CachedTokens *ExceptionSpecTokens;
|
||||
|
||||
ExceptionSpecificationType EST
|
||||
= tryParseExceptionSpecification(/*Delayed=*/false, SpecificationRange,
|
||||
DynamicExceptions,
|
||||
DynamicExceptionRanges, NoexceptExpr,
|
||||
ExceptionSpecTokens);
|
||||
|
||||
// Clean up the remaining tokens.
|
||||
if (Tok.is(tok::cxx_exceptspec_end))
|
||||
ConsumeToken();
|
||||
else if (EST != EST_None)
|
||||
Diag(Tok.getLocation(), diag::err_except_spec_unparsed);
|
||||
|
||||
// Attach the exception-specification to the method.
|
||||
if (EST != EST_None)
|
||||
Actions.actOnDelayedExceptionSpecification(LM.Method, EST,
|
||||
SpecificationRange,
|
||||
DynamicExceptions,
|
||||
DynamicExceptionRanges,
|
||||
NoexceptExpr.isUsable()?
|
||||
NoexceptExpr.get() : nullptr);
|
||||
|
||||
assert(!PP.getSourceManager().isBeforeInTranslationUnit(origLoc,
|
||||
Tok.getLocation()) &&
|
||||
"tryParseExceptionSpecification went over the exception tokens!");
|
||||
|
||||
// There could be leftover tokens (e.g. because of an error).
|
||||
// Skip through until we reach the original token position.
|
||||
while (Tok.getLocation() != origLoc && Tok.isNot(tok::eof))
|
||||
ConsumeAnyToken();
|
||||
|
||||
delete Toks;
|
||||
LM.ExceptionSpecTokens = nullptr;
|
||||
}
|
||||
|
||||
PrototypeScope.Exit();
|
||||
|
||||
// Finish the delayed C++ method declaration.
|
||||
|
|
|
@ -5193,6 +5193,7 @@ void Parser::ParseFunctionDeclarator(Declarator &D,
|
|||
SmallVector<ParsedType, 2> DynamicExceptions;
|
||||
SmallVector<SourceRange, 2> DynamicExceptionRanges;
|
||||
ExprResult NoexceptExpr;
|
||||
CachedTokens *ExceptionSpecTokens = 0;
|
||||
ParsedAttributes FnAttrs(AttrFactory);
|
||||
TypeResult TrailingReturnType;
|
||||
|
||||
|
@ -5279,10 +5280,14 @@ void Parser::ParseFunctionDeclarator(Declarator &D,
|
|||
IsCXX11MemberFunction);
|
||||
|
||||
// Parse exception-specification[opt].
|
||||
ESpecType = tryParseExceptionSpecification(ESpecRange,
|
||||
bool Delayed = D.isFirstDeclarationOfMember() &&
|
||||
D.isFunctionDeclaratorAFunctionDeclaration();
|
||||
ESpecType = tryParseExceptionSpecification(Delayed,
|
||||
ESpecRange,
|
||||
DynamicExceptions,
|
||||
DynamicExceptionRanges,
|
||||
NoexceptExpr);
|
||||
NoexceptExpr,
|
||||
ExceptionSpecTokens);
|
||||
if (ESpecType != EST_None)
|
||||
EndLoc = ESpecRange.getEnd();
|
||||
|
||||
|
@ -5322,6 +5327,7 @@ void Parser::ParseFunctionDeclarator(Declarator &D,
|
|||
DynamicExceptions.size(),
|
||||
NoexceptExpr.isUsable() ?
|
||||
NoexceptExpr.get() : nullptr,
|
||||
ExceptionSpecTokens,
|
||||
StartLoc, LocalEndLoc, D,
|
||||
TrailingReturnType),
|
||||
FnAttrs, EndLoc);
|
||||
|
|
|
@ -1875,16 +1875,34 @@ AccessSpecifier Parser::getAccessSpecifierIfPresent() const {
|
|||
}
|
||||
|
||||
/// \brief If the given declarator has any parts for which parsing has to be
|
||||
/// delayed, e.g., default arguments, create a late-parsed method declaration
|
||||
/// record to handle the parsing at the end of the class definition.
|
||||
/// delayed, e.g., default arguments or an exception-specification, create a
|
||||
/// late-parsed method declaration record to handle the parsing at the end of
|
||||
/// the class definition.
|
||||
void Parser::HandleMemberFunctionDeclDelays(Declarator& DeclaratorInfo,
|
||||
Decl *ThisDecl) {
|
||||
// We just declared a member function. If this member function
|
||||
// has any default arguments, we'll need to parse them later.
|
||||
// has any default arguments or an exception-specification, we'll need to
|
||||
// parse them later.
|
||||
LateParsedMethodDeclaration *LateMethod = nullptr;
|
||||
DeclaratorChunk::FunctionTypeInfo &FTI
|
||||
= DeclaratorInfo.getFunctionTypeInfo();
|
||||
|
||||
// If there was a late-parsed exception-specification, hold onto its tokens.
|
||||
if (FTI.getExceptionSpecType() == EST_Unparsed) {
|
||||
// Push this method onto the stack of late-parsed method
|
||||
// declarations.
|
||||
LateMethod = new LateParsedMethodDeclaration(this, ThisDecl);
|
||||
getCurrentClass().LateParsedDeclarations.push_back(LateMethod);
|
||||
LateMethod->TemplateScope = getCurScope()->isTemplateParamScope();
|
||||
|
||||
// Stash the exception-specification tokens in the late-pased mthod.
|
||||
LateMethod->ExceptionSpecTokens = FTI.ExceptionSpecTokens;
|
||||
FTI.ExceptionSpecTokens = 0;
|
||||
|
||||
// Reserve space for the parameters.
|
||||
LateMethod->DefaultArgs.reserve(FTI.NumParams);
|
||||
}
|
||||
|
||||
for (unsigned ParamIdx = 0; ParamIdx < FTI.NumParams; ++ParamIdx) {
|
||||
if (LateMethod || FTI.Params[ParamIdx].DefaultArgTokens) {
|
||||
if (!LateMethod) {
|
||||
|
@ -2857,7 +2875,7 @@ void Parser::ParseCXXMemberSpecification(SourceLocation RecordLoc,
|
|||
|
||||
// C++11 [class.mem]p2:
|
||||
// Within the class member-specification, the class is regarded as complete
|
||||
// within function bodies, default arguments, and
|
||||
// within function bodies, default arguments, exception-specifications, and
|
||||
// brace-or-equal-initializers for non-static data members (including such
|
||||
// things in nested classes).
|
||||
if (TagDecl && NonNestedClass) {
|
||||
|
@ -3076,13 +3094,63 @@ MemInitResult Parser::ParseMemInitializer(Decl *ConstructorDecl) {
|
|||
/// 'noexcept'
|
||||
/// 'noexcept' '(' constant-expression ')'
|
||||
ExceptionSpecificationType
|
||||
Parser::tryParseExceptionSpecification(
|
||||
Parser::tryParseExceptionSpecification(bool Delayed,
|
||||
SourceRange &SpecificationRange,
|
||||
SmallVectorImpl<ParsedType> &DynamicExceptions,
|
||||
SmallVectorImpl<SourceRange> &DynamicExceptionRanges,
|
||||
ExprResult &NoexceptExpr) {
|
||||
ExprResult &NoexceptExpr,
|
||||
CachedTokens *&ExceptionSpecTokens) {
|
||||
ExceptionSpecificationType Result = EST_None;
|
||||
ExceptionSpecTokens = 0;
|
||||
|
||||
// Handle delayed parsing of exception-specifications.
|
||||
if (Delayed) {
|
||||
if (Tok.isNot(tok::kw_throw) && Tok.isNot(tok::kw_noexcept))
|
||||
return EST_None;
|
||||
|
||||
// Consume and cache the starting token.
|
||||
bool IsNoexcept = Tok.is(tok::kw_noexcept);
|
||||
Token StartTok = Tok;
|
||||
SpecificationRange = SourceRange(ConsumeToken());
|
||||
|
||||
// Check for a '('.
|
||||
if (!Tok.is(tok::l_paren)) {
|
||||
// If this is a bare 'noexcept', we're done.
|
||||
if (IsNoexcept) {
|
||||
Diag(Tok, diag::warn_cxx98_compat_noexcept_decl);
|
||||
NoexceptExpr = 0;
|
||||
return EST_BasicNoexcept;
|
||||
}
|
||||
|
||||
Diag(Tok, diag::err_expected_lparen_after) << "throw";
|
||||
return EST_DynamicNone;
|
||||
}
|
||||
|
||||
// Cache the tokens for the exception-specification.
|
||||
ExceptionSpecTokens = new CachedTokens;
|
||||
ExceptionSpecTokens->push_back(StartTok); // 'throw' or 'noexcept'
|
||||
ExceptionSpecTokens->push_back(Tok); // '('
|
||||
SpecificationRange.setEnd(ConsumeParen()); // '('
|
||||
|
||||
if (!ConsumeAndStoreUntil(tok::r_paren, *ExceptionSpecTokens,
|
||||
/*StopAtSemi=*/true,
|
||||
/*ConsumeFinalToken=*/true)) {
|
||||
NoexceptExpr = 0;
|
||||
delete ExceptionSpecTokens;
|
||||
ExceptionSpecTokens = 0;
|
||||
return IsNoexcept? EST_BasicNoexcept : EST_DynamicNone;
|
||||
}
|
||||
SpecificationRange.setEnd(Tok.getLocation());
|
||||
|
||||
// Add the 'stop' token.
|
||||
Token End;
|
||||
End.startToken();
|
||||
End.setKind(tok::cxx_exceptspec_end);
|
||||
End.setLocation(Tok.getLocation());
|
||||
ExceptionSpecTokens->push_back(End);
|
||||
return EST_Unparsed;
|
||||
}
|
||||
|
||||
// See if there's a dynamic specification.
|
||||
if (Tok.is(tok::kw_throw)) {
|
||||
Result = ParseDynamicExceptionSpecification(SpecificationRange,
|
||||
|
|
|
@ -2642,6 +2642,7 @@ ExprResult Parser::ParseBlockLiteralExpression() {
|
|||
/*ExceptionRanges=*/nullptr,
|
||||
/*NumExceptions=*/0,
|
||||
/*NoexceptExpr=*/nullptr,
|
||||
/*ExceptionSpecTokens=*/nullptr,
|
||||
CaretLoc, CaretLoc,
|
||||
ParamInfo),
|
||||
attrs, CaretLoc);
|
||||
|
|
|
@ -1061,10 +1061,13 @@ ExprResult Parser::ParseLambdaExpressionAfterIntroducer(
|
|||
SmallVector<ParsedType, 2> DynamicExceptions;
|
||||
SmallVector<SourceRange, 2> DynamicExceptionRanges;
|
||||
ExprResult NoexceptExpr;
|
||||
ESpecType = tryParseExceptionSpecification(ESpecRange,
|
||||
CachedTokens *ExceptionSpecTokens;
|
||||
ESpecType = tryParseExceptionSpecification(/*Delayed=*/false,
|
||||
ESpecRange,
|
||||
DynamicExceptions,
|
||||
DynamicExceptionRanges,
|
||||
NoexceptExpr);
|
||||
NoexceptExpr,
|
||||
ExceptionSpecTokens);
|
||||
|
||||
if (ESpecType != EST_None)
|
||||
DeclEndLoc = ESpecRange.getEnd();
|
||||
|
@ -1105,6 +1108,7 @@ ExprResult Parser::ParseLambdaExpressionAfterIntroducer(
|
|||
DynamicExceptions.size(),
|
||||
NoexceptExpr.isUsable() ?
|
||||
NoexceptExpr.get() : nullptr,
|
||||
/*ExceptionSpecTokens*/nullptr,
|
||||
LParenLoc, FunLocalRangeEnd, D,
|
||||
TrailingReturnType),
|
||||
Attr, DeclEndLoc);
|
||||
|
@ -1173,6 +1177,7 @@ ExprResult Parser::ParseLambdaExpressionAfterIntroducer(
|
|||
/*ExceptionRanges=*/nullptr,
|
||||
/*NumExceptions=*/0,
|
||||
/*NoexceptExpr=*/nullptr,
|
||||
/*ExceptionSpecTokens=*/nullptr,
|
||||
DeclLoc, DeclEndLoc, D,
|
||||
TrailingReturnType),
|
||||
Attr, DeclEndLoc);
|
||||
|
|
|
@ -182,6 +182,7 @@ DeclaratorChunk DeclaratorChunk::getFunction(bool hasProto,
|
|||
SourceRange *ExceptionRanges,
|
||||
unsigned NumExceptions,
|
||||
Expr *NoexceptExpr,
|
||||
CachedTokens *ExceptionSpecTokens,
|
||||
SourceLocation LocalRangeBegin,
|
||||
SourceLocation LocalRangeEnd,
|
||||
Declarator &TheDeclarator,
|
||||
|
@ -219,6 +220,9 @@ DeclaratorChunk DeclaratorChunk::getFunction(bool hasProto,
|
|||
TrailingReturnType.isInvalid();
|
||||
I.Fun.TrailingReturnType = TrailingReturnType.get();
|
||||
|
||||
assert(I.Fun.TypeQuals == TypeQuals && "bitfield overflow");
|
||||
assert(I.Fun.ExceptionSpecType == ESpecType && "bitfield overflow");
|
||||
|
||||
// new[] a parameter array if needed.
|
||||
if (NumParams) {
|
||||
// If the 'InlineParams' in Declarator is unused and big enough, put our
|
||||
|
@ -255,6 +259,10 @@ DeclaratorChunk DeclaratorChunk::getFunction(bool hasProto,
|
|||
case EST_ComputedNoexcept:
|
||||
I.Fun.NoexceptExpr = NoexceptExpr;
|
||||
break;
|
||||
|
||||
case EST_Unparsed:
|
||||
I.Fun.ExceptionSpecTokens = ExceptionSpecTokens;
|
||||
break;
|
||||
}
|
||||
return I;
|
||||
}
|
||||
|
|
|
@ -10682,6 +10682,7 @@ NamedDecl *Sema::ImplicitlyDefineFunction(SourceLocation Loc,
|
|||
/*ExceptionRanges=*/nullptr,
|
||||
/*NumExceptions=*/0,
|
||||
/*NoexceptExpr=*/nullptr,
|
||||
/*ExceptionSpecTokens=*/nullptr,
|
||||
Loc, Loc, D),
|
||||
DS.getAttributes(),
|
||||
SourceLocation());
|
||||
|
|
|
@ -5286,6 +5286,12 @@ void Sema::CheckExplicitlyDefaultedSpecialMember(CXXMethodDecl *MD) {
|
|||
/// C++11 [dcl.fct.def.default]p2.
|
||||
void Sema::CheckExplicitlyDefaultedMemberExceptionSpec(
|
||||
CXXMethodDecl *MD, const FunctionProtoType *SpecifiedType) {
|
||||
// If the exception specification was explicitly specified but hadn't been
|
||||
// parsed when the method was defaulted, grab it now.
|
||||
if (SpecifiedType->getExceptionSpecType() == EST_Unparsed)
|
||||
SpecifiedType =
|
||||
MD->getTypeSourceInfo()->getType()->castAs<FunctionProtoType>();
|
||||
|
||||
// Compute the implicit exception specification.
|
||||
CallingConv CC = Context.getDefaultCallingConvention(/*IsVariadic=*/false,
|
||||
/*IsCXXMethod=*/true);
|
||||
|
@ -13245,6 +13251,7 @@ bool Sema::checkThisInStaticMemberFunctionExceptionSpec(CXXMethodDecl *Method) {
|
|||
FindCXXThisExpr Finder(*this);
|
||||
|
||||
switch (Proto->getExceptionSpecType()) {
|
||||
case EST_Unparsed:
|
||||
case EST_Uninstantiated:
|
||||
case EST_Unevaluated:
|
||||
case EST_BasicNoexcept:
|
||||
|
@ -13372,6 +13379,45 @@ void Sema::checkExceptionSpecification(
|
|||
}
|
||||
}
|
||||
|
||||
void Sema::actOnDelayedExceptionSpecification(Decl *MethodD,
|
||||
ExceptionSpecificationType EST,
|
||||
SourceRange SpecificationRange,
|
||||
ArrayRef<ParsedType> DynamicExceptions,
|
||||
ArrayRef<SourceRange> DynamicExceptionRanges,
|
||||
Expr *NoexceptExpr) {
|
||||
if (!MethodD)
|
||||
return;
|
||||
|
||||
// Dig out the method we're referring to.
|
||||
if (FunctionTemplateDecl *FunTmpl = dyn_cast<FunctionTemplateDecl>(MethodD))
|
||||
MethodD = FunTmpl->getTemplatedDecl();
|
||||
|
||||
CXXMethodDecl *Method = dyn_cast<CXXMethodDecl>(MethodD);
|
||||
if (!Method)
|
||||
return;
|
||||
|
||||
// Check the exception specification.
|
||||
llvm::SmallVector<QualType, 4> Exceptions;
|
||||
FunctionProtoType::ExceptionSpecInfo ESI;
|
||||
checkExceptionSpecification(/*IsTopLevel*/true, EST, DynamicExceptions,
|
||||
DynamicExceptionRanges, NoexceptExpr, Exceptions,
|
||||
ESI);
|
||||
|
||||
// Update the exception specification on the function type.
|
||||
Context.adjustExceptionSpec(Method, ESI, /*AsWritten*/true);
|
||||
|
||||
if (Method->isStatic())
|
||||
checkThisInStaticMemberFunctionExceptionSpec(Method);
|
||||
|
||||
if (Method->isVirtual()) {
|
||||
// Check overrides, which we previously had to delay.
|
||||
for (CXXMethodDecl::method_iterator O = Method->begin_overridden_methods(),
|
||||
OEnd = Method->end_overridden_methods();
|
||||
O != OEnd; ++O)
|
||||
CheckOverridingFunctionExceptionSpec(Method, *O);
|
||||
}
|
||||
}
|
||||
|
||||
/// HandleMSProperty - Analyze a __delcspec(property) field of a C++ class.
|
||||
///
|
||||
MSPropertyDecl *Sema::HandleMSProperty(Scope *S, RecordDecl *Record,
|
||||
|
|
|
@ -112,6 +112,11 @@ bool Sema::CheckDistantExceptionSpec(QualType T) {
|
|||
|
||||
const FunctionProtoType *
|
||||
Sema::ResolveExceptionSpec(SourceLocation Loc, const FunctionProtoType *FPT) {
|
||||
if (FPT->getExceptionSpecType() == EST_Unparsed) {
|
||||
Diag(Loc, diag::err_exception_spec_not_parsed);
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
if (!isUnresolvedExceptionSpec(FPT->getExceptionSpecType()))
|
||||
return FPT;
|
||||
|
||||
|
@ -135,16 +140,8 @@ Sema::ResolveExceptionSpec(SourceLocation Loc, const FunctionProtoType *FPT) {
|
|||
void
|
||||
Sema::UpdateExceptionSpec(FunctionDecl *FD,
|
||||
const FunctionProtoType::ExceptionSpecInfo &ESI) {
|
||||
for (auto *Redecl : FD->redecls()) {
|
||||
auto *RedeclFD = dyn_cast<FunctionDecl>(Redecl);
|
||||
const FunctionProtoType *Proto =
|
||||
RedeclFD->getType()->castAs<FunctionProtoType>();
|
||||
|
||||
// Overwrite the exception spec and rebuild the function type.
|
||||
RedeclFD->setType(Context.getFunctionType(
|
||||
Proto->getReturnType(), Proto->getParamTypes(),
|
||||
Proto->getExtProtoInfo().withExceptionSpec(ESI)));
|
||||
}
|
||||
for (auto *Redecl : FD->redecls())
|
||||
Context.adjustExceptionSpec(cast<FunctionDecl>(Redecl), ESI);
|
||||
|
||||
// If we've fully resolved the exception specification, notify listeners.
|
||||
if (!isUnresolvedExceptionSpec(ESI.Type))
|
||||
|
@ -790,6 +787,11 @@ bool Sema::CheckOverridingFunctionExceptionSpec(const CXXMethodDecl *New,
|
|||
return false;
|
||||
}
|
||||
}
|
||||
// If the exception specification hasn't been parsed yet, skip the check.
|
||||
// We'll get called again once it's been parsed.
|
||||
if (New->getType()->castAs<FunctionProtoType>()->getExceptionSpecType() ==
|
||||
EST_Unparsed)
|
||||
return false;
|
||||
unsigned DiagID = diag::err_override_exception_spec;
|
||||
if (getLangOpts().MicrosoftExt)
|
||||
DiagID = diag::ext_override_exception_spec;
|
||||
|
|
|
@ -661,27 +661,27 @@ static void maybeSynthesizeBlockSignature(TypeProcessingState &state,
|
|||
// ...and *prepend* it to the declarator.
|
||||
SourceLocation NoLoc;
|
||||
declarator.AddInnermostTypeInfo(DeclaratorChunk::getFunction(
|
||||
/*HasProto=*/true,
|
||||
/*IsAmbiguous=*/false,
|
||||
/*LParenLoc=*/NoLoc,
|
||||
/*ArgInfo=*/nullptr,
|
||||
/*NumArgs=*/0,
|
||||
/*EllipsisLoc=*/NoLoc,
|
||||
/*RParenLoc=*/NoLoc,
|
||||
/*TypeQuals=*/0,
|
||||
/*RefQualifierIsLvalueRef=*/true,
|
||||
/*RefQualifierLoc=*/NoLoc,
|
||||
/*ConstQualifierLoc=*/NoLoc,
|
||||
/*VolatileQualifierLoc=*/NoLoc,
|
||||
/*RestrictQualifierLoc=*/NoLoc,
|
||||
/*MutableLoc=*/NoLoc,
|
||||
EST_None,
|
||||
/*ESpecLoc=*/NoLoc,
|
||||
/*Exceptions=*/nullptr,
|
||||
/*ExceptionRanges=*/nullptr,
|
||||
/*NumExceptions=*/0,
|
||||
/*NoexceptExpr=*/nullptr,
|
||||
loc, loc, declarator));
|
||||
/*HasProto=*/true,
|
||||
/*IsAmbiguous=*/false,
|
||||
/*LParenLoc=*/NoLoc,
|
||||
/*ArgInfo=*/nullptr,
|
||||
/*NumArgs=*/0,
|
||||
/*EllipsisLoc=*/NoLoc,
|
||||
/*RParenLoc=*/NoLoc,
|
||||
/*TypeQuals=*/0,
|
||||
/*RefQualifierIsLvalueRef=*/true,
|
||||
/*RefQualifierLoc=*/NoLoc,
|
||||
/*ConstQualifierLoc=*/NoLoc,
|
||||
/*VolatileQualifierLoc=*/NoLoc,
|
||||
/*RestrictQualifierLoc=*/NoLoc,
|
||||
/*MutableLoc=*/NoLoc, EST_None,
|
||||
/*ESpecLoc=*/NoLoc,
|
||||
/*Exceptions=*/nullptr,
|
||||
/*ExceptionRanges=*/nullptr,
|
||||
/*NumExceptions=*/0,
|
||||
/*NoexceptExpr=*/nullptr,
|
||||
/*ExceptionSpecTokens=*/nullptr,
|
||||
loc, loc, declarator));
|
||||
|
||||
// For consistency, make sure the state still has us as processing
|
||||
// the decl spec.
|
||||
|
|
|
@ -2782,10 +2782,8 @@ void ASTDeclReader::attachPreviousDeclImpl(ASTReader &Reader,
|
|||
if (FPT && PrevFPT &&
|
||||
isUnresolvedExceptionSpec(FPT->getExceptionSpecType()) &&
|
||||
!isUnresolvedExceptionSpec(PrevFPT->getExceptionSpecType())) {
|
||||
FunctionProtoType::ExtProtoInfo EPI = PrevFPT->getExtProtoInfo();
|
||||
FD->setType(Reader.Context.getFunctionType(
|
||||
FPT->getReturnType(), FPT->getParamTypes(),
|
||||
FPT->getExtProtoInfo().withExceptionSpec(EPI.ExceptionSpec)));
|
||||
Reader.Context.adjustExceptionSpec(
|
||||
FD, PrevFPT->getExtProtoInfo().ExceptionSpec);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -56,3 +56,33 @@ namespace test3 {
|
|||
|
||||
template struct A2<int>;
|
||||
}
|
||||
|
||||
namespace PR12629 {
|
||||
struct S {
|
||||
static int (f)() throw();
|
||||
static int ((((((g))))() throw(U)));
|
||||
int (*h)() noexcept(false);
|
||||
static int (&i)() noexcept(true);
|
||||
static int (*j)() throw(U); // expected-error {{unknown type name 'U'}}
|
||||
static int (k)() throw(U);
|
||||
|
||||
struct U {};
|
||||
};
|
||||
static_assert(noexcept(S::f()), "");
|
||||
static_assert(!noexcept(S::g()), "");
|
||||
static_assert(!noexcept(S().h()), "");
|
||||
static_assert(noexcept(S::i()), "");
|
||||
}
|
||||
|
||||
namespace PR12688 {
|
||||
struct S {
|
||||
// FIXME: Producing one error saying this can't have the same name
|
||||
// as the class because it's not a constructor, then producing
|
||||
// another error saying this can't have a return type because
|
||||
// it is a constructor, is redundant and inconsistent.
|
||||
nonsense S() throw (more_nonsense); // \
|
||||
// expected-error {{'nonsense'}} \
|
||||
// expected-error {{has the same name as its class}} \
|
||||
// expected-error {{constructor cannot have a return type}}
|
||||
};
|
||||
}
|
||||
|
|
|
@ -502,15 +502,15 @@ namespace dr436 { // dr436: yes
|
|||
void f(); // expected-error {{redefinition}}
|
||||
}
|
||||
|
||||
namespace dr437 { // dr437: no
|
||||
namespace dr437 { // dr437: sup 1308
|
||||
// This is superseded by 1308, which is in turn superseded by 1330,
|
||||
// which restores this rule.
|
||||
template<typename U> struct T : U {}; // expected-error {{incomplete}}
|
||||
struct S { // expected-note {{not complete}}
|
||||
template<typename U> struct T : U {};
|
||||
struct S {
|
||||
void f() throw(S);
|
||||
void g() throw(T<S>); // expected-note {{in instantiation of}}
|
||||
struct U; // expected-note {{forward}}
|
||||
void h() throw(U); // expected-error {{incomplete}}
|
||||
void g() throw(T<S>);
|
||||
struct U;
|
||||
void h() throw(U);
|
||||
struct U {};
|
||||
};
|
||||
}
|
||||
|
|
|
@ -136,12 +136,11 @@ namespace Static {
|
|||
|
||||
namespace PR12564 {
|
||||
struct Base {
|
||||
void bar(Base&) {} // FIXME: expected-note {{here}}
|
||||
void bar(Base&) {}
|
||||
};
|
||||
|
||||
struct Derived : Base {
|
||||
// FIXME: This should be accepted.
|
||||
void foo(Derived& d) noexcept(noexcept(d.bar(d))) {} // expected-error {{cannot bind to a value of unrelated type}}
|
||||
void foo(Derived& d) noexcept(noexcept(d.bar(d))) {}
|
||||
};
|
||||
}
|
||||
|
||||
|
|
|
@ -23,7 +23,7 @@ struct array
|
|||
{
|
||||
T data[N];
|
||||
|
||||
void swap(array& a) noexcept(noexcept(swap(declval<T&>(), declval<T&>())));
|
||||
void swap(array& a) noexcept(noexcept(::swap(declval<T&>(), declval<T&>())));
|
||||
};
|
||||
|
||||
struct DefaultOnly
|
||||
|
@ -38,3 +38,4 @@ int main()
|
|||
{
|
||||
array<DefaultOnly, 1> a, b;
|
||||
}
|
||||
|
||||
|
|
|
@ -46,13 +46,12 @@ namespace InClassInitializers {
|
|||
}
|
||||
|
||||
namespace ExceptionSpecification {
|
||||
// A type is permitted to be used in a dynamic exception specification when it
|
||||
// is still being defined, but isn't complete within such an exception
|
||||
// specification.
|
||||
struct Nested { // expected-note {{not complete}}
|
||||
// FIXME: This diagnostic is quite useless; we should indicate whose
|
||||
// exception specification we were looking for and why.
|
||||
struct Nested {
|
||||
struct T {
|
||||
T() noexcept(!noexcept(Nested())); // expected-error{{incomplete type}}
|
||||
} t;
|
||||
T() noexcept(!noexcept(Nested()));
|
||||
} t; // expected-error{{exception specification is not available until end of class definition}}
|
||||
};
|
||||
}
|
||||
|
||||
|
|
Loading…
Reference in New Issue