Skip to content

Commit 55c0115

Browse files
committed
fix up tests, get templates working better
1 parent d8fa6bf commit 55c0115

32 files changed

+245
-453
lines changed

clang/include/clang/AST/Decl.h

Lines changed: 0 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -2745,10 +2745,6 @@ class FunctionDecl : public DeclaratorDecl,
27452745
/// parameter packs are not treated specially here.
27462746
bool hasOneParamOrDefaultArgs() const;
27472747

2748-
2749-
bool hasResultNameIntroducer();
2750-
ResultNameDecl *getCanonicalResultNameIntroducer();
2751-
27522748
/// Find the source location information for how the type of this function
27532749
/// was written. May be absent (for example if the function was declared via
27542750
/// a typedef) and may contain a different type from that of the function

clang/include/clang/AST/DeclCXX.h

Lines changed: 63 additions & 53 deletions
Original file line numberDiff line numberDiff line change
@@ -4408,63 +4408,67 @@ const StreamingDiagnostic &operator<<(const StreamingDiagnostic &DB,
44084408
///
44094409
/// Where `r` refers to the value returned by the function
44104410
class ResultNameDecl : public ValueDecl {
4411-
4411+
friend class ContractSpecifierDecl;
44124412
/// The canonical declaration of a result name is the result name declared in
44134413
/// the first post condition (with a result name) on a particular function.
44144414
///
44154415
/// The canonical decl is used as the key for the value of the return value
44164416
/// during codegen and constant evaluation. This is necessary because the
44174417
/// changes to the return value in the post conditions must be visible to
44184418
/// subsequent post conditions.
4419-
ResultNameDecl *CanonicalResultNameDecl = nullptr;
4419+
///
4420+
// FIXME(EricWF): Remove this? I think we can dig the canonical result name
4421+
// out of the decl context? But I think that will be rather bug prone. Maybe
4422+
// we could make the ContractSpecifierDecl a DeclContext and dig it up from
4423+
// there?
4424+
ResultNameDecl *CanonicalResultName = nullptr;
4425+
4426+
/// Whether this result name is using a dummy placeholder type to represent
4427+
/// the deduced return type of a non-template function until the actual return
4428+
/// type is known.
4429+
///
4430+
/// Result names are only allowed on non-template functions with deduced
4431+
/// return types if that function declaration is also a definition.
44204432
bool HasInventedPlaceholderType = false;
44214433

44224434
ResultNameDecl(DeclContext *DC, SourceLocation IdLoc, IdentifierInfo *Id,
4423-
QualType T, ResultNameDecl *CanonicalResultNameDecl = nullptr,
4435+
QualType T, ResultNameDecl *CanonicalDecl = nullptr,
44244436
bool HasInventedPlaceholderType = false)
44254437
: ValueDecl(Decl::ResultName, DC, IdLoc, Id, T),
4426-
CanonicalResultNameDecl(CanonicalResultNameDecl),
4427-
HasInventedPlaceholderType(HasInventedPlaceholderType) {
4428-
assert(!CanonicalResultNameDecl ||
4429-
CanonicalResultNameDecl->CanonicalResultNameDecl == nullptr);
4430-
assert(!CanonicalResultNameDecl || CanonicalResultNameDecl->getType() == T);
4438+
HasInventedPlaceholderType(HasInventedPlaceholderType) {}
4439+
4440+
void setCanonicalResultName(ResultNameDecl *CRND) {
4441+
assert(CRND != this &&
4442+
"setCanonicalResultName called on the canonical result");
4443+
this->CanonicalResultName = CRND;
44314444
}
44324445

44334446
void anchor() override;
44344447

44354448
public:
44364449
friend class ASTDeclReader;
44374450

4438-
static ResultNameDecl *
4439-
Create(ASTContext &C, DeclContext *DC, SourceLocation IdLoc,
4440-
IdentifierInfo *Id, QualType T,
4441-
ResultNameDecl *CanonicalResultNameDecl = nullptr,
4442-
bool HasInventedPlaceholderType = false);
4451+
static ResultNameDecl *Create(ASTContext &C, DeclContext *DC,
4452+
SourceLocation IdLoc, IdentifierInfo *Id,
4453+
QualType T, ResultNameDecl *CRND = nullptr,
4454+
bool HasInventedPlaceholderType = false);
44434455
static ResultNameDecl *CreateDeserialized(ASTContext &C, GlobalDeclID ID);
44444456

44454457
using ValueDecl::getDeclName;
44464458
using ValueDecl::setType;
44474459

4448-
void setCanonicalResultNameDecl(ResultNameDecl *D) {
4449-
CanonicalResultNameDecl = D;
4450-
}
4451-
44524460
/// Returns true if this declaration is the canonical result name declaration
44534461
/// (This is true if it doesn't reference another result name).
4454-
bool isCanonicalResultNameDecl() const {
4455-
return CanonicalResultNameDecl == nullptr;
4462+
bool isCanonicalResultName() const {
4463+
return getCanonicalResultName() == this;
44564464
}
44574465

4458-
ResultNameDecl *getCanonicalResultNameDecl() {
4459-
if (CanonicalResultNameDecl)
4460-
return CanonicalResultNameDecl;
4461-
return this;
4466+
ResultNameDecl *getCanonicalResultName() {
4467+
return CanonicalResultName ? CanonicalResultName : this;
44624468
}
44634469

4464-
const ResultNameDecl *getCanonicalResultNameDecl() const {
4465-
if (CanonicalResultNameDecl)
4466-
return CanonicalResultNameDecl;
4467-
return this;
4470+
const ResultNameDecl *getCanonicalResultName() const {
4471+
return CanonicalResultName ? CanonicalResultName : this;
44684472
}
44694473

44704474
bool hasInventedPlaceholderType() const { return HasInventedPlaceholderType; }
@@ -4473,13 +4477,20 @@ class ResultNameDecl : public ValueDecl {
44734477
static bool classofKind(Kind K) { return K == Decl::ResultName; }
44744478
};
44754479

4476-
/// Represents a C++11 static_assert declaration.
4480+
/// Represents a series of contracts on a function declaration.
4481+
/// For instance:
4482+
///
4483+
/// int foo(const int x) pre(x) post(r : x < r);
4484+
///
4485+
/// This declaration also stores whether any of the contracts are invalid.
44774486
class ContractSpecifierDecl final
44784487
: public Decl,
44794488
private llvm::TrailingObjects<ContractSpecifierDecl, ContractStmt *> {
4489+
friend class TrailingObjects;
44804490
friend class ASTDeclReader;
44814491
friend class ASTDeclWriter;
44824492

4493+
/// The number of contracts in this sequence.
44834494
unsigned NumContracts;
44844495

44854496
static bool IsPreconditionPred(const ContractStmt *);
@@ -4496,65 +4507,64 @@ class ContractSpecifierDecl final
44964507
ContractSpecifierDecl(DeclContext *DC, SourceLocation Loc,
44974508
ArrayRef<ContractStmt *> Contracts, bool IsInvalid);
44984509

4499-
void setContracts(ArrayRef<ContractStmt *> Contracts) {
4500-
assert(*getTrailingObjects<ContractStmt *>() == nullptr);
4501-
std::copy(Contracts.begin(), Contracts.end(),
4502-
getTrailingObjects<ContractStmt *>());
4503-
}
4510+
void setContracts(ArrayRef<ContractStmt *> Contracts);
45044511

45054512
using FilterRangeT = llvm::iterator_range<llvm::filter_iterator<
45064513
ArrayRef<ContractStmt *>::iterator, bool (*)(const ContractStmt *)>>;
45074514

45084515
virtual void anchor();
45094516

45104517
public:
4511-
friend class TrailingObjects;
4512-
4513-
using PreconditionRangeT = FilterRangeT;
4514-
using PostconditionRangeT = FilterRangeT;
4518+
static ContractSpecifierDecl *Create(ASTContext &C, DeclContext *DC,
4519+
SourceLocation Loc,
4520+
ArrayRef<ContractStmt *> Contracts,
4521+
bool IsInvalid);
4522+
static ContractSpecifierDecl *
4523+
CreateDeserialized(ASTContext &C, GlobalDeclID ID, unsigned NumContracts);
45154524

4525+
public:
45164526
ArrayRef<ContractStmt *> contracts() const {
45174527
return llvm::ArrayRef(getTrailingObjects<ContractStmt *>(), NumContracts);
45184528
}
45194529

4530+
/// Returns a range representing the preconditions in this contract sequence
4531+
/// (in order of declaration)
45204532
auto preconditions() const {
45214533
return llvm::make_filter_range(contracts(), IsPreconditionPred);
45224534
}
45234535

4536+
/// Returns a range representing the postconditions in this contract sequence
4537+
/// (in order of declaration).
45244538
auto postconditions() const {
45254539
return llvm::make_filter_range(contracts(), IsPostconditionPred);
45264540
}
45274541

4542+
/// Returns a range representing the result names in this contract sequence
4543+
/// (in order of declaration).
45284544
auto result_names() const {
45294545
return llvm::make_filter_range(
45304546
llvm::map_range(postconditions(), ExtractResultName),
45314547
[](ResultNameDecl *R) { return R != nullptr; });
45324548
}
45334549

4550+
/// Returns true if this function contract sequence contains result names &
4551+
/// those result names use an invented placeholder type to allow us to delay
4552+
/// the deduction of the return type.
45344553
bool hasInventedPlaceholdersTypes() const;
45354554

45364555
unsigned getNumContracts() const { return NumContracts; }
4537-
unsigned getNumPreconditions() const {
4538-
return std::distance(preconditions().begin(), preconditions().end());
4539-
}
4540-
4541-
unsigned getNumPostconditions() const {
4542-
return std::distance(postconditions().begin(), postconditions().end());
4543-
}
45444556

4557+
/// True if and only if there is a postcondition with a result name in this
4558+
/// contract sequence.
45454559
bool hasCanonicalResultName() const;
4546-
ResultNameDecl *getCanonicalResultName() const;
45474560

4548-
SourceRange getSourceRange() const override LLVM_READONLY;
4561+
/// Returns the canonical result name for this contract sequence.
4562+
const ResultNameDecl *getCanonicalResultName() const;
45494563

4550-
friend class ASTDeclReader;
4564+
/// Update the declaration context of this contract sequence and of any result name declarations contained within it.
4565+
void setOwningFunction(DeclContext *FD);
45514566

4552-
static ContractSpecifierDecl *Create(ASTContext &C, DeclContext *DC,
4553-
SourceLocation Loc,
4554-
ArrayRef<ContractStmt *> Contracts,
4555-
bool IsInvalid);
4556-
static ContractSpecifierDecl *
4557-
CreateDeserialized(ASTContext &C, GlobalDeclID ID, unsigned NumContracts);
4567+
SourceRange getSourceRange() const override LLVM_READONLY;
45584568

45594569
static bool classof(const Decl *D) { return classofKind(D->getKind()); }
45604570
static bool classofKind(Kind K) { return K == Decl::ContractSpecifier; }

clang/include/clang/Basic/LangOptions.def

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -160,7 +160,6 @@ LANGOPT(GNUAsm , 1, 1, "GNU-style inline assembly")
160160
LANGOPT(Coroutines , 1, 0, "C++20 coroutines")
161161
LANGOPT(Contracts , 1, 1, "C++2c contracts")
162162
LANGOPT(ContractExceptions, 1, 1, "Contracts report a violation on exception")
163-
LANGOPT(LateParsedContracts, 1, 0, "Late Parse function contracts")
164163
LANGOPT(CoroAlignedAllocation, 1, 0, "prefer Aligned Allocation according to P2014 Option 2")
165164
LANGOPT(DllExportInlines , 1, 1, "dllexported classes dllexport inline methods")
166165
LANGOPT(RelaxedTemplateTemplateArgs, 1, 1, "C++17 relaxed matching of template template arguments")

clang/include/clang/Driver/Options.td

Lines changed: 0 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1703,12 +1703,6 @@ defm contract_exceptions : BoolFOption<"contract-exceptions",
17031703
"Enable contract violation on exception">,
17041704
NegFlag<SetFalse, [], [ClangOption, CC1Option],
17051705
"Disable contract violations on exception">>;
1706-
defm late_parsed_contracts : BoolFOption<"late-parsed-contracts",
1707-
LangOpts<"LateParsedContracts">, DefaultFalse,
1708-
PosFlag<SetTrue, [], [ClangOption, CC1Option],
1709-
"Enable contract violation on exception">,
1710-
NegFlag<SetFalse, [], [ClangOption, CC1Option],
1711-
"Disable contract violations on exception">>;
17121706
// C++ Coroutines
17131707
defm coroutines : BoolFOption<"coroutines",
17141708
LangOpts<"Coroutines">, Default<cpp20.KeyPath>,

clang/include/clang/Sema/DeclSpec.h

Lines changed: 3 additions & 47 deletions
Original file line numberDiff line numberDiff line change
@@ -2137,6 +2137,9 @@ class Declarator {
21372137
CommaLoc = SourceLocation();
21382138
EllipsisLoc = SourceLocation();
21392139
PackIndexingExpr = nullptr;
2140+
Contracts = nullptr;
2141+
assert(LateParsedContracts.empty() && "Late-parsed contracts unhandled");
2142+
LateParsedContracts.clear();
21402143
}
21412144

21422145
/// mayOmitIdentifier - Return true if the identifier is either optional or
@@ -2800,53 +2803,6 @@ struct FieldDeclarator {
28002803
BitfieldSize(nullptr) {}
28012804
};
28022805

2803-
class ContractSpecifiers {
2804-
public:
2805-
enum Specifier { CS_None = 0, CS_Pre, CS_Post };
2806-
2807-
struct ContractInfo {
2808-
Specifier Kind;
2809-
// Either the parsed expression or token soup for the contract.
2810-
const IdentifierInfo *ReturnValueIdent;
2811-
SourceLocation ReturnValueIdentLoc;
2812-
2813-
Expr *ParsedContract;
2814-
std::unique_ptr<CachedTokens> ContractTokens;
2815-
2816-
public:
2817-
ContractInfo(Specifier Kind, const IdentifierInfo *ReturnValueIdent,
2818-
SourceLocation ReturnValueIdentLoc, Expr *ParsedContract,
2819-
std::unique_ptr<CachedTokens> xContractTokens)
2820-
: Kind(Kind), ReturnValueIdent(ReturnValueIdent),
2821-
ReturnValueIdentLoc(ReturnValueIdentLoc),
2822-
ParsedContract(ParsedContract),
2823-
ContractTokens(std::move(xContractTokens)) {
2824-
2825-
assert(Kind == CS_Post || ReturnValueIdent == nullptr);
2826-
assert((ContractTokens == nullptr) != (ParsedContract == nullptr));
2827-
}
2828-
2829-
bool isDelayed() const {
2830-
assert(ParsedContract == nullptr || ContractTokens == nullptr);
2831-
return ContractTokens != nullptr;
2832-
}
2833-
bool isPre() const { return Kind == CS_Pre; }
2834-
bool isPost() const { return Kind == CS_Post; }
2835-
bool hasReturnIdentifier() const { return ReturnValueIdent != nullptr; }
2836-
};
2837-
2838-
void addContract(ContractInfo CI) { Contracts.push_back(std::move(CI)); }
2839-
2840-
const SmallVectorImpl<ContractInfo> &getContracts() const {
2841-
return Contracts;
2842-
}
2843-
2844-
bool hasContracts() const { return !Contracts.empty(); }
2845-
2846-
private:
2847-
SmallVector<ContractInfo, 2> Contracts;
2848-
};
2849-
28502806
/// Represents a C++11 virt-specifier-seq.
28512807
class VirtSpecifiers {
28522808
public:

clang/include/clang/Sema/Sema.h

Lines changed: 13 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -2746,29 +2746,34 @@ class Sema final : public SemaBase {
27462746

27472747
ContractSpecifierDecl *
27482748
BuildContractSpecifierDecl(ArrayRef<ContractStmt *> Contracts,
2749-
SourceLocation Loc, bool IsInvalid);
2749+
DeclContext *DC, SourceLocation Loc,
2750+
bool IsInvalid);
27502751

27512752
// Check two function declarations for equivalent contract sequences.
27522753
// Return true if a diagnostic was issued, false otherwise.
27532754
bool CheckEquivalentContractSequence(FunctionDecl *OrigDecl,
27542755
FunctionDecl *NewDecl);
2756+
bool CheckContractsOnRedeclaration(FunctionDecl *OrigDecl,
2757+
FunctionDecl *NewDecl);
2758+
2759+
2760+
/// Perform semantic analysis for a contract specifier on the specified function.
2761+
/// For function templates, these checks should be performed with the instantiation of
2762+
/// the body, and not the declaration.
2763+
void CheckFunctionContracts(FunctionDecl *FD, bool IsDefinition,
2764+
bool IsInstantiation);
27552765

27562766
// FIXME(EricWF): Remove me. These are just convinence hooks while I move
27572767
// things around in the implementation.
27582768
ContractSpecifierDecl *
27592769
ActOnFinishContractSpecifierSequence(ArrayRef<ContractStmt *> ContractStmts,
27602770
SourceLocation Loc, bool IsInvalid);
27612771

2762-
void CheckFunctionContractSpecifier(FunctionDecl *FD);
2763-
2764-
void ActOnContractsOnStartOfFunctionDef(Scope *S, FunctionDecl *FD);
27652772
void ActOnContractsOnFinishFunctionDecl(FunctionDecl *FD, bool IsDefinition);
27662773
void ActOnContractsOnFinishFunctionBody(FunctionDecl *FD);
2767-
void ActOnContractsOnMergeFunctionDecl(FunctionDecl *OrigDecl,
2768-
FunctionDecl *NewDecl);
27692774

2770-
/// Rebuild the contract specifier written on one declaration in the context
2771-
/// of a the definition. This rebinds parameters and result names as needed.
2775+
/// Rebuild the contract specifier against another declaration of the function
2776+
/// (using the new functions parameters)
27722777
ContractSpecifierDecl *
27732778
RebuildContractSpecifierForDecl(FunctionDecl *FirstDecl,
27742779
FunctionDecl *Definition);
@@ -13916,11 +13921,6 @@ class Sema final : public SemaBase {
1391613921
LocalInstantiationScope &Scope,
1391713922
const MultiLevelTemplateArgumentList &TemplateArgs);
1391813923

13919-
bool addInstantiatedResultNamesToScope(
13920-
FunctionDecl *Function, const FunctionDecl *PatternDecl,
13921-
LocalInstantiationScope &Scope,
13922-
const MultiLevelTemplateArgumentList &TemplateArgs);
13923-
1392413924
int ParsingClassDepth = 0;
1392513925

1392613926
class SavePendingParsedClassStateRAII {

clang/lib/AST/Decl.cpp

Lines changed: 1 addition & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -2025,29 +2025,7 @@ void DeclaratorDecl::setContracts(ContractSpecifierDecl *NewContracts) {
20252025
getExtInfo()->TInfo = savedTInfo;
20262026
}
20272027

2028-
// FIXME(EricWF): This should be empty already
2029-
auto &Contracts = getExtInfo()->Contracts;
2030-
2031-
#if 0
2032-
assert(
2033-
Contracts.empty() || NewContracts.size() == Contracts.size() ||
2034-
NewContracts.empty() ||
2035-
this->isInvalidDecl() &&
2036-
"Adding a different amount of contracts than were initially present");
2037-
#endif
2038-
ERICWF_DEBUG_BLOCK_QUIET {
2039-
if (Contracts && NewContracts && !NewContracts->isInvalidDecl()) {
2040-
if (Contracts != NewContracts &&
2041-
Contracts->getNumContracts() != NewContracts->getNumContracts()) {
2042-
llvm::errs() << "\n\nOverwriting existing contracts!!!\n";
2043-
Contracts->dumpColor();
2044-
NewContracts->dumpColor();
2045-
llvm::errs() << "\n\n==============================\n\n";
2046-
}
2047-
}
2048-
}
2049-
2050-
Contracts = NewContracts;
2028+
getExtInfo()->Contracts = NewContracts;
20512029
}
20522030

20532031
void DeclaratorDecl::setTemplateParameterListsInfo(

0 commit comments

Comments
 (0)