Skip to content

Commit 65f6611

Browse files
committed
[Clang] Functions called in discarded statements should not be instantiated
Functions referenced in discarded statements could be treated as odr-used because we did not properly set the correct evaluation context in some places. Fixes #140449
1 parent 78af0f3 commit 65f6611

File tree

6 files changed

+60
-29
lines changed

6 files changed

+60
-29
lines changed

clang/docs/ReleaseNotes.rst

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -738,6 +738,7 @@ Bug Fixes to C++ Support
738738
- Fixed a function declaration mismatch that caused inconsistencies between concepts and variable template declarations. (#GH139476)
739739
- Clang no longer segfaults when there is a configuration mismatch between modules and their users (http://crbug.com/400353616).
740740
- Fix an incorrect deduction when calling an explicit object member function template through an overload set address.
741+
- Clang could incorrectly instantiate functions in discarded contexts (#GH140449)
741742

742743
Bug Fixes to AST Handling
743744
^^^^^^^^^^^^^^^^^^^^^^^^^

clang/include/clang/Sema/Sema.h

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -6825,8 +6825,9 @@ class Sema final : public SemaBase {
68256825

68266826
bool isDiscardedStatementContext() const {
68276827
return Context == ExpressionEvaluationContext::DiscardedStatement ||
6828-
(Context ==
6829-
ExpressionEvaluationContext::ImmediateFunctionContext &&
6828+
((Context ==
6829+
ExpressionEvaluationContext::ImmediateFunctionContext ||
6830+
isPotentiallyEvaluated()) &&
68306831
InDiscardedStatement);
68316832
}
68326833
};

clang/lib/Sema/SemaCoroutine.cpp

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -699,6 +699,9 @@ bool Sema::ActOnCoroutineBodyStart(Scope *SC, SourceLocation KWLoc,
699699
// Ignore previous expr evaluation contexts.
700700
EnterExpressionEvaluationContext PotentiallyEvaluated(
701701
*this, Sema::ExpressionEvaluationContext::PotentiallyEvaluated);
702+
703+
ExprEvalContexts.back().InDiscardedStatement = false;
704+
702705
if (!checkCoroutineContext(*this, KWLoc, Keyword))
703706
return false;
704707
auto *ScopeInfo = getCurFunction();

clang/lib/Sema/SemaDecl.cpp

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -15885,6 +15885,9 @@ Decl *Sema::ActOnStartOfFunctionDef(Scope *FnBodyScope, Decl *D,
1588515885
ExprEvalContexts.back().InImmediateEscalatingFunctionContext =
1588615886
getLangOpts().CPlusPlus20 && FD->isImmediateEscalating();
1588715887

15888+
// A function that is not a lambda is never in a discarded statement
15889+
ExprEvalContexts.back().InDiscardedStatement = false;
15890+
1588815891
// Check for defining attributes before the check for redefinition.
1588915892
if (const auto *Attr = FD->getAttr<AliasAttr>()) {
1589015893
Diag(Attr->getLocation(), diag::err_alias_is_definition) << FD << 0;

clang/lib/Sema/SemaExpr.cpp

Lines changed: 17 additions & 27 deletions
Original file line numberDiff line numberDiff line change
@@ -18361,35 +18361,23 @@ enum class OdrUseContext {
1836118361
/// Are we within a context in which references to resolved functions or to
1836218362
/// variables result in odr-use?
1836318363
static OdrUseContext isOdrUseContext(Sema &SemaRef) {
18364-
OdrUseContext Result;
18364+
const Sema::ExpressionEvaluationContextRecord &Context =
18365+
SemaRef.currentEvaluationContext();
1836518366

18366-
switch (SemaRef.ExprEvalContexts.back().Context) {
18367-
case Sema::ExpressionEvaluationContext::Unevaluated:
18368-
case Sema::ExpressionEvaluationContext::UnevaluatedList:
18369-
case Sema::ExpressionEvaluationContext::UnevaluatedAbstract:
18370-
return OdrUseContext::None;
18371-
18372-
case Sema::ExpressionEvaluationContext::ConstantEvaluated:
18373-
case Sema::ExpressionEvaluationContext::ImmediateFunctionContext:
18374-
case Sema::ExpressionEvaluationContext::PotentiallyEvaluated:
18375-
Result = OdrUseContext::Used;
18376-
break;
18377-
18378-
case Sema::ExpressionEvaluationContext::DiscardedStatement:
18379-
Result = OdrUseContext::FormallyOdrUsed;
18380-
break;
18381-
18382-
case Sema::ExpressionEvaluationContext::PotentiallyEvaluatedIfUsed:
18383-
// A default argument formally results in odr-use, but doesn't actually
18384-
// result in a use in any real sense until it itself is used.
18385-
Result = OdrUseContext::FormallyOdrUsed;
18386-
break;
18387-
}
18367+
if (Context.isUnevaluated())
18368+
return OdrUseContext::None;
1838818369

1838918370
if (SemaRef.CurContext->isDependentContext())
1839018371
return OdrUseContext::Dependent;
1839118372

18392-
return Result;
18373+
if (Context.isDiscardedStatementContext())
18374+
return OdrUseContext::FormallyOdrUsed;
18375+
18376+
else if (Context.Context ==
18377+
Sema::ExpressionEvaluationContext::PotentiallyEvaluatedIfUsed)
18378+
return OdrUseContext::FormallyOdrUsed;
18379+
18380+
return OdrUseContext::Used;
1839318381
}
1839418382

1839518383
static bool isImplicitlyDefinableConstexprFunction(FunctionDecl *Func) {
@@ -20356,9 +20344,11 @@ MarkExprReferenced(Sema &SemaRef, SourceLocation Loc, Decl *D, Expr *E,
2035620344
}
2035720345

2035820346
void Sema::MarkDeclRefReferenced(DeclRefExpr *E, const Expr *Base) {
20359-
// TODO: update this with DR# once a defect report is filed.
20360-
// C++11 defect. The address of a pure member should not be an ODR use, even
20361-
// if it's a qualified reference.
20347+
// [basic.def.odr] (CWG 1614)
20348+
// A function is named by an expression or conversion [...]
20349+
// unless it is a pure virtual function and either the expression is not an
20350+
// id-expression naming the function with an explicitly qualified name or
20351+
// the expression forms a pointer to member
2036220352
bool OdrUse = true;
2036320353
if (const CXXMethodDecl *Method = dyn_cast<CXXMethodDecl>(E->getDecl()))
2036420354
if (Method->isVirtual() &&

clang/test/CXX/stmt.stmt/stmt.select/stmt.if/p2.cpp

Lines changed: 33 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -177,4 +177,37 @@ void f() {
177177
}
178178
} // namespace deduced_return_type_in_discareded_statement
179179

180+
namespace GH140449 {
181+
182+
template <typename T>
183+
int f() {
184+
T *ptr;
185+
return 0;
186+
}
187+
188+
template <typename T>
189+
constexpr int g() {
190+
T *ptr; // expected-error{{'ptr' declared as a pointer to a reference of type 'int &'}}
191+
return 0;
192+
}
193+
194+
template <typename T>
195+
auto h() {
196+
T *ptr; // expected-error{{'ptr' declared as a pointer to a reference of type 'int &'}}
197+
return 0;
198+
}
199+
200+
void test() {
201+
if constexpr (false) {
202+
int x = f<int &>();
203+
constexpr int y = g<int &>();
204+
// expected-error@-1 {{constexpr variable 'y' must be initialized by a constant expression}} \
205+
// expected-note@-1{{in instantiation of function template specialization}}
206+
int z = h<int &>();
207+
// expected-note@-1{{in instantiation of function template specialization}}
208+
209+
}
210+
}
211+
}
212+
180213
#endif

0 commit comments

Comments
 (0)