|
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