Left: | ||
Right: |
OLD | NEW |
---|---|
1 //===--- SemaDeclAttr.cpp - Declaration Attribute Handling ----------------===// | 1 //===--- SemaDeclAttr.cpp - Declaration Attribute Handling ----------------===// |
2 // | 2 // |
3 // The LLVM Compiler Infrastructure | 3 // The LLVM Compiler Infrastructure |
4 // | 4 // |
5 // This file is distributed under the University of Illinois Open Source | 5 // This file is distributed under the University of Illinois Open Source |
6 // License. See LICENSE.TXT for details. | 6 // License. See LICENSE.TXT for details. |
7 // | 7 // |
8 //===----------------------------------------------------------------------===// | 8 //===----------------------------------------------------------------------===// |
9 // | 9 // |
10 // This file implements decl-related attribute processing. | 10 // This file implements decl-related attribute processing. |
(...skipping 255 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
266 // now check if we point to record type | 266 // now check if we point to record type |
267 if(!RT && QT->isPointerType()){ | 267 if(!RT && QT->isPointerType()){ |
268 QualType PT = QT->getAs<PointerType>()->getPointeeType(); | 268 QualType PT = QT->getAs<PointerType>()->getPointeeType(); |
269 RT = PT->getAs<RecordType>(); | 269 RT = PT->getAs<RecordType>(); |
270 } | 270 } |
271 return RT; | 271 return RT; |
272 } | 272 } |
273 | 273 |
274 /// \brief Thread Safety Analysis: Checks that all attribute arguments, starting | 274 /// \brief Thread Safety Analysis: Checks that all attribute arguments, starting |
275 /// from Sidx, resolve to a lockable object. May flag an error. | 275 /// from Sidx, resolve to a lockable object. May flag an error. |
276 static bool checkAttrArgsAreLockableObjs(Sema & S, Decl *D, | 276 static bool checkAttrArgsAreLockableObjs(Sema &S, Decl *D, |
277 const AttributeList & Attr, | 277 const AttributeList &Attr, |
278 SmallVectorImpl<Expr*> &outArgs, | |
chandlerc
2011/08/19 23:54:06
Just "Args" is fine.
supertri
2011/08/22 18:30:16
Done.
| |
278 int Sidx = 0, | 279 int Sidx = 0, |
279 bool ParamIdxOk = false) { | 280 bool ParamIdxOk = false) { |
280 for(unsigned int Idx = Sidx; Idx < Attr.getNumArgs(); ++Idx) { | 281 for(unsigned int Idx = Sidx; Idx < Attr.getNumArgs(); ++Idx) { |
281 Expr *ArgExp = Attr.getArg(Idx); | 282 Expr *ArgExp = Attr.getArg(Idx); |
282 if (ArgExp->isTypeDependent()) | 283 if (ArgExp->isTypeDependent()) |
283 continue; | 284 continue; |
284 | 285 |
285 QualType Arg_QT = ArgExp->getType(); | 286 QualType Arg_QT = ArgExp->getType(); |
286 | 287 |
287 // Get record type. | 288 // Get record type. |
(...skipping 25 matching lines...) Expand all Loading... | |
313 << Attr.getName(); | 314 << Attr.getName(); |
314 return false; | 315 return false; |
315 } | 316 } |
316 | 317 |
317 // Flag error if the type is not lockable | 318 // Flag error if the type is not lockable |
318 if (!RT->getDecl()->getAttr<LockableAttr>()) { | 319 if (!RT->getDecl()->getAttr<LockableAttr>()) { |
319 S.Diag(Attr.getLoc(), diag::err_attribute_argument_not_lockable) | 320 S.Diag(Attr.getLoc(), diag::err_attribute_argument_not_lockable) |
320 << Attr.getName(); | 321 << Attr.getName(); |
321 return false; | 322 return false; |
322 } | 323 } |
324 | |
325 outArgs.push_back(ArgExp); | |
323 } | 326 } |
324 return true; | 327 return true; |
325 } | 328 } |
326 | 329 |
327 //===----------------------------------------------------------------------===// | 330 //===----------------------------------------------------------------------===// |
328 // Attribute Implementations | 331 // Attribute Implementations |
329 //===----------------------------------------------------------------------===// | 332 //===----------------------------------------------------------------------===// |
330 | 333 |
331 // FIXME: All this manual attribute parsing code is gross. At the | 334 // FIXME: All this manual attribute parsing code is gross. At the |
332 // least add some helper functions to check most argument patterns (# | 335 // least add some helper functions to check most argument patterns (# |
(...skipping 22 matching lines...) Expand all Loading... | |
355 D->addAttr(::new (S.Context) GuardedVarAttr(Attr.getLoc(), S.Context)); | 358 D->addAttr(::new (S.Context) GuardedVarAttr(Attr.getLoc(), S.Context)); |
356 } | 359 } |
357 | 360 |
358 static void handleGuardedByAttr(Sema &S, Decl *D, const AttributeList &Attr, | 361 static void handleGuardedByAttr(Sema &S, Decl *D, const AttributeList &Attr, |
359 bool pointer = false) { | 362 bool pointer = false) { |
360 assert(!Attr.isInvalid()); | 363 assert(!Attr.isInvalid()); |
361 | 364 |
362 if (!checkAttributeNumArgs(S, Attr, 1)) | 365 if (!checkAttributeNumArgs(S, Attr, 1)) |
363 return; | 366 return; |
364 | 367 |
368 Expr *Arg = Attr.getArg(0); | |
369 | |
365 // D must be either a member field or global (potentially shared) variable. | 370 // D must be either a member field or global (potentially shared) variable. |
366 if (!mayBeSharedVariable(D)) { | 371 if (!mayBeSharedVariable(D)) { |
367 S.Diag(Attr.getLoc(), diag::warn_attribute_wrong_decl_type) | 372 S.Diag(Attr.getLoc(), diag::warn_attribute_wrong_decl_type) |
368 << Attr.getName() << ExpectedFieldOrGlobalVar; | 373 << Attr.getName() << ExpectedFieldOrGlobalVar; |
369 return; | 374 return; |
370 } | 375 } |
371 | 376 |
372 if (pointer && !checkIsPointer(S, D, Attr)) | 377 if (pointer && !checkIsPointer(S, D, Attr)) |
373 return; | 378 return; |
374 | 379 |
375 // check that all arguments are lockable objects | 380 // check that all arguments are lockable objects |
376 if (!checkAttrArgsAreLockableObjs(S, D, Attr)) | 381 SmallVector<Expr*, 1> ArgVector; |
chandlerc
2011/08/19 23:54:06
FIXME to actually use the argcs?
supertri
2011/08/22 18:30:16
Refactored this to make it more clear that I am ju
| |
382 if (!checkAttrArgsAreLockableObjs(S, D, Attr, ArgVector)) | |
377 return; | 383 return; |
378 | 384 |
379 if (pointer) | 385 if (pointer) |
380 D->addAttr(::new (S.Context) PtGuardedByAttr(Attr.getLoc(), S.Context)); | 386 D->addAttr(::new (S.Context) PtGuardedByAttr(Attr.getLoc(), |
387 S.Context, Arg)); | |
381 else | 388 else |
382 D->addAttr(::new (S.Context) GuardedByAttr(Attr.getLoc(), S.Context)); | 389 D->addAttr(::new (S.Context) GuardedByAttr(Attr.getLoc(), S.Context, Arg)); |
383 } | 390 } |
384 | 391 |
385 | 392 |
386 static void handleLockableAttr(Sema &S, Decl *D, const AttributeList &Attr, | 393 static void handleLockableAttr(Sema &S, Decl *D, const AttributeList &Attr, |
387 bool scoped = false) { | 394 bool scoped = false) { |
388 assert(!Attr.isInvalid()); | 395 assert(!Attr.isInvalid()); |
389 | 396 |
390 if (!checkAttributeNumArgs(S, Attr, 0)) | 397 if (!checkAttributeNumArgs(S, Attr, 0)) |
391 return; | 398 return; |
392 | 399 |
(...skipping 45 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
438 QualType QT = VD->getType(); | 445 QualType QT = VD->getType(); |
439 if (!QT->isDependentType()) { | 446 if (!QT->isDependentType()) { |
440 const RecordType *RT = getRecordType(QT); | 447 const RecordType *RT = getRecordType(QT); |
441 if (!RT || !RT->getDecl()->getAttr<LockableAttr>()) { | 448 if (!RT || !RT->getDecl()->getAttr<LockableAttr>()) { |
442 S.Diag(Attr.getLoc(), diag::err_attribute_decl_not_lockable) | 449 S.Diag(Attr.getLoc(), diag::err_attribute_decl_not_lockable) |
443 << Attr.getName(); | 450 << Attr.getName(); |
444 return; | 451 return; |
445 } | 452 } |
446 } | 453 } |
447 | 454 |
455 SmallVector<Expr*, 1> Args; | |
448 // check that all arguments are lockable objects | 456 // check that all arguments are lockable objects |
449 if (!checkAttrArgsAreLockableObjs(S, D, Attr)) | 457 if (!checkAttrArgsAreLockableObjs(S, D, Attr, Args)) |
450 return; | 458 return; |
451 | 459 |
460 unsigned Size = Args.size(); | |
461 assert(Size == Attr.getNumArgs()); | |
462 Expr **StartArg = Size == 0 ? 0 : &Args[0]; | |
463 | |
452 if (before) | 464 if (before) |
453 D->addAttr(::new (S.Context) AcquiredBeforeAttr(Attr.getLoc(), S.Context)); | 465 D->addAttr(::new (S.Context) AcquiredBeforeAttr(Attr.getLoc(), S.Context, |
466 StartArg, Size)); | |
454 else | 467 else |
455 D->addAttr(::new (S.Context) AcquiredAfterAttr(Attr.getLoc(), S.Context)); | 468 D->addAttr(::new (S.Context) AcquiredAfterAttr(Attr.getLoc(), S.Context, |
469 StartArg, Size)); | |
456 } | 470 } |
457 | 471 |
458 static void handleLockFunAttr(Sema &S, Decl *D, const AttributeList &Attr, | 472 static void handleLockFunAttr(Sema &S, Decl *D, const AttributeList &Attr, |
459 bool exclusive = false) { | 473 bool exclusive = false) { |
460 assert(!Attr.isInvalid()); | 474 assert(!Attr.isInvalid()); |
461 | 475 |
462 // zero or more arguments ok | 476 // zero or more arguments ok |
463 | 477 |
464 // check that the attribute is applied to a function | 478 // check that the attribute is applied to a function |
465 if (!isa<FunctionDecl>(D) && !isa<FunctionTemplateDecl>(D)) { | 479 if (!isa<FunctionDecl>(D) && !isa<FunctionTemplateDecl>(D)) { |
466 S.Diag(Attr.getLoc(), diag::warn_attribute_wrong_decl_type) | 480 S.Diag(Attr.getLoc(), diag::warn_attribute_wrong_decl_type) |
467 << Attr.getName() << ExpectedFunctionOrMethod; | 481 << Attr.getName() << ExpectedFunctionOrMethod; |
468 return; | 482 return; |
469 } | 483 } |
470 | 484 |
471 // check that all arguments are lockable objects | 485 // check that all arguments are lockable objects |
472 if (!checkAttrArgsAreLockableObjs(S, D, Attr, 0, /*ParamIdxOk=*/true)) | 486 SmallVector<Expr*, 1> Args; |
487 if (!checkAttrArgsAreLockableObjs(S, D, Attr, Args, 0, /*ParamIdxOk=*/true)) | |
473 return; | 488 return; |
474 | 489 |
490 unsigned Size = Args.size(); | |
491 assert(Size == Attr.getNumArgs()); | |
492 Expr **StartArg = Size == 0 ? 0 : &Args[0]; | |
493 | |
475 if (exclusive) | 494 if (exclusive) |
476 D->addAttr(::new (S.Context) ExclusiveLockFunctionAttr(Attr.getLoc(), | 495 D->addAttr(::new (S.Context) ExclusiveLockFunctionAttr(Attr.getLoc(), |
477 S.Context)); | 496 S.Context, StartArg, |
497 Size)); | |
478 else | 498 else |
479 D->addAttr(::new (S.Context) SharedLockFunctionAttr(Attr.getLoc(), | 499 D->addAttr(::new (S.Context) SharedLockFunctionAttr(Attr.getLoc(), |
480 S.Context)); | 500 S.Context, StartArg, |
501 Size)); | |
481 } | 502 } |
482 | 503 |
483 static void handleTrylockFunAttr(Sema &S, Decl *D, const AttributeList &Attr, | 504 static void handleTrylockFunAttr(Sema &S, Decl *D, const AttributeList &Attr, |
484 bool exclusive = false) { | 505 bool exclusive = false) { |
485 assert(!Attr.isInvalid()); | 506 assert(!Attr.isInvalid()); |
486 | 507 |
487 if (!checkAttributeAtLeastNumArgs(S, Attr, 1)) | 508 if (!checkAttributeAtLeastNumArgs(S, Attr, 1)) |
488 return; | 509 return; |
489 | 510 |
490 | 511 |
491 if (!isa<FunctionDecl>(D) && !isa<FunctionTemplateDecl>(D)) { | 512 if (!isa<FunctionDecl>(D) && !isa<FunctionTemplateDecl>(D)) { |
492 S.Diag(Attr.getLoc(), diag::warn_attribute_wrong_decl_type) | 513 S.Diag(Attr.getLoc(), diag::warn_attribute_wrong_decl_type) |
493 << Attr.getName() << ExpectedFunctionOrMethod; | 514 << Attr.getName() << ExpectedFunctionOrMethod; |
494 return; | 515 return; |
495 } | 516 } |
496 | 517 |
497 if (!isIntOrBool(Attr.getArg(0))) { | 518 if (!isIntOrBool(Attr.getArg(0))) { |
498 S.Diag(Attr.getLoc(), diag::err_attribute_first_argument_not_int_or_bool) | 519 S.Diag(Attr.getLoc(), diag::err_attribute_first_argument_not_int_or_bool) |
499 << Attr.getName(); | 520 << Attr.getName(); |
500 return; | 521 return; |
501 } | 522 } |
502 | 523 |
524 SmallVector<Expr*, 2> Args; | |
525 Args.push_back(Attr.getArg(0)); //FIXME | |
503 // check that all arguments are lockable objects | 526 // check that all arguments are lockable objects |
504 if (!checkAttrArgsAreLockableObjs(S, D, Attr, 1)) | 527 if (!checkAttrArgsAreLockableObjs(S, D, Attr, Args, 1)) |
505 return; | 528 return; |
506 | 529 |
530 unsigned Size = Args.size(); | |
531 assert(Size == Attr.getNumArgs()); | |
532 Expr **StartArg = Size == 0 ? 0 : &Args[0]; | |
533 | |
507 if (exclusive) | 534 if (exclusive) |
508 D->addAttr(::new (S.Context) ExclusiveTrylockFunctionAttr(Attr.getLoc(), | 535 D->addAttr(::new (S.Context) ExclusiveTrylockFunctionAttr(Attr.getLoc(), |
509 S.Context)); | 536 S.Context, |
537 StartArg, Size)); | |
510 else | 538 else |
511 D->addAttr(::new (S.Context) SharedTrylockFunctionAttr(Attr.getLoc(), | 539 D->addAttr(::new (S.Context) SharedTrylockFunctionAttr(Attr.getLoc(), |
512 S.Context)); | 540 S.Context, StartArg, |
541 Size)); | |
513 } | 542 } |
514 | 543 |
515 static void handleLocksRequiredAttr(Sema &S, Decl *D, const AttributeList &Attr, | 544 static void handleLocksRequiredAttr(Sema &S, Decl *D, const AttributeList &Attr, |
516 bool exclusive = false) { | 545 bool exclusive = false) { |
517 assert(!Attr.isInvalid()); | 546 assert(!Attr.isInvalid()); |
518 | 547 |
519 if (!checkAttributeAtLeastNumArgs(S, Attr, 1)) | 548 if (!checkAttributeAtLeastNumArgs(S, Attr, 1)) |
520 return; | 549 return; |
521 | 550 |
522 if (!isa<FunctionDecl>(D) && !isa<FunctionTemplateDecl>(D)) { | 551 if (!isa<FunctionDecl>(D) && !isa<FunctionTemplateDecl>(D)) { |
523 S.Diag(Attr.getLoc(), diag::warn_attribute_wrong_decl_type) | 552 S.Diag(Attr.getLoc(), diag::warn_attribute_wrong_decl_type) |
524 << Attr.getName() << ExpectedFunctionOrMethod; | 553 << Attr.getName() << ExpectedFunctionOrMethod; |
525 return; | 554 return; |
526 } | 555 } |
527 | 556 |
528 // check that all arguments are lockable objects | 557 // check that all arguments are lockable objects |
529 if (!checkAttrArgsAreLockableObjs(S, D, Attr)) | 558 SmallVector<Expr*, 1> Args; |
559 if (!checkAttrArgsAreLockableObjs(S, D, Attr, Args)) | |
530 return; | 560 return; |
531 | 561 |
562 unsigned Size = Args.size(); | |
563 assert(Size == Attr.getNumArgs()); | |
564 Expr **StartArg = Size == 0 ? 0 : &Args[0]; | |
565 | |
532 if (exclusive) | 566 if (exclusive) |
533 D->addAttr(::new (S.Context) ExclusiveLocksRequiredAttr(Attr.getLoc(), | 567 D->addAttr(::new (S.Context) ExclusiveLocksRequiredAttr(Attr.getLoc(), |
534 S.Context)); | 568 S.Context, StartArg, |
569 Size)); | |
535 else | 570 else |
536 D->addAttr(::new (S.Context) SharedLocksRequiredAttr(Attr.getLoc(), | 571 D->addAttr(::new (S.Context) SharedLocksRequiredAttr(Attr.getLoc(), |
537 S.Context)); | 572 S.Context, StartArg, |
573 Size)); | |
538 } | 574 } |
539 | 575 |
540 static void handleUnlockFunAttr(Sema &S, Decl *D, | 576 static void handleUnlockFunAttr(Sema &S, Decl *D, |
541 const AttributeList &Attr) { | 577 const AttributeList &Attr) { |
542 assert(!Attr.isInvalid()); | 578 assert(!Attr.isInvalid()); |
543 | 579 |
544 // zero or more arguments ok | 580 // zero or more arguments ok |
545 | 581 |
546 if (!isa<FunctionDecl>(D) && !isa<FunctionTemplateDecl>(D)) { | 582 if (!isa<FunctionDecl>(D) && !isa<FunctionTemplateDecl>(D)) { |
547 S.Diag(Attr.getLoc(), diag::warn_attribute_wrong_decl_type) | 583 S.Diag(Attr.getLoc(), diag::warn_attribute_wrong_decl_type) |
548 << Attr.getName() << ExpectedFunctionOrMethod; | 584 << Attr.getName() << ExpectedFunctionOrMethod; |
549 return; | 585 return; |
550 } | 586 } |
551 | 587 |
552 // check that all arguments are lockable objects | 588 // check that all arguments are lockable objects |
553 if (!checkAttrArgsAreLockableObjs(S, D, Attr, 0, /*ParamIdxOk=*/true)) | 589 SmallVector<Expr*, 1> Args; |
590 if (!checkAttrArgsAreLockableObjs(S, D, Attr, Args, 0, /*ParamIdxOk=*/true)) | |
554 return; | 591 return; |
555 | 592 |
556 D->addAttr(::new (S.Context) UnlockFunctionAttr(Attr.getLoc(), S.Context)); | 593 unsigned Size = Args.size(); |
594 assert(Size == Attr.getNumArgs()); | |
595 Expr **StartArg = Size == 0 ? 0 : &Args[0]; | |
596 | |
597 D->addAttr(::new (S.Context) UnlockFunctionAttr(Attr.getLoc(), S.Context, | |
598 StartArg, Size)); | |
557 } | 599 } |
558 | 600 |
559 static void handleLockReturnedAttr(Sema &S, Decl *D, | 601 static void handleLockReturnedAttr(Sema &S, Decl *D, |
560 const AttributeList &Attr) { | 602 const AttributeList &Attr) { |
561 assert(!Attr.isInvalid()); | 603 assert(!Attr.isInvalid()); |
562 | 604 |
563 if (!checkAttributeNumArgs(S, Attr, 1)) | 605 if (!checkAttributeNumArgs(S, Attr, 1)) |
564 return; | 606 return; |
607 Expr *Arg = Attr.getArg(0); | |
565 | 608 |
566 if (!isa<FunctionDecl>(D) && !isa<FunctionTemplateDecl>(D)) { | 609 if (!isa<FunctionDecl>(D) && !isa<FunctionTemplateDecl>(D)) { |
567 S.Diag(Attr.getLoc(), diag::warn_attribute_wrong_decl_type) | 610 S.Diag(Attr.getLoc(), diag::warn_attribute_wrong_decl_type) |
568 << Attr.getName() << ExpectedFunctionOrMethod; | 611 << Attr.getName() << ExpectedFunctionOrMethod; |
569 return; | 612 return; |
570 } | 613 } |
571 | 614 |
572 // check that all arguments are lockable objects | 615 // check that all arguments are lockable objects |
573 if (!checkAttrArgsAreLockableObjs(S, D, Attr)) | 616 SmallVector<Expr*, 1> Args; |
chandlerc
2011/08/19 23:54:06
FIXME to actually use the args? Also it'd be nice
supertri
2011/08/22 18:30:16
On 2011/08/19 23:54:06, chandlerc wrote:
See previ
| |
617 if (!checkAttrArgsAreLockableObjs(S, D, Attr, Args)) | |
574 return; | 618 return; |
575 | 619 |
576 D->addAttr(::new (S.Context) LockReturnedAttr(Attr.getLoc(), S.Context)); | 620 D->addAttr(::new (S.Context) LockReturnedAttr(Attr.getLoc(), S.Context, Arg)); |
577 } | 621 } |
578 | 622 |
579 static void handleLocksExcludedAttr(Sema &S, Decl *D, | 623 static void handleLocksExcludedAttr(Sema &S, Decl *D, |
580 const AttributeList &Attr) { | 624 const AttributeList &Attr) { |
581 assert(!Attr.isInvalid()); | 625 assert(!Attr.isInvalid()); |
582 | 626 |
583 if (!checkAttributeAtLeastNumArgs(S, Attr, 1)) | 627 if (!checkAttributeAtLeastNumArgs(S, Attr, 1)) |
584 return; | 628 return; |
585 | 629 |
586 if (!isa<FunctionDecl>(D) && !isa<FunctionTemplateDecl>(D)) { | 630 if (!isa<FunctionDecl>(D) && !isa<FunctionTemplateDecl>(D)) { |
587 S.Diag(Attr.getLoc(), diag::warn_attribute_wrong_decl_type) | 631 S.Diag(Attr.getLoc(), diag::warn_attribute_wrong_decl_type) |
588 << Attr.getName() << ExpectedFunctionOrMethod; | 632 << Attr.getName() << ExpectedFunctionOrMethod; |
589 return; | 633 return; |
590 } | 634 } |
591 | 635 |
592 // check that all arguments are lockable objects | 636 // check that all arguments are lockable objects |
593 if (!checkAttrArgsAreLockableObjs(S, D, Attr)) | 637 SmallVector<Expr*, 1> Args; |
638 if (!checkAttrArgsAreLockableObjs(S, D, Attr, Args)) | |
594 return; | 639 return; |
595 | 640 |
596 D->addAttr(::new (S.Context) LocksExcludedAttr(Attr.getLoc(), S.Context)); | 641 unsigned Size = Args.size(); |
642 assert(Size == Attr.getNumArgs()); | |
643 Expr **StartArg = Size == 0 ? 0 : &Args[0]; | |
644 | |
645 D->addAttr(::new (S.Context) LocksExcludedAttr(Attr.getLoc(), S.Context, | |
646 StartArg, Size)); | |
597 } | 647 } |
598 | 648 |
599 | 649 |
600 static void handleExtVectorTypeAttr(Sema &S, Scope *scope, Decl *D, | 650 static void handleExtVectorTypeAttr(Sema &S, Scope *scope, Decl *D, |
601 const AttributeList &Attr) { | 651 const AttributeList &Attr) { |
602 TypedefNameDecl *tDecl = dyn_cast<TypedefNameDecl>(D); | 652 TypedefNameDecl *tDecl = dyn_cast<TypedefNameDecl>(D); |
603 if (tDecl == 0) { | 653 if (tDecl == 0) { |
604 S.Diag(Attr.getLoc(), diag::err_typecheck_ext_vector_not_typedef); | 654 S.Diag(Attr.getLoc(), diag::err_typecheck_ext_vector_not_typedef); |
605 return; | 655 return; |
606 } | 656 } |
(...skipping 3191 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
3798 << Message; | 3848 << Message; |
3799 else { | 3849 else { |
3800 if (!UnknownObjCClass) | 3850 if (!UnknownObjCClass) |
3801 Diag(Loc, diag::warn_deprecated) << D->getDeclName(); | 3851 Diag(Loc, diag::warn_deprecated) << D->getDeclName(); |
3802 else { | 3852 else { |
3803 Diag(Loc, diag::warn_deprecated_fwdclass_message) << D->getDeclName(); | 3853 Diag(Loc, diag::warn_deprecated_fwdclass_message) << D->getDeclName(); |
3804 Diag(UnknownObjCClass->getLocation(), diag::note_forward_class); | 3854 Diag(UnknownObjCClass->getLocation(), diag::note_forward_class); |
3805 } | 3855 } |
3806 } | 3856 } |
3807 } | 3857 } |
OLD | NEW |