Hi rsmith, rnk,
__noop is declared with manually checked arguments ("t") that prevents any
checking of argument completeness. __noop can be called with void arguments now.
It is declared that __noop has constant zero return value. So __noop can be
assigned as a pointer now.
Special flag is added which indicates that parsing is inside __noop expression.
Functions aren't marked as referenced if they are __noop parameters. This
prevents from template instantiation of function that is used only in __noop
expression.
This behavior is the same as MS compiler behavior.
http://reviews.llvm.org/D9000
Files:
include/clang/Basic/Builtins.def
include/clang/Sema/Sema.h
lib/AST/ExprConstant.cpp
lib/Parse/ParseExpr.cpp
lib/Sema/Sema.cpp
lib/Sema/SemaChecking.cpp
lib/Sema/SemaExpr.cpp
test/CodeGen/builtin-ms-noop.cpp
test/Sema/builtin-ms-noop-errors.cpp
EMAIL PREFERENCES
http://reviews.llvm.org/settings/panel/emailpreferences/
Index: test/Sema/builtin-ms-noop-errors.cpp
===================================================================
--- test/Sema/builtin-ms-noop-errors.cpp
+++ test/Sema/builtin-ms-noop-errors.cpp
@@ -0,0 +1,85 @@
+// RUN: %clang_cc1 -fms-extensions -fdelayed-template-parsing -fms-compatibility -Wunused -verify %s
+
+class A {
+public:
+ ~A(){};
+};
+template<typename T> static A function1(int a) { sdklfj sdfjsd sdfksdf }
+template<typename T> static int function2() { fwedq rfgr dfgsdg }
+template<typename T> int function3(int a) { fwedq rfgr dfgsdg }
+int Z(){return 0;}
+int Z1(int){return 0;}
+void Z2(){}
+
+void D1() {
+ int var1, var2, var3, var4, var5, var6, var7, var8;
+ ((__noop))(function2<void>()); // expected-note{{'__noop' is a builtin with type 'int ()'}}
+ __noop(Z(), Z(), (function2<int>()), Z1(function2<int>()));
+ __noop(Z2());
+ __noop(function2<void>() + var1 + var2);
+ __noop(function1<int>(var3));
+ __noop(function2<int>() + Z1(var4) - function3<float>(var5));
+ __noop(function1<void>(function3<int>(__noop(var6 + function3<int>(var7)))));
+ __noop(function1<int>(Z1(var8)));
+}
+
+int D2() {
+ int arr[] = {9,8,7,6,5,4,3,2,1,0};
+ int T2 = arr[__noop() + 1];
+ int T3 = arr[__noop + 2];
+ return T2 + T3;
+}
+
+int D3() {
+ class A {};
+ int *A1 = __noop; // expected-warning{{expression which evaluates to zero treated as a null pointer constant of type 'int *'}}
+ int *A2 = __noop(); // expected-warning{{expression which evaluates to zero treated as a null pointer constant of type 'int *'}}
+ int *A3;
+ A3 = __noop; // expected-warning{{expression which evaluates to zero treated as a null pointer constant of type 'int *'}}
+ A3 = __noop(); // expected-warning{{expression which evaluates to zero treated as a null pointer constant of type 'int *'}}
+ int (*A4)() = __noop; // expected-warning{{expression which evaluates to zero treated as a null pointer constant of type 'int (*)()'}}
+ int (*A5)();
+ A5 = __noop; // expected-warning{{expression which evaluates to zero treated as a null pointer constant of type 'int (*)()'}}
+ void (*A6)();
+ A6 = __noop; // expected-warning{{expression which evaluates to zero treated as a null pointer constant of type 'void (*)()'}}
+ const int (*A7)(const float);
+ A7 = __noop(2); // expected-warning{{expression which evaluates to zero treated as a null pointer constant of type 'const int (*)(const float)'}}
+ void (A::*A8)();
+ A8 = __noop;
+ return A1[0] + A2[0] + A3[0] + A4() + A5();
+}
+
+void D4() {
+ int arr[10];
+ int T1 = arr[__noop(4 asdfasdf^*^&$^, 5) + __noop]; //expected-error{{expected ')'}} expected-note{{to match this '('}}
+ &__noop; // expected-error{{cannot take the address of an rvalue of type 'int'}}
+ &__noop(); // expected-error{{cannot take the address of an rvalue of type 'int'}}
+ int __noop() = 12; // expected-error{{conflicting types for '__noop'}}
+ int A = __noop[5]; // expected-error{{subscripted value is not an array, pointer, or vector}}
+ int __noop = 10;
+ int A1 = __noop(); // expected-error{{called object type 'int' is not a function or function pointer}}
+}
+
+int D5() {
+ int a1 = __noop(42, 56);
+ int a2 = __noop;
+ int a3; a3 = __noop(5);
+ int a4 = (__noop)();
+ int a5 = (__noop);
+ int a6 = (__noop());
+ int a7 = ((__noop)(5));
+ int a8 = ((__noop))();
+ return a1 + a2 + a3 + a4 + a5 + a6 + a7 + a8;
+}
+
+int D7() {
+ __noop;
+ __noop();
+ int T1 = __noop;
+ int T2 = __noop();
+ int __noop = 12;
+ int *A = &__noop;
+ int T3 = __noop;
+ int T4 = *A;
+ return T1 + T2 + T3 + T4;
+}
Index: test/CodeGen/builtin-ms-noop.cpp
===================================================================
--- test/CodeGen/builtin-ms-noop.cpp
+++ test/CodeGen/builtin-ms-noop.cpp
@@ -28,3 +28,9 @@
// CHECK: define i32 @i()
// CHECK: ret i32 1
}
+
+extern "C" void j() {
+ int *A = __noop;
+// CHECK: define void @j()
+// CHECK: store i32* null, i32** %A
+}
Index: include/clang/Basic/Builtins.def
===================================================================
--- include/clang/Basic/Builtins.def
+++ include/clang/Basic/Builtins.def
@@ -709,7 +709,7 @@
LANGBUILTIN(_InterlockedExchange, "LiLiD*Li", "n", ALL_MS_LANGUAGES)
LANGBUILTIN(_InterlockedExchangePointer, "v*v*D*v*", "n", ALL_MS_LANGUAGES)
LANGBUILTIN(_InterlockedIncrement, "LiLiD*", "n", ALL_MS_LANGUAGES)
-LANGBUILTIN(__noop, "i.", "n", ALL_MS_LANGUAGES)
+LANGBUILTIN(__noop, "i.", "tn", ALL_MS_LANGUAGES)
LANGBUILTIN(__readfsdword, "ULiULi", "n", ALL_MS_LANGUAGES)
LANGBUILTIN(__va_start, "vc**.", "nt", ALL_MS_LANGUAGES)
Index: include/clang/Sema/Sema.h
===================================================================
--- include/clang/Sema/Sema.h
+++ include/clang/Sema/Sema.h
@@ -6339,6 +6339,24 @@
/// to implement it anywhere else.
ActiveTemplateInstantiation LastTemplateInstantiationErrorContext;
+ /// \brief This indicator indicates if current parsing is doing
+ /// inside arguments of __noop builtin.
+ bool InsideNoop;
+
+ /// \brief RAII object used to change InsideNoop indicator.
+ class InsideNoopRAII {
+ Sema &Self;
+ bool OldInsideNoop;
+
+ public:
+ InsideNoopRAII(Sema &Self, bool NewInsideNoop)
+ : Self(Self), OldInsideNoop(Self.InsideNoop) {
+ Self.InsideNoop = NewInsideNoop || Self.InsideNoop;
+ }
+
+ ~InsideNoopRAII() { Self.InsideNoop = OldInsideNoop; }
+ };
+
/// \brief The current index into pack expansion arguments that will be
/// used for substitution of parameter packs.
///
Index: lib/Sema/SemaChecking.cpp
===================================================================
--- lib/Sema/SemaChecking.cpp
+++ lib/Sema/SemaChecking.cpp
@@ -332,6 +332,9 @@
if (checkArgCount(*this, TheCall, 1)) return true;
TheCall->setType(Context.IntTy);
break;
+ case Builtin::BI__noop:
+ TheCall->setType(Context.IntTy);
+ break;
case Builtin::BI__sync_fetch_and_add:
case Builtin::BI__sync_fetch_and_add_1:
case Builtin::BI__sync_fetch_and_add_2:
Index: lib/Sema/SemaExpr.cpp
===================================================================
--- lib/Sema/SemaExpr.cpp
+++ lib/Sema/SemaExpr.cpp
@@ -13048,7 +13048,12 @@
if (CXXMethodDecl *Method = dyn_cast<CXXMethodDecl>(E->getDecl()))
if (Method->isVirtual())
OdrUse = false;
- MarkExprReferenced(*this, E->getLocation(), E->getDecl(), E, OdrUse);
+ // If we are insidecall of __noop intrinsic we shouldn't match function as
+ // referenced. We do so not to instantiate template functions. However we
+ // should mark variables as usual to avoid warnings about unused variables.
+ // This behaviour is the same as Microsoft compiler behaviour.
+ if (!InsideNoop || !isa<FunctionDecl>(E->getDecl()))
+ MarkExprReferenced(*this, E->getLocation(), E->getDecl(), E, OdrUse);
}
/// \brief Perform reference-marking and odr-use handling for a MemberExpr.
Index: lib/Sema/Sema.cpp
===================================================================
--- lib/Sema/Sema.cpp
+++ lib/Sema/Sema.cpp
@@ -100,11 +100,11 @@
TUKind(TUKind),
NumSFINAEErrors(0),
AccessCheckingSFINAE(false), InNonInstantiationSFINAEContext(false),
- NonInstantiationEntries(0), ArgumentPackSubstitutionIndex(-1),
- CurrentInstantiationScope(nullptr), DisableTypoCorrection(false),
- TyposCorrected(0), AnalysisWarnings(*this), ThreadSafetyDeclCache(nullptr),
- VarDataSharingAttributesStack(nullptr), CurScope(nullptr),
- Ident_super(nullptr), Ident___float128(nullptr)
+ NonInstantiationEntries(0), InsideNoop(false),
+ ArgumentPackSubstitutionIndex(-1), CurrentInstantiationScope(nullptr),
+ DisableTypoCorrection(false), TyposCorrected(0), AnalysisWarnings(*this),
+ ThreadSafetyDeclCache(nullptr), VarDataSharingAttributesStack(nullptr),
+ CurScope(nullptr), Ident_super(nullptr), Ident___float128(nullptr)
{
TUScope = nullptr;
Index: lib/AST/ExprConstant.cpp
===================================================================
--- lib/AST/ExprConstant.cpp
+++ lib/AST/ExprConstant.cpp
@@ -6229,6 +6229,9 @@
default:
return ExprEvaluatorBaseTy::VisitCallExpr(E);
+ case Builtin::BI__noop:
+ return Success(0, E);
+
case Builtin::BI__builtin_object_size: {
if (TryEvaluateBuiltinObjectSize(E))
return true;
Index: lib/Parse/ParseExpr.cpp
===================================================================
--- lib/Parse/ParseExpr.cpp
+++ lib/Parse/ParseExpr.cpp
@@ -1454,6 +1454,17 @@
if (OpKind == tok::l_paren || !LHS.isInvalid()) {
if (Tok.isNot(tok::r_paren)) {
+ unsigned BuiltinId = 0;
+ if (LHS.isUsable()) {
+ Expr *Fn = LHS.get()->IgnoreParens();
+ if (DeclRefExpr *DRE = dyn_cast_or_null<DeclRefExpr>(Fn)) {
+ FunctionDecl *FnDecl =
+ dyn_cast_or_null<FunctionDecl>(DRE->getDecl());
+ BuiltinId = (FnDecl ? FnDecl->getBuiltinID() : 0);
+ }
+ }
+ Sema::InsideNoopRAII SubstIndex(Actions,
+ BuiltinId == Builtin::BI__noop);
if (ParseExpressionList(ArgExprs, CommaLocs, [&] {
Actions.CodeCompleteCall(getCurScope(), LHS.get(), ArgExprs);
})) {
_______________________________________________
cfe-commits mailing list
[email protected]
http://lists.cs.uiuc.edu/mailman/listinfo/cfe-commits