Skip to content

Commit 4b91b34

Browse files
committed
Get templates working.
The template stuff is a bit of a hack. I'm considering simply inserting the statements into the function body and letting the existing code handle the rest. Also add some cheaky diagnostics, fix a few name lookup bugs, and delete some old code.
1 parent 93a6ba5 commit 4b91b34

File tree

15 files changed

+158
-121
lines changed

15 files changed

+158
-121
lines changed

clang/include/clang/AST/StmtCXX.h

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,7 @@
2222
namespace clang {
2323

2424
class VarDecl;
25+
class ResultNameDecl;
2526

2627
/// CXXCatchStmt - This represents a C++ catch block.
2728
///
@@ -574,13 +575,15 @@ class ContractStmt final : public Stmt,
574575

575576
bool hasResultNameDecl() const { return ContractAssertBits.HasResultName; }
576577

577-
DeclStmt *getResultNameDecl() const {
578+
DeclStmt *getResultNameDeclStmt() const {
578579
return hasResultNameDecl()
579580
? static_cast<DeclStmt *>(
580581
getTrailingObjects<Stmt *>()[ResultNameDeclOffset])
581582
: nullptr;
582583
}
583584

585+
ResultNameDecl *getResultNameDecl() const;
586+
584587
void setResultNameDecl(DeclStmt *D) {
585588
assert(hasResultNameDecl() && "no result name decl");
586589
getTrailingObjects<Stmt *>()[ResultNameDeclOffset] = D;

clang/include/clang/Basic/DiagnosticSemaKinds.td

Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -11879,6 +11879,28 @@ def err_coroutine_return_type : Error<
1187911879
>;
1188011880
} // end of coroutines issue category
1188111881

11882+
let CategoryName = "Contract Issue" in {
11883+
def err_ericwf_unimplemented : Error<
11884+
"contract feature %0 is not yet implemented (complain to [email protected])"
11885+
>;
11886+
def warn_ericwf_unimplemented : Warning<
11887+
"contract feature %0 is not yet _correctly_ implemented (Danm it Eric!)"
11888+
>;
11889+
11890+
def err_ericwf_fixme : Error<
11891+
"woops... FIXME(EricWF): %0"
11892+
>;
11893+
def warn_ericwf_fixme : Warning<
11894+
"woops... FIXME(EricWF): %0"
11895+
>;
11896+
def err_result_name_shadows_param : Error<
11897+
"declaration of result name %0 shadows parameter">;
11898+
def err_void_result_name : Error<
11899+
"result name %0 cannot be used with a void return type">;
11900+
def err_deduced_auto_result_name_without_body : Error<
11901+
"result name on function with deduced return type requires a body">;
11902+
11903+
} // end of contracts issues
1188211904
let CategoryName = "Documentation Issue" in {
1188311905
def warn_not_a_doxygen_trailing_member_comment : Warning<
1188411906
"not a Doxygen trailing comment">, InGroup<Documentation>, DefaultIgnore;

clang/include/clang/Sema/Sema.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2729,6 +2729,7 @@ class Sema final : public SemaBase {
27292729

27302730
public:
27312731
StmtResult ActOnContractAssert(SourceLocation KeywordLoc, Expr *Cond);
2732+
27322733
StmtResult ActOnPreContractAssert(SourceLocation KeywordLoc, Expr *Cond);
27332734
StmtResult ActOnPostContractAssert(SourceLocation KeywordLoc, Expr *Cond,
27342735
DeclStmt *ResultNameDecl = nullptr);

clang/lib/AST/DeclBase.cpp

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1103,6 +1103,7 @@ bool Decl::AccessDeclContextCheck() const {
11031103
// FIXME: a ParmVarDecl can have ClassTemplateSpecialization
11041104
// as DeclContext (?).
11051105
isa<ParmVarDecl>(this) ||
1106+
isa<ResultNameDecl>(this) ||
11061107
// FIXME: a ClassTemplateSpecialization or CXXRecordDecl can have
11071108
// AS_none as access specifier.
11081109
isa<CXXRecordDecl>(this) || isa<LifetimeExtendedTemporaryDecl>(this))

clang/lib/AST/StmtCXX.cpp

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,7 @@
1111
//===----------------------------------------------------------------------===//
1212

1313
#include "clang/AST/StmtCXX.h"
14-
14+
#include "clang/AST/DeclCXX.h"
1515
#include "clang/AST/ASTContext.h"
1616

1717
using namespace clang;
@@ -146,3 +146,9 @@ ContractStmt *ContractStmt::Create(const ASTContext &C, ContractKind Kind,
146146
S->setResultNameDecl(ResultNameDecl);
147147
return S;
148148
}
149+
150+
ResultNameDecl *ContractStmt::getResultNameDecl() const {
151+
DeclStmt* D = getResultNameDeclStmt();
152+
assert(D);
153+
return cast<ResultNameDecl>(D->getSingleDecl());
154+
}

clang/lib/Parse/ParseDecl.cpp

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2593,7 +2593,6 @@ Parser::DeclGroupPtrTy Parser::ParseDeclGroup(ParsingDeclSpec &DS,
25932593
if (!isDeclarationSpecifier(ImplicitTypenameContext::No))
25942594
SkipMalformedDecl();
25952595
}
2596-
assert(D.getContracts().empty());
25972596

25982597
return Actions.FinalizeDeclaratorGroup(getCurScope(), DS, DeclsInGroup);
25992598
}
@@ -7192,6 +7191,7 @@ void Parser::ParseDirectDeclarator(Declarator &D) {
71927191
Actions.ActOnStartFunctionDeclarationDeclarator(D,
71937192
TemplateParameterDepth);
71947193
ParseFunctionDeclarator(D, attrs, T, IsAmbiguous);
7194+
assert(D.getContracts().empty());
71957195
if (IsFunctionDeclaration) {
71967196
assert(D.getContracts().empty());
71977197
Actions.ActOnFinishFunctionDeclarationDeclarator(D);

clang/lib/Parse/ParseDeclCXX.cpp

Lines changed: 5 additions & 96 deletions
Original file line numberDiff line numberDiff line change
@@ -4404,6 +4404,7 @@ bool Parser::LateParseFunctionContractSpecifier(Declarator &DeclaratorInfo, Cach
44044404
return true;
44054405

44064406
}
4407+
#pragma clang diagnostic ignored "-Wunused-variable"
44074408

44084409
StmtResult Parser::ParseFunctionContractSpecifier(Declarator &DeclaratorInfo) {
44094410
auto [CK, CKStr] = [&]() -> std::pair<ContractKind, const char *> {
@@ -4434,7 +4435,7 @@ StmtResult Parser::ParseFunctionContractSpecifier(Declarator &DeclaratorInfo) {
44344435
}
44354436

44364437
ParseScope ParamScope(this, Scope::DeclScope |
4437-
Scope::FunctionDeclarationScope |
4438+
// Scope::FunctionDeclarationScope |
44384439
Scope::FunctionPrototypeScope |
44394440
Scope::PostConditionScope);
44404441

@@ -4458,35 +4459,19 @@ StmtResult Parser::ParseFunctionContractSpecifier(Declarator &DeclaratorInfo) {
44584459
IdentifierInfo *Id = Tok.getIdentifierInfo();
44594460
SourceLocation IdLoc = ConsumeToken();
44604461

4461-
//ImplicitParamDecl *D = ImplicitParamDecl::Create(Actions.getASTContext(), nullptr, IdLoc, Id, QualType(),
4462-
//Id, /* Type here*/nullptr, ImplicitParamDecl::Other);
4463-
// NamedDecl *ND = NameDecl::Create(Actions.getASTContext(), Id, IdLoc);
44644462
SourceLocation ColonLoc = ConsumeToken();
44654463
((void)ColonLoc);
44664464

4467-
auto& DI = DeclaratorInfo;
4468-
auto &DS = DI.getDeclSpec();
4469-
DeclSpec RetNameDS(AttrFactory);
4470-
ParsedAttributes DeclAttrs(AttrFactory);
4471-
4472-
assert(DI.isFunctionDeclarator());
4473-
if (auto DeclRep = DS.getRepAsDecl(); DeclRep != nullptr) {
4474-
DeclRep->dumpColor();
4475-
assert(false);
4476-
}
4477-
ParsedType ParsedResultType = DS.getRepAsType();
4478-
ParsedResultType.get().dump();
4479-
4480-
44814465
StmtResult RNStmt = Actions.ActOnResultNameDeclarator(getCurScope(), DeclaratorInfo, IdLoc, Id);
44824466
if (RNStmt.isUsable())
44834467
ResultNameStmt = cast<DeclStmt>(RNStmt.get());
4468+
else
4469+
return StmtError();
44844470
}
44854471

44864472
SourceLocation Start = Tok.getLocation();
4487-
4488-
44894473
ExprResult Cond = ParseConditionalExpression();
4474+
44904475
if (Cond.isUsable()) {
44914476
Cond = Actions.CorrectDelayedTyposInExpr(Cond, /*InitDecl=*/nullptr,
44924477
/*RecoverUncorrectedTypos=*/true);
@@ -4508,82 +4493,6 @@ StmtResult Parser::ParseFunctionContractSpecifier(Declarator &DeclaratorInfo) {
45084493
}
45094494
}
45104495

4511-
/*
4512-
void Parser::ParsePostContract(Declarator &DeclaratorInfo) {
4513-
ConsumeToken();
4514-
4515-
ParseScope ParamScope(this, Scope::DeclScope |
4516-
Scope::FunctionDeclarationScope |
4517-
Scope::FunctionPrototypeScope);
4518-
4519-
DeclaratorChunk::FunctionTypeInfo FTI = DeclaratorInfo.getFunctionTypeInfo();
4520-
for (unsigned i = 0; i != FTI.NumParams; ++i) {
4521-
ParmVarDecl *Param = cast<ParmVarDecl>(FTI.Params[i].Param);
4522-
Actions.ActOnReenterCXXMethodParameter(getCurScope(), Param);
4523-
}
4524-
4525-
if (Tok.isNot(tok::l_paren)) {
4526-
Diag(Tok.getLocation(), diag::err_expected) << tok::l_paren;
4527-
return;
4528-
}
4529-
ConsumeParen();
4530-
4531-
// Post contracts start with <identifier> colon <expression>
4532-
// As we have to support the "auto f() post (r : r > 42) {...}" case, we cannot parse here
4533-
// the return type is not guaranteed to be known until after the function body parses
4534-
4535-
4536-
if (Tok.isNot(tok::identifier)) {
4537-
Diag(Tok.getLocation(), diag::err_expected) << tok::identifier;
4538-
return;
4539-
}
4540-
4541-
ParsingDeclSpec DS(*this);
4542-
4543-
ParsedTemplateInfo TemplateInfo;
4544-
DeclSpecContext DSContext =
4545-
getDeclSpecContextFromDeclaratorContext(DeclaratorContext::Block);
4546-
ParseDeclarationSpecifiers(DS, TemplateInfo, AS_none, DSContext);
4547-
4548-
ParsedAttributes LocalAttrs(AttrFactory);
4549-
ParsingDeclarator D(*this, DS, LocalAttrs, DeclaratorContext::Block);
4550-
4551-
D.setObjectType(getAsFunction().getReturnType());
4552-
IdentifierInfo *Id = Tok.getIdentifierInfo();
4553-
SourceLocation IdLoc = ConsumeToken();
4554-
D.setIdentifier(Id, IdLoc);
4555-
4556-
Decl* ThisDecl = Actions.ActOnDeclarator(getCurScope(), D);
4557-
Actions.ActOnUninitializedDecl(ThisDecl);
4558-
Actions.FinalizeDeclaration(ThisDecl);
4559-
D.complete(ThisDecl);
4560-
if (Tok.isNot(tok::colon)) {
4561-
Diag(Tok.getLocation(), diag::err_expected) << tok::colon;
4562-
return;
4563-
}
4564-
4565-
ExprResult Expr = ParseExpression();
4566-
if (Expr.isInvalid()) {
4567-
Diag(Tok.getLocation(), diag::err_invalid_pcs);
4568-
return;
4569-
}
4570-
DeclaratorInfo.addContract(Expr.get());
4571-
4572-
ExprResult Expr = ParseExpression();
4573-
if (Expr.isInvalid()) {
4574-
Diag(Tok.getLocation(), diag::err_invalid_pcs);
4575-
return;
4576-
}
4577-
// DeclaratorInfo.addContract(Expr.get());
4578-
4579-
if (Tok.isNot(tok::r_paren)) {
4580-
Diag(Tok.getLocation(), diag::err_expected) << tok::r_paren;
4581-
return;
4582-
}
4583-
ConsumeParen();
4584-
}
4585-
*/
4586-
45874496
/// ParseTrailingReturnType - Parse a trailing return type on a new-style
45884497
/// function declaration.
45894498
TypeResult Parser::ParseTrailingReturnType(SourceRange &Range,

clang/lib/Sema/SemaContract.cpp

Lines changed: 27 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -81,9 +81,8 @@ StmtResult Sema::ActOnPreContractAssert(SourceLocation KeywordLoc, Expr *Cond) {
8181

8282
StmtResult Sema::ActOnPostContractAssert(SourceLocation KeywordLoc, Expr *Cond,
8383
DeclStmt *ResultNameDecl) {
84-
assert(ResultNameDecl == nullptr && "Result name decl not supported yet");
85-
assert(Cond);
8684

85+
assert(Cond);
8786
return BuildContractStmt(ContractKind::Post, KeywordLoc, Cond,
8887
ResultNameDecl);
8988
}
@@ -103,20 +102,32 @@ void Sema::ActOnStartContracts(Scope *S, Declarator &D) {
103102
}
104103

105104

106-
/// ActOnParamDeclarator - Called from Parser::ParseFunctionDeclarator()
105+
/// ActOnResultNameDeclarator - Called from Parser::ParseFunctionDeclarator()
107106
/// to introduce parameters into function prototype scope.
108107
StmtResult Sema::ActOnResultNameDeclarator(Scope *S, Declarator &FuncDecl,
109108
SourceLocation IDLoc,
110109
IdentifierInfo *II) {
111-
const DeclSpec &DS = FuncDecl.getDeclSpec();
112-
113-
114-
DiagnoseFunctionSpecifiers(DS);
115-
110+
assert(S && S->isPostConditionScope() && "Invalid scope for result name");
111+
assert(II && "ResultName requires an identifier");
116112
//CheckFunctionOrTemplateParamDeclarator(S, D);
117113

118114
TypeSourceInfo *TInfo = GetTypeForDeclarator(FuncDecl);
119-
QualType parmDeclType = TInfo->getType();
115+
assert(TInfo && "no type from declarator in ActOnParamDeclarator");
116+
QualType FuncType = TInfo->getType();
117+
assert(FuncType->isFunctionType());
118+
auto *FT = FuncType->getAs<FunctionType>();
119+
assert(FT && "FunctionType is null");
120+
QualType RetType = FT->getReturnType();
121+
122+
if (RetType->isVoidType()) {
123+
Diag(IDLoc, diag::err_void_result_name) << II;
124+
return StmtError();
125+
}
126+
127+
if (RetType->isUndeducedAutoType()) {
128+
Diag(IDLoc, diag::err_ericwf_unimplemented) << "Undeduced Auto Result Name";
129+
}
130+
120131

121132
// Check for redeclaration of parameters, e.g. int foo(int x, int x);
122133
if (II) {
@@ -133,22 +144,23 @@ StmtResult Sema::ActOnResultNameDeclarator(Scope *S, Declarator &FuncDecl,
133144
}
134145
// FIXME(EricWF): Diagnose lookup conflicts with lambda captures and parameter declarations.
135146
if (auto* PVD = dyn_cast<ParmVarDecl>(PrevDecl)) {
136-
Diag(IDLoc, diag::err_param_redefinition) << II; // FIXME(EricWF): Change the diagnostic here.
147+
Diag(IDLoc, diag::err_result_name_shadows_param) << II; // FIXME(EricWF): Change the diagnostic here.
137148
Diag(PVD->getLocation(), diag::note_previous_declaration);
138149
} else if (auto *CD = dyn_cast<CapturedDecl>(PrevDecl)) {
139150
Diag(IDLoc, diag::err_redefinition_different_kind) << II;
140151
Diag(PrevDecl->getLocation(), diag::note_previous_declaration);
152+
} else {
153+
Diag(IDLoc, diag::err_ericwf_fixme) << "Add A Diagnostic Here";
141154
}
142155
}
143156
}
144157

145158
// Temporarily put parameter variables in the translation unit, not
146159
// the enclosing context. This prevents them from accidentally
147160
// looking like class members in C++.
148-
CurContext->dumpDeclContext();
149-
ResultNameDecl *New =
150-
ResultNameDecl::Create(Context, CurContext,
151-
IDLoc, II, parmDeclType);
161+
162+
auto *New = ResultNameDecl::Create(Context, CurContext,
163+
IDLoc, II, RetType);
152164

153165
if (FuncDecl.isInvalidType())
154166
New->setInvalidDecl();
@@ -162,8 +174,7 @@ StmtResult Sema::ActOnResultNameDeclarator(Scope *S, Declarator &FuncDecl,
162174

163175
// Add the parameter declaration into this scope.
164176
S->AddDecl(New);
165-
if (II)
166-
IdResolver.AddDecl(New);
177+
IdResolver.AddDecl(New);
167178

168179
return ActOnDeclStmt(ConvertDeclToDeclGroup(New), IDLoc, IDLoc);
169180
}

clang/lib/Sema/SemaDecl.cpp

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9692,6 +9692,8 @@ Sema::ActOnFunctionDeclarator(Scope *S, Declarator &D, DeclContext *DC,
96929692
isVirtualOkay);
96939693
if (!NewFD) return nullptr;
96949694

9695+
NewFD->dumpDeclContext();
9696+
96959697
if (OriginalLexicalContext && OriginalLexicalContext->isObjCContainer())
96969698
NewFD->setTopLevelDeclInObjCContainer();
96979699

clang/lib/Sema/SemaTemplateInstantiateDecl.cpp

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5164,6 +5164,20 @@ void Sema::InstantiateFunctionDefinition(SourceLocation PointOfInstantiation,
51645164
InstantiateDefaultCtorDefaultArgs(Ctor);
51655165
}
51665166
}
5167+
// If the function has contracts, instantiate them now
5168+
SmallVector<ContractStmt*> Contracts = Function->getContracts();
5169+
if (!Contracts.empty()) {
5170+
SmallVector<ContractStmt*> NewContracts;
5171+
for (auto *C : Contracts) {
5172+
StmtResult NewStmt = SubstStmt(C, TemplateArgs);
5173+
if (NewStmt.isInvalid()) {
5174+
Function->setInvalidDecl();
5175+
} else {
5176+
NewContracts.push_back(NewStmt.getAs<ContractStmt>());
5177+
}
5178+
}
5179+
Function->setContracts(NewContracts);
5180+
}
51675181

51685182
// Instantiate the function body.
51695183
Body = SubstStmt(Pattern, TemplateArgs);

0 commit comments

Comments
 (0)