Skip to content

Parse bounds declarations for function return values. #21

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 2 commits into from
Jul 22, 2016
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
9 changes: 8 additions & 1 deletion include/clang/AST/Decl.h
Original file line number Diff line number Diff line change
Expand Up @@ -1584,6 +1584,8 @@ class FunctionDecl : public DeclaratorDecl, public DeclContext,
/// 'enum Y' in 'void f(enum Y {AA} x) {}'.
ArrayRef<NamedDecl *> DeclsInPrototypeScope;

BoundsExpr *ReturnBoundsExpr;

LazyDeclStmtPtr Body;

// FIXME: This can be packed into the bitfields in DeclContext.
Expand Down Expand Up @@ -1687,7 +1689,7 @@ class FunctionDecl : public DeclaratorDecl, public DeclContext,
StartLoc),
DeclContext(DK),
redeclarable_base(C),
ParamInfo(nullptr), Body(),
ParamInfo(nullptr), ReturnBoundsExpr(nullptr), Body(),
SClass(S),
IsInline(isInlineSpecified), IsInlineSpecified(isInlineSpecified),
IsVirtualAsWritten(false), IsPure(false), HasInheritedPrototype(false),
Expand Down Expand Up @@ -2065,6 +2067,11 @@ class FunctionDecl : public DeclaratorDecl, public DeclContext,
/// computed linkage of symbol, see getLinkage.
StorageClass getStorageClass() const { return StorageClass(SClass); }

/// \brief Returns the bounds expression for the return value of this function, if
/// any.
BoundsExpr *getReturnBoundsExpr() { return ReturnBoundsExpr; }
void setReturnBoundsExpr(BoundsExpr *E) { ReturnBoundsExpr = E; }

/// \brief Determine whether the "inline" keyword was specified for this
/// function.
bool isInlineSpecified() const { return IsInlineSpecified; }
Expand Down
16 changes: 16 additions & 0 deletions include/clang/Sema/DeclSpec.h
Original file line number Diff line number Diff line change
Expand Up @@ -1287,11 +1287,18 @@ struct DeclaratorChunk {
/// \brief The end location of the exception specification, if any.
unsigned ExceptionSpecLocEnd;

/// The location of the ':' for the return bounds expression in the source
unsigned ReturnBoundsColonLoc;

/// Params - This is a pointer to a new[]'d array of ParamInfo objects that
/// describe the parameters specified by this function declarator. null if
/// there are no parameters specified.
ParamInfo *Params;

/// The bounds for the value returned by the function. Null if there is
/// no bounds specified.
BoundsExpr *ReturnBounds;

union {
/// \brief Pointer to a new[]'d array of TypeAndRange objects that
/// contain the types in the function's dynamic exception specification
Expand Down Expand Up @@ -1352,6 +1359,10 @@ struct DeclaratorChunk {
return SourceLocation::getFromRawEncoding(RParenLoc);
}

SourceLocation getReturnBoundsColonLoc() const {
return SourceLocation::getFromRawEncoding(ReturnBoundsColonLoc);
}

SourceLocation getExceptionSpecLocBeg() const {
return SourceLocation::getFromRawEncoding(ExceptionSpecLocBeg);
}
Expand Down Expand Up @@ -1408,6 +1419,9 @@ struct DeclaratorChunk {

/// \brief Get the trailing-return-type for this function declarator.
ParsedType getTrailingReturnType() const { return TrailingReturnType; }

/// \brief The bounds expression for the return value
BoundsExpr *getReturnBounds() const { return ReturnBounds; }
};

struct BlockPointerTypeInfo : TypeInfoCommon {
Expand Down Expand Up @@ -1552,6 +1566,8 @@ struct DeclaratorChunk {
CachedTokens *ExceptionSpecTokens,
SourceLocation LocalRangeBegin,
SourceLocation LocalRangeEnd,
SourceLocation ReturnBoundsColonLoc,
BoundsExpr *ReturnBoundsExpr,
Declarator &TheDeclarator,
TypeResult TrailingReturnType =
TypeResult());
Expand Down
1 change: 1 addition & 0 deletions include/clang/Sema/Sema.h
Original file line number Diff line number Diff line change
Expand Up @@ -4116,6 +4116,7 @@ class Sema {

void ActOnBoundsExpr(VarDecl *D, BoundsExpr *Expr);
void ActOnInvalidBoundsExpr(VarDecl *D);
BoundsExpr *CreateInvalidBoundsExpr();

//===---------------------------- Clang Extensions ----------------------===//

Expand Down
23 changes: 22 additions & 1 deletion lib/Parse/ParseDecl.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -5586,6 +5586,10 @@ void Parser::ParseParenDeclarator(Declarator &D) {
/// dynamic-exception-specification
/// noexcept-specification
///
/// For Checked C, after the parameter-list, it also parses the optional return
/// bounds expression for the function declarator:
/// [Checked C] ':' bounds-expression
////
void Parser::ParseFunctionDeclarator(Declarator &D,
ParsedAttributes &FirstArgAttrs,
BalancedDelimiterTracker &Tracker,
Expand Down Expand Up @@ -5626,6 +5630,8 @@ void Parser::ParseFunctionDeclarator(Declarator &D,
SourceLocation LParenLoc, RParenLoc;
LParenLoc = Tracker.getOpenLocation();
StartLoc = LParenLoc;
SourceLocation BoundsColonLoc;
BoundsExpr *ReturnBoundsExpr = nullptr;

if (isFunctionDeclaratorIdentifierList()) {
if (RequiresArg)
Expand Down Expand Up @@ -5741,6 +5747,19 @@ void Parser::ParseFunctionDeclarator(Declarator &D,
}
}

// Parse optional Checked C bounds expression with the form:
// ':' bounds-expression.
if (getLangOpts().CheckedC && Tok.is(tok::colon)) {
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

if (getLangOpts().CheckedC && Tok.is(tok::colon)) { [](start = 2, length = 51)

I know you called it out in the header comment for this function, but a quick brief comment calling out that this is for the return bounds expression might be nice (similar to the ones in the few code chunks directly above).

BoundsColonLoc = Tok.getLocation();
ConsumeToken();
ExprResult BoundsExprResult = ParseBoundsExpression();
if (BoundsExprResult.isInvalid()) {
ReturnBoundsExpr = Actions.CreateInvalidBoundsExpr();
SkipUntil(tok::l_brace, SkipUntilFlags::StopAtSemi | SkipUntilFlags::StopBeforeMatch);
} else
ReturnBoundsExpr = cast<BoundsExpr>(BoundsExprResult.get());
}

// Remember that we parsed a function type, and remember the attributes.
D.AddTypeInfo(DeclaratorChunk::getFunction(HasProto,
IsAmbiguous,
Expand All @@ -5760,7 +5779,9 @@ void Parser::ParseFunctionDeclarator(Declarator &D,
NoexceptExpr.isUsable() ?
NoexceptExpr.get() : nullptr,
ExceptionSpecTokens,
StartLoc, LocalEndLoc, D,
StartLoc, LocalEndLoc,
BoundsColonLoc, ReturnBoundsExpr,
D,
TrailingReturnType),
FnAttrs, EndLoc);
}
Expand Down
17 changes: 13 additions & 4 deletions lib/Parse/ParseExpr.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -2795,10 +2795,8 @@ ExprResult Parser::ParseBoundsExpression() {
ExprResult LowerBound =
Actions.CorrectDelayedTyposInExpr(ParseAssignmentExpression());

if (ExpectAndConsume(tok::comma))
// We didn't find a comma, so don't try to parse the upper bounds expression.
Result = ExprError();
else {
if (Tok.getKind() == tok::comma) {
ConsumeToken();
ExprResult UpperBound =
Actions.CorrectDelayedTyposInExpr(ParseAssignmentExpression());
if (LowerBound.isInvalid() || UpperBound.isInvalid())
Expand All @@ -2807,6 +2805,15 @@ ExprResult Parser::ParseBoundsExpression() {
Result = Actions.ActOnRangeBoundsExpr(BoundsKWLoc, LowerBound.get(),
UpperBound.get(),
Tok.getLocation());
} else {
// We didn't find a comma. Only issue an error message if the
// LowerBound expression is valid. Otherwise, we already issued an
// error message when parsing the lower bound. Emitting an error
// message here could be spurious or confusing.
if (!LowerBound.isInvalid()) {
Diag(Tok, diag::err_expected) << tok::comma;
}
Result = ExprError();
}
} // if (!FoundNullaryOperator)
} else {
Expand Down Expand Up @@ -2971,6 +2978,8 @@ ExprResult Parser::ParseBlockLiteralExpression() {
/*NoexceptExpr=*/nullptr,
/*ExceptionSpecTokens=*/nullptr,
CaretLoc, CaretLoc,
/*ReturnBoundsColon=*/NoLoc,
/*ReturnBoundsExpr=*/nullptr,
ParamInfo),
attrs, CaretLoc);

Expand Down
10 changes: 8 additions & 2 deletions lib/Parse/ParseExprCXX.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1221,7 +1221,10 @@ ExprResult Parser::ParseLambdaExpressionAfterIntroducer(
NoexceptExpr.isUsable() ?
NoexceptExpr.get() : nullptr,
/*ExceptionSpecTokens*/nullptr,
LParenLoc, FunLocalRangeEnd, D,
LParenLoc, FunLocalRangeEnd,
/*ReturnBoundsColonLoc=*/NoLoc,
/*ReturnBoundsExpr=*/nullptr,
D,
TrailingReturnType),
Attr, DeclEndLoc);
} else if (Tok.isOneOf(tok::kw_mutable, tok::arrow, tok::kw___attribute,
Expand Down Expand Up @@ -1290,7 +1293,10 @@ ExprResult Parser::ParseLambdaExpressionAfterIntroducer(
/*NumExceptions=*/0,
/*NoexceptExpr=*/nullptr,
/*ExceptionSpecTokens=*/nullptr,
DeclLoc, DeclEndLoc, D,
DeclLoc, DeclEndLoc,
/*ReturnBoundsColonLoc=*/NoLoc,
/*ReturnBoundsExpr=*/nullptr,
D,
TrailingReturnType),
Attr, DeclEndLoc);
}
Expand Down
4 changes: 4 additions & 0 deletions lib/Sema/DeclSpec.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -175,6 +175,8 @@ DeclaratorChunk DeclaratorChunk::getFunction(bool hasProto,
CachedTokens *ExceptionSpecTokens,
SourceLocation LocalRangeBegin,
SourceLocation LocalRangeEnd,
SourceLocation ReturnBoundsColonLoc,
BoundsExpr *ReturnBoundsExpr,
Declarator &TheDeclarator,
TypeResult TrailingReturnType) {
assert(!(TypeQuals & DeclSpec::TQ_atomic) &&
Expand Down Expand Up @@ -210,6 +212,8 @@ DeclaratorChunk DeclaratorChunk::getFunction(bool hasProto,
I.Fun.HasTrailingReturnType = TrailingReturnType.isUsable() ||
TrailingReturnType.isInvalid();
I.Fun.TrailingReturnType = TrailingReturnType.get();
I.Fun.ReturnBoundsColonLoc = ReturnBoundsColonLoc.getRawEncoding();
I.Fun.ReturnBounds = ReturnBoundsExpr;

assert(I.Fun.TypeQuals == TypeQuals && "bitfield overflow");
assert(I.Fun.ExceptionSpecType == ESpecType && "bitfield overflow");
Expand Down
22 changes: 19 additions & 3 deletions lib/Sema/SemaDecl.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -7973,6 +7973,14 @@ Sema::ActOnFunctionDeclarator(Scope *S, Declarator &D, DeclContext *DC,
// Finally, we know we have the right number of parameters, install them.
NewFD->setParams(Params);

// TODO: clang-checked-issue #20. Issue #20 is attaching bounds information
// to function types. After it is address, we need to make sure that bounds
// information is propgated to newFD from the FunctionPrototype instance.
if (D.isFunctionDeclarator()) {
DeclaratorChunk::FunctionTypeInfo &FTI = D.getFunctionTypeInfo();
NewFD->setReturnBoundsExpr(FTI.getReturnBounds());
}

// Find all anonymous symbols defined during the declaration of this function
// and add to NewFD. This lets us track decls such 'enum Y' in:
//
Expand Down Expand Up @@ -10880,13 +10888,19 @@ void Sema::ActOnInvalidBoundsExpr(VarDecl *D) {
if (!D)
return;

BoundsExpr *InvalidExpr = CreateInvalidBoundsExpr();
D->setBoundsExpr(InvalidExpr);
}

BoundsExpr *Sema::CreateInvalidBoundsExpr() {
ExprResult Result =
ActOnNullaryBoundsExpr(SourceLocation(),
NullaryBoundsExpr::Kind::Invalid,
SourceLocation());

if (!Result.isInvalid())
D->setBoundsExpr(cast<BoundsExpr>(Result.get()));
return cast<BoundsExpr>(Result.get());
else
return nullptr;
}

Decl *
Expand Down Expand Up @@ -11613,7 +11627,9 @@ NamedDecl *Sema::ImplicitlyDefineFunction(SourceLocation Loc,
/*NumExceptions=*/0,
/*NoexceptExpr=*/nullptr,
/*ExceptionSpecTokens=*/nullptr,
Loc, Loc, D),
Loc, Loc,
/*ReturnBoundsColonLoc=*/NoLoc,
/*ReturnBoundsExpr=*/nullptr, D),
DS.getAttributes(),
SourceLocation());
D.SetIdentifier(&II, Loc);
Expand Down
9 changes: 8 additions & 1 deletion lib/Sema/SemaType.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -718,7 +718,10 @@ static void maybeSynthesizeBlockSignature(TypeProcessingState &state,
/*NumExceptions=*/0,
/*NoexceptExpr=*/nullptr,
/*ExceptionSpecTokens=*/nullptr,
loc, loc, declarator));
loc, loc,
/*ReturnBoundsColon=*/NoLoc,
/*ReturnBoundsExpr=*/nullptr,
declarator));

// For consistency, make sure the state still has us as processing
// the decl spec.
Expand Down Expand Up @@ -4238,6 +4241,10 @@ static TypeSourceInfo *GetFullTypeForDeclarator(TypeProcessingState &state,
SmallVector<QualType, 16> ParamTys;
ParamTys.reserve(FTI.NumParams);

// TODO: checkedc-clang issue #20: represent bounds information
// in function types. The code below will need to be updated
// to add the bounds information to the FunctionType.

SmallVector<FunctionProtoType::ExtParameterInfo, 16>
ExtParameterInfos(FTI.NumParams);
bool HasAnyInterestingExtParameterInfos = false;
Expand Down