Index: include/clang/Basic/Builtins.def =================================================================== --- include/clang/Basic/Builtins.def +++ include/clang/Basic/Builtins.def @@ -710,7 +710,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 @@ -6446,6 +6446,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/AST/ExprConstant.cpp =================================================================== --- lib/AST/ExprConstant.cpp +++ lib/AST/ExprConstant.cpp @@ -6228,6 +6228,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 @@ -1468,6 +1468,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(Fn)) { + FunctionDecl *FnDecl = + dyn_cast_or_null(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); })) { Index: lib/Sema/Sema.cpp =================================================================== --- lib/Sema/Sema.cpp +++ lib/Sema/Sema.cpp @@ -101,11 +101,11 @@ NumSFINAEErrors(0), CachedFakeTopLevelModule(nullptr), 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/Sema/SemaChecking.cpp =================================================================== --- lib/Sema/SemaChecking.cpp +++ lib/Sema/SemaChecking.cpp @@ -337,6 +337,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 @@ -13227,6 +13227,13 @@ /// \brief Perform reference-marking and odr-use handling for a DeclRefExpr. void Sema::MarkDeclRefReferenced(DeclRefExpr *E) { + // If we are inside call of __noop intrinsic we shouldn't mark 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(E->getDecl())) + return; + // TODO: update this with DR# once a defect report is filed. // C++11 defect. The address of a pure member should not be an ODR use, even // if it's a qualified reference. Index: test/CodeGen/builtin-ms-noop.cpp =================================================================== --- test/CodeGen/builtin-ms-noop.cpp +++ test/CodeGen/builtin-ms-noop.cpp @@ -4,6 +4,8 @@ ~A() {} }; +int *p; + extern "C" int f() { // CHECK: define i32 @f() // CHECK-NOT: call void @_ZN1AD1Ev @@ -28,3 +30,9 @@ // CHECK: define i32 @i() // CHECK: ret i32 1 } + +extern "C" void j() { + p = __noop; +// CHECK: define void @j() +// CHECK: store i32* null, i32** @p +} 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,84 @@ +// RUN: %clang_cc1 -fms-extensions -fdelayed-template-parsing -fms-compatibility -Wunused -verify %s + +class A { +public: + ~A(){}; +}; +template static A function1(int a) { sdklfj sdfjsd sdfksdf } +template static int function2() { fwedq rfgr dfgsdg } +template 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()); + __noop(Z(), Z(), (function2()), Z1(function2())); + __noop(Z2()); + __noop(function2() + var1 + var2); + __noop(function1(var3)); + __noop(function2() + Z1(var4) - function3(var5)); + __noop(function1(function3(__noop(var6 + function3(var7))))); + __noop(function1(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 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; +}