aaron.ballman added a comment.

In D135551#3850308 <https://reviews.llvm.org/D135551#3850308>, @dblaikie wrote:

> In D135551#3850266 <https://reviews.llvm.org/D135551#3850266>, @inclyc wrote:
>
>> This makes sense! However I think `assert(0)` should not be used in this 
>> case, we could expose another `llvm_unreachable`-like api and probably 
>> `llvm_report_error` shall be fine. Are there some changed assertions 
>> actually "Aspirationally unreachable" in this patch?
>
> No, I really don't think  we should go down that path.
>
> I believe these are not actually distinct cases - in either case, the program 
> has UB if they violated the invariants/preconditions - whether or not they 
> called through the C API.

The C Index test cases I commented on earlier in the review are a good example 
of when there's no UB but we still want to alert people to the problem of code 
they should not be reaching. The assumption that "reached here unexpectedly" == 
"UB" is invalid. Some things are logic bugs that exhibit no UB.

> unreachable is no more a guarantee/proven thing than an assertion - both are 
> written by humans and a claim "if this is reached-or-false, there is a bug in 
> some code, somewhere". The statement is not stronger in the unreachable case 
> and the style guide supports that perspective and the way we triage/treat 
> bugs is pretty consistent with that - we get bugs all the time when an 
> unreachable is reached and that doesn't seem to surprise most/anyone - we 
> treat it the same as a bug when an assertion fires.
>
> The discourse discussion, I think, supports this ^ perspective.
>
> As there's still disagreement, should this escalate to the RFC process to 
> change the style guide, Aaron?

Yes, I would appreciate that. I don't think we're interpreting our policy the 
same way. Specifically "Use llvm_unreachable to mark a specific point in code 
that should never be reached." -- "should" is turning out to be interpreted in 
two ways:

- "used to indicate obligation, duty, or correctness, typically when 
criticizing someone's actions. e.g., he should have been careful": I am 
asserting it is impossible to reach this.
- "used to indicate what is probable. e.g., $348 million should be enough to 
buy him out": I am asserting you probably won't get here, but you won't be 
happy if you do.

In D135551#3850266 <https://reviews.llvm.org/D135551#3850266>, @inclyc wrote:

> This makes sense! However I think `assert(0)` should not be used in this 
> case, we could expose another `llvm_unreachable`-like api and probably 
> `llvm_report_error` shall be fine. Are there some changed assertions actually 
> "Aspirationally unreachable" in this patch?

I'm totally fine not using `assert(0)` and using an `llvm_unreachable`-like API 
(or even using a macro to dispatch to `llvm_unreachable` under a different 
name).

There are more aspirationally unreachable issues in this patch, I've commented 
on the ones I spotted, but I stopped commenting pretty quickly because I think 
a lot of the cases are made slightly worse by switching to `llvm_unreachable` 
instead of more targeted changes. I'd be especially curious to hear what 
@dblaikie thinks of the suggestions I have though -- it might be easier to see 
the distinction with real world code (or it might not!).



================
Comment at: clang/include/clang/AST/Redeclarable.h:265
         if (PassedFirst) {
-          assert(0 && "Passed first decl twice, invalid redecl chain!");
+          llvm_unreachable("Passed first decl twice, invalid redecl chain!");
           Current = nullptr;
----------------
This looks like it should probably be: `assert(!PassedFirst && "Passed first 
decl twice, invalid redecl chain!");` rather than an `if` statement with 
recovery mechanisms.


================
Comment at: 
clang/include/clang/StaticAnalyzer/Core/PathSensitive/MemRegion.h:601
     assert(isa<ObjCMethodDecl>(FD));
-    assert(false && "Getting the type of ObjCMethod is not supported yet");
+    llvm_unreachable("Getting the type of ObjCMethod is not supported yet");
 
----------------
This looks like it possibly should have been an error reported to the user? If 
not, this is a wonderful example of what I mean by aspirationally unreachable 
code. We aspire to not getting here -- but we can get here just the same and 
there is not UB as a result (we return a valid object, UB might happen 
elsewhere based on invalid assumptions of what is returned).


================
Comment at: clang/lib/AST/ASTImporter.cpp:9976
   else {
-    assert(0 && "CompleteDecl called on a Decl that can't be completed");
+    llvm_unreachable("CompleteDecl called on a Decl that can't be completed");
   }
----------------
According to our style guide, this probably should have been 
`assert(isa<ObjCInterfaceDecl, ObjCProtocolDecl, TagDecl>(D) && "CompleteDecl 
called on a Decl that can't be completed");` but IMO that's worse than using 
`assert(0)` because it's less maintainable (any time you add a new else if 
chain you have to also update the assert). I think `llvm_unreachable` is wrong 
to use here.


================
Comment at: clang/lib/AST/ExprConstant.cpp:7561-7564
     if (Source == E) {
-      assert(0 && "OpaqueValueExpr recursively refers to itself");
+      llvm_unreachable("OpaqueValueExpr recursively refers to itself");
       return Error(E);
     }
----------------
Probably should be `assert(Source != E && "OpaqueValueExpr recursively refers 
to itself");`


================
Comment at: clang/lib/AST/Interp/ByteCodeExprGen.cpp:136-137
 
   default:
-    assert(false && "Cast not implemented");
+    llvm_unreachable("Cast not implemented");
   }
----------------
I think this can just be removed, right? There's another unreachable for 
falling out of the `switch` that seems to be covering the same situation.


================
Comment at: clang/lib/AST/Interp/ByteCodeExprGen.cpp:598
       } else {
-        assert(false && "Unhandled type in array initializer initlist");
+        llvm_unreachable("Unhandled type in array initializer initlist");
       }
----------------
The rest of the ones here are somewhat interesting in that the interpreter is 
an experiment under active development and is known to be incomplete. In all of 
these cases, I think the switch to unreachable is flat-out wrong -- these 
asserts serve explicitly to find unimplemented cases when we hit them.


================
Comment at: clang/lib/Basic/SourceManager.cpp:62-65
   if (Buffer == nullptr) {
-    assert(0 && "Buffer should never be null");
+    llvm_unreachable("Buffer should never be null");
     return llvm::MemoryBuffer::MemoryBuffer_Malloc;
   }
----------------
`assert(Buffer != nullptr && "Buffer should never be null");`

but that said, this one might be an optimization hint that suggests we should 
be using `__builtin_assume(Buffer != nullptr)`, I'm not certain.


================
Comment at: clang/lib/Basic/SourceManager.cpp:863-866
   if (SLocOffset < CurrentLoadedOffset) {
-    assert(0 && "Invalid SLocOffset or bad function choice");
+    llvm_unreachable("Invalid SLocOffset or bad function choice");
     return FileID();
   }
----------------
`assert(SLocOffset >= CurrentLoadedOffset && "Invalid SLocOffset or bad 
function choice");`


Repository:
  rG LLVM Github Monorepo

CHANGES SINCE LAST ACTION
  https://reviews.llvm.org/D135551/new/

https://reviews.llvm.org/D135551

_______________________________________________
cfe-commits mailing list
cfe-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits

Reply via email to