Skip to content

Commit c6eac65

Browse files
committed
get constification working for "this"
1 parent acd41cd commit c6eac65

File tree

10 files changed

+73
-63
lines changed

10 files changed

+73
-63
lines changed

clang/include/clang/Basic/Builtins.td

Lines changed: 0 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -2617,24 +2617,6 @@ def SetJmpEx : MSLibBuiltin<"setjmpex.h"> {
26172617
let Prototype = "int(jmp_buf)";
26182618
}
26192619

2620-
// C++ contracts
2621-
def ContractViolation : Builtin {
2622-
let Spellings = ["handle_contract_violation"];
2623-
let Prototype = "void()";
2624-
let Attributes = [NoThrow, NoReturn, Constexpr];
2625-
}
2626-
2627-
def UnnamedConstant : Builtin {
2628-
let Spellings = ["__builtin_unnamed_constant"];
2629-
let Prototype = "void(...)";
2630-
let Attributes = [NoThrow, CustomTypeChecking, Constexpr];
2631-
}
2632-
2633-
def CurrentContractEvaluationSemantic : Builtin {
2634-
let Spellings = ["__builtin_contract_evaluation_semantic"];
2635-
let Prototype = "int()";
2636-
let Attributes = [NoThrow, Constexpr];
2637-
}
26382620

26392621
// C99 library functions
26402622
// C99 stdarg.h

clang/include/clang/Basic/LangOptions.h

Lines changed: 0 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -533,10 +533,6 @@ class LangOptions : public LangOptionsBase {
533533
/// A prefix map for __FILE__, __BASE_FILE__ and __builtin_FILE().
534534
std::map<std::string, std::string, std::greater<std::string>> MacroPrefixMap;
535535

536-
/// A map from a "contract group" or "contract subgroup" to the value
537-
/// indicating whether the group is enabled or disabled from the command line.
538-
std::unordered_map<std::string, bool> EnabledContractGroups;
539-
540536
/// Triples of the OpenMP targets that the host code codegen should
541537
/// take into account in order to generate accurate offloading descriptors.
542538
std::vector<llvm::Triple> OMPTargetTriples;

clang/include/clang/Driver/Options.td

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1681,7 +1681,7 @@ def fcontract_evaluation_semantic_EQ : Joined<["-"], "fcontract-evaluation-seman
16811681
Visibility<[ClangOption, CC1Option]>,
16821682
NormalizedValuesScope<"LangOptions::ContractEvaluationSemantic">,
16831683
NormalizedValues<["Ignore", "Enforce", "Observe", "QuickEnforce"]>,
1684-
MarshallingInfoEnum<LangOpts<"ContractEvalSemantic">, "Enforce">;
1684+
MarshallingInfoEnum<LangOpts<"ContractOptions.DefaultSemantic">, "Enforce">;
16851685

16861686
def fcontract_group_evaluation_semantic_EQ : CommaJoined<["-"], "fcontract-group-evaluation-semantic=">,
16871687
Visibility<[ClangOption, CC1Option]>,

clang/include/clang/Sema/Sema.h

Lines changed: 11 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -2741,7 +2741,16 @@ class Sema final : public SemaBase {
27412741
StmtResult BuildContractStmt(ContractKind CK, SourceLocation KeywordLoc,
27422742
Expr *Cond, DeclStmt *ResultNameDecl,
27432743
ArrayRef<const Attr *> Attrs);
2744+
struct ContractScopeRAII {
2745+
ContractScopeRAII(Sema &S);
2746+
~ContractScopeRAII();
27442747

2748+
ContractScopeRAII(ContractScopeRAII const &) = delete;
2749+
2750+
Sema *S;
2751+
QualType OldCXXThisType;
2752+
bool OldIsContractScope;
2753+
};
27452754
///@}
27462755

27472756
//
@@ -6369,7 +6378,6 @@ class Sema final : public SemaBase {
63696378
EK_Decltype,
63706379
EK_TemplateArgument,
63716380
EK_BoundsAttrArgument,
6372-
EK_ContractStmt,
63736381
EK_Other
63746382
} ExprContext;
63756383

@@ -6459,10 +6467,7 @@ class Sema final : public SemaBase {
64596467
InDiscardedStatement);
64606468
}
64616469

6462-
bool isContractStatementContext() const {
6463-
6464-
return InContractStatement || ExprContext == EK_ContractStmt;
6465-
}
6470+
bool isContractStatementContext() const { return InContractStatement; }
64666471
};
64676472

64686473
const ExpressionEvaluationContextRecord &currentEvaluationContext() const {
@@ -6494,10 +6499,7 @@ class Sema final : public SemaBase {
64946499
}
64956500

64966501
bool isContractStmtContext() const {
6497-
return ExprEvalContexts.back().ExprContext ==
6498-
ExpressionEvaluationContextRecord::ExpressionKind::
6499-
EK_ContractStmt ||
6500-
ExprEvalContexts.back().InContractStatement;
6502+
return ExprEvalContexts.back().InContractStatement;
65016503
}
65026504

65036505
/// Increment when we find a reference; decrement when we find an ignored

clang/lib/Parse/ParseDeclCXX.cpp

Lines changed: 4 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -4421,13 +4421,6 @@ StmtResult Parser::ParseFunctionContractSpecifier(Declarator &DeclaratorInfo) {
44214421
ParsedAttributes CXX11Attrs(AttrFactory);
44224422
MaybeParseCXX11Attributes(CXX11Attrs);
44234423

4424-
using ExpressionKind =
4425-
Sema::ExpressionEvaluationContextRecord::ExpressionKind;
4426-
EnterExpressionEvaluationContext EC(
4427-
Actions, Sema::ExpressionEvaluationContext::PotentiallyEvaluated, nullptr,
4428-
ExpressionKind::EK_ContractStmt);
4429-
Actions.currentEvaluationContext().InContractStatement = true;
4430-
44314424
if (Tok.isNot(tok::l_paren)) {
44324425
Diag(Tok, diag::err_expected_lparen_after) << CKStr;
44334426
SkipUntil({tok::equal, tok::l_brace, tok::arrow, tok::kw_try, tok::comma,
@@ -4449,8 +4442,12 @@ StmtResult Parser::ParseFunctionContractSpecifier(Declarator &DeclaratorInfo) {
44494442
Scope::FunctionPrototypeScope |
44504443
Scope::ContractAssertScope);
44514444

4445+
EnterExpressionEvaluationContext EC(
4446+
Actions, Sema::ExpressionEvaluationContext::PotentiallyEvaluated);
4447+
44524448
std::optional<Sema::CXXThisScopeRAII> ThisScope;
44534449
InitCXXThisScopeForDeclaratorIfRelevant(DeclaratorInfo, DeclaratorInfo.getDeclSpec(), ThisScope);
4450+
Sema::ContractScopeRAII ContractExpressionScope(Actions);
44544451

44554452
DeclaratorChunk::FunctionTypeInfo FTI = DeclaratorInfo.getFunctionTypeInfo();
44564453

clang/lib/Parse/ParseStmt.cpp

Lines changed: 1 addition & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -2440,13 +2440,7 @@ StmtResult Parser::ParseContractAssertStatement() {
24402440
SourceLocation KeywordLoc = ConsumeToken(); // eat the 'contract_assert'.
24412441

24422442
// Adjust the scope for the purposes of constification.
2443-
EnterContractAssertScopeRAII EnterCAS(getCurScope());
2444-
using ExpressionKind =
2445-
Sema::ExpressionEvaluationContextRecord::ExpressionKind;
2446-
EnterExpressionEvaluationContext EC(
2447-
Actions, Sema::ExpressionEvaluationContext::PotentiallyEvaluated, nullptr,
2448-
ExpressionKind::EK_ContractStmt);
2449-
Actions.currentEvaluationContext().InContractStatement = true;
2443+
Sema::ContractScopeRAII ContractScope(Actions);
24502444

24512445
ParsedAttributes CXX11Attrs(AttrFactory);
24522446
MaybeParseCXX11Attributes(CXX11Attrs);

clang/lib/Sema/SemaContract.cpp

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -201,3 +201,17 @@ StmtResult Sema::ActOnResultNameDeclarator(Scope *S, Declarator &FuncDecl,
201201

202202
return ActOnDeclStmt(ConvertDeclToDeclGroup(New), IDLoc, IDLoc);
203203
}
204+
205+
Sema::ContractScopeRAII::ContractScopeRAII(Sema &SemaRef)
206+
: S(&SemaRef), OldCXXThisType(SemaRef.CXXThisTypeOverride),
207+
OldIsContractScope(SemaRef.ExprEvalContexts.back().InContractStatement) {
208+
QualType NewT = S->CXXThisTypeOverride;
209+
210+
S->CXXThisTypeOverride = NewT;
211+
S->ExprEvalContexts.back().InContractStatement = true;
212+
}
213+
214+
Sema::ContractScopeRAII::~ContractScopeRAII() {
215+
S->CXXThisTypeOverride = OldCXXThisType;
216+
S->ExprEvalContexts.back().InContractStatement = OldIsContractScope;
217+
}

clang/lib/Sema/SemaExprCXX.cpp

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1112,6 +1112,18 @@ bool Sema::CheckCXXThrowOperand(SourceLocation ThrowLoc,
11121112
return false;
11131113
}
11141114

1115+
static QualType adjustCVQualifiersForCXXThisWithinContract(QualType ThisTy,
1116+
ASTContext &ASTCtx) {
1117+
QualType ClassType = ThisTy->getPointeeType();
1118+
if (not ClassType.isConstQualified()) {
1119+
// If the 'this' object is const-qualified, we need to remove the
1120+
// const-qualification for the contract check.
1121+
ClassType.addConst();
1122+
return ASTCtx.getPointerType(ClassType);
1123+
}
1124+
return ThisTy;
1125+
}
1126+
11151127
static QualType adjustCVQualifiersForCXXThisWithinLambda(
11161128
ArrayRef<FunctionScopeInfo *> FunctionScopes, QualType ThisTy,
11171129
DeclContext *CurSemaContext, ASTContext &ASTCtx) {
@@ -1247,6 +1259,9 @@ QualType Sema::getCurrentThisType() {
12471259
if (!ThisTy.isNull() && isLambdaCallOperator(CurContext))
12481260
return adjustCVQualifiersForCXXThisWithinLambda(FunctionScopes, ThisTy,
12491261
CurContext, Context);
1262+
if (!ThisTy.isNull() && currentEvaluationContext().InContractStatement) {
1263+
return adjustCVQualifiersForCXXThisWithinContract(ThisTy, Context);
1264+
}
12501265
return ThisTy;
12511266
}
12521267

clang/lib/Sema/TreeTransform.h

Lines changed: 1 addition & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -1609,11 +1609,7 @@ class TreeTransform {
16091609
StmtResult RebuildContractStmt(ContractKind K, SourceLocation KeywordLoc,
16101610
Expr *Cond, DeclStmt *ResultName,
16111611
ArrayRef<const Attr *> Attrs) {
1612-
const bool LastVal =
1613-
getSema().currentEvaluationContext().InContractStatement;
1614-
getSema().currentEvaluationContext().InContractStatement = true;
16151612
return getSema().BuildContractStmt(K, KeywordLoc, Cond, ResultName, Attrs);
1616-
getSema().currentEvaluationContext().InContractStatement = LastVal;
16171613
}
16181614

16191615
/// Build a new Objective-C \@try statement.
@@ -8589,21 +8585,10 @@ TreeTransform<Derived>::TransformCoyieldExpr(CoyieldExpr *E) {
85898585

85908586
// C++ Contract Statements
85918587

8592-
struct ValueGuard {
8593-
ValueGuard(bool *Value, bool NewValue) : Value(Value), OldVal(*Value) {
8594-
*Value = NewValue;
8595-
}
8596-
~ValueGuard() { *Value = OldVal; }
8597-
8598-
bool *Value;
8599-
bool OldVal;
8600-
};
8601-
86028588
template <typename Derived>
86038589
StmtResult TreeTransform<Derived>::TransformContractStmt(ContractStmt *S) {
86048590

8605-
ValueGuard InContractGuard(
8606-
&SemaRef.currentEvaluationContext().InContractStatement, true);
8591+
Sema::ContractScopeRAII ContractScope(getSema());
86078592

86088593
StmtResult NewResultName;
86098594
if (S->hasResultNameDecl()) {

clang/test/SemaCXX/ericwf.cpp

Lines changed: 26 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,31 @@
33

44
void foo(int x) {
55
int y = x;
6-
contract_assert(++y);
6+
contract_assert(++y); // expected-error {{read-only variable is not assignable}}
7+
contract_assert(y++); // expected-error {{read-only variable is not assignable}}
78
++y;
89
}
10+
11+
12+
template <class T>
13+
void bar(T v) {
14+
contract_assert(v);
15+
contract_assert(v++); // expected-error {{read-only variable is not assignable}}
16+
contract_assert(++v); // expected-error {{read-only variable is not assignable}}
17+
}
18+
19+
template void bar<int>(int); // expected-note {{requested here}}
20+
21+
int g = 42;
22+
23+
struct A {
24+
void a(int x) {
25+
contract_assert(b()); // expected-error {{this' argument to member function 'b' has type 'const A', but function is not marked const}}
26+
contract_assert(z++); // expected-error {{read-only variable is not assignable}}
27+
contract_assert(++g); // OK
28+
contract_assert(const_cast<decltype(this)>(this)->b()); // OK
29+
}
30+
31+
int b() {} // expected-note {{declared here}}
32+
int z;
33+
};

0 commit comments

Comments
 (0)