@@ -99,67 +99,98 @@ static QualType lookupPromiseType(Sema &S, const FunctionProtoType *FnType,
99
99
return PromiseType;
100
100
}
101
101
102
- // / Check that this is a context in which a coroutine suspension can appear.
103
- static FunctionScopeInfo *
104
- checkCoroutineContext (Sema &S, SourceLocation Loc, StringRef Keyword) {
102
+ static bool isValidCoroutineContext (Sema &S, SourceLocation Loc,
103
+ StringRef Keyword) {
105
104
// 'co_await' and 'co_yield' are not permitted in unevaluated operands.
106
105
if (S.isUnevaluatedContext ()) {
107
106
S.Diag (Loc, diag::err_coroutine_unevaluated_context) << Keyword;
108
- return nullptr ;
107
+ return false ;
109
108
}
110
109
111
110
// Any other usage must be within a function.
112
- // FIXME: Reject a coroutine with a deduced return type.
113
111
auto *FD = dyn_cast<FunctionDecl>(S.CurContext );
114
112
if (!FD) {
115
113
S.Diag (Loc, isa<ObjCMethodDecl>(S.CurContext )
116
114
? diag::err_coroutine_objc_method
117
115
: diag::err_coroutine_outside_function) << Keyword;
118
- } else if (isa<CXXConstructorDecl>(FD) || isa<CXXDestructorDecl>(FD)) {
119
- // Coroutines TS [special]/6:
120
- // A special member function shall not be a coroutine.
121
- //
122
- // FIXME: We assume that this really means that a coroutine cannot
123
- // be a constructor or destructor.
124
- S.Diag (Loc, diag::err_coroutine_ctor_dtor)
125
- << isa<CXXDestructorDecl>(FD) << Keyword;
126
- } else if (FD->isConstexpr ()) {
127
- S.Diag (Loc, diag::err_coroutine_constexpr) << Keyword;
128
- } else if (FD->isVariadic ()) {
129
- S.Diag (Loc, diag::err_coroutine_varargs) << Keyword;
130
- } else if (FD->isMain ()) {
131
- S.Diag (FD->getLocStart (), diag::err_coroutine_main);
132
- S.Diag (Loc, diag::note_declared_coroutine_here)
133
- << (Keyword == " co_await" ? 0 :
134
- Keyword == " co_yield" ? 1 : 2 );
135
- } else {
136
- auto *ScopeInfo = S.getCurFunction ();
137
- assert (ScopeInfo && " missing function scope for function" );
138
-
139
- // If we don't have a promise variable, build one now.
140
- if (!ScopeInfo->CoroutinePromise ) {
141
- QualType T =
142
- FD->getType ()->isDependentType ()
143
- ? S.Context .DependentTy
144
- : lookupPromiseType (S, FD->getType ()->castAs <FunctionProtoType>(),
145
- Loc);
146
- if (T.isNull ())
147
- return nullptr ;
148
-
149
- // Create and default-initialize the promise.
150
- ScopeInfo->CoroutinePromise =
151
- VarDecl::Create (S.Context , FD, FD->getLocation (), FD->getLocation (),
152
- &S.PP .getIdentifierTable ().get (" __promise" ), T,
153
- S.Context .getTrivialTypeSourceInfo (T, Loc), SC_None);
154
- S.CheckVariableDeclarationType (ScopeInfo->CoroutinePromise );
155
- if (!ScopeInfo->CoroutinePromise ->isInvalidDecl ())
156
- S.ActOnUninitializedDecl (ScopeInfo->CoroutinePromise , false );
157
- }
116
+ return false ;
117
+ }
118
+
119
+ // An enumeration for mapping the diagnostic type to the correct diagnostic
120
+ // selection index.
121
+ enum InvalidFuncDiag {
122
+ DiagCtor = 0 ,
123
+ DiagDtor,
124
+ DiagCopyAssign,
125
+ DiagMoveAssign,
126
+ DiagMain,
127
+ DiagConstexpr,
128
+ DiagAutoRet,
129
+ DiagVarargs,
130
+ };
131
+ bool Diagnosed = false ;
132
+ auto DiagInvalid = [&](InvalidFuncDiag ID) {
133
+ S.Diag (Loc, diag::err_coroutine_invalid_func_context) << ID << Keyword;
134
+ Diagnosed = true ;
135
+ return false ;
136
+ };
137
+
138
+ // Diagnose when a constructor, destructor, copy/move assignment operator,
139
+ // or the function 'main' are declared as a coroutine.
140
+ auto *MD = dyn_cast<CXXMethodDecl>(FD);
141
+ if (MD && isa<CXXConstructorDecl>(MD))
142
+ return DiagInvalid (DiagCtor);
143
+ else if (MD && isa<CXXDestructorDecl>(MD))
144
+ return DiagInvalid (DiagDtor);
145
+ else if (MD && MD->isCopyAssignmentOperator ())
146
+ return DiagInvalid (DiagCopyAssign);
147
+ else if (MD && MD->isMoveAssignmentOperator ())
148
+ return DiagInvalid (DiagMoveAssign);
149
+ else if (FD->isMain ())
150
+ return DiagInvalid (DiagMain);
151
+
152
+ // Emit a diagnostics for each of the following conditions which is not met.
153
+ if (FD->isConstexpr ())
154
+ DiagInvalid (DiagConstexpr);
155
+ if (FD->getReturnType ()->isUndeducedType ())
156
+ DiagInvalid (DiagAutoRet);
157
+ if (FD->isVariadic ())
158
+ DiagInvalid (DiagVarargs);
159
+
160
+ return !Diagnosed;
161
+ }
162
+
163
+ // / Check that this is a context in which a coroutine suspension can appear.
164
+ static FunctionScopeInfo *checkCoroutineContext (Sema &S, SourceLocation Loc,
165
+ StringRef Keyword) {
166
+ if (!isValidCoroutineContext (S, Loc, Keyword))
167
+ return nullptr ;
158
168
159
- return ScopeInfo;
169
+ assert (isa<FunctionDecl>(S.CurContext ) && " not in a function scope" );
170
+ auto *FD = cast<FunctionDecl>(S.CurContext );
171
+ auto *ScopeInfo = S.getCurFunction ();
172
+ assert (ScopeInfo && " missing function scope for function" );
173
+
174
+ // If we don't have a promise variable, build one now.
175
+ if (!ScopeInfo->CoroutinePromise ) {
176
+ QualType T = FD->getType ()->isDependentType ()
177
+ ? S.Context .DependentTy
178
+ : lookupPromiseType (
179
+ S, FD->getType ()->castAs <FunctionProtoType>(), Loc);
180
+ if (T.isNull ())
181
+ return nullptr ;
182
+
183
+ // Create and default-initialize the promise.
184
+ ScopeInfo->CoroutinePromise =
185
+ VarDecl::Create (S.Context , FD, FD->getLocation (), FD->getLocation (),
186
+ &S.PP .getIdentifierTable ().get (" __promise" ), T,
187
+ S.Context .getTrivialTypeSourceInfo (T, Loc), SC_None);
188
+ S.CheckVariableDeclarationType (ScopeInfo->CoroutinePromise );
189
+ if (!ScopeInfo->CoroutinePromise ->isInvalidDecl ())
190
+ S.ActOnUninitializedDecl (ScopeInfo->CoroutinePromise , false );
160
191
}
161
192
162
- return nullptr ;
193
+ return ScopeInfo ;
163
194
}
164
195
165
196
static Expr *buildBuiltinCall (Sema &S, SourceLocation Loc, Builtin::ID Id,
0 commit comments