|
12 | 12 | #include "clang/Sema/SemaLambda.h"
|
13 | 13 | #include "TypeLocBuilder.h"
|
14 | 14 | #include "clang/AST/ASTLambda.h"
|
| 15 | +#include "clang/AST/CXXInheritance.h" |
15 | 16 | #include "clang/AST/ExprCXX.h"
|
16 | 17 | #include "clang/Basic/TargetInfo.h"
|
17 | 18 | #include "clang/Sema/DeclSpec.h"
|
@@ -386,30 +387,69 @@ buildTypeForLambdaCallOperator(Sema &S, clang::CXXRecordDecl *Class,
|
386 | 387 | // parameter, if any, of the lambda's function call operator (possibly
|
387 | 388 | // instantiated from a function call operator template) shall be either:
|
388 | 389 | // - the closure type,
|
389 |
| -// - class type derived from the closure type, or |
| 390 | +// - class type publicly and unambiguously derived from the closure type, or |
390 | 391 | // - a reference to a possibly cv-qualified such type.
|
391 |
| -void Sema::DiagnoseInvalidExplicitObjectParameterInLambda( |
392 |
| - CXXMethodDecl *Method) { |
| 392 | +bool Sema::DiagnoseInvalidExplicitObjectParameterInLambda( |
| 393 | + CXXMethodDecl *Method, SourceLocation CallLoc) { |
393 | 394 | if (!isLambdaCallWithExplicitObjectParameter(Method))
|
394 |
| - return; |
| 395 | + return false; |
395 | 396 | CXXRecordDecl *RD = Method->getParent();
|
396 | 397 | if (Method->getType()->isDependentType())
|
397 |
| - return; |
| 398 | + return false; |
398 | 399 | if (RD->isCapturelessLambda())
|
399 |
| - return; |
400 |
| - QualType ExplicitObjectParameterType = Method->getParamDecl(0) |
401 |
| - ->getType() |
| 400 | + return false; |
| 401 | + |
| 402 | + ParmVarDecl *Param = Method->getParamDecl(0); |
| 403 | + QualType ExplicitObjectParameterType = Param->getType() |
402 | 404 | .getNonReferenceType()
|
403 | 405 | .getUnqualifiedType()
|
404 | 406 | .getDesugaredType(getASTContext());
|
405 | 407 | QualType LambdaType = getASTContext().getRecordType(RD);
|
406 | 408 | if (LambdaType == ExplicitObjectParameterType)
|
407 |
| - return; |
408 |
| - if (IsDerivedFrom(RD->getLocation(), ExplicitObjectParameterType, LambdaType)) |
409 |
| - return; |
410 |
| - Diag(Method->getParamDecl(0)->getLocation(), |
411 |
| - diag::err_invalid_explicit_object_type_in_lambda) |
412 |
| - << ExplicitObjectParameterType; |
| 409 | + return false; |
| 410 | + |
| 411 | + // Don't check the same instantiation twice. |
| 412 | + // |
| 413 | + // If this call operator is ill-formed, there is no point in issuing |
| 414 | + // a diagnostic every time it is called because the problem is in the |
| 415 | + // definition of the derived type, not at the call site. |
| 416 | + // |
| 417 | + // FIXME: Move this check to where we instantiate the method? This should |
| 418 | + // be possible, but the naive approach of just marking the method as invalid |
| 419 | + // leads to us emitting more diagnostics than we should have to for this case |
| 420 | + // (1 error here *and* 1 error about there being no matching overload at the |
| 421 | + // call site). It might be possible to avoid that by also checking if there |
| 422 | + // is an empty cast path for the method stored in the context (signalling that |
| 423 | + // we've already diagnosed it) and then just not building the call, but that |
| 424 | + // doesn't really seem any simpler than diagnosing it at the call site... |
| 425 | + if (auto It = Context.LambdaCastPaths.find(Method); |
| 426 | + It != Context.LambdaCastPaths.end()) |
| 427 | + return It->second.empty(); |
| 428 | + |
| 429 | + CXXCastPath &Path = Context.LambdaCastPaths[Method]; |
| 430 | + CXXBasePaths Paths(/*FindAmbiguities=*/true, /*RecordPaths=*/true, |
| 431 | + /*DetectVirtual=*/false); |
| 432 | + if (!IsDerivedFrom(RD->getLocation(), ExplicitObjectParameterType, LambdaType, |
| 433 | + Paths)) { |
| 434 | + Diag(Param->getLocation(), diag::err_invalid_explicit_object_type_in_lambda) |
| 435 | + << ExplicitObjectParameterType; |
| 436 | + return true; |
| 437 | + } |
| 438 | + |
| 439 | + if (Paths.isAmbiguous(LambdaType->getCanonicalTypeUnqualified())) { |
| 440 | + std::string PathsDisplay = getAmbiguousPathsDisplayString(Paths); |
| 441 | + Diag(CallLoc, diag::err_explicit_object_lambda_ambiguous_base) |
| 442 | + << LambdaType << PathsDisplay; |
| 443 | + return true; |
| 444 | + } |
| 445 | + |
| 446 | + if (CheckBaseClassAccess(CallLoc, LambdaType, ExplicitObjectParameterType, |
| 447 | + Paths.front(), |
| 448 | + diag::err_explicit_object_lambda_inaccessible_base)) |
| 449 | + return true; |
| 450 | + |
| 451 | + BuildBasePathArray(Paths, Path); |
| 452 | + return false; |
413 | 453 | }
|
414 | 454 |
|
415 | 455 | void Sema::handleLambdaNumbering(
|
|
0 commit comments