SourceLocation Loc = E->getSourceRange().getBegin();
+ // Venture through the macro stacks to get to the source of macro arguments.
+ // The new location is a better location than the complete location that was
+ // passed in.
+ while (S.SourceMgr.isMacroArgExpansion(Loc))
+ Loc = S.SourceMgr.getImmediateMacroCallerLoc(Loc);
+
+ while (S.SourceMgr.isMacroArgExpansion(CC))
+ CC = S.SourceMgr.getImmediateMacroCallerLoc(CC);
+
// __null is usually wrapped in a macro. Go up a macro if that is the case.
- if (NullKind == Expr::NPCK_GNUNull) {
- if (Loc.isMacroID()) {
- StringRef MacroName = Lexer::getImmediateMacroNameForDiagnostics(
- Loc, S.SourceMgr, S.getLangOpts());
- if (MacroName == "NULL")
- Loc = S.SourceMgr.getImmediateExpansionRange(Loc).first;
- }
+ if (NullKind == Expr::NPCK_GNUNull && Loc.isMacroID()) {
+ StringRef MacroName = Lexer::getImmediateMacroNameForDiagnostics(
+ Loc, S.SourceMgr, S.getLangOpts());
+ if (MacroName == "NULL")
+ Loc = S.SourceMgr.getImmediateExpansionRange(Loc).first;
}
// Only warn if the null and context location are in the same macro expansion.
}
}
+
+// More tests with macros. Specficially, test function-like macros that either
+// have a pointer return type or take pointer arguments. Basically, if the
+// macro was changed into a function and Clang doesn't warn, then it shouldn't
+// warn for the macro either.
+namespace test13 {
+#define check_str_nullptr_13(str) ((str) ? str : nullptr)
+#define check_str_null_13(str) ((str) ? str : NULL)
+#define test13(condition) if (condition) return;
+#define identity13(arg) arg
+#define CHECK13(condition) test13(identity13(!(condition)))
+
+void function1(const char* str) {
+ CHECK13(check_str_nullptr_13(str));
+ CHECK13(check_str_null_13(str));
+}
+
+bool some_bool_function(bool);
+void function2() {
+ CHECK13(some_bool_function(nullptr)); // expected-warning{{implicit conversion of nullptr constant to 'bool'}}
+ CHECK13(some_bool_function(NULL)); // expected-warning{{implicit conversion of NULL constant to 'bool'}}
+}
+
+#define run_check_nullptr_13(str) \
+ if (check_str_nullptr_13(str)) return;
+#define run_check_null_13(str) \
+ if (check_str_null_13(str)) return;
+void function3(const char* str) {
+ run_check_nullptr_13(str)
+ run_check_null_13(str)
+ if (check_str_nullptr_13(str)) return;
+ if (check_str_null_13(str)) return;
+}
+
+void run(int* ptr);
+#define conditional_run_13(ptr) \
+ if (ptr) run(ptr);
+void function4() {
+ conditional_run_13(nullptr);
+ conditional_run_13(NULL);
+}
+}