Compiling lambda as Objective-C++ causes block cast - clang

I have a non-copyable C++ lambda which captures a unique_ptr, and certain situations when compiling with Apple Clang as Objective-C++ cause the lambda to get converted to a block pointer, at which point the compilation fails due to an attempted copy of the lambda. A simple example is as follows:
int main(int argc, const char * argv[])
{
std::unique_ptr<int> myHeapInt = std::make_unique<int>(4);
int myStackInt = 0;
auto myLambda = [&, myHeapInt = std::move(myHeapInt)]()
{
myStackInt = *myHeapInt;
};
if(bool(myLambda)) //Error ar this point
{
*myHeapInt = 5;
}
std::invoke(myLambda);
return 0;
}
The error is as follows:
Call to implicitly-deleted copy constructor of 'const lambda...
Implicit capture of lambda object due to conversion to block pointer here
Is there a way around this conversion?

What is that bool(myLambda)? I have no clue.
The only thing you can do with a lambda is evoke it: myLambda(). You cannot test for whether it exists or anything.

So, I'm not entirely seeing the relevance of Objective-C++ here, as this code doesn't compile as C++ either:
objc++-noncopy-lambda.cpp:15:9: error: cannot convert '(lambda at objc++-noncopy-lambda.cpp:9:21)' to 'bool' without a conversion operator
if (bool(myLambda))
^~~~~~~~~~~~~
1 error generated.
The error message is different; I assume there's some attempt at implicitly converting lambdas to blocks in Objective-C++, I've tried to stay away from weird edge cases like that, but it seems that in the absence of an operator bool it might try the conversion to a block first.
Either way the code you're attempting to write doesn't make any sense and the compiler is correctly rejecting it.
I see in the comments that you're actually trying to do something different. Could you perhaps post a reduced version of the code you're actually trying to write, which supposedly compiles as C++ but not as Objective-C++?

I was trying to compile a templated header-file class replacement for std::function (github.com/Naios/function2) as Objective-C++, which implements a vtable and optimises it if the callable implements operator bool() or can be converted to bool.
In the end I just decided to disable this optimisation if compiled as Objective-C++ as converting to a block pointer is by design in Clang for block-lambda interoperability (http://clang.llvm.org/docs/LanguageExtensions.html#interoperability-with-c-11-lambdas).

Related

Getting the address of a section with Clang on OSX/iOS

For quite a while I've been using linker sections for registering elements that are used at runtime. I find that it's a simple way to make generic and extensible interface. A particularly useful use-case is something like unit tests or a multitool (e.g. busybox) so one can do something like:
$ ./tool <handler>
Where handler is a simple string that is "looked up" at runtime by walking the linker section. In this way, your parser doesn't have to "know" what commands are supported. It just finds their handlers in the linker section dedicated for them or it doesn't.
With GCC I've been doing something like (you can do this with Clang as well):
#define __tool __attribute__((__section__("tools")))
Then each handler I want to register gets a simple structure (with more or less information as needed)
struct tool {
const char *name;
const char *help;
int (*handler)(int argc, char **argv);
}
Then, for each tool you just do something like (often conveniently wrapped in a macro):
int example_tool0(int argc, char **argv)
{
return -1;
}
static const struct tool example_tool0 = {
.name = "exmaple_tool0",
.help = "usage: ...",
.handler = example_tool0
};
__tool static const struct tool *ptr = &example_tool0;
And used a such:
$ ./tool example_tool0
And because of __tool, each pointer registered in this way is packed into a linker section that can be walked.
Now, on GCC the linker creates two magic variables for each section: __start_SECTION and __stop_SECTION. So, to "walk" all of our registered handlers you just take the size of this section, divide by the size of a pointer, and then strncmp against the name (in this example) in the struct.
All of the above just to say, how can this be done using the OSX/iOS Clang-based toolchain? I would rather not use a custom linker script to achieve this seemingly simple operation.
Is there a way do this on OSX? I have worked around the issue by registering an empty entry at the beginning of the section and at the end. But doing so requires forcing the link order of the object files.
While OSX/iOS uses Clang as their platform compiler, they do not use the LLVM linker. Rather, they implement their own ld64 (which is open source) for whatever reason. So, it may just not be supported. I didn't readily see anything in man ld on OSX, but it's a bit info-dense.
For reference with ELF and GCC
And so this has been answered by others already. I did search, but I must have missed this answer. I've actually looked for an answer to this question many times before but must've never used the right words.
https://stackoverflow.com/a/22366882/2446071
In summary, apparently the linker supports syntax to define these desired symbols yourself:
extern char __start_SECTION __asm("section$start$SEGMENT$SECTION");
extern char __stop_SECTION __asm("section$end$SEGMENT$SECTION");

Is it possible to change a static constant from another file? [duplicate]

This question already has answers here:
Closed 12 years ago.
Possible Duplicate:
Does the evil cast get trumped by the evil compiler?
Hello,
If I can modify a constant through a pointer, then what is the purpose of it?
Below is code:
#include <stdio.h>
#include <stdlib.h>
int main()
{
const int a = 10;
int *p = (int *)&a;
printf("Before: %d \n", a);
*p = 2;
/*a = 2; gives error*/
printf("After: %d \n", *p);
return 0;
}
OUTPUT:
Before: 10
After: 2
Press any key to continue . . .
Using Visual Studio 2008.
The reason you could modify the value is because you did a pointer typecast that stripped off the constness:
int *p = (int *)&a;
This typecasts a const int* (namely &a) to an int *, allowing you to freely modify the variable. Normally the compiler would warn you about this, but the explicit typecast suppressed the warning.
The main rationale behind const at all is to prevent you from accidentally modifying something that you promised not to. It's not sacrosanct, as you've seen, and you can cast away constness with impunity, much in the same way that you can do other unsafe things like converting pointers to integers or vice-versa. The idea is that you should try your best not to mess with const, and the compiler will warn you if you do. Of course, adding in a cast tells the compiler "I know what I'm doing," and so in your case the above doesn't generate any sort of warnings.
If i can modify a constant through a
pointer then what is the purpose of
it? below is code:
This is Undefined Behavior and should be avoided at all costs:
§ C99 6.7.3p5
If an attempt is made to modify an
object defined with a const-qualified
type through use of an lvalue with
non-const-qualified type, the
behavior is undefined.

warning on typedef enum when converting app to 64-bit

I am converting my iOS app to 64-bit. I have the latest Xcode 5.1 (beta 4) installed.
When I compiled the app, I received over 100 warnings and most of them are pretty easy to fix. However, I have a warning on the following code:
+ (CommentResponseStatus)commentReponseStatusCodeWithStatusString:(NSString *)_status
{
NSArray *commentStatusString = [NSArray arrayWithObjects:#"success", #"needConfirmation", #"stopped", nil];
return [commentStatusString indexOfObject:_status];
}
Where CommentResponseStatus is declared as:
typedef enum {
success,
needConfirmation,
stopped
} CommentResponseStatus;
I have a warning "Implicit conversion loses integer precision: 'NSUInteger' (aka 'unsigned long') to 'CommentResponseStatus'"
The warning is on the line return [commentStatusString indexOfObject:_status];
In NSArray we have - (NSUInteger)indexOfObject:(id)anObject;
I am confused about this warning and don't know for now how to fix it. Any quick help would be appreciated.
According to apple docs about 64-bit changes.
Enumerations Are Also Typed : In the LLVM compiler, enumerated types can
define the size of the enumeration. This means that some enumerated
types may also have a size that is larger than you expect. The
solution, as in all the other cases, is to make no assumptions about a
data type’s size. Instead, assign any enumerated values to a variable
with the proper data type
To solve this, create enumeration with type as below syntax.
typedef NS_ENUM(NSUInteger, CommentResponseStatus) {
success,
needConfirmation,
stopped
};
or
typedef enum CommentResponseStatus : NSUInteger {
success,
needConfirmation,
stopped
} CommentResponseStatus;

Can I enable warning for comparing a enum and a non enum values?

I recently debugged an issue which was caused because an enum was being compared with a non-enum value. Here is a simplified example:
typedef NS_ENUM(NSInteger, MyType) {
TypeVal1,
};
...
MyType type = TypeVal1;
int randomValue = 0;
BOOL compareTypeAndPrimiative = (randomValue == typeA); // No warning
Is it possible to turn on a warning for this?
I could suppress if if needed by explicitly casting:
BOOL iKnowWhatImDoing = (randomValue == (int) typeA);
There is no support for this kind of warning because C enums are not strongly typed, and I believe the standards require them to be treated as ints (or unsigned ints). Comparing them with regular integers has always been allowed as part of the C standard, and a warning of this type would end up flagging a lot of correct code. I'm sure somebody can link to the appropriate section of the C standards.
Particularly with iOS and Apple APIs, you will find that enum values are often used as bitmasks. In these situations it is common to write code like this:
if ((value & flag) == kFlag) { ... }
You could argue that using enums for this purpose is a bad idea, but you would probably end up having to disable this warning for all sorts of code.
I just ran through LLVM manual and it seems there is no option for this. Then I tried to turn on all the compiler warnings (-Weverything), however there was no warning your enum case.
So the answer is no.
The best solution to avoid such bugs is to name the variables/constants appropiately. Make obvious what the variable/constant represent. Then the error in comparison should be obvious, too.

How to access C function from another C function in iOS

I'm trying to assign a function to the AURenderCallback inputProc
int setupRemoteIO(audio unit etc){
inProc.inputProc = playerCallback
}
but it says that playerCallback is not declared in this scope although playerCallback is present in the same file and class as setupRemoteIO.
The player callback is like this
static OSStatus playerCallback(void *inRefCon etc)
What could be the problem?
In C, you need to declare a function before its first use, i.e. higher up in the file than the point where you try to use the function. That's why include files are usually clustered at the top of a file; all of the symbols declared in the headers will be available throughout the code in the including file.
In this case, that means the declaration of your callback:
static OSStatus playerCallback(void *inRefCon etc);
must appear before your setupRemoteIO() function so that the compiler knows the function exists when you come to use it.
As you're on iOS, I'll also make the point that in recent compilers this restriction doesn't apply to Objective-C methods. It used to: you could only use method selectors that had already been seen. But in newer versions of Clang an Objective-C method can make use of a selector declared later in the same file without error.

Resources